[SCM] python-pyo/master: Imported Upstream version 0.7.4
tiago at users.alioth.debian.org
tiago at users.alioth.debian.org
Fri Jan 30 04:34:08 UTC 2015
The following commit has been merged in the master branch:
commit 6d35ddffd63e8b1287e09c3f32e1c3636ac4cef3
Author: Tiago Bortoletto Vaz <tiago at debian.org>
Date: Thu Jan 29 22:48:04 2015 -0500
Imported Upstream version 0.7.4
diff --git a/pyolib/COPYING.txt b/COPYING.txt
similarity index 100%
copy from pyolib/COPYING.txt
copy to COPYING.txt
diff --git a/ChangeLog b/ChangeLog
index ef1d32f..1e01dd5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,242 @@
+2015-01-29 belangeo <belangeo at gmail.com>
+
+ * Release tag: 0.7.4
+ - rev 1284
+
+2015-01-29 belangeo <belangeo at gmail.com>
+
+ * Added new function: floatmap, 0-1 range mapper. Fixed bug in DataTable initialization
+ and added an automatic refresh of the DataTable grapher window.
+ - rev 1282
+
+2015-01-26 belangeo <belangeo at gmail.com>
+
+ * Added new objet: Particle, a full control granular synthesis generator.
+ - rev 1281
+
+2015-01-24 belangeo <belangeo at gmail.com>
+
+ * Added setSync method to Granule object. Allow to toggle between synchronous
+ and asynchronous granulation. Added noteon and noteoff trigger streams to Notein
+ object.
+
+ - rev 1280
+
+2014-12-15 belangeo <belangeo at gmail.com>
+
+ * Added reset method to CtlScan and CtlScan2 objects.
+ - rev 1279
+
+2014-12-03 belangeo <belangeo at gmail.com>
+
+ * Added new objet: PeakAmp, a peak amplitude follower.
+ - rev 1277
+
+2014-11-27 belangeo <belangeo at gmail.com>
+
+ * Added reset method to Beat and Euclide objects.
+ - rev 1275
+
+-------------------------------------------------------------------------------------
+
+2014-10-17 belangeo <belangeo at gmail.com>
+
+ * Release tag: 0.7.3.
+ - rev 1273
+
+2014-11-15 belangeo <belangeo at gmail.com>
+
+ * Added new objet: Scope, an audio waveform display.
+ - rev 1270
+
+2014-11-12 belangeo <belangeo at gmail.com>
+
+ * E-Pyo: Fix marker's line numbering.
+ - rev 1267
+
+2014-11-08 belangeo <belangeo at gmail.com>
+
+ * E-Pyo: Added Save As Template... menu item.
+ - rev 1263
+
+2014-11-02 belangeo <belangeo at gmail.com>
+
+ * Fixed bug in Fader decreasing ramp.
+ - rev 1262
+
+2014-10-28 belangeo <belangeo at gmail.com>
+
+ * Added midi output methods to the Server object. noteout, afterout, ctlout, programout, pressout and bendout.
+ - rev 1261
+
+2014-10-28 belangeo <belangeo at gmail.com>
+
+ * Server.setMidiOutputDevice(idx) with `idx` greater than the higher portmidi devices index opens all available output devices.
+ - rev 1260
+
+2014-10-24 belangeo <belangeo at gmail.com>
+
+ * Added new object: FToM, converts an audio stream containning frequencies in hertz to a midi note audio stream.
+ - rev 1259
+
+2014-10-23 belangeo <belangeo at gmail.com>
+
+ * Added new function: hzToMidi, converts a frequency in hertz to a midi note value.
+ - rev 1258
+
+-------------------------------------------------------------------------------------
+
+2014-10-17 belangeo <belangeo at gmail.com>
+
+ * Release tag: 0.7.2.
+ - rev 1256
+
+2014-10-16 belangeo <belangeo at gmail.com>
+
+ * Server.setMidiInputDevice(idx) with `idx` greater than the higher portmidi input index opens all available devices.
+ - rev 1254
+
+2014-10-16 belangeo <belangeo at gmail.com>
+
+ * OSX installer: Also install pyo in anaconda site-packages directory if exist.
+ - rev 1253
+
+2014-10-16 belangeo <belangeo at gmail.com>
+
+ * Added new object : TrigBurst, generates a time/amplitude expandable trigger pattern.
+ - rev 1252
+
+2014-10-14 belangeo <belangeo at gmail.com>
+
+ * Added new object : Euclide, Euclidean rhythm generator.
+ - rev 1251
+
+2014-10-13 belangeo <belangeo at gmail.com>
+
+ * Windows installers now check for the current python installation directory before installing files.
+ - rev 1244 - 1250
+
+2014-10-10 belangeo <belangeo at gmail.com>
+
+ * E-Pyo: Fixed inconsistencies in Find/Replace behaviours.
+ - rev 1241
+
+2014-10-10 belangeo <belangeo at gmail.com>
+
+ * Added new object : SmoothDelay, a delay line that does not produce clicks or pitch shifting when the delay time is changing.
+ - rev 1239
+
+2014-10-08 belangeo <belangeo at gmail.com>
+
+ * Added new object : AttackDetector, audio signal onset detection.
+ - rev 1238
+
+2014-10-07 belangeo <belangeo at gmail.com>
+
+ * Added new object : Centroid, Computes the spectral centroid of an input signal.
+ - rev 1237
+
+-------------------------------------------------------------------------------------
+
+2014-08-29 belangeo <belangeo at gmail.com>
+
+ * Release tag: 0.7.1.
+ - rev 1236
+
+2014-09-12 belangeo <belangeo at gmail.com>
+
+ * E-Pyo: Added RadioPyo to the template choices.
+ - rev 1234
+
+2014-09-09 belangeo <belangeo at gmail.com>
+
+ * Fixed Compare when used with None or a string. Print a warning and set 'comp' attribute to 0.
+ - rev 1229
+
+2014-09-05 belangeo <belangeo at gmail.com>
+
+ * Fixed live interpreter of the server window when using arrow keys navigation.
+ - rev 1228
+
+2014-09-04 belangeo <belangeo at gmail.com>
+
+ * E-Pyo: Check if WxPython 3.0 is installed, otherwise uses 2.8.
+ - rev 1227
+
+2014-09-02 belangeo <belangeo at gmail.com>
+
+ * Added anti-aliasing to PyoTableObject's grapher widget. Fixed Ctrl+W on the grapher.
+ - rev 1225, 1226
+
+-------------------------------------------------------------------------------------
+
+2014-08-29 belangeo <belangeo at gmail.com>
+
+ * Release tag: 0.7.0.
+ - rev 1224
+
+2014-08-26 belangeo <belangeo at gmail.com>
+
+ * pyo can now be used without any GUI toolkit (WxPython or TKinter). Widgets are simply disabled.
+ - rev 1208
+
+2014-06-22 belangeo <belangeo at gmail.com>
+
+ * Added Server methods to auto-connect Jack ports to already opened ports.
+ - rev 1201
+
+2014-05-23 belangeo <belangeo at gmail.com>
+
+ * E-Pyo: output log now in realtime.
+ - rev 1197
+
+2014-04-24 belangeo <belangeo at gmail.com>
+
+ * Added new object: Tanh, hyperbolic tangent function on audio signal.
+ - rev 1188
+
+-------------------------------------------------------------------------------------
+
+2014-04-11 belangeo <belangeo at gmail.com>
+
+ * Release tag: 0.6.9.
+ - rev 1185
+
+2014-04-11 belangeo <belangeo at gmail.com>
+
+ * Added lot of methods to PyoTableObject (retify, bipolarGain, invert, lowpass, fadein, fadeout, pow).
+ - rev 1182
+
+2014-04-04 belangeo <belangeo at gmail.com>
+
+ * Added new object: PartialTable, generates waveforms made of inharmonic components.
+ - rev 1177
+
+2014-03-12 belangeo <belangeo at gmail.com>
+
+ * Added a Scope example in examples/utilities.
+ - rev 1168
+
+2013-12-24 belangeo <belangeo at gmail.com>
+
+ * Added new object: STRev, Stereo reverb.
+ - rev 1154
+
+2013-12-24 belangeo <belangeo at gmail.com>
+
+ * Added dataOnly argument to SLMap. User can now control parameters, in ctrl window, that do not accept audio signal but discreet values.
+ - rev 1153
+
+2013-12-10 belangeo <belangeo at gmail.com>
+
+ * Added new object: ComplexRes, Complex one-pole resonator filter.
+ - rev 1148
+
+2013-10-18 belangeo <belangeo at gmail.com>
+
+ * Added new object: TrackHold, Performs a 'thru' and hold on its input signal.
+ - rev 1143
+
-------------------------------------------------------------------------------------
2013-10-16 belangeo <belangeo at gmail.com>
diff --git a/doc-sphinx/build.py b/doc-sphinx/build.py
index fdcb309..50c9fe8 100644
--- a/doc-sphinx/build.py
+++ b/doc-sphinx/build.py
@@ -62,10 +62,8 @@ os.system("sphinx-build -a -b %s ./source %s" % (build_format, build_folder))
if build_format == "latex":
os.system("cd build_latex; pdflatex -interaction nonstopmode Pyo; pdflatex -interaction nonstopmode Pyo")
-else:
- # Upload on iACT server
- print "Upload documentation (y/n)?"
- ans = raw_input()
- if (ans == 'y'):
- os.system('scp -r %s/* sysop at 132.204.178.49:/Library/WebServer/Documents/pyo/manual-dev/' % build_folder)
+
+rep = raw_input("Do you want to upload to ajax server (y/n) ? ")
+if rep == "y":
+ os.system("scp -r build_html/* jeadum1 at ajaxsoundstudio.com:/home/jeadum1/ajaxsoundstudio.com/pyodoc")
diff --git a/doc-sphinx/source/about.rst b/doc-sphinx/source/about.rst
index 4add116..b7488f9 100644
--- a/doc-sphinx/source/about.rst
+++ b/doc-sphinx/source/about.rst
@@ -12,4 +12,4 @@ For questions and comments, please subscribe to the `pyo-discuss <http://groups.
To report a bug or to request a feature, use the `issues tracker <http://code.google.com/p/pyo/issues/list>`_ on googlecode.
Sources and binaries can be downloaded at:
-http://code.google.com/p/pyo/
+http://ajaxsoundstudio.com/software/pyo/
diff --git a/doc-sphinx/source/api/alphabetical.rst b/doc-sphinx/source/api/alphabetical.rst
index 3b2862b..a67b7d7 100644
--- a/doc-sphinx/source/api/alphabetical.rst
+++ b/doc-sphinx/source/api/alphabetical.rst
@@ -12,6 +12,7 @@ Alphabetical class reference
- :py:class:`Allpass` : Delay line based allpass filter.
- :py:class:`Atan2` : Computes the principal value of the arc tangent of b/a.
- :py:class:`Atone` : A first-order recursive high-pass filter with variable frequency response.
+- :py:class:`AttackDetector` : Audio signal onset detection.
- :py:class:`Average` : Moving average filter.
- :py:class:`Balance` : Adjust rms power of an audio signal according to the rms power of another.
- :py:class:`BandSplit` : Splits an input signal into multiple frequency bands.
@@ -30,6 +31,7 @@ Alphabetical class reference
- :py:class:`CallAfter` : Calls a Python function after a given time.
- :py:class:`CarToPol` : Performs the cartesian to polar conversion.
- :py:class:`Ceil` : Rounds to smallest integral value greater than or equal to the input signal.
+- :py:class:`Centroid` : Computes the spectral centroid of an input signal.
- :py:class:`CentsToTranspo` : Returns the transposition factor equivalent of a given cents value.
- :py:class:`Change` : Sends trigger that informs when input value has changed.
- :py:class:`ChebyTable` : Chebyshev polynomials of the first kind.
@@ -39,6 +41,7 @@ Alphabetical class reference
- :py:class:`Clip` : Clips a signal to a predefined limit.
- :py:class:`Cloud` : Generates random triggers.
- :py:class:`Compare` : Comparison object.
+- :py:class:`ComplexRes` : Complex one-pole resonator filter.
- :py:class:`Compress` : Reduces the dynamic range of an audio signal.
- :py:class:`ControlRead` : Reads control values previously stored in text files.
- :py:class:`ControlRec` : Records control values and writes them in a text file.
@@ -63,10 +66,12 @@ Alphabetical class reference
- :py:class:`Disto` : Arc tangent distortion.
- :py:class:`Dummy` : Dummy object used to perform arithmetics on PyoObject.
- :py:class:`EQ` : Equalizer filter.
+- :py:class:`Euclide` : Euclidean rhythm generator.
- :py:class:`ExpTable` : Construct a table from exponential interpolated segments.
- :py:class:`Expseg` : Trace a series of exponential segments between specified break-points.
- :py:class:`FFT` : Fast Fourier Transform.
- :py:class:`FM` : A simple frequency modulation generator.
+- :py:class:`FToM` : Returns the midi note equivalent to a frequency in Hz.
- :py:class:`Fader` : Fadein - fadeout envelope generator.
- :py:class:`Floor` : Rounds to largest integral value not greater than audio signal.
- :py:class:`Follower2` : Envelope follower with different attack and release times.
@@ -153,11 +158,15 @@ Alphabetical class reference
- :py:class:`PVVerb` : Spectral domain reverberation.
- :py:class:`Pan` : Cosinus panner with control on the spread factor.
- :py:class:`ParaTable` : Generates parabola window function.
+- :py:class:`PartialTable` : Inharmonic waveform generator.
+- :py:class:`Particle` : A full control granular synthesis generator.
- :py:class:`Pattern` : Periodically calls a Python function.
+- :py:class:`PeakAmp` : Peak amplitude follower.
- :py:class:`Percent` : Lets pass a certain percentage of the input triggers.
- :py:class:`Phaser` : Multi-stages second-order phase shifter allpass filters.
- :py:class:`Phasor` : A simple phase incrementor.
- :py:class:`PinkNoise` : A pink noise generator.
+- :py:class:`Pointer2` : High quality table reader with control on the pointer position.
- :py:class:`Pointer` : Table reader with control on the pointer position.
- :py:class:`PolToCar` : Performs the polar to cartesian conversion.
- :py:class:`Port` : Exponential portamento.
@@ -183,10 +192,12 @@ Alphabetical class reference
- :py:class:`SLMapPhase` : SLMap with normalized values for a 'phase' slider.
- :py:class:`SLMapQ` : SLMap with normalized values for a 'q' slider.
- :py:class:`SPan` : Simple equal power panner.
+- :py:class:`STRev` : Stereo reverb.
- :py:class:`SVF` : Fourth-order state variable filter allowing continuous change of the filter type.
- :py:class:`SampHold` : Performs a sample-and-hold operation on its input.
- :py:class:`SawTable` : Sawtooth waveform generator.
- :py:class:`Scale` : Maps an input range of audio values to an output range.
+- :py:class:`Scope` : Oscilloscope - audio waveform display.
- :py:class:`Score` : Calls functions by incrementation of a preformatted name.
- :py:class:`Select` : Sends trigger on matching integer values.
- :py:class:`Selector` : Audio selector.
@@ -200,6 +211,7 @@ Alphabetical class reference
- :py:class:`SincTable` : Generates sinc window function.
- :py:class:`SineLoop` : A simple sine wave oscillator with feedback.
- :py:class:`Sine` : A simple sine wave oscillator.
+- :py:class:`SmoothDelay` : Artifact free sweepable recursive delay.
- :py:class:`Snap` : Snap input values on a user's defined midi scale.
- :py:class:`SndTable` : Transfers data from a soundfile into a function table.
- :py:class:`Spectrum` : Spectrum analyzer and display.
@@ -215,11 +227,14 @@ Alphabetical class reference
- :py:class:`TableRec` : TableRec is for writing samples into a previously created NewTable.
- :py:class:`TableScale` : Scales all the values contained in a PyoTableObject.
- :py:class:`Tan` : Performs a tangent function on audio signal.
+- :py:class:`Tanh` : Performs a hyperbolic tangent function on audio signal.
- :py:class:`Thresh` : Informs when a signal crosses a threshold.
- :py:class:`Timer` : Reports elapsed time between two trigs.
- :py:class:`Tone` : A first-order recursive low-pass filter with variable frequency response.
- :py:class:`Touchin` : Get the current value of an after-touch Midi controller.
+- :py:class:`TrackHold` : Performs a track-and-hold operation on its input.
- :py:class:`TranspoToCents` : Returns the cents value equivalent of a transposition factor.
+- :py:class:`TrigBurst` : Generates a time/amplitude expandable trigger pattern.
- :py:class:`TrigChoice` : Random generator from user's defined values.
- :py:class:`TrigEnv` : Envelope reader generator.
- :py:class:`TrigExpseg` : Exponential segments trigger.
diff --git a/doc-sphinx/source/api/classes/analysis.rst b/doc-sphinx/source/api/classes/analysis.rst
index 233842a..6a94baa 100644
--- a/doc-sphinx/source/api/classes/analysis.rst
+++ b/doc-sphinx/source/api/classes/analysis.rst
@@ -33,3 +33,32 @@ can use them for controlling parameters of others objects.
.. autoclass:: Yin
:members:
+*Centroid*
+------------
+
+.. autoclass:: Centroid
+ :members:
+
+*AttackDetector*
+-----------------
+
+.. autoclass:: AttackDetector
+ :members:
+
+*Spectrum*
+-----------------------------------
+
+.. autoclass:: Spectrum
+ :members:
+
+*Scope*
+-----------------------------------
+
+.. autoclass:: Scope
+ :members:
+
+*PeakAmp*
+-----------------------------------
+
+.. autoclass:: PeakAmp
+ :members:
diff --git a/doc-sphinx/source/api/classes/arithmetic.rst b/doc-sphinx/source/api/classes/arithmetic.rst
index af5fc7f..757bdfc 100644
--- a/doc-sphinx/source/api/classes/arithmetic.rst
+++ b/doc-sphinx/source/api/classes/arithmetic.rst
@@ -23,6 +23,12 @@ Tools to perform arithmetic operations on audio signals.
.. autoclass:: Tan
:members:
+*Tanh*
+------------
+
+.. autoclass:: Tanh
+ :members:
+
*Abs*
------------
diff --git a/doc-sphinx/source/api/classes/dynamics.rst b/doc-sphinx/source/api/classes/dynamics.rst
index 0ac8200..cb68212 100644
--- a/doc-sphinx/source/api/classes/dynamics.rst
+++ b/doc-sphinx/source/api/classes/dynamics.rst
@@ -11,6 +11,12 @@ Objects to modify the dynamic range and sample quality of audio signals.
.. autoclass:: Clip
:members:
+*Degrade*
+----------
+
+.. autoclass:: Degrade
+ :members:
+
*Mirror*
------------
diff --git a/doc-sphinx/source/api/classes/effects.rst b/doc-sphinx/source/api/classes/effects.rst
index be32c61..25a3201 100644
--- a/doc-sphinx/source/api/classes/effects.rst
+++ b/doc-sphinx/source/api/classes/effects.rst
@@ -78,3 +78,15 @@ as distortions, delays, chorus and reverbs.
.. autoclass:: FreqShift
:members:
+*STRev*
+------------
+
+.. autoclass:: STRev
+ :members:
+
+*SmoothDelay*
+---------------
+
+.. autoclass:: SmoothDelay
+ :members:
+
diff --git a/doc-sphinx/source/api/classes/filters.rst b/doc-sphinx/source/api/classes/filters.rst
index 865fb9a..358744b 100644
--- a/doc-sphinx/source/api/classes/filters.rst
+++ b/doc-sphinx/source/api/classes/filters.rst
@@ -180,4 +180,9 @@ sinusoidal component according to its frequency.
.. autoclass:: ButBR
:members:
+*ComplexRes*
+------------
+
+.. autoclass:: ComplexRes
+ :members:
diff --git a/doc-sphinx/source/api/classes/fourier.rst b/doc-sphinx/source/api/classes/fourier.rst
index 148ea3d..1955415 100644
--- a/doc-sphinx/source/api/classes/fourier.rst
+++ b/doc-sphinx/source/api/classes/fourier.rst
@@ -51,12 +51,6 @@ spectral domain.
.. autoclass:: CvlVerb
:members:
-*Spectrum*
------------------------------------
-
-.. autoclass:: Spectrum
- :members:
-
*Vectral*
-----------------------------------
diff --git a/doc-sphinx/source/api/classes/tableprocess.rst b/doc-sphinx/source/api/classes/tableprocess.rst
index 3ad98e6..c883866 100644
--- a/doc-sphinx/source/api/classes/tableprocess.rst
+++ b/doc-sphinx/source/api/classes/tableprocess.rst
@@ -56,12 +56,24 @@ store audio samples or algorithmic sequences for future uses.
.. autoclass:: OscTrig
:members:
+*Particle*
+-----------------------------------
+
+.. autoclass:: Particle
+ :members:
+
*Pointer*
-----------------------------------
.. autoclass:: Pointer
:members:
+*Pointer2*
+-----------------------------------
+
+.. autoclass:: Pointer2
+ :members:
+
*Pulsar*
-----------------------------------
diff --git a/doc-sphinx/source/api/classes/tables.rst b/doc-sphinx/source/api/classes/tables.rst
index 569743b..1891218 100644
--- a/doc-sphinx/source/api/classes/tables.rst
+++ b/doc-sphinx/source/api/classes/tables.rst
@@ -78,6 +78,12 @@ in memory and access them quickly.
.. autoclass:: ParaTable
:members:
+*PartialTable*
+-----------------------------------
+
+.. autoclass:: PartialTable
+ :members:
+
*SawTable*
-----------------------------------
diff --git a/doc-sphinx/source/api/classes/triggers.rst b/doc-sphinx/source/api/classes/triggers.rst
index 778d1d9..917c802 100644
--- a/doc-sphinx/source/api/classes/triggers.rst
+++ b/doc-sphinx/source/api/classes/triggers.rst
@@ -40,6 +40,12 @@ processes with sample rate timing accuracy.
.. autoclass:: Counter
:members:
+*Euclide*
+-----------------------------------
+
+.. autoclass:: Euclide
+ :members:
+
*Iter*
-----------------------------------
@@ -94,6 +100,12 @@ processes with sample rate timing accuracy.
.. autoclass:: Trig
:members:
+*TrigBurst*
+-----------------------------------
+
+.. autoclass:: TrigBurst
+ :members:
+
*TrigChoice*
-----------------------------------
diff --git a/doc-sphinx/source/api/classes/utils.rst b/doc-sphinx/source/api/classes/utils.rst
index 58ebb12..c84bbab 100644
--- a/doc-sphinx/source/api/classes/utils.rst
+++ b/doc-sphinx/source/api/classes/utils.rst
@@ -125,3 +125,9 @@ Miscellaneous objects.
.. autoclass:: TranspoToCents
:members:
+*TrackHold*
+-----------------------------------
+
+.. autoclass:: TrackHold
+ :members:
+
diff --git a/doc-sphinx/source/api/functions/audio.rst b/doc-sphinx/source/api/functions/audio.rst
index d9b36ec..eeff482 100644
--- a/doc-sphinx/source/api/functions/audio.rst
+++ b/doc-sphinx/source/api/functions/audio.rst
@@ -3,6 +3,16 @@ Audio Setup
.. module:: pyo
+*pa_get_version*
+---------------------------------
+
+.. autofunction:: pa_get_version
+
+*pa_get_version_text*
+---------------------------------
+
+.. autofunction:: pa_get_version_text
+
*pa_count_host_apis*
---------------------------------
diff --git a/doc-sphinx/source/api/functions/conv.rst b/doc-sphinx/source/api/functions/conv.rst
index ec0273c..9261abd 100644
--- a/doc-sphinx/source/api/functions/conv.rst
+++ b/doc-sphinx/source/api/functions/conv.rst
@@ -33,6 +33,11 @@ Conversions
.. autofunction:: rescale(data, xmin=0.0, xmax=1.0, ymin=0.0, ymax=1.0, xlog=False, ylog=False)
+*floatmap*
+---------------------------------
+
+.. autofunction:: floatmap(x, min=0.0, max=1.0, exp=1.0)
+
*distanceToSegment*
---------------------------------
diff --git a/doc-sphinx/source/compiling.rst b/doc-sphinx/source/compiling.rst
index 78adfb0..b984826 100644
--- a/doc-sphinx/source/compiling.rst
+++ b/doc-sphinx/source/compiling.rst
@@ -9,26 +9,25 @@ Dependencies
To compile pyo, you will need the following dependencies:
- `Python 2.6 or 2.7 <http://www.python.org/download/releases/>`_
+- `WxPython 3.0 <http://www.wxpython.org/download.php/>`_
- `Portaudio <http://www.portaudio.com/>`_
- `Portmidi <http://portmedia.sourceforge.net/portmidi/>`_
- `libsndfile <http://www.mega-nerd.com/libsndfile/>`_
- `liblo <http://liblo.sourceforge.net/>`_
+Under Mac OS X, you can use Homebrew to retrieve necessary dependency librairies and headers (except for wxpython 3.0) to compile pyo.
-Under Mac OS X, to retrieve necessary dependency librairies and headers to compile pyo, you can run the "get_dependencies.sh" script from the scripts folder in pyo sources, it will download them to /usr/local/lib and /usr/local/include directory.
-
-For i386 architecture (32-bit python):
+First, install Homebrew with this command:
.. code-block:: bash
- sh scripts/get_dependencies.sh
+ ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"
-For i386/x86_64 architectures (64-bit python):
+Then, install packages:
.. code-block:: bash
- sh scripts/get_dependencies_x86_64.sh
-
+ brew install python liblo libsndfile portaudio portmidi --universal
Getting sources
-------------------
@@ -135,7 +134,7 @@ Under OS X, it is very simple to build pyo from sources with the Homebrew packag
.. code-block:: bash
- brew install python liblo libsndfile portaudio portmidi
+ brew install python liblo libsndfile portaudio portmidi --universal
svn checkout http://pyo.googlecode.com/svn/trunk/ pyo
cd pyo
python setup.py install --use-coreaudio --use-double
diff --git a/doc-sphinx/source/conf.py b/doc-sphinx/source/conf.py
index 55ad51d..c2779e5 100644
--- a/doc-sphinx/source/conf.py
+++ b/doc-sphinx/source/conf.py
@@ -12,6 +12,7 @@
# serve to show the default.
import sys, os
+from pyo import PYO_VERSION
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@@ -42,16 +43,16 @@ master_doc = 'index'
# General information about the project.
project = u'Pyo'
-copyright = u'2013, Olivier Bélanger'
+copyright = u'2014, Olivier Bélanger'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
-version = '0.6.8'
+version = PYO_VERSION
# The full version, including alpha/beta/rc tags.
-release = '0.6.8'
+release = PYO_VERSION
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/doc-sphinx/source/download.rst b/doc-sphinx/source/download.rst
index fdf63a4..fb5024b 100644
--- a/doc-sphinx/source/download.rst
+++ b/doc-sphinx/source/download.rst
@@ -1,8 +1,8 @@
Downloading
=================
-Installers are available for Windows (XP, Vista, 7, 8) and for Max OS X (from 10.5 to 10.8).
+Installers are available for Windows (Win 7/8) and for Max OS X (from 10.6 to 10.9).
-To download the latest pre-compiled version of pyo, go to the pyo's googlecode `download <http://code.google.com/p/pyo/downloads/list>`_ page.
+To download the latest pre-compiled version of pyo, go to the pyo's `web page <http://ajaxsoundstudio.com/software/pyo/>`_.
Under Debian distros, you can get pyo from the package manager. The library's name is **python-pyo**.
diff --git a/doc-sphinx/source/index.rst b/doc-sphinx/source/index.rst
index abf1888..d2de0de 100644
--- a/doc-sphinx/source/index.rst
+++ b/doc-sphinx/source/index.rst
@@ -3,7 +3,7 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
-Welcome to the Pyo 0.6.8 documentation
+Welcome to the Pyo 0.7.4 documentation
===================================================
.. toctree::
diff --git a/doc-sphinx/source/tutorials/pyoobject2.rst b/doc-sphinx/source/tutorials/pyoobject2.rst
index db3db1c..3b31ba5 100644
--- a/doc-sphinx/source/tutorials/pyoobject2.rst
+++ b/doc-sphinx/source/tutorials/pyoobject2.rst
@@ -30,7 +30,7 @@ First of all, we need to import the pyo module
Step 1 - Declaring the class
------------------------------
-We will create a new class called RingMod with PyoObject as its parent class.
+We will create a new class called Flanger with PyoObject as its parent class.
Another good habit is to put a __doc__ string at the beginning of our classes.
Doing so will allow other users to retrieve the object's documentation with the
standard python help() function.
diff --git a/embedded/m_pyo.h b/embedded/m_pyo.h
new file mode 100644
index 0000000..c0a5235
--- /dev/null
+++ b/embedded/m_pyo.h
@@ -0,0 +1,312 @@
+#include <stdlib.h>
+#include "Python.h"
+
+#ifndef __m_pyo_h_
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+extern "C" {
+#endif
+
+/*
+** Creates a new python interpreter and starts a pyo server in it.
+** Each instance of pyo, in order to be fully independent of other
+** instances, must be started in its own interpreter. An instance
+** can be an object in a programming language or a plugin in a daw.
+**
+** arguments:
+** chnls : int, number of in/out channels of the pyo server.
+**
+** returns the new python thread's interpreter state.
+*/
+inline PyThreadState * pyo_new_interpreter(int chnls) {
+ char msg[64];
+ PyThreadState *interp;
+ if(!Py_IsInitialized()) {
+ Py_Initialize();
+ PyEval_InitThreads();
+ PyEval_ReleaseLock();
+ }
+ PyEval_AcquireLock(); /* get the GIL */
+ interp = Py_NewInterpreter(); /* add a new sub-interpreter */
+ PyRun_SimpleString("from pyo import *");
+ sprintf(msg, "_s_ = Server(44100, %d, 256, 1, 'embedded')", chnls);
+ PyRun_SimpleString(msg);
+ PyRun_SimpleString("_s_.boot()\n_s_.start()\n_s_.setServer()");
+ PyRun_SimpleString("_in_address_ = _s_.getInputAddr()");
+ PyRun_SimpleString("_out_address_ = _s_.getOutputAddr()");
+ PyRun_SimpleString("_server_id_ = _s_.getServerID()");
+ PyRun_SimpleString("_emb_callback_ = _s_.getEmbedICallbackAddr()");
+ PyEval_ReleaseThread(interp);
+ return interp;
+}
+
+/*
+** Returns the address, as unsigned long, of the pyo input buffer.
+** Used this function if pyo's audio samples resolution is 32-bit.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long" that should be recast to a float pointer.
+*/
+inline unsigned long pyo_get_input_buffer_address(PyThreadState *interp) {
+ PyObject *module, *obj;
+ char *address;
+ unsigned long uadd;
+ PyEval_AcquireThread(interp);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_in_address_");
+ address = PyString_AsString(obj);
+ uadd = strtoul(address, NULL, 0);
+ PyEval_ReleaseThread(interp);
+ return uadd;
+}
+
+/*
+** Returns the address, as unsigned long long, of the pyo input buffer.
+** Used this function if pyo's audio samples resolution is 64-bit.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long long" that should be recast to a double pointer.
+*/
+inline unsigned long long pyo_get_input_buffer_address_64(PyThreadState *interp) {
+ PyObject *module, *obj;
+ char *address;
+ unsigned long long uadd;
+ PyEval_AcquireThread(interp);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_in_address_");
+ address = PyString_AsString(obj);
+ uadd = strtoull(address, NULL, 0);
+ PyEval_ReleaseThread(interp);
+ return uadd;
+}
+
+/*
+** Returns the address, as unsigned long, of the pyo output buffer.
+** Used this function if pyo's audio samples resolution is 32-bit.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long" that should be recast to a float pointer.
+*/
+inline unsigned long pyo_get_output_buffer_address(PyThreadState *interp) {
+ PyObject *module, *obj;
+ char *address;
+ unsigned long uadd;
+ PyEval_AcquireThread(interp);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_out_address_");
+ address = PyString_AsString(obj);
+ uadd = strtoul(address, NULL, 0);
+ PyEval_ReleaseThread(interp);
+ return uadd;
+}
+
+/*
+** Returns the address, as unsigned long, of the pyo embedded callback.
+** This callback must be called in the host's perform routine whenever
+** pyo has to compute a new buffer of samples.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long" that should be recast to a void pointer.
+**
+** The callback should be called with the server id (int) as argument.
+**
+** Prototype:
+** void (*callback)(int);
+*/
+inline unsigned long pyo_get_embedded_callback_address(PyThreadState *interp) {
+ PyObject *module, *obj;
+ char *address;
+ unsigned long uadd;
+ PyEval_AcquireThread(interp);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_emb_callback_");
+ address = PyString_AsString(obj);
+ uadd = strtoul(address, NULL, 0);
+ PyEval_ReleaseThread(interp);
+ return uadd;
+}
+
+/*
+** Returns the pyo server id of this thread, as an integer.
+** The id must be pass as argument to the callback function.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an integer.
+*/
+inline int pyo_get_server_id(PyThreadState *interp) {
+ PyObject *module, *obj;
+ int id;
+ PyEval_AcquireThread(interp);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_server_id_");
+ id = PyInt_AsLong(obj);
+ PyEval_ReleaseThread(interp);
+ return id;
+}
+
+/*
+** Closes the interpreter linked to the thread state given as argument.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+*/
+inline void pyo_end_interpreter(PyThreadState *interp) {
+ PyEval_AcquireThread(interp);
+ Py_EndInterpreter(interp);
+ PyEval_ReleaseLock();
+}
+
+/*
+** Shutdown and reboot the pyo server while keeping current in/out buffers.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+*/
+inline void pyo_server_reboot(PyThreadState *interp) {
+ PyEval_AcquireThread(interp);
+ PyRun_SimpleString("_s_.setServer()\n_s_.stop()\n_s_.shutdown()");
+ PyRun_SimpleString("_s_.boot(newBuffer=False).start()");
+ PyEval_ReleaseThread(interp);
+}
+
+/*
+** Reboot the pyo server with new sampling rate and buffer size.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+** sr : float, host sampling rate.
+** bufsize : int, host buffer size.
+*/
+inline void pyo_set_server_params(PyThreadState *interp, float sr, int bufsize) {
+ char msg[64];
+ PyEval_AcquireThread(interp);
+ PyRun_SimpleString("_s_.setServer()\n_s_.stop()\n_s_.shutdown()");
+ sprintf(msg, "_s_.setSamplingRate(%f)", sr);
+ PyRun_SimpleString(msg);
+ sprintf(msg, "_s_.setBufferSize(%d)", bufsize);
+ PyRun_SimpleString(msg);
+ PyRun_SimpleString("_s_.boot(newBuffer=False).start()");
+ PyEval_ReleaseThread(interp);
+}
+
+/*
+** Returns 1 if the pyo server is started for the given thread,
+** Otherwise returns 0.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+*/
+inline int pyo_is_server_started(PyThreadState *interp) {
+ int started;
+ PyObject *module, *obj;
+ PyEval_AcquireThread(interp);
+ PyRun_SimpleString("started = _s_.getIsStarted()");
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "started");
+ started = PyInt_AsLong(obj);
+ PyEval_ReleaseThread(interp);
+ return started;
+}
+
+/*
+** Execute a python script "file" in the given thread's interpreter (interp).
+** A pre-allocated string "msg" must be given to create the python command
+** used for error handling. An integer "add" is needed to indicate if the
+** pyo server should be reboot or not.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+** file : char *, filename to execute as a python script. The file is first
+** searched in the current working directory. If not found,
+** the module will try to open it as an absolute path.
+** msg : char *, pre-allocated string used to create the python command
+** used for error handling.
+** add, int, if positive, the commands in the file will be added to whatever
+** is already running in the pyo server. If 0, the server will be
+** shutdown and reboot before executing the file.
+*/
+inline int pyo_exec_file(PyThreadState *interp, const char *file, char *msg, int add) {
+ int ok, err = 0;
+ PyObject *module, *obj;
+ PyEval_AcquireThread(interp);
+ sprintf(msg, "import os\n_ok_ = os.path.isfile('./%s')", file);
+ PyRun_SimpleString(msg);
+ sprintf(msg, "if not _ok_:\n _ok_ = os.path.isfile('%s')", file);
+ PyRun_SimpleString(msg);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_ok_");
+ ok = PyInt_AsLong(obj);
+ if (ok) {
+ sprintf(msg, "try:\n execfile('./%s')\nexcept:\n execfile('%s')",
+ file, file);
+ if (!add) {
+ PyRun_SimpleString("_s_.setServer()\n_s_.stop()\n_s_.shutdown()");
+ PyRun_SimpleString("_s_.boot(newBuffer=False).start()");
+ }
+ PyRun_SimpleString(msg);
+ }
+ else
+ err = 1;
+ PyEval_ReleaseThread(interp);
+ return err;
+}
+
+/*
+** Execute a python statement "msg" in the thread's interpreter "interp".
+** If "debug" is true, the statement will be executed in a try - except
+** block. The error message, if any, will be write back in the *msg
+** pointer and the function will return 1. If no error occured, the
+** function returned 0. If debug is false, the statement is executed
+** without any error checking (unsafe but faster).
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+** msg : char *, pointer to a string containing the statement to execute.
+** In debug mode, if an error occured, the output log will
+** be write back in this string.
+** debug, int, if positive, the commands will be executed in a try-except
+** statement. If 0, there will be no error checking, which is
+** much faster.
+*/
+inline int pyo_exec_statement(PyThreadState *interp, char *msg, int debug) {
+ int err = 0;
+ if (debug) {
+ PyObject *module, *obj;
+ char pp[26] = "_error_=None\ntry:\n ";
+ memmove(msg + strlen(pp), msg, strlen(msg)+1);
+ memmove(msg, pp, strlen(pp));
+ strcat(msg, "\nexcept Exception, _e_:\n _error_=str(_e_)");
+ PyEval_AcquireThread(interp);
+ PyRun_SimpleString(msg);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_error_");
+ if (obj != Py_None) {
+ strcpy(msg, PyString_AsString(obj));
+ err = 1;
+ }
+ PyEval_ReleaseThread(interp);
+ }
+ else {
+ PyEval_AcquireThread(interp);
+ PyRun_SimpleString(msg);
+ PyEval_ReleaseThread(interp);
+ }
+ return err;
+}
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
+
+#define __m_pyo_h_
+#endif /* __m_pyo_h_ */
diff --git a/embedded/openframeworks/PyoClass.cpp b/embedded/openframeworks/PyoClass.cpp
new file mode 100644
index 0000000..972541c
--- /dev/null
+++ b/embedded/openframeworks/PyoClass.cpp
@@ -0,0 +1,204 @@
+#include "PyoClass.h"
+
+/*
+** Creates a python interpreter and initialize a pyo server inside it.
+** This function must be called, once per Pyo object, before any other
+** calls.
+**
+** arguments:
+** nChannels : int, number of in/out channels.
+** bufferSize : int, number of samples per buffer.
+** sampleRate : int, sample rate frequency.
+**
+** All arguments should be equal to the host audio settings.
+*/
+void Pyo::setup(int _nChannels, int _bufferSize, int _sampleRate) {
+ nChannels = _nChannels;
+ bufferSize = _bufferSize;
+ sampleRate = _sampleRate;
+ interpreter = pyo_new_interpreter(nChannels);
+ pyoInBuffer = reinterpret_cast<float*>(pyo_get_input_buffer_address(interpreter));
+ pyoOutBuffer = reinterpret_cast<float*>(pyo_get_output_buffer_address(interpreter));
+ pyoCallback = reinterpret_cast<callPtr*>(pyo_get_embedded_callback_address(interpreter));
+ pyoId = pyo_get_server_id(interpreter);
+ pyo_set_server_params(interpreter, sampleRate, bufferSize);
+}
+
+/*
+** Terminates this object's interpreter.
+*/
+Pyo::~Pyo() {
+ pyo_end_interpreter(interpreter);
+}
+
+/*
+** This function fills pyo's input buffers with new samples. Should be called
+** once per process block, inside the host's audioIn function.
+**
+** arguments:
+** *buffer : float *, float pointer pointing to the host's input buffers.
+*/
+void Pyo::fillin(float *buffer) {
+ for (int i=0; i<(bufferSize*nChannels); i++) pyoInBuffer[i] = buffer[i];
+}
+
+
+/*
+** This function tells pyo to process a buffer of samples and fills the host's
+** output buffer with new samples. Should be called once per process block,
+** inside the host's audioOut function.
+**
+** arguments:
+** *buffer : float *, float pointer pointing to the host's output buffers.
+*/
+void Pyo::process(float *buffer) {
+ pyoCallback(pyoId);
+ for (int i=0; i<(bufferSize*nChannels); i++) buffer[i] = pyoOutBuffer[i];
+}
+
+/*
+** Execute a python script "file" in the objectès thread's interpreter.
+** An integer "add" is needed to indicate if the pyo server should be
+** reboot or not.
+**
+** arguments:
+** file : char *, filename to execute as a python script. The file is first
+** searched in the current working directory. If not found,
+** the module will try to open it as an absolute path.
+** add, int, if positive, the commands in the file will be added to whatever
+** is already running in the pyo server. If 0, the server will be
+** shutdown and reboot before executing the file.
+*/
+int Pyo::loadfile(const char *file, int add) {
+ return pyo_exec_file(interpreter, file, pyoMsg, add);
+}
+
+/*
+** Sends a numerical value to an existing Sig or SigTo object.
+**
+** arguments:
+** name : const char *, variable name of the object.
+** value : float, value to be assign.
+**
+** Example:
+**
+** inside the script file:
+**
+** freq = SigTo(value=440, time=0.1, init=440)
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** pyo.value("freq", 880);
+*/
+int Pyo::value(const char *name, float value) {
+ sprintf(pyoMsg, "%s.value=%f", name, value);
+ return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Sends an array of numerical values to an existing Sig or SigTo object.
+**
+** arguments:
+** name : const char *, variable name of the object.
+** value : float *, array of floats.
+** len : int, number of elements in the array.
+**
+** Example:
+**
+** inside the script file:
+**
+** freq = SigTo(value=[100,200,300,400], time=0.1, init=[100,200,300,400])
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** float frequencies[4] = {150, 250, 350, 450};
+** pyo.value("freq", frequencies, 4);
+*/
+int Pyo::value(const char *name, float *value, int len) {
+ char fchar[32];
+ sprintf(pyoMsg, "%s.value=[", name);
+ for (int i=0; i<len; i++) {
+ sprintf(fchar, "%f,", value[i]);
+ strcat(pyoMsg, fchar);
+ }
+ strcat(pyoMsg, "]");
+ return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Sends a numerical value to a Pyo object's attribute.
+**
+** arguments:
+** name : const char *, object name and attribute separated by a point.
+** value : float, value to be assign.
+**
+** Example:
+**
+** inside the script file:
+**
+** filter = Biquad(input=Noise(0.5), freq=1000, q=4, type=2)
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** pyo.set("filter.freq", 2000);
+*/
+int Pyo::set(const char *name, float value) {
+ sprintf(pyoMsg, "%s=%f", name, value);
+ return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Sends an array of numerical values to a Pyo object's attribute.
+**
+** arguments:
+** name : const char *, object name and attribute separated by a point.
+** value : float *, array of floats.
+** len : int, number of elements in the array.
+**
+** Example:
+**
+** inside the script file:
+**
+** filters = Biquad(input=Noise(0.5), freq=[250, 500, 1000, 2000], q=5, type=2)
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** float frequencies[4] = {350, 700, 1400, 2800};
+** pyo.set("filters.freq", frequencies, 4);
+*/
+int Pyo::set(const char *name, float *value, int len) {
+ char fchar[32];
+ sprintf(pyoMsg, "%s=[", name);
+ for (int i=0; i<len; i++) {
+ sprintf(fchar, "%f,", value[i]);
+ strcat(pyoMsg, fchar);
+ }
+ strcat(pyoMsg, "]");
+ return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Executes any raw valid python statement. With this function, one can dynamically
+** creates and manipulates audio objects and algorithms.
+**
+** arguments:
+** msg : const char *, pointer to a string containing the statement to execute.
+**
+** Example (for a Pyo object named `pyo`):
+**
+** pyo.exec("pits = [0.001, 0.002, 0.003, 0.004]")
+** pyo.exec("fr = Rossler(pitch=pits, chaos=0.9, mul=250, add=500)")
+** pyo.exec("b = SumOsc(freq=fr, ratio=0.499, index=0.4, mul=0.2).out()")
+*/
+int Pyo::exec(const char *_msg) {
+ strcpy(pyoMsg, _msg);
+ return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Shutdown and reboot the pyo server while keeping current in/out buffers.
+** This will erase audio objects currently active within the server.
+**
+*/void Pyo::clear() {
+ pyo_server_reboot(interpreter);
+}
diff --git a/embedded/openframeworks/PyoClass.h b/embedded/openframeworks/PyoClass.h
new file mode 100644
index 0000000..2ca65b4
--- /dev/null
+++ b/embedded/openframeworks/PyoClass.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "m_pyo.h"
+
+typedef int callPtr(int);
+
+class Pyo {
+ public:
+ ~Pyo();
+ void setup(int nChannels, int bufferSize, int sampleRate);
+ void process(float *buffer);
+ void fillin(float *buffer);
+ void clear();
+ int loadfile(const char *file, int add);
+ int exec(const char *msg);
+ int value(const char *name, float value);
+ int value(const char *name, float *value, int len);
+ int set(const char *name, float value);
+ int set(const char *name, float *value, int len);
+
+ private:
+ int nChannels;
+ int bufferSize;
+ int sampleRate;
+ PyThreadState *interpreter;
+ float *pyoInBuffer;
+ float *pyoOutBuffer;
+ callPtr *pyoCallback;
+ int pyoId;
+ char pyoMsg[262144];
+};
diff --git a/embedded/openframeworks/PyoTemplate/Makefile b/embedded/openframeworks/PyoTemplate/Makefile
new file mode 100644
index 0000000..7a7fe8b
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/Makefile
@@ -0,0 +1,13 @@
+# Attempt to load a config.make file.
+# If none is found, project defaults in config.project.make will be used.
+ifneq ($(wildcard config.make),)
+ include config.make
+endif
+
+# make sure the the OF_ROOT location is defined
+ifndef OF_ROOT
+ OF_ROOT=../../..
+endif
+
+# call the project makefile!
+include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk
diff --git a/embedded/openframeworks/PyoTemplate/config.make b/embedded/openframeworks/PyoTemplate/config.make
new file mode 100644
index 0000000..2a5b520
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/config.make
@@ -0,0 +1,141 @@
+################################################################################
+# CONFIGURE PROJECT MAKEFILE (optional)
+# This file is where we make project specific configurations.
+################################################################################
+
+################################################################################
+# OF ROOT
+# The location of your root openFrameworks installation
+# (default) OF_ROOT = ../../..
+################################################################################
+# OF_ROOT = ../../..
+
+################################################################################
+# PROJECT ROOT
+# The location of the project - a starting place for searching for files
+# (default) PROJECT_ROOT = . (this directory)
+#
+################################################################################
+# PROJECT_ROOT = .
+
+################################################################################
+# PROJECT SPECIFIC CHECKS
+# This is a project defined section to create internal makefile flags to
+# conditionally enable or disable the addition of various features within
+# this makefile. For instance, if you want to make changes based on whether
+# GTK is installed, one might test that here and create a variable to check.
+################################################################################
+# None
+
+################################################################################
+# PROJECT EXTERNAL SOURCE PATHS
+# These are fully qualified paths that are not within the PROJECT_ROOT folder.
+# Like source folders in the PROJECT_ROOT, these paths are subject to
+# exlclusion via the PROJECT_EXLCUSIONS list.
+#
+# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank)
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXTERNAL_SOURCE_PATHS =
+
+################################################################################
+# PROJECT EXCLUSIONS
+# These makefiles assume that all folders in your current project directory
+# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations
+# to look for source code. The any folders or files that match any of the
+# items in the PROJECT_EXCLUSIONS list below will be ignored.
+#
+# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete
+# string unless teh user adds a wildcard (%) operator to match subdirectories.
+# GNU make only allows one wildcard for matching. The second wildcard (%) is
+# treated literally.
+#
+# (default) PROJECT_EXCLUSIONS = (blank)
+#
+# Will automatically exclude the following:
+#
+# $(PROJECT_ROOT)/bin%
+# $(PROJECT_ROOT)/obj%
+# $(PROJECT_ROOT)/%.xcodeproj
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXCLUSIONS =
+
+################################################################################
+# PROJECT LINKER FLAGS
+# These flags will be sent to the linker when compiling the executable.
+#
+# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs
+#
+# Note: Leave a leading space when adding list items with the += operator
+#
+# Currently, shared libraries that are needed are copied to the
+# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to
+# add a runtime path to search for those shared libraries, since they aren't
+# incorporated directly into the final executable application binary.
+################################################################################
+PROJECT_LDFLAGS = `python-config --ldflags`
+
+################################################################################
+# PROJECT DEFINES
+# Create a space-delimited list of DEFINES. The list will be converted into
+# CFLAGS with the "-D" flag later in the makefile.
+#
+# (default) PROJECT_DEFINES = (blank)
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_DEFINES =
+
+################################################################################
+# PROJECT CFLAGS
+# This is a list of fully qualified CFLAGS required when compiling for this
+# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS
+# defined in your platform specific core configuration files. These flags are
+# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below.
+#
+# (default) PROJECT_CFLAGS = (blank)
+#
+# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in
+# your platform specific configuration file will be applied by default and
+# further flags here may not be needed.
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+PROJECT_CFLAGS = `python-config --cflags`
+
+################################################################################
+# PROJECT OPTIMIZATION CFLAGS
+# These are lists of CFLAGS that are target-specific. While any flags could
+# be conditionally added, they are usually limited to optimization flags.
+# These flags are added BEFORE the PROJECT_CFLAGS.
+#
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets.
+#
+# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank)
+#
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets.
+#
+# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank)
+#
+# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the
+# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration
+# file will be applied by default and further optimization flags here may not
+# be needed.
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE =
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG =
+
+################################################################################
+# PROJECT COMPILERS
+# Custom compilers can be set for CC and CXX
+# (default) PROJECT_CXX = (blank)
+# (default) PROJECT_CC = (blank)
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_CXX =
+# PROJECT_CC =
diff --git a/embedded/openframeworks/PyoTemplate/scripts/stereoDelay.py b/embedded/openframeworks/PyoTemplate/scripts/stereoDelay.py
new file mode 100644
index 0000000..0d98f4e
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/scripts/stereoDelay.py
@@ -0,0 +1,5 @@
+# Get the input sound and apply a stereo delay + reverb on it.
+st_input = Input([0,1])
+st_delay = Delay(st_input, delay=[.4, .5], feedback=0.7)
+st_rev = WGVerb(st_delay, feedback=0.8, cutoff=4000, bal=0.25).out()
+
diff --git a/embedded/openframeworks/PyoTemplate/src/PyoClass.cpp b/embedded/openframeworks/PyoTemplate/src/PyoClass.cpp
new file mode 100644
index 0000000..972541c
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/src/PyoClass.cpp
@@ -0,0 +1,204 @@
+#include "PyoClass.h"
+
+/*
+** Creates a python interpreter and initialize a pyo server inside it.
+** This function must be called, once per Pyo object, before any other
+** calls.
+**
+** arguments:
+** nChannels : int, number of in/out channels.
+** bufferSize : int, number of samples per buffer.
+** sampleRate : int, sample rate frequency.
+**
+** All arguments should be equal to the host audio settings.
+*/
+void Pyo::setup(int _nChannels, int _bufferSize, int _sampleRate) {
+ nChannels = _nChannels;
+ bufferSize = _bufferSize;
+ sampleRate = _sampleRate;
+ interpreter = pyo_new_interpreter(nChannels);
+ pyoInBuffer = reinterpret_cast<float*>(pyo_get_input_buffer_address(interpreter));
+ pyoOutBuffer = reinterpret_cast<float*>(pyo_get_output_buffer_address(interpreter));
+ pyoCallback = reinterpret_cast<callPtr*>(pyo_get_embedded_callback_address(interpreter));
+ pyoId = pyo_get_server_id(interpreter);
+ pyo_set_server_params(interpreter, sampleRate, bufferSize);
+}
+
+/*
+** Terminates this object's interpreter.
+*/
+Pyo::~Pyo() {
+ pyo_end_interpreter(interpreter);
+}
+
+/*
+** This function fills pyo's input buffers with new samples. Should be called
+** once per process block, inside the host's audioIn function.
+**
+** arguments:
+** *buffer : float *, float pointer pointing to the host's input buffers.
+*/
+void Pyo::fillin(float *buffer) {
+ for (int i=0; i<(bufferSize*nChannels); i++) pyoInBuffer[i] = buffer[i];
+}
+
+
+/*
+** This function tells pyo to process a buffer of samples and fills the host's
+** output buffer with new samples. Should be called once per process block,
+** inside the host's audioOut function.
+**
+** arguments:
+** *buffer : float *, float pointer pointing to the host's output buffers.
+*/
+void Pyo::process(float *buffer) {
+ pyoCallback(pyoId);
+ for (int i=0; i<(bufferSize*nChannels); i++) buffer[i] = pyoOutBuffer[i];
+}
+
+/*
+** Execute a python script "file" in the objectès thread's interpreter.
+** An integer "add" is needed to indicate if the pyo server should be
+** reboot or not.
+**
+** arguments:
+** file : char *, filename to execute as a python script. The file is first
+** searched in the current working directory. If not found,
+** the module will try to open it as an absolute path.
+** add, int, if positive, the commands in the file will be added to whatever
+** is already running in the pyo server. If 0, the server will be
+** shutdown and reboot before executing the file.
+*/
+int Pyo::loadfile(const char *file, int add) {
+ return pyo_exec_file(interpreter, file, pyoMsg, add);
+}
+
+/*
+** Sends a numerical value to an existing Sig or SigTo object.
+**
+** arguments:
+** name : const char *, variable name of the object.
+** value : float, value to be assign.
+**
+** Example:
+**
+** inside the script file:
+**
+** freq = SigTo(value=440, time=0.1, init=440)
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** pyo.value("freq", 880);
+*/
+int Pyo::value(const char *name, float value) {
+ sprintf(pyoMsg, "%s.value=%f", name, value);
+ return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Sends an array of numerical values to an existing Sig or SigTo object.
+**
+** arguments:
+** name : const char *, variable name of the object.
+** value : float *, array of floats.
+** len : int, number of elements in the array.
+**
+** Example:
+**
+** inside the script file:
+**
+** freq = SigTo(value=[100,200,300,400], time=0.1, init=[100,200,300,400])
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** float frequencies[4] = {150, 250, 350, 450};
+** pyo.value("freq", frequencies, 4);
+*/
+int Pyo::value(const char *name, float *value, int len) {
+ char fchar[32];
+ sprintf(pyoMsg, "%s.value=[", name);
+ for (int i=0; i<len; i++) {
+ sprintf(fchar, "%f,", value[i]);
+ strcat(pyoMsg, fchar);
+ }
+ strcat(pyoMsg, "]");
+ return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Sends a numerical value to a Pyo object's attribute.
+**
+** arguments:
+** name : const char *, object name and attribute separated by a point.
+** value : float, value to be assign.
+**
+** Example:
+**
+** inside the script file:
+**
+** filter = Biquad(input=Noise(0.5), freq=1000, q=4, type=2)
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** pyo.set("filter.freq", 2000);
+*/
+int Pyo::set(const char *name, float value) {
+ sprintf(pyoMsg, "%s=%f", name, value);
+ return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Sends an array of numerical values to a Pyo object's attribute.
+**
+** arguments:
+** name : const char *, object name and attribute separated by a point.
+** value : float *, array of floats.
+** len : int, number of elements in the array.
+**
+** Example:
+**
+** inside the script file:
+**
+** filters = Biquad(input=Noise(0.5), freq=[250, 500, 1000, 2000], q=5, type=2)
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** float frequencies[4] = {350, 700, 1400, 2800};
+** pyo.set("filters.freq", frequencies, 4);
+*/
+int Pyo::set(const char *name, float *value, int len) {
+ char fchar[32];
+ sprintf(pyoMsg, "%s=[", name);
+ for (int i=0; i<len; i++) {
+ sprintf(fchar, "%f,", value[i]);
+ strcat(pyoMsg, fchar);
+ }
+ strcat(pyoMsg, "]");
+ return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Executes any raw valid python statement. With this function, one can dynamically
+** creates and manipulates audio objects and algorithms.
+**
+** arguments:
+** msg : const char *, pointer to a string containing the statement to execute.
+**
+** Example (for a Pyo object named `pyo`):
+**
+** pyo.exec("pits = [0.001, 0.002, 0.003, 0.004]")
+** pyo.exec("fr = Rossler(pitch=pits, chaos=0.9, mul=250, add=500)")
+** pyo.exec("b = SumOsc(freq=fr, ratio=0.499, index=0.4, mul=0.2).out()")
+*/
+int Pyo::exec(const char *_msg) {
+ strcpy(pyoMsg, _msg);
+ return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Shutdown and reboot the pyo server while keeping current in/out buffers.
+** This will erase audio objects currently active within the server.
+**
+*/void Pyo::clear() {
+ pyo_server_reboot(interpreter);
+}
diff --git a/embedded/openframeworks/PyoTemplate/src/PyoClass.h b/embedded/openframeworks/PyoTemplate/src/PyoClass.h
new file mode 100644
index 0000000..2ca65b4
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/src/PyoClass.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "m_pyo.h"
+
+typedef int callPtr(int);
+
+class Pyo {
+ public:
+ ~Pyo();
+ void setup(int nChannels, int bufferSize, int sampleRate);
+ void process(float *buffer);
+ void fillin(float *buffer);
+ void clear();
+ int loadfile(const char *file, int add);
+ int exec(const char *msg);
+ int value(const char *name, float value);
+ int value(const char *name, float *value, int len);
+ int set(const char *name, float value);
+ int set(const char *name, float *value, int len);
+
+ private:
+ int nChannels;
+ int bufferSize;
+ int sampleRate;
+ PyThreadState *interpreter;
+ float *pyoInBuffer;
+ float *pyoOutBuffer;
+ callPtr *pyoCallback;
+ int pyoId;
+ char pyoMsg[262144];
+};
diff --git a/embedded/openframeworks/PyoTemplate/src/m_pyo.h b/embedded/openframeworks/PyoTemplate/src/m_pyo.h
new file mode 100644
index 0000000..c0a5235
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/src/m_pyo.h
@@ -0,0 +1,312 @@
+#include <stdlib.h>
+#include "Python.h"
+
+#ifndef __m_pyo_h_
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+extern "C" {
+#endif
+
+/*
+** Creates a new python interpreter and starts a pyo server in it.
+** Each instance of pyo, in order to be fully independent of other
+** instances, must be started in its own interpreter. An instance
+** can be an object in a programming language or a plugin in a daw.
+**
+** arguments:
+** chnls : int, number of in/out channels of the pyo server.
+**
+** returns the new python thread's interpreter state.
+*/
+inline PyThreadState * pyo_new_interpreter(int chnls) {
+ char msg[64];
+ PyThreadState *interp;
+ if(!Py_IsInitialized()) {
+ Py_Initialize();
+ PyEval_InitThreads();
+ PyEval_ReleaseLock();
+ }
+ PyEval_AcquireLock(); /* get the GIL */
+ interp = Py_NewInterpreter(); /* add a new sub-interpreter */
+ PyRun_SimpleString("from pyo import *");
+ sprintf(msg, "_s_ = Server(44100, %d, 256, 1, 'embedded')", chnls);
+ PyRun_SimpleString(msg);
+ PyRun_SimpleString("_s_.boot()\n_s_.start()\n_s_.setServer()");
+ PyRun_SimpleString("_in_address_ = _s_.getInputAddr()");
+ PyRun_SimpleString("_out_address_ = _s_.getOutputAddr()");
+ PyRun_SimpleString("_server_id_ = _s_.getServerID()");
+ PyRun_SimpleString("_emb_callback_ = _s_.getEmbedICallbackAddr()");
+ PyEval_ReleaseThread(interp);
+ return interp;
+}
+
+/*
+** Returns the address, as unsigned long, of the pyo input buffer.
+** Used this function if pyo's audio samples resolution is 32-bit.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long" that should be recast to a float pointer.
+*/
+inline unsigned long pyo_get_input_buffer_address(PyThreadState *interp) {
+ PyObject *module, *obj;
+ char *address;
+ unsigned long uadd;
+ PyEval_AcquireThread(interp);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_in_address_");
+ address = PyString_AsString(obj);
+ uadd = strtoul(address, NULL, 0);
+ PyEval_ReleaseThread(interp);
+ return uadd;
+}
+
+/*
+** Returns the address, as unsigned long long, of the pyo input buffer.
+** Used this function if pyo's audio samples resolution is 64-bit.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long long" that should be recast to a double pointer.
+*/
+inline unsigned long long pyo_get_input_buffer_address_64(PyThreadState *interp) {
+ PyObject *module, *obj;
+ char *address;
+ unsigned long long uadd;
+ PyEval_AcquireThread(interp);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_in_address_");
+ address = PyString_AsString(obj);
+ uadd = strtoull(address, NULL, 0);
+ PyEval_ReleaseThread(interp);
+ return uadd;
+}
+
+/*
+** Returns the address, as unsigned long, of the pyo output buffer.
+** Used this function if pyo's audio samples resolution is 32-bit.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long" that should be recast to a float pointer.
+*/
+inline unsigned long pyo_get_output_buffer_address(PyThreadState *interp) {
+ PyObject *module, *obj;
+ char *address;
+ unsigned long uadd;
+ PyEval_AcquireThread(interp);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_out_address_");
+ address = PyString_AsString(obj);
+ uadd = strtoul(address, NULL, 0);
+ PyEval_ReleaseThread(interp);
+ return uadd;
+}
+
+/*
+** Returns the address, as unsigned long, of the pyo embedded callback.
+** This callback must be called in the host's perform routine whenever
+** pyo has to compute a new buffer of samples.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long" that should be recast to a void pointer.
+**
+** The callback should be called with the server id (int) as argument.
+**
+** Prototype:
+** void (*callback)(int);
+*/
+inline unsigned long pyo_get_embedded_callback_address(PyThreadState *interp) {
+ PyObject *module, *obj;
+ char *address;
+ unsigned long uadd;
+ PyEval_AcquireThread(interp);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_emb_callback_");
+ address = PyString_AsString(obj);
+ uadd = strtoul(address, NULL, 0);
+ PyEval_ReleaseThread(interp);
+ return uadd;
+}
+
+/*
+** Returns the pyo server id of this thread, as an integer.
+** The id must be pass as argument to the callback function.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an integer.
+*/
+inline int pyo_get_server_id(PyThreadState *interp) {
+ PyObject *module, *obj;
+ int id;
+ PyEval_AcquireThread(interp);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_server_id_");
+ id = PyInt_AsLong(obj);
+ PyEval_ReleaseThread(interp);
+ return id;
+}
+
+/*
+** Closes the interpreter linked to the thread state given as argument.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+*/
+inline void pyo_end_interpreter(PyThreadState *interp) {
+ PyEval_AcquireThread(interp);
+ Py_EndInterpreter(interp);
+ PyEval_ReleaseLock();
+}
+
+/*
+** Shutdown and reboot the pyo server while keeping current in/out buffers.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+*/
+inline void pyo_server_reboot(PyThreadState *interp) {
+ PyEval_AcquireThread(interp);
+ PyRun_SimpleString("_s_.setServer()\n_s_.stop()\n_s_.shutdown()");
+ PyRun_SimpleString("_s_.boot(newBuffer=False).start()");
+ PyEval_ReleaseThread(interp);
+}
+
+/*
+** Reboot the pyo server with new sampling rate and buffer size.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+** sr : float, host sampling rate.
+** bufsize : int, host buffer size.
+*/
+inline void pyo_set_server_params(PyThreadState *interp, float sr, int bufsize) {
+ char msg[64];
+ PyEval_AcquireThread(interp);
+ PyRun_SimpleString("_s_.setServer()\n_s_.stop()\n_s_.shutdown()");
+ sprintf(msg, "_s_.setSamplingRate(%f)", sr);
+ PyRun_SimpleString(msg);
+ sprintf(msg, "_s_.setBufferSize(%d)", bufsize);
+ PyRun_SimpleString(msg);
+ PyRun_SimpleString("_s_.boot(newBuffer=False).start()");
+ PyEval_ReleaseThread(interp);
+}
+
+/*
+** Returns 1 if the pyo server is started for the given thread,
+** Otherwise returns 0.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+*/
+inline int pyo_is_server_started(PyThreadState *interp) {
+ int started;
+ PyObject *module, *obj;
+ PyEval_AcquireThread(interp);
+ PyRun_SimpleString("started = _s_.getIsStarted()");
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "started");
+ started = PyInt_AsLong(obj);
+ PyEval_ReleaseThread(interp);
+ return started;
+}
+
+/*
+** Execute a python script "file" in the given thread's interpreter (interp).
+** A pre-allocated string "msg" must be given to create the python command
+** used for error handling. An integer "add" is needed to indicate if the
+** pyo server should be reboot or not.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+** file : char *, filename to execute as a python script. The file is first
+** searched in the current working directory. If not found,
+** the module will try to open it as an absolute path.
+** msg : char *, pre-allocated string used to create the python command
+** used for error handling.
+** add, int, if positive, the commands in the file will be added to whatever
+** is already running in the pyo server. If 0, the server will be
+** shutdown and reboot before executing the file.
+*/
+inline int pyo_exec_file(PyThreadState *interp, const char *file, char *msg, int add) {
+ int ok, err = 0;
+ PyObject *module, *obj;
+ PyEval_AcquireThread(interp);
+ sprintf(msg, "import os\n_ok_ = os.path.isfile('./%s')", file);
+ PyRun_SimpleString(msg);
+ sprintf(msg, "if not _ok_:\n _ok_ = os.path.isfile('%s')", file);
+ PyRun_SimpleString(msg);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_ok_");
+ ok = PyInt_AsLong(obj);
+ if (ok) {
+ sprintf(msg, "try:\n execfile('./%s')\nexcept:\n execfile('%s')",
+ file, file);
+ if (!add) {
+ PyRun_SimpleString("_s_.setServer()\n_s_.stop()\n_s_.shutdown()");
+ PyRun_SimpleString("_s_.boot(newBuffer=False).start()");
+ }
+ PyRun_SimpleString(msg);
+ }
+ else
+ err = 1;
+ PyEval_ReleaseThread(interp);
+ return err;
+}
+
+/*
+** Execute a python statement "msg" in the thread's interpreter "interp".
+** If "debug" is true, the statement will be executed in a try - except
+** block. The error message, if any, will be write back in the *msg
+** pointer and the function will return 1. If no error occured, the
+** function returned 0. If debug is false, the statement is executed
+** without any error checking (unsafe but faster).
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+** msg : char *, pointer to a string containing the statement to execute.
+** In debug mode, if an error occured, the output log will
+** be write back in this string.
+** debug, int, if positive, the commands will be executed in a try-except
+** statement. If 0, there will be no error checking, which is
+** much faster.
+*/
+inline int pyo_exec_statement(PyThreadState *interp, char *msg, int debug) {
+ int err = 0;
+ if (debug) {
+ PyObject *module, *obj;
+ char pp[26] = "_error_=None\ntry:\n ";
+ memmove(msg + strlen(pp), msg, strlen(msg)+1);
+ memmove(msg, pp, strlen(pp));
+ strcat(msg, "\nexcept Exception, _e_:\n _error_=str(_e_)");
+ PyEval_AcquireThread(interp);
+ PyRun_SimpleString(msg);
+ module = PyImport_AddModule("__main__");
+ obj = PyObject_GetAttrString(module, "_error_");
+ if (obj != Py_None) {
+ strcpy(msg, PyString_AsString(obj));
+ err = 1;
+ }
+ PyEval_ReleaseThread(interp);
+ }
+ else {
+ PyEval_AcquireThread(interp);
+ PyRun_SimpleString(msg);
+ PyEval_ReleaseThread(interp);
+ }
+ return err;
+}
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
+
+#define __m_pyo_h_
+#endif /* __m_pyo_h_ */
diff --git a/embedded/openframeworks/PyoTemplate/src/main.cpp b/embedded/openframeworks/PyoTemplate/src/main.cpp
new file mode 100644
index 0000000..a7d241d
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/src/main.cpp
@@ -0,0 +1,13 @@
+#include "ofMain.h"
+#include "testApp.h"
+
+//========================================================================
+int main( ){
+ ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context
+
+ // this kicks off the running of my app
+ // can be OF_WINDOW or OF_FULLSCREEN
+ // pass in width and height too:
+ ofRunApp(new testApp());
+
+}
diff --git a/embedded/openframeworks/PyoTemplate/src/testApp.cpp b/embedded/openframeworks/PyoTemplate/src/testApp.cpp
new file mode 100644
index 0000000..882cec7
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/src/testApp.cpp
@@ -0,0 +1,80 @@
+#include "testApp.h"
+
+//--------------------------------------------------------------
+void testApp::setup(){
+ // define audio properties
+ int sampleRate = 44100;
+ int bufferSize = 256;
+ int nChannels = 2;
+ // initialize a pyo server
+ pyo.setup(nChannels, bufferSize, sampleRate);
+ // load a python file
+ pyo.loadfile("../scripts/stereoDelay.py", 0);
+ // initialize OpenFrameworks audio streaming channels
+ soundStream.setup(this, nChannels, nChannels, sampleRate, bufferSize, 4);
+}
+
+void testApp::audioIn(float * input, int bufferSize, int nChannels){
+ // send audio samples to pyo
+ pyo.fillin(input);
+}
+
+void testApp::audioOut(float * output, int bufferSize, int nChannels){
+ // process and get new audio samples from pyo
+ pyo.process(output);
+}
+
+//--------------------------------------------------------------
+void testApp::update(){
+
+}
+
+//--------------------------------------------------------------
+void testApp::draw(){
+
+}
+
+//--------------------------------------------------------------
+void testApp::keyPressed(int key){
+
+}
+
+//--------------------------------------------------------------
+void testApp::keyReleased(int key){
+
+}
+
+//--------------------------------------------------------------
+void testApp::mouseMoved(int x, int y ){
+
+}
+
+//--------------------------------------------------------------
+void testApp::mouseDragged(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void testApp::mousePressed(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void testApp::mouseReleased(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void testApp::windowResized(int w, int h){
+
+}
+
+//--------------------------------------------------------------
+void testApp::gotMessage(ofMessage msg){
+
+}
+
+//--------------------------------------------------------------
+void testApp::dragEvent(ofDragInfo dragInfo){
+
+}
diff --git a/embedded/openframeworks/PyoTemplate/src/testApp.h b/embedded/openframeworks/PyoTemplate/src/testApp.h
new file mode 100644
index 0000000..4a98213
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/src/testApp.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "ofMain.h"
+#include "PyoClass.h"
+
+class testApp : public ofBaseApp{
+ public:
+ void setup();
+ void update();
+ void draw();
+
+ void keyPressed(int key);
+ void keyReleased(int key);
+ void mouseMoved(int x, int y );
+ void mouseDragged(int x, int y, int button);
+ void mousePressed(int x, int y, int button);
+ void mouseReleased(int x, int y, int button);
+ void windowResized(int w, int h);
+ void dragEvent(ofDragInfo dragInfo);
+ void gotMessage(ofMessage msg);
+
+ void audioIn(float * input, int bufferSize, int nChannels);
+ void audioOut(float * input, int bufferSize, int nChannels);
+ ofSoundStream soundStream;
+ Pyo pyo;
+};
diff --git a/embedded/openframeworks/README b/embedded/openframeworks/README
new file mode 100644
index 0000000..7879578
--- /dev/null
+++ b/embedded/openframeworks/README
@@ -0,0 +1,101 @@
+Introduction on how to use pyo inside an OpenFrameworks project.
+================================================================
+
+To use pyo inside an OpenFrameworks project, first you need a
+working install of pyo on your system. After installing pyo,
+you can go and create an OpenFrameworks project.
+
+------------------------------------------------------------------------
+Step 1 - Create a default project with project generator.
+
+------------------------------------------------------------------------
+Step 2 - Add pyo files to your project. You only need to copy
+these files in your project's src folder:
+
+- from this folder:
+PyoClass.cpp
+PyoClass.h
+
+- from the folder "embedded":
+m_pyo.h
+
+------------------------------------------------------------------------
+Step 3 - Make sure that your project includes flags for compiling
+and linking against Python. On Unix systems, you can set the Python
+flags in the file config.make. Uncomment and complete these lines:
+
+PROJECT_LDFLAGS = `python-config --ldflags` # linker flags for Python
+PROJECT_CFLAGS = `python-config --cflags` # compiler flags for Python
+
+------------------------------------------------------------------------
+Step 4 - Make a scripts folder at the root level of your project and
+create a python file, named "stereoDelay.py", with these lines in it:
+
+# Get the input sound and apply a stereo delay + reverb on it.
+st_input = Input([0,1])
+st_delay = Delay(st_input, delay=[.4, .5], feedback=0.7)
+st_rev = WGVerb(st_delay, feedback=0.8, cutoff=4000, bal=0.25).out()
+
+------------------------------------------------------------------------
+Step 5 - Edit src/testApp.h.
+
+- Include PyoClass definition:
+
+#include "PyoClass.h"
+
+- Add audio in/out callbacks to the public attributes of the testApp class:
+
+void audioIn(float * input, int bufferSize, int nChannels);
+void audioOut(float * input, int bufferSize, int nChannels);
+
+- Add an ofSoundStream object to the public attributes of the testApp class:
+
+ofSoundStream soundStream;
+
+- Add a Pyo object to the public attributes of the testApp class:
+
+Pyo pyo;
+
+------------------------------------------------------------------------
+Step 6 - Edit src/testApp.cpp.
+
+- Creates the setup() function:
+
+void testApp::setup(){
+ // define audio properties
+ int sampleRate = 44100;
+ int bufferSize = 256;
+ int nChannels = 2;
+ // initialize a pyo server
+ pyo.setup(nChannels, bufferSize, sampleRate);
+ // load a python file
+ pyo.loadfile("../scripts/stereoDelay.py", 0);
+ // initialize OpenFrameworks audio streaming channels
+ soundStream.setup(this, nChannels, nChannels, sampleRate, bufferSize, 4);
+}
+
+- Creates audio in/out functions:
+
+void testApp::audioIn(float * input, int bufferSize, int nChannels){
+ // send audio samples to pyo
+ pyo.fillin(input);
+}
+
+void testApp::audioOut(float * output, int bufferSize, int nChannels){
+ // process and get new audio samples from pyo
+ pyo.process(output);
+}
+
+------------------------------------------------------------------------
+Here you go! Compile, Run and Enjoy!
+
+Documentation
+=============
+
+For a complete description of functions that can be used to communicate
+with the pyo embedded processes, see documentation comments in the file
+PyoClass.cpp.
+
+belangeo
+
+
diff --git a/embedded/puredata/Makefile b/embedded/puredata/Makefile
new file mode 100644
index 0000000..6637883
--- /dev/null
+++ b/embedded/puredata/Makefile
@@ -0,0 +1,467 @@
+## Pd library template version 1.0.13
+# For instructions on how to use this template, see:
+# http://puredata.info/docs/developer/MakefileTemplate
+LIBRARY_NAME = pyo~
+
+# add your .c source files, one object per file, to the SOURCES
+# variable, help files will be included automatically, and for GUI
+# objects, the matching .tcl file too
+SOURCES = pyo~.c
+
+# list all pd objects (i.e. myobject.pd) files here, and their helpfiles will
+# be included automatically
+PDOBJECTS = pyo~.pd
+
+# example patches and related files, in the 'examples' subfolder
+EXAMPLES =
+
+# manuals and related files, in the 'manual' subfolder
+MANUAL = manual.txt
+
+# if you want to include any other files in the source and binary tarballs,
+# list them here. This can be anything from header files, test patches,
+# documentation, etc. README.txt and LICENSE.txt are required and therefore
+# automatically included
+EXTRA_DIST = m_pyo.h
+
+# unit tests and related files here, in the 'unittests' subfolder
+UNITTESTS =
+
+# added to support the multiple shared source files
+SHARED_SOURCE =
+SHARED_LIB = lib$(LIBRARY_NAME).$(SHARED_EXTENSION)
+
+
+#------------------------------------------------------------------------------#
+#
+# things you might need to edit if you are using other C libraries
+#
+#------------------------------------------------------------------------------#
+UNAME := $(shell uname -s)
+ifeq (MINGW,$(findstring MINGW,$(UNAME)))
+ ALL_CFLAGS = -I"$(PD_INCLUDE)" -I.. -Wno-unused-parameter -I/c/Python27/include
+ ALL_LDFLAGS = -lpython27
+ SHARED_LDFLAGS =
+ ALL_LIBS = -L/c/Python27/libs
+endif
+ifeq ($(UNAME),Darwin)
+ MAC_SDK = # put the path to your base SDK if you have problem to compile with the one given by python (ex: /Developer/SDKs/MacOSX10.6.sdk)
+ ARCH_TYPE = i386 # can put multiple architectures if they are available with your environment (ex: ppc i386)
+ ifeq ($(MAC_SDK),)
+ PYTHONFLAGS = $(shell python-config --cflags)
+ else
+ PYTHONFLAGS = $(patsubst /%, $(MAC_SDK), $(shell python-config --cflags))
+ endif
+ ALL_CFLAGS = -I"$(PD_INCLUDE)" -I.. -Wno-unused-parameter $(PYTHONFLAGS)
+ ALL_LDFLAGS = $(shell python-config --ldflags)
+ SHARED_LDFLAGS =
+ # ALL_LIBS = $(shell python-config --libs)
+ ALL_LIBS = -ldl -framework CoreFoundation -framework Python
+endif
+ifeq ($(UNAME),Linux)
+ ALL_CFLAGS = -I"$(PD_INCLUDE)" -I.. -Wno-unused-parameter $(shell python-config --cflags)
+ ALL_LDFLAGS = $(shell python-config --ldflags)
+ SHARED_LDFLAGS =
+ ALL_LIBS = $(shell python-config --libs)
+endif
+
+#------------------------------------------------------------------------------#
+#
+# you shouldn't need to edit anything below here, if we did it right :)
+#
+#------------------------------------------------------------------------------#
+
+# these can be set from outside without (usually) breaking the build
+CFLAGS = -Wall -W -g
+LDFLAGS =
+LIBS =
+
+# get library version from meta file
+LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd)
+
+ALL_CFLAGS += -DPD -DVERSION='"$(LIBRARY_VERSION)"'
+
+PD_INCLUDE = $(PD_PATH)/include/pd
+# where to install the library, overridden below depending on platform
+prefix = /usr/local
+libdir = $(prefix)/lib
+pkglibdir = $(libdir)/pd-externals
+objectsdir = $(pkglibdir)
+
+INSTALL = install
+INSTALL_PROGRAM = $(INSTALL) -p -m 644
+INSTALL_DATA = $(INSTALL) -p -m 644
+INSTALL_DIR = $(INSTALL) -p -m 755 -d
+
+ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \
+ $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows)
+
+DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION)
+ORIGDIR=pd-$(LIBRARY_NAME:~=)_$(LIBRARY_VERSION)
+
+UNAME := $(shell uname -s)
+ifeq ($(UNAME),Darwin)
+ CPU := $(shell uname -p)
+ ifeq ($(CPU),arm) # iPhone/iPod Touch
+ SOURCES += $(SOURCES_iphoneos)
+ EXTENSION = pd_darwin
+ SHARED_EXTENSION = dylib
+ OS = iphoneos
+ PD_PATH = /Applications/Pd-extended.app/Contents/Resources
+ IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin
+ CC=$(IPHONE_BASE)/gcc
+ CPP=$(IPHONE_BASE)/cpp
+ CXX=$(IPHONE_BASE)/g++
+ ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk
+ IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6
+ OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer
+ ALL_CFLAGS := $(IPHONE_CFLAGS) $(ALL_CFLAGS)
+ ALL_LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT)
+ SHARED_LDFLAGS += -arch armv6 -dynamiclib -undefined dynamic_lookup $(ISYSROOT)
+ ALL_LIBS += -lc $(LIBS_iphoneos)
+ STRIP = strip -x
+ DISTBINDIR=$(DISTDIR)-$(OS)
+ else # Mac OS X
+ SOURCES += $(SOURCES_macosx)
+ EXTENSION = pd_darwin
+ SHARED_EXTENSION = dylib
+ OS = macosx
+ PD_PATH = /Applications/Pd-extended.app/Contents/Resources
+ OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast
+# build universal 32-bit on 10.4 and 32/64 on newer
+ ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8)
+ # FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.5
+ ARCHWITHOUT64 := $(filter-out x86_64,$(ARCH_TYPE))
+ FAT_FLAGS = $(patsubst %,-arch %, $(ARCHWITHOUT64)) -mmacosx-version-min=10.5
+ else
+ # FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.5
+ FAT_FLAGS = $(patsubst %,-arch %, $(ARCH_TYPE)) -mmacosx-version-min=10.5
+ SOURCES += $(SOURCES_iphoneos)
+ endif
+ ALL_CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include
+ # if the 'pd' binary exists, check the linking against it to aid with stripping
+ BUNDLE_LOADER = $(shell test ! -e $(PD_PATH)/bin/pd || echo -bundle_loader $(PD_PATH)/bin/pd)
+ ALL_LDFLAGS += $(FAT_FLAGS) -headerpad_max_install_names -bundle $(BUNDLE_LOADER) \
+ -undefined dynamic_lookup -L/sw/lib
+ SHARED_LDFLAGS += $(FAT_FLAGS) -dynamiclib -undefined dynamic_lookup \
+ -install_name @loader_path/$(SHARED_LIB) -compatibility_version 1 -current_version 1.0
+ ALL_LIBS += -lc $(LIBS_macosx)
+ STRIP = strip -x
+ DISTBINDIR=$(DISTDIR)-$(OS)
+# install into ~/Library/Pd on Mac OS X since /usr/local isn't used much
+ pkglibdir=$(HOME)/Library/Pd
+ endif
+endif
+# Tho Android uses Linux, we use this fake uname to provide an easy way to
+# setup all this things needed to cross-compile for Android using the NDK
+ifeq ($(UNAME),ANDROID)
+ CPU := arm
+ SOURCES += $(SOURCES_android)
+ EXTENSION = pd_linux
+ SHARED_EXTENSION = so
+ OS = android
+ PD_PATH = /usr
+ NDK_BASE := /usr/local/android-ndk
+ NDK_PLATFORM_VERSION := 5
+ NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_VERSION)/arch-arm
+ NDK_UNAME := $(shell uname -s | tr '[A-Z]' '[a-z]')
+ NDK_TOOLCHAIN_BASE=$(NDK_BASE)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/$(NDK_UNAME)-x86
+ CC := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-gcc --sysroot=$(NDK_SYSROOT)
+ OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+ CFLAGS +=
+ LDFLAGS += -rdynamic -shared
+ SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared
+ LIBS += -lc $(LIBS_android)
+ STRIP := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-strip \
+ --strip-unneeded -R .note -R .comment
+ DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),Linux)
+ CPU := $(shell uname -m)
+ SOURCES += $(SOURCES_linux)
+ EXTENSION = pd_linux
+ SHARED_EXTENSION = so
+ OS = linux
+ PD_PATH = /usr
+ OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+ ALL_CFLAGS += -fPIC
+ ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+ SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared
+ ALL_LIBS += -lc $(LIBS_linux)
+ STRIP = strip --strip-unneeded -R .note -R .comment
+ DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),GNU)
+ # GNU/Hurd, should work like GNU/Linux for basically all externals
+ CPU := $(shell uname -m)
+ SOURCES += $(SOURCES_linux)
+ EXTENSION = pd_linux
+ SHARED_EXTENSION = so
+ OS = linux
+ PD_PATH = /usr
+ OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+ ALL_CFLAGS += -fPIC
+ ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+ SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB)
+ ALL_LIBS += -lc $(LIBS_linux)
+ STRIP = strip --strip-unneeded -R .note -R .comment
+ DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),GNU/kFreeBSD)
+ # Debian GNU/kFreeBSD, should work like GNU/Linux for basically all externals
+ CPU := $(shell uname -m)
+ SOURCES += $(SOURCES_linux)
+ EXTENSION = pd_linux
+ SHARED_EXTENSION = so
+ OS = linux
+ PD_PATH = /usr
+ OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+ ALL_CFLAGS += -fPIC
+ ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+ SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB)
+ ALL_LIBS += -lc $(LIBS_linux)
+ STRIP = strip --strip-unneeded -R .note -R .comment
+ DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME)))
+ CPU := $(shell uname -m)
+ SOURCES += $(SOURCES_cygwin)
+ EXTENSION = dll
+ SHARED_EXTENSION = dll
+ OS = cygwin
+ PD_PATH = $(shell cygpath $$PROGRAMFILES)/pd
+ OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+ ALL_CFLAGS +=
+ ALL_LDFLAGS += -rdynamic -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin"
+ SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB)
+ ALL_LIBS += -lc -lpd $(LIBS_cygwin)
+ STRIP = strip --strip-unneeded -R .note -R .comment
+ DISTBINDIR=$(DISTDIR)-$(OS)
+endif
+ifeq (MINGW,$(findstring MINGW,$(UNAME)))
+ CPU := $(shell uname -m)
+ SOURCES += $(SOURCES_windows)
+ EXTENSION = dll
+ SHARED_EXTENSION = dll
+ OS = windows
+ PD_PATH = $(shell cd "$$PROGRAMFILES/pd" && pwd)
+ # MinGW doesn't seem to include cc so force gcc
+ CC=gcc
+ OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer
+ ALL_CFLAGS += -mms-bitfields
+ ALL_LDFLAGS += -s -shared -Wl,--enable-auto-import
+ SHARED_LDFLAGS += -shared
+ ALL_LIBS += -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj" \
+ -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 -liberty $(LIBS_windows)
+ STRIP = strip --strip-unneeded -R .note -R .comment
+ DISTBINDIR=$(DISTDIR)-$(OS)
+endif
+
+# in case somebody manually set the HELPPATCHES above
+HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.pd=-help.pd)
+
+ALL_CFLAGS := $(ALL_CFLAGS) $(CFLAGS) $(OPT_CFLAGS)
+ALL_LDFLAGS := $(LDFLAGS) $(ALL_LDFLAGS)
+ALL_LIBS := $(LIBS) $(ALL_LIBS)
+
+SHARED_SOURCE ?= $(wildcard lib$(LIBRARY_NAME).c)
+SHARED_HEADER ?= $(shell test ! -e $(LIBRARY_NAME).h || echo $(LIBRARY_NAME).h)
+SHARED_LIB ?= $(SHARED_SOURCE:.c=.$(SHARED_EXTENSION))
+SHARED_TCL_LIB = $(wildcard lib$(LIBRARY_NAME).tcl)
+
+.PHONY = install libdir_install single_install install-doc install-examples install-manual install-unittests clean distclean dist etags $(LIBRARY_NAME)
+
+all: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB)
+
+%.o: %.c
+ $(CC) $(ALL_CFLAGS) -o "$*.o" -c "$*.c"
+
+%.$(EXTENSION): %.o $(SHARED_LIB)
+ $(CC) $(ALL_LDFLAGS) -o "$*.$(EXTENSION)" "$*.o" $(ALL_LIBS) $(SHARED_LIB)
+ chmod a-x "$*.$(EXTENSION)"
+
+# this links everything into a single binary file
+$(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o lib$(LIBRARY_NAME).o
+ $(CC) $(ALL_LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) \
+ $(LIBRARY_NAME).o lib$(LIBRARY_NAME).o $(ALL_LIBS)
+ chmod a-x $(LIBRARY_NAME).$(EXTENSION)
+
+$(SHARED_LIB): $(SHARED_SOURCE:.c=.o)
+ $(CC) $(SHARED_LDFLAGS) -o $(SHARED_LIB) $(SHARED_SOURCE:.c=.o) $(ALL_LIBS)
+
+install: single_install
+
+# The meta and help files are explicitly installed to make sure they are
+# actually there. Those files are not optional, then need to be there.
+libdir_install: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) install-doc install-examples install-manual install-unittests
+ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+ $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \
+ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+ test -z "$(strip $(SOURCES))" || (\
+ $(INSTALL_PROGRAM) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \
+ $(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION))))
+ test -z "$(strip $(SHARED_LIB))" || \
+ $(INSTALL_DATA) $(SHARED_LIB) \
+ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+ test -z "$(strip $(wildcard $(SOURCES:.c=.tcl)))" || \
+ $(INSTALL_DATA) $(wildcard $(SOURCES:.c=.tcl)) \
+ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+ test -z "$(strip $(PDOBJECTS))" || \
+ $(INSTALL_DATA) $(PDOBJECTS) \
+ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+ test -z "$(strip $(SHARED_TCL_LIB))" || \
+ $(INSTALL_DATA) $(SHARED_TCL_LIB) \
+ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+
+# install library linked as single binary
+single_install: $(LIBRARY_NAME) install-doc install-examples install-manual install-unittests
+ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+ $(INSTALL_PROGRAM) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+ $(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION)
+
+install-doc:
+ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+ test -z "$(strip $(SOURCES) $(PDOBJECTS))" || \
+ $(INSTALL_DATA) $(HELPPATCHES) \
+ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+ $(INSTALL_DATA) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt
+ $(INSTALL_DATA) LICENSE.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt
+
+install-examples:
+ test -z "$(strip $(EXAMPLES))" || \
+ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \
+ for file in $(EXAMPLES); do \
+ $(INSTALL_DATA) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \
+ done
+
+install-manual:
+ test -z "$(strip $(MANUAL))" || \
+ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \
+ for file in $(MANUAL); do \
+ $(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \
+ done
+
+install-unittests:
+ test -z "$(strip $(UNITTESTS))" || \
+ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/unittests && \
+ for file in $(UNITTESTS); do \
+ $(INSTALL_DATA) unittests/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/unittests; \
+ done
+
+clean:
+ -rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o) $(SHARED_SOURCE:.c=.o)
+ -rm -f -- $(SOURCES:.c=.$(EXTENSION))
+ -rm -f -- $(LIBRARY_NAME).o
+ -rm -f -- $(LIBRARY_NAME).$(EXTENSION)
+ -rm -f -- $(SHARED_LIB)
+
+distclean: clean
+ -rm -f -- $(DISTBINDIR).tar.gz
+ -rm -rf -- $(DISTBINDIR)
+ -rm -f -- $(DISTDIR).tar.gz
+ -rm -rf -- $(DISTDIR)
+ -rm -f -- $(ORIGDIR).tar.gz
+ -rm -rf -- $(ORIGDIR)
+
+
+$(DISTBINDIR):
+ $(INSTALL_DIR) $(DISTBINDIR)
+
+libdir: all $(DISTBINDIR)
+ $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTBINDIR)
+ $(INSTALL_DATA) $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER) $(DISTBINDIR)
+ $(INSTALL_DATA) $(HELPPATCHES) $(DISTBINDIR)
+ test -z "$(strip $(EXTRA_DIST))" || \
+ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTBINDIR)
+# tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR)
+
+$(DISTDIR):
+ $(INSTALL_DIR) $(DISTDIR)
+
+$(ORIGDIR):
+ $(INSTALL_DIR) $(ORIGDIR)
+
+dist: $(DISTDIR)
+ $(INSTALL_DATA) Makefile $(DISTDIR)
+ $(INSTALL_DATA) README.txt $(DISTDIR)
+ $(INSTALL_DATA) LICENSE.txt $(DISTDIR)
+ $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTDIR)
+ test -z "$(strip $(ALLSOURCES))" || \
+ $(INSTALL_DATA) $(ALLSOURCES) $(DISTDIR)
+ test -z "$(strip $(wildcard $(ALLSOURCES:.c=.tcl)))" || \
+ $(INSTALL_DATA) $(wildcard $(ALLSOURCES:.c=.tcl)) $(DISTDIR)
+ test -z "$(strip $(wildcard $(LIBRARY_NAME).c))" || \
+ $(INSTALL_DATA) $(LIBRARY_NAME).c $(DISTDIR)
+ test -z "$(strip $(SHARED_HEADER))" || \
+ $(INSTALL_DATA) $(SHARED_HEADER) $(DISTDIR)
+ test -z "$(strip $(SHARED_SOURCE))" || \
+ $(INSTALL_DATA) $(SHARED_SOURCE) $(DISTDIR)
+ test -z "$(strip $(SHARED_TCL_LIB))" || \
+ $(INSTALL_DATA) $(SHARED_TCL_LIB) $(DISTDIR)
+ test -z "$(strip $(PDOBJECTS))" || \
+ $(INSTALL_DATA) $(PDOBJECTS) $(DISTDIR)
+ test -z "$(strip $(HELPPATCHES))" || \
+ $(INSTALL_DATA) $(HELPPATCHES) $(DISTDIR)
+ test -z "$(strip $(EXTRA_DIST))" || \
+ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTDIR)
+ test -z "$(strip $(EXAMPLES))" || \
+ $(INSTALL_DIR) $(DISTDIR)/examples && \
+ for file in $(EXAMPLES); do \
+ $(INSTALL_DATA) examples/$$file $(DISTDIR)/examples; \
+ done
+ test -z "$(strip $(MANUAL))" || \
+ $(INSTALL_DIR) $(DISTDIR)/manual && \
+ for file in $(MANUAL); do \
+ $(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \
+ done
+ test -z "$(strip $(UNITTESTS))" || \
+ $(INSTALL_DIR) $(DISTDIR)/unittests && \
+ for file in $(UNITTESTS); do \
+ $(INSTALL_DATA) unittests/$$file $(DISTDIR)/unittests; \
+ done
+ tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR)
+
+# make a Debian source package
+dpkg-source:
+ debclean
+ make distclean dist
+ mv $(DISTDIR) $(ORIGDIR)
+ tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR)
+ rm -f -- $(DISTDIR).tar.gz
+ rm -rf -- $(DISTDIR) $(ORIGDIR)
+ cd .. && dpkg-source -b $(LIBRARY_NAME)
+
+etags: TAGS
+
+TAGS: $(wildcard $(PD_INCLUDE)/*.h) $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER)
+ etags $(wildcard $(PD_INCLUDE)/*.h)
+ etags -a *.h $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER)
+ etags -a --language=none --regex="/proc[ \t]+\([^ \t]+\)/\1/" *.tcl
+
+showsetup:
+ @echo "CC: $(CC)"
+ @echo "CFLAGS: $(CFLAGS)"
+ @echo "LDFLAGS: $(LDFLAGS)"
+ @echo "LIBS: $(LIBS)"
+ @echo "ALL_CFLAGS: $(ALL_CFLAGS)"
+ @echo "ALL_LDFLAGS: $(ALL_LDFLAGS)"
+ @echo "ALL_LIBS: $(ALL_LIBS)"
+ @echo "PD_INCLUDE: $(PD_INCLUDE)"
+ @echo "PD_PATH: $(PD_PATH)"
+ @echo "objectsdir: $(objectsdir)"
+ @echo "LIBRARY_NAME: $(LIBRARY_NAME)"
+ @echo "LIBRARY_VERSION: $(LIBRARY_VERSION)"
+ @echo "SOURCES: $(SOURCES)"
+ @echo "SHARED_HEADER: $(SHARED_HEADER)"
+ @echo "SHARED_SOURCE: $(SHARED_SOURCE)"
+ @echo "SHARED_LIB: $(SHARED_LIB)"
+ @echo "SHARED_TCL_LIB: $(SHARED_TCL_LIB)"
+ @echo "PDOBJECTS: $(PDOBJECTS)"
+ @echo "ALLSOURCES: $(ALLSOURCES)"
+ @echo "ALLSOURCES TCL: $(wildcard $(ALLSOURCES:.c=.tcl))"
+ @echo "UNAME: $(UNAME)"
+ @echo "CPU: $(CPU)"
+ @echo "pkglibdir: $(pkglibdir)"
+ @echo "DISTDIR: $(DISTDIR)"
+ @echo "ORIGDIR: $(ORIGDIR)"
+
diff --git a/embedded/puredata/examples/cvlverb.py b/embedded/puredata/examples/cvlverb.py
new file mode 100644
index 0000000..739e176
--- /dev/null
+++ b/embedded/puredata/examples/cvlverb.py
@@ -0,0 +1,3 @@
+bal = SigTo(0.25, 0.005, 0.25)
+ins = Input([0,1])
+dist = CvlVerb(ins, size=512, bal=bal, mul=0.3).out()
\ No newline at end of file
diff --git a/embedded/puredata/examples/random_waves.py b/embedded/puredata/examples/random_waves.py
new file mode 100644
index 0000000..6b9cc90
--- /dev/null
+++ b/embedded/puredata/examples/random_waves.py
@@ -0,0 +1,13 @@
+import random
+
+feed = SigTo(0.05, 0.05, 0.05)
+amp = Fader(fadein=0.005, fadeout=0.12, dur=0.125)
+syn = SineLoop(freq=[500,510], feedback=feed, mul=amp*amp)
+rev = WGVerb(syn, feedback=0.85, cutoff=4500, bal=0.1).out()
+
+def choose(a, b):
+ x = random.randint(a, b)
+ deg = [0,2,3,5,7,8,11][x%7]
+ hz = midiToHz(deg + (x / 7 * 12 + 36))
+ syn.freq = [hz,hz*1.005]
+ amp.play()
diff --git a/embedded/puredata/examples/resonators.py b/embedded/puredata/examples/resonators.py
new file mode 100644
index 0000000..233ae54
--- /dev/null
+++ b/embedded/puredata/examples/resonators.py
@@ -0,0 +1,8 @@
+reson = SigTo(2, 0.005, 2)
+freqs = SigTo([50,100,150,200,250,300,350,400], time=0.2)
+
+ins = Input([0,1])
+wgs = Waveguide(ins, freq=freqs, dur=reson, mul=0.1)
+wgss = wgs.mix(2)
+wgss.out()
+
diff --git a/embedded/puredata/examples/resonators_add_delays.py b/embedded/puredata/examples/resonators_add_delays.py
new file mode 100644
index 0000000..554ecce
--- /dev/null
+++ b/embedded/puredata/examples/resonators_add_delays.py
@@ -0,0 +1,3 @@
+deltime = SigTo(.25, 0.005, 0.25)
+delfeed = SigTo(.25, 0.005, 0.25)
+dd = Delay(wgs, delay=deltime, feedback=delfeed).out(0)
diff --git a/embedded/puredata/m_pd.h b/embedded/puredata/m_pd.h
new file mode 100755
index 0000000..71bd28e
--- /dev/null
+++ b/embedded/puredata/m_pd.h
@@ -0,0 +1,665 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __m_pd_h_
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+extern "C" {
+#endif
+
+#define PD_MAJOR_VERSION 0
+#define PD_MINOR_VERSION 41
+#define PD_BUGFIX_VERSION 4
+#define PD_TEST_VERSION "extended"
+
+/* old name for "MSW" flag -- we have to take it for the sake of many old
+"nmakefiles" for externs, which will define NT and not MSW */
+#if defined(NT) && !defined(MSW)
+#define MSW
+#endif
+
+/* These pragmas are only used for MSVC, not MinGW or Cygwin <hans at at.or.at> */
+#ifdef _MSC_VER
+/* #pragma warning( disable : 4091 ) */
+#pragma warning( disable : 4305 ) /* uncast const double to float */
+#pragma warning( disable : 4244 ) /* uncast float/int conversion etc. */
+#pragma warning( disable : 4101 ) /* unused automatic variables */
+#endif /* _MSC_VER */
+
+ /* the external storage class is "extern" in UNIX; in MSW it's ugly. */
+#ifdef MSW
+#ifdef PD_INTERNAL
+#define EXTERN __declspec(dllexport) extern
+#else
+#define EXTERN __declspec(dllimport) extern
+#endif /* PD_INTERNAL */
+#else
+#define EXTERN extern
+#endif /* MSW */
+
+ /* and depending on the compiler, hidden data structures are
+ declared differently: */
+#if defined( __GNUC__) || defined( __BORLANDC__ ) || defined( __MWERKS__ )
+#define EXTERN_STRUCT struct
+#else
+#define EXTERN_STRUCT extern struct
+#endif
+
+
+#if !defined(_SIZE_T) && !defined(_SIZE_T_)
+#include <stddef.h> /* just for size_t -- how lame! */
+#endif
+
+#define MAXPDSTRING 1000 /* must be >= FILENAME_MAX */
+#define MAXPDARG 5 /* max number of args we can typecheck today */
+
+/* signed and unsigned integer types the size of a pointer: */
+/* GG: long is the size of a pointer */
+typedef long t_int;
+
+typedef float t_float; /* a floating-point number at most the same size */
+typedef float t_floatarg; /* floating-point type for function calls */
+
+typedef struct _symbol
+{
+ char *s_name;
+ struct _class **s_thing;
+ struct _symbol *s_next;
+} t_symbol;
+
+EXTERN_STRUCT _array;
+#define t_array struct _array /* g_canvas.h */
+
+/* pointers to glist and array elements go through a "stub" which sticks
+around after the glist or array is freed. The stub itself is deleted when
+both the glist/array is gone and the refcount is zero, ensuring that no
+gpointers are pointing here. */
+
+#define GP_NONE 0 /* the stub points nowhere (has been cut off) */
+#define GP_GLIST 1 /* the stub points to a glist element */
+#define GP_ARRAY 2 /* ... or array */
+
+typedef struct _gstub
+{
+ union
+ {
+ struct _glist *gs_glist; /* glist we're in */
+ struct _array *gs_array; /* array we're in */
+ } gs_un;
+ int gs_which; /* GP_GLIST/GP_ARRAY */
+ int gs_refcount; /* number of gpointers pointing here */
+} t_gstub;
+
+typedef struct _gpointer /* pointer to a gobj in a glist */
+{
+ union
+ {
+ struct _scalar *gp_scalar; /* scalar we're in (if glist) */
+ union word *gp_w; /* raw data (if array) */
+ } gp_un;
+ int gp_valid; /* number which must match gpointee */
+ t_gstub *gp_stub; /* stub which points to glist/array */
+} t_gpointer;
+
+#define PD_BLOBS 1 /* MP20070211 Use this to test for blob capability */
+/* MP20061223 blob type: */
+typedef struct _blob /* pointer to a blob */
+{
+ unsigned long s_length; /* length of blob in bytes */
+ unsigned char *s_data; /* pointer to 1st byte of blob */
+} t_blob;
+/* ...MP20061223 blob type */
+
+
+typedef union word
+{
+ t_float w_float;
+ t_symbol *w_symbol;
+ t_gpointer *w_gpointer;
+ t_array *w_array;
+ struct _glist *w_list;
+ int w_index;
+ t_blob *w_blob; /* MP20061223 blob type */
+} t_word;
+
+typedef enum
+{
+ A_NULL,
+ A_FLOAT,
+ A_SYMBOL,
+ A_POINTER,
+ A_SEMI,
+ A_COMMA,
+ A_DEFFLOAT,
+ A_DEFSYM,
+ A_DOLLAR,
+ A_DOLLSYM,
+ A_GIMME,
+ A_CANT,
+ A_BLOB /* MP20061223 blob type */
+} t_atomtype;
+
+#define A_DEFSYMBOL A_DEFSYM /* better name for this */
+
+typedef struct _atom
+{
+ t_atomtype a_type;
+ union word a_w;
+} t_atom;
+
+EXTERN_STRUCT _class;
+#define t_class struct _class
+
+EXTERN_STRUCT _outlet;
+#define t_outlet struct _outlet
+
+EXTERN_STRUCT _inlet;
+#define t_inlet struct _inlet
+
+EXTERN_STRUCT _binbuf;
+#define t_binbuf struct _binbuf
+
+EXTERN_STRUCT _clock;
+#define t_clock struct _clock
+
+EXTERN_STRUCT _outconnect;
+#define t_outconnect struct _outconnect
+
+EXTERN_STRUCT _glist;
+#define t_glist struct _glist
+#define t_canvas struct _glist /* LATER lose this */
+
+typedef t_class *t_pd; /* pure datum: nothing but a class pointer */
+
+typedef struct _gobj /* a graphical object */
+{
+ t_pd g_pd; /* pure datum header (class) */
+ struct _gobj *g_next; /* next in list */
+} t_gobj;
+
+typedef struct _scalar /* a graphical object holding data */
+{
+ t_gobj sc_gobj; /* header for graphical object */
+ t_symbol *sc_template; /* template name (LATER replace with pointer) */
+ t_word sc_vec[1]; /* indeterminate-length array of words */
+} t_scalar;
+
+typedef struct _text /* patchable object - graphical, with text */
+{
+ t_gobj te_g; /* header for graphical object */
+ t_binbuf *te_binbuf; /* holder for the text */
+ t_outlet *te_outlet; /* linked list of outlets */
+ t_inlet *te_inlet; /* linked list of inlets */
+ short te_xpix; /* x&y location (within the toplevel) */
+ short te_ypix;
+ short te_width; /* requested width in chars, 0 if auto */
+ unsigned int te_type:2; /* from defs below */
+} t_text;
+
+#define T_TEXT 0 /* just a textual comment */
+#define T_OBJECT 1 /* a MAX style patchable object */
+#define T_MESSAGE 2 /* a MAX stype message */
+#define T_ATOM 3 /* a cell to display a number or symbol */
+
+#define te_pd te_g.g_pd
+
+ /* t_object is synonym for t_text (LATER unify them) */
+
+typedef struct _text t_object;
+
+#define ob_outlet te_outlet
+#define ob_inlet te_inlet
+#define ob_binbuf te_binbuf
+#define ob_pd te_g.g_pd
+#define ob_g te_g
+
+typedef void (*t_method)(void);
+typedef void *(*t_newmethod)( void);
+typedef void (*t_gotfn)(void *x, ...);
+
+/* ---------------- pre-defined objects and symbols --------------*/
+EXTERN t_pd pd_objectmaker; /* factory for creating "object" boxes */
+EXTERN t_pd pd_canvasmaker; /* factory for creating canvases */
+EXTERN t_symbol s_pointer;
+EXTERN t_symbol s_float;
+EXTERN t_symbol s_symbol;
+EXTERN t_symbol s_blob;
+EXTERN t_symbol s_bang;
+EXTERN t_symbol s_list;
+EXTERN t_symbol s_anything;
+EXTERN t_symbol s_signal;
+EXTERN t_symbol s__N;
+EXTERN t_symbol s__X;
+EXTERN t_symbol s_x;
+EXTERN t_symbol s_y;
+EXTERN t_symbol s_;
+
+/* --------- prototypes from the central message system ----------- */
+EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv);
+EXTERN t_symbol *gensym(const char *s);
+EXTERN t_gotfn getfn(t_pd *x, t_symbol *s);
+EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s);
+EXTERN void nullfn(void);
+EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...);
+#define mess0(x, s) ((*getfn((x), (s)))((x)))
+#define mess1(x, s, a) ((*getfn((x), (s)))((x), (a)))
+#define mess2(x, s, a,b) ((*getfn((x), (s)))((x), (a),(b)))
+#define mess3(x, s, a,b,c) ((*getfn((x), (s)))((x), (a),(b),(c)))
+#define mess4(x, s, a,b,c,d) ((*getfn((x), (s)))((x), (a),(b),(c),(d)))
+#define mess5(x, s, a,b,c,d,e) ((*getfn((x), (s)))((x), (a),(b),(c),(d),(e)))
+EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN t_pd *pd_newest(void);
+
+/* --------------- memory management -------------------- */
+EXTERN void *getbytes(size_t nbytes);
+EXTERN void *getzbytes(size_t nbytes);
+EXTERN void *copybytes(void *src, size_t nbytes);
+EXTERN void freebytes(void *x, size_t nbytes);
+EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize);
+
+/* -------------------- atoms ----------------------------- */
+
+#define SETSEMI(atom) ((atom)->a_type = A_SEMI, (atom)->a_w.w_index = 0)
+#define SETCOMMA(atom) ((atom)->a_type = A_COMMA, (atom)->a_w.w_index = 0)
+#define SETPOINTER(atom, gp) ((atom)->a_type = A_POINTER, \
+ (atom)->a_w.w_gpointer = (gp))
+#define SETFLOAT(atom, f) ((atom)->a_type = A_FLOAT, (atom)->a_w.w_float = (f))
+#define SETSYMBOL(atom, s) ((atom)->a_type = A_SYMBOL, \
+ (atom)->a_w.w_symbol = (s))
+#define SETBLOB(atom, st) ((atom)->a_type = A_BLOB, (atom)->a_w.w_blob = (st)) /* MP 20061226 blob type */
+#define SETDOLLAR(atom, n) ((atom)->a_type = A_DOLLAR, \
+ (atom)->a_w.w_index = (n))
+#define SETDOLLSYM(atom, s) ((atom)->a_type = A_DOLLSYM, \
+ (atom)->a_w.w_symbol= (s))
+
+EXTERN t_float atom_getfloat(t_atom *a);
+EXTERN t_int atom_getint(t_atom *a);
+EXTERN t_symbol *atom_getsymbol(t_atom *a);
+EXTERN t_blob *atom_getblob(t_atom *a);/* MP 20070108 blob type */
+EXTERN t_symbol *atom_gensym(t_atom *a);
+EXTERN t_float atom_getfloatarg(int which, int argc, t_atom *argv);
+EXTERN t_int atom_getintarg(int which, int argc, t_atom *argv);
+EXTERN t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv);
+
+EXTERN void atom_string(t_atom *a, char *buf, unsigned int bufsize);
+
+/* ------------------ binbufs --------------- */
+
+EXTERN t_binbuf *binbuf_new(void);
+EXTERN void binbuf_free(t_binbuf *x);
+EXTERN t_binbuf *binbuf_duplicate(t_binbuf *y);
+
+EXTERN void binbuf_text(t_binbuf *x, char *text, size_t size);
+EXTERN void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp);
+EXTERN void binbuf_clear(t_binbuf *x);
+EXTERN void binbuf_add(t_binbuf *x, int argc, t_atom *argv);
+EXTERN void binbuf_addv(t_binbuf *x, char *fmt, ...);
+EXTERN void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y);
+EXTERN void binbuf_addsemi(t_binbuf *x);
+EXTERN void binbuf_restore(t_binbuf *x, int argc, t_atom *argv);
+EXTERN void binbuf_print(t_binbuf *x);
+EXTERN int binbuf_getnatom(t_binbuf *x);
+EXTERN t_atom *binbuf_getvec(t_binbuf *x);
+EXTERN void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv);
+EXTERN int binbuf_read(t_binbuf *b, char *filename, char *dirname,
+ int crflag);
+EXTERN int binbuf_read_via_canvas(t_binbuf *b, char *filename, t_canvas *canvas,
+ int crflag);
+EXTERN int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname,
+ int crflag);
+EXTERN int binbuf_write(t_binbuf *x, char *filename, char *dir,
+ int crflag);
+EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir);
+EXTERN t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av,
+ int tonew);
+
+/* ------------------ clocks --------------- */
+
+EXTERN t_clock *clock_new(void *owner, t_method fn);
+EXTERN void clock_set(t_clock *x, double systime);
+EXTERN void clock_delay(t_clock *x, double delaytime);
+EXTERN void clock_unset(t_clock *x);
+EXTERN double clock_getlogicaltime(void);
+EXTERN double clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */
+EXTERN double clock_gettimesince(double prevsystime);
+EXTERN double clock_getsystimeafter(double delaytime);
+EXTERN void clock_free(t_clock *x);
+
+/* ----------------- pure data ---------------- */
+EXTERN t_pd *pd_new(t_class *cls);
+EXTERN void pd_free(t_pd *x);
+EXTERN void pd_bind(t_pd *x, t_symbol *s);
+EXTERN void pd_unbind(t_pd *x, t_symbol *s);
+EXTERN t_pd *pd_findbyclass(t_symbol *s, t_class *c);
+EXTERN void pd_pushsym(t_pd *x);
+EXTERN void pd_popsym(t_pd *x);
+EXTERN t_symbol *pd_getfilename(void);
+EXTERN t_symbol *pd_getdirname(void);
+EXTERN void pd_bang(t_pd *x);
+EXTERN void pd_pointer(t_pd *x, t_gpointer *gp);
+EXTERN void pd_float(t_pd *x, t_float f);
+EXTERN void pd_symbol(t_pd *x, t_symbol *s);
+EXTERN void pd_blob(t_pd *x, t_blob *st); /* MP 20061226 blob type */
+EXTERN void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void pd_anything(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+#define pd_class(x) (*(x))
+
+/* ----------------- pointers ---------------- */
+EXTERN void gpointer_init(t_gpointer *gp);
+EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto);
+EXTERN void gpointer_unset(t_gpointer *gp);
+EXTERN int gpointer_check(const t_gpointer *gp, int headok);
+
+/* ----------------- patchable "objects" -------------- */
+EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1,
+ t_symbol *s2);
+EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp);
+EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp);
+EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp);
+EXTERN t_inlet *signalinlet_new(t_object *owner, t_float f);
+EXTERN void inlet_free(t_inlet *x);
+
+EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s);
+EXTERN void outlet_bang(t_outlet *x);
+EXTERN void outlet_pointer(t_outlet *x, t_gpointer *gp);
+EXTERN void outlet_float(t_outlet *x, t_float f);
+EXTERN void outlet_symbol(t_outlet *x, t_symbol *s);
+EXTERN void outlet_blob(t_outlet *x, t_blob *st); /* MP 20061226 blob type */
+EXTERN void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN t_symbol *outlet_getsymbol(t_outlet *x);
+EXTERN void outlet_free(t_outlet *x);
+EXTERN t_object *pd_checkobject(t_pd *x);
+
+
+/* -------------------- canvases -------------- */
+
+EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir);
+
+EXTERN void canvas_setargs(int argc, t_atom *argv);
+EXTERN void canvas_getargs(int *argcp, t_atom **argvp);
+EXTERN t_symbol *canvas_getcurrentdir(void);
+EXTERN t_glist *canvas_getcurrent(void);
+EXTERN void canvas_makefilename(t_glist *c, char *file,
+ char *result,int resultsize);
+EXTERN t_symbol *canvas_getdir(t_glist *x);
+EXTERN char sys_font[]; /* default typeface set in s_main.c */
+EXTERN char sys_fontweight[]; /* default font weight set in s_main.c */
+EXTERN int sys_fontwidth(int fontsize);
+EXTERN int sys_fontheight(int fontsize);
+EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b);
+EXTERN int canvas_open(t_canvas *x, const char *name, const char *ext,
+ char *dirresult, char **nameresult, unsigned int size, int bin);
+
+/* ---------------- widget behaviors ---------------------- */
+
+EXTERN_STRUCT _widgetbehavior;
+#define t_widgetbehavior struct _widgetbehavior
+
+EXTERN_STRUCT _parentwidgetbehavior;
+#define t_parentwidgetbehavior struct _parentwidgetbehavior
+EXTERN t_parentwidgetbehavior *pd_getparentwidget(t_pd *x);
+
+/* -------------------- classes -------------- */
+
+#define CLASS_DEFAULT 0 /* flags for new classes below */
+#define CLASS_PD 1
+#define CLASS_GOBJ 2
+#define CLASS_PATCHABLE 3
+#define CLASS_NOINLET 8
+
+#define CLASS_TYPEMASK 3
+
+
+EXTERN t_class *class_new(t_symbol *name, t_newmethod newmethod,
+ t_method freemethod, size_t size, int flags, t_atomtype arg1, ...);
+EXTERN void class_addcreator(t_newmethod newmethod, t_symbol *s,
+ t_atomtype type1, ...);
+EXTERN void class_addmethod(t_class *c, t_method fn, t_symbol *sel,
+ t_atomtype arg1, ...);
+EXTERN void class_addbang(t_class *c, t_method fn);
+EXTERN void class_addpointer(t_class *c, t_method fn);
+EXTERN void class_doaddfloat(t_class *c, t_method fn);
+EXTERN void class_addsymbol(t_class *c, t_method fn);
+EXTERN void class_addblob(t_class *c, t_method fn);/* MP 20061226 blob type */
+EXTERN void class_addlist(t_class *c, t_method fn);
+EXTERN void class_addanything(t_class *c, t_method fn);
+EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s);
+EXTERN void class_setwidget(t_class *c, t_widgetbehavior *w);
+EXTERN void class_setparentwidget(t_class *c, t_parentwidgetbehavior *w);
+EXTERN t_parentwidgetbehavior *class_parentwidget(t_class *c);
+EXTERN char *class_getname(t_class *c);
+EXTERN char *class_gethelpname(t_class *c);
+EXTERN void class_setdrawcommand(t_class *c);
+EXTERN int class_isdrawcommand(t_class *c);
+EXTERN void class_domainsignalin(t_class *c, int onset);
+EXTERN void class_set_extern_dir(t_symbol *s);
+#define CLASS_MAINSIGNALIN(c, type, field) \
+ class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0)
+
+ /* prototype for functions to save Pd's to a binbuf */
+typedef void (*t_savefn)(t_gobj *x, t_binbuf *b);
+EXTERN void class_setsavefn(t_class *c, t_savefn f);
+EXTERN t_savefn class_getsavefn(t_class *c);
+ /* prototype for functions to open properties dialogs */
+typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist);
+EXTERN void class_setpropertiesfn(t_class *c, t_propertiesfn f);
+EXTERN t_propertiesfn class_getpropertiesfn(t_class *c);
+
+#ifndef PD_CLASS_DEF
+#define class_addbang(x, y) class_addbang((x), (t_method)(y))
+#define class_addpointer(x, y) class_addpointer((x), (t_method)(y))
+#define class_addfloat(x, y) class_doaddfloat((x), (t_method)(y))
+#define class_addsymbol(x, y) class_addsymbol((x), (t_method)(y))
+#define class_addblob(x, y) class_addblob((x), (t_method)(y)) /* MP20061226 blob type */
+#define class_addlist(x, y) class_addlist((x), (t_method)(y))
+#define class_addanything(x, y) class_addanything((x), (t_method)(y))
+#endif
+
+/* ------------ printing --------------------------------- */
+EXTERN void post(const char *fmt, ...);
+EXTERN void startpost(const char *fmt, ...);
+EXTERN void poststring(const char *s);
+EXTERN void postfloat(float f);
+EXTERN void postatom(int argc, t_atom *argv);
+EXTERN void endpost(void);
+EXTERN void error(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+EXTERN void verbose(int level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+EXTERN void bug(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+EXTERN void pd_error(void *object, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+EXTERN void sys_logerror(const char *object, const char *s);
+EXTERN void sys_unixerror(const char *object);
+EXTERN void sys_ouch(void);
+
+
+/* ------------ system interface routines ------------------- */
+EXTERN int sys_isreadablefile(const char *name);
+EXTERN int sys_isabsolutepath(const char *dir);
+EXTERN void sys_bashfilename(const char *from, char *to);
+EXTERN void sys_unbashfilename(const char *from, char *to);
+EXTERN int open_via_path(const char *name, const char *ext, const char *dir,
+ char *dirresult, char **nameresult, unsigned int size, int bin);
+EXTERN int sched_geteventno(void);
+EXTERN double sys_getrealtime(void);
+EXTERN int (*sys_idlehook)(void); /* hook to add idle time computation */
+
+
+/* ------------ threading ------------------- */
+EXTERN void sys_lock(void);
+EXTERN void sys_unlock(void);
+EXTERN int sys_trylock(void);
+
+
+/* --------------- signals ----------------------------------- */
+
+typedef float t_sample;
+#define MAXLOGSIG 32
+#define MAXSIGSIZE (1 << MAXLOGSIG)
+
+typedef struct _signal
+{
+ int s_n; /* number of points in the array */
+ t_sample *s_vec; /* the array */
+ t_float s_sr; /* sample rate */
+ int s_refcount; /* number of times used */
+ int s_isborrowed; /* whether we're going to borrow our array */
+ struct _signal *s_borrowedfrom; /* signal to borrow it from */
+ struct _signal *s_nextfree; /* next in freelist */
+ struct _signal *s_nextused; /* next in used list */
+ int s_vecsize; /* allocated size of array in points */
+} t_signal;
+
+typedef t_int *(*t_perfroutine)(t_int *args);
+
+EXTERN t_int *plus_perform(t_int *args);
+EXTERN t_int *zero_perform(t_int *args);
+EXTERN t_int *copy_perform(t_int *args);
+
+EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n);
+EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n);
+EXTERN void dsp_add_scalarcopy(t_float *in, t_sample *out, int n);
+EXTERN void dsp_add_zero(t_sample *out, int n);
+
+EXTERN int sys_getblksize(void);
+EXTERN t_float sys_getsr(void);
+EXTERN int sys_get_inchannels(void);
+EXTERN int sys_get_outchannels(void);
+
+EXTERN void dsp_add(t_perfroutine f, int n, ...);
+EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec);
+EXTERN void pd_fft(t_float *buf, int npoints, int inverse);
+EXTERN int ilog2(int n);
+
+EXTERN void mayer_fht(t_sample *fz, int n);
+EXTERN void mayer_fft(int n, t_sample *real, t_sample *imag);
+EXTERN void mayer_ifft(int n, t_sample *real, t_sample *imag);
+EXTERN void mayer_realfft(int n, t_sample *real);
+EXTERN void mayer_realifft(int n, t_sample *real);
+
+EXTERN float *cos_table;
+#define LOGCOSTABSIZE 9
+#define COSTABSIZE (1<<LOGCOSTABSIZE)
+
+EXTERN int canvas_suspend_dsp(void);
+EXTERN void canvas_resume_dsp(int oldstate);
+EXTERN void canvas_update_dsp(void);
+EXTERN int canvas_dspstate;
+
+/* up/downsampling */
+typedef struct _resample
+{
+ int method; /* up/downsampling method ID */
+
+ t_int downsample; /* downsampling factor */
+ t_int upsample; /* upsampling factor */
+
+ t_sample *s_vec; /* here we hold the resampled data */
+ int s_n;
+
+ t_sample *coeffs; /* coefficients for filtering... */
+ int coefsize;
+
+ t_sample *buffer; /* buffer for filtering */
+ int bufsize;
+} t_resample;
+
+EXTERN void resample_init(t_resample *x);
+EXTERN void resample_free(t_resample *x);
+
+EXTERN void resample_dsp(t_resample *x, t_sample *in, int insize, t_sample *out, int outsize, int method);
+EXTERN void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method);
+EXTERN void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method);
+
+/* ----------------------- utility functions for signals -------------- */
+EXTERN t_float mtof(t_float);
+EXTERN t_float ftom(t_float);
+EXTERN t_float rmstodb(t_float);
+EXTERN t_float powtodb(t_float);
+EXTERN t_float dbtorms(t_float);
+EXTERN t_float dbtopow(t_float);
+
+EXTERN t_float q8_sqrt(t_float);
+EXTERN t_float q8_rsqrt(t_float);
+#ifndef N32
+EXTERN t_float qsqrt(t_float); /* old names kept for extern compatibility */
+EXTERN t_float qrsqrt(t_float);
+#endif
+/* --------------------- data --------------------------------- */
+
+ /* graphical arrays */
+EXTERN_STRUCT _garray;
+#define t_garray struct _garray
+
+EXTERN t_class *garray_class;
+EXTERN int garray_getfloatarray(t_garray *x, int *size, t_float **vec);
+EXTERN int garray_getfloatwords(t_garray *x, int *size, t_word **vec);
+EXTERN t_float garray_get(t_garray *x, t_symbol *s, t_int indx);
+EXTERN void garray_redraw(t_garray *x);
+EXTERN int garray_npoints(t_garray *x);
+EXTERN char *garray_vec(t_garray *x);
+EXTERN void garray_resize(t_garray *x, t_floatarg f);
+EXTERN void garray_usedindsp(t_garray *x);
+EXTERN void garray_setsaveit(t_garray *x, int saveit);
+EXTERN t_class *scalar_class;
+
+EXTERN t_float *value_get(t_symbol *s);
+EXTERN void value_release(t_symbol *s);
+EXTERN int value_getfloat(t_symbol *s, t_float *f);
+EXTERN int value_setfloat(t_symbol *s, t_float f);
+
+/* ------- GUI interface - functions to send strings to TK --------- */
+typedef void (*t_guicallbackfn)(t_gobj *client, t_glist *glist);
+
+EXTERN void sys_vgui(char *fmt, ...);
+EXTERN void sys_gui(char *s);
+EXTERN void sys_pretendguibytes(int n);
+EXTERN void sys_queuegui(void *client, t_glist *glist, t_guicallbackfn f);
+EXTERN void sys_unqueuegui(void *client);
+ /* dialog window creation and destruction */
+EXTERN void gfxstub_new(t_pd *owner, void *key, const char *cmd);
+EXTERN void gfxstub_deleteforkey(void *key);
+
+extern t_class *glob_pdobject; /* object to send "pd" messages */
+
+/*------------- Max 0.26 compatibility --------------------*/
+
+/* the following reflects the new way classes are laid out, with the class
+ pointing to the messlist and not vice versa. Externs shouldn't feel it. */
+typedef t_class *t_externclass;
+
+EXTERN void c_extern(t_externclass *cls, t_newmethod newroutine,
+ t_method freeroutine, t_symbol *name, size_t size, int tiny, \
+ t_atomtype arg1, ...);
+EXTERN void c_addmess(t_method fn, t_symbol *sel, t_atomtype arg1, ...);
+
+#define t_getbytes getbytes
+#define t_freebytes freebytes
+#define t_resizebytes resizebytes
+#define typedmess pd_typedmess
+#define vmess pd_vmess
+
+/* A definition to help gui objects straddle 0.34-0.35 changes. If this is
+defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */
+
+#define PD_USE_TE_XPIX
+
+#if defined(__i386__) || defined(__x86_64__)
+/* a test for NANs and denormals. Should only be necessary on i386. */
+#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \
+ (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000))
+/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */
+#define PD_BIGORSMALL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \
+ (((*(unsigned int*)&(f))&0x60000000)==0x60000000))
+#else
+#define PD_BADFLOAT(f) 0
+#define PD_BIGORSMALL(f) 0
+#endif
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
+
+#define __m_pd_h_
+#endif /* __m_pd_h_ */
diff --git a/embedded/puredata/pyo~-help.pd b/embedded/puredata/pyo~-help.pd
new file mode 100644
index 0000000..e8c9c8a
--- /dev/null
+++ b/embedded/puredata/pyo~-help.pd
@@ -0,0 +1,311 @@
+#N canvas 296 140 952 365 10;
+#X obj 28 108 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X obj 144 108 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1
+1;
+#X obj 13 234 *~;
+#X obj 51 234 *~;
+#X obj 13 256 dac~;
+#X obj 72 213 hsl 128 15 0 1 0 1 empty empty master_gain -2 -8 0 10
+-262144 -1 -1 6200 1;
+#X obj 274 223 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1
+1;
+#X msg 274 243 \; pd dsp \$1;
+#X obj 13 59 r msg_to_pyo;
+#X text 161 107 play;
+#X obj 13 166 pyo~ 2;
+#X text 66 168 argument sets the number of audio ins/outs (defaults
+to 2).;
+#N canvas 1 75 824 583 resonators_example 0;
+#X obj 35 103 hsl 128 15 0.01 30 1 0 empty empty resonance -2 -8 0
+10 -262144 -1 -1 11200 0;
+#X floatatom 32 120 5 0 0 0 - - -;
+#X obj 21 530 s msg_to_pyo;
+#X obj 98 387 hsl 128 15 0 1 0 0 empty empty delay_time -2 -8 0 10
+-262144 -1 -1 1300 0;
+#X floatatom 95 403 5 0 0 0 - - -;
+#X msg 95 418 value deltime \$1;
+#X obj 111 454 hsl 128 15 0 1 0 0 empty empty delay_feedback -2 -8
+0 10 -262144 -1 -1 10800 0;
+#X floatatom 108 470 5 0 0 0 - - -;
+#X msg 108 485 value delfeed \$1;
+#X msg 32 136 value reson \$1;
+#X obj 52 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 4700 0;
+#X obj 71 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 3200 0;
+#X obj 91 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 5800 0;
+#X obj 110 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 7100 0;
+#X obj 130 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 5500 0;
+#X obj 149 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 7100 0;
+#X obj 169 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 4400 0;
+#X obj 189 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 1800 0;
+#X msg 52 306 value freqs \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8;
+#X obj 52 264 bondo 8 ____________;
+#X obj 52 285 pack f f f f f f f f;
+#X msg 21 66 read examples/resonators.py;
+#X msg 73 351 read -a examples/resonators_add_delays.py;
+#X text 52 159 resonator frequencies;
+#X text 20 30 load pyo processing file (audio signal must be given
+in pyo~ inputs).;
+#X text 168 103 adjust resonance in seconds;
+#X text 214 209 play with resonator frequencies;
+#X text 380 352 add a stereo delay taking resonator outputs as its
+input;
+#X text 234 387 adjust delay time;
+#X text 246 453 adjust delay feedback;
+#X connect 0 0 1 0;
+#X connect 1 0 9 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 8 0 2 0;
+#X connect 9 0 2 0;
+#X connect 10 0 19 0;
+#X connect 11 0 19 1;
+#X connect 12 0 19 2;
+#X connect 13 0 19 3;
+#X connect 14 0 19 4;
+#X connect 15 0 19 5;
+#X connect 16 0 19 6;
+#X connect 17 0 19 7;
+#X connect 18 0 2 0;
+#X connect 19 0 20 0;
+#X connect 19 1 20 1;
+#X connect 19 2 20 2;
+#X connect 19 3 20 3;
+#X connect 19 4 20 4;
+#X connect 19 5 20 5;
+#X connect 19 6 20 6;
+#X connect 19 7 20 7;
+#X connect 20 0 18 0;
+#X connect 21 0 2 0;
+#X connect 22 0 2 0;
+#X restore 531 60 pd resonators_example;
+#X msg 553 171 clear;
+#X obj 531 199 s msg_to_pyo;
+#X text 598 172 shutdown and reboot the server;
+#N canvas 1 75 450 300 synthesis_example 0;
+#N canvas 1 75 375 358 choose_sines 0;
+#X obj 57 77 metro 125;
+#X obj 78 109 hsl 128 15 0 36 0 0 empty empty empty -2 -8 0 10 -262144
+-1 -1 4233 1;
+#X obj 127 144 hsl 128 15 0 36 0 0 empty empty empty -2 -8 0 10 -262144
+-1 -1 4233 1;
+#X floatatom 75 125 5 0 0 0 - - -;
+#X floatatom 124 160 5 0 0 0 - - -;
+#X obj 124 209 +;
+#X obj 124 179 t b f;
+#X obj 75 144 t f f;
+#X obj 57 240 int;
+#X obj 124 232 int;
+#X msg 57 288 call choose \$1 \$2;
+#X obj 57 311 outlet;
+#X obj 57 54 inlet;
+#X obj 57 265 pack 24 24;
+#X text 7 3 Choose a random midi pitch between x and x+y;
+#X text 213 109 x;
+#X text 263 142 y;
+#X obj 224 42 loadbang;
+#X msg 224 64 12;
+#X obj 117 54 inlet speed;
+#X connect 0 0 8 0;
+#X connect 1 0 3 0;
+#X connect 2 0 4 0;
+#X connect 3 0 7 0;
+#X connect 4 0 6 0;
+#X connect 5 0 9 0;
+#X connect 6 0 5 0;
+#X connect 6 1 5 1;
+#X connect 7 0 8 1;
+#X connect 7 1 5 0;
+#X connect 8 0 13 0;
+#X connect 9 0 13 1;
+#X connect 10 0 11 0;
+#X connect 12 0 0 0;
+#X connect 13 0 10 0;
+#X connect 17 0 18 0;
+#X connect 18 0 1 0;
+#X connect 18 0 2 0;
+#X connect 19 0 0 1;
+#X restore 53 130 pd choose_sines;
+#X obj 41 246 s msg_to_pyo;
+#X obj 53 96 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1
+;
+#X obj 67 172 hsl 128 15 0 0.25 0 0 empty empty brightness -2 -8 0
+10 -262144 -1 -1 0 0;
+#X floatatom 64 188 5 0 0 0 - - -;
+#X msg 64 203 value feed \$1;
+#X obj 158 75 hsl 128 15 50 500 0 0 empty empty metro_speed -2 -8 0
+10 -262144 -1 -1 0 1;
+#X floatatom 155 93 5 0 0 0 - - -;
+#X floatatom 222 186 5 0 0 0 - - -;
+#X msg 222 216 set amp.fadeout \$1;
+#X msg 281 184 set amp.dur \$1;
+#X floatatom 281 165 5 0 0 0 - - -;
+#X obj 222 132 * 0.001;
+#X obj 221 111 - 20;
+#X obj 222 165 - 0.005;
+#X msg 41 33 read -a examples/random_waves.py;
+#X text 54 80 GO!;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 5 0 1 0;
+#X connect 6 0 7 0;
+#X connect 7 0 0 1;
+#X connect 7 0 13 0;
+#X connect 8 0 9 0;
+#X connect 9 0 1 0;
+#X connect 10 0 1 0;
+#X connect 11 0 10 0;
+#X connect 12 0 11 0;
+#X connect 12 0 14 0;
+#X connect 13 0 12 0;
+#X connect 14 0 8 0;
+#X connect 15 0 1 0;
+#X restore 531 84 pd synthesis_example;
+#N canvas 1 75 629 295 loop_soundfile 0;
+#X obj 43 42 openpanel;
+#X obj 43 64 t a b;
+#X obj 43 170 soundfiler;
+#X obj 236 80 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X obj 43 20 inlet open file;
+#X obj 392 16 inlet start;
+#X obj 236 52 sel 1;
+#X obj 236 205 outlet~;
+#X obj 347 163 spigot 1;
+#X obj 43 126 pack s s s;
+#X obj 71 86 symbol \$0-table_l;
+#X obj 100 105 symbol \$0-table_r;
+#X msg 43 148 read -resize \$1 \$2 \$3;
+#X obj 44 200 table \$0-table_l;
+#X obj 44 223 table \$0-table_r;
+#X obj 423 206 outlet~;
+#X obj 236 140 tabplay~ \$0-table_l;
+#X obj 424 140 tabplay~ \$0-table_r;
+#X connect 0 0 1 0;
+#X connect 1 0 9 0;
+#X connect 1 1 10 0;
+#X connect 1 1 11 0;
+#X connect 3 0 16 0;
+#X connect 3 0 17 0;
+#X connect 4 0 0 0;
+#X connect 5 0 6 0;
+#X connect 5 0 8 1;
+#X connect 6 0 3 0;
+#X connect 8 0 16 0;
+#X connect 8 0 17 0;
+#X connect 9 0 12 0;
+#X connect 10 0 9 1;
+#X connect 11 0 9 2;
+#X connect 12 0 2 0;
+#X connect 16 0 7 0;
+#X connect 16 1 8 0;
+#X connect 17 0 15 0;
+#X restore 28 126 pd loop_soundfile;
+#X text 44 108 load file;
+#N canvas 1 75 532 224 conv_reverb_example 0;
+#X obj 24 110 hsl 128 15 0 1 0 0 empty empty balance -2 -8 0 10 -262144
+-1 -1 0 0;
+#X floatatom 21 127 5 0 0 0 - - -;
+#X msg 21 143 value bal \$1;
+#X obj -3 170 s msg_to_pyo;
+#X msg -3 74 read examples/cvlverb.py;
+#X text -5 38 load pyo processing file (audio signal must be given
+in pyo~ inputs).;
+#X text 162 110 balance between dry and wet signal;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 4 0 3 0;
+#X restore 531 36 pd conv_reverb_example;
+#X text 26 86 play a soundfile to send audio signals to pyo;
+#N canvas 114 140 450 300 README 0;
+#X restore 406 227 pd README;
+#N canvas 198 75 1001 402 MESSAGES 0;
+#X text 20 53 read [-a] path/to/python/script;
+#X text 37 74 The message "read" executes the commands contained in
+the specified python script into the object's internal interpreter.
+If the "-a" flag is given \, new commands will be added to previously
+executed ones. Without the flag \, the server is shut down (this will
+erase actual processing) before the execution of the script.;
+#X text 18 164 value varname \$1 [\$2 \$3 ...];
+#X text 19 250 set varname.attribute \$1 [\$2 \$3 ...];
+#X text 499 43 call function [arg1 arg2 ...];
+#X text 499 229 clear;
+#X text 516 250 Shutdown and reboot pyo's server. This message will
+erase the current processing loaded into the object.;
+#X text 36 185 The messsage "value" sends value(s) to a pyo's Sig or
+SigTo object (with variable name "varname"). Values can be pyo's variables
+(already created in the loaded file) \, float or list (composed of
+floats and/or pyo objects).;
+#X text 516 63 The message "call" executes the function (or object's
+method) with optional arguments. If the callable is a method \, the
+syntax will looks like:;
+#X text 515 103 call varname.method [arg1 arg2 ...];
+#X text 36 351 set frequencies 100 200 300 400 500 600;
+#X text 499 130 create varname object [\$1 \$2 ...];
+#X text -16 3 Here are the messages that can be used to control the
+internal processing of the pyo~ object.;
+#X text 513 149 The message "create" creates a new python object of
+the class "object" \, stored in variable "varname" \, with optional
+initialization arguments. Arguments can be of the form freq=500 or
+mul=0.3 \, without spaces. Named arguments can't be followed by unamed
+arguments.;
+#X text 36 272 The messsage "set" sends value(s) to an attribute of
+any pyo object (with variable name "varname"). Values can be pyo's
+variables (already created in the loaded file) \, float or list (composed
+of floats and/or pyo objects). This message can be used to create a
+standard python variable like (to create a list of floats in variable
+"frequencies"):;
+#X text 499 291 debug \$1;
+#X text 516 312 If \$1 is positive \, messages to pyo will be sent
+through an Exception handler. This is safer and can help to debug messages
+to pyo but it is slower. For a faster execution \, turn off debug mode.
+;
+#X restore 406 248 pd MESSAGES;
+#X msg 553 297 call b.out;
+#X text 11 7 pyo~ object allows to execute processing with pyo (python
+dsp module) inside a puredata patch \, with any number of audio in/out
+channels.;
+#X obj 531 121 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X msg 531 144 debug \$1;
+#X text 549 113 Verbose mode. If on \, error messages from pyo will
+be printed to the Pd window.;
+#X obj 518 323 s msg_to_pyo;
+#X msg 553 234 set pits 0.001 0.002 0.003 0.004;
+#X msg 553 255 create fr Rossler pitch=pits chaos=0.9 mul=250 add=500
+;
+#X msg 553 276 create b SumOsc freq=fr ratio=0.499 index=0.4 mul=0.2
+;
+#X connect 0 0 17 0;
+#X connect 1 0 17 1;
+#X connect 2 0 4 0;
+#X connect 3 0 4 1;
+#X connect 5 0 3 1;
+#X connect 5 0 2 1;
+#X connect 6 0 7 0;
+#X connect 8 0 10 0;
+#X connect 10 0 2 0;
+#X connect 10 1 3 0;
+#X connect 13 0 14 0;
+#X connect 17 0 10 0;
+#X connect 17 1 10 1;
+#X connect 23 0 28 0;
+#X connect 25 0 26 0;
+#X connect 26 0 14 0;
+#X connect 29 0 28 0;
+#X connect 30 0 28 0;
+#X connect 31 0 28 0;
diff --git a/embedded/puredata/pyo~-meta.pd b/embedded/puredata/pyo~-meta.pd
new file mode 100644
index 0000000..18a355f
--- /dev/null
+++ b/embedded/puredata/pyo~-meta.pd
@@ -0,0 +1,6 @@
+#N canvas 15 49 200 200 10;
+#N canvas 25 49 420 300 META 1;
+#X text 13 41 NAME pyo~;
+#X text 10 25 AUTHOR belangeo at gmail.com;
+#X text 10 10 VERSION 0.1;
+#X restore 10 10 pd META;
diff --git a/embedded/puredata/pyo~.c b/embedded/puredata/pyo~.c
new file mode 100644
index 0000000..1e675b1
--- /dev/null
+++ b/embedded/puredata/pyo~.c
@@ -0,0 +1,250 @@
+#include <stdlib.h>
+#include "m_pd.h"
+#include "Python.h"
+#include "m_pyo.h"
+
+static t_class *pyo_tilde_class;
+
+typedef struct _pyo_tilde {
+ t_object obj;
+ t_sample f;
+ int debug;
+ int bs;
+ int add;
+ int chnls;
+ float sr;
+ char *file;
+ t_sample **in;
+ t_sample **out;
+ int id; /* pyo server id */
+ float *inbuf; /* pyo input buffer */
+ float *outbuf; /* pyo output buffer */
+ char *msg; /* preallocated string to construct message for pyo */
+ void (*callback)(int); /* pointer to pyo embedded server callback */
+ PyThreadState *interp; /* Python thread state linked to this sub interpreter */
+} t_pyo_tilde;
+
+t_int *pyo_tilde_perform(t_int *w) {
+ int i, j, n;
+ t_pyo_tilde *x = (t_pyo_tilde *)(w[1]); /* pointer to instance struct */
+ n = (int)(w[2]); /* vector size */
+ t_sample **in = x->in;
+ t_sample **out = x->out;
+ for (i=0; i<n; i++) {
+ for (j=0; j<x->chnls; j++) {
+ x->inbuf[i*x->chnls+j] = in[j][i];
+ }
+ }
+ (*x->callback)(x->id);
+ for (i=0; i<n; i++) {
+ for (j=0; j<x->chnls; j++) {
+ out[j][i] = x->outbuf[i*x->chnls+j];
+ }
+ }
+ return (w+3);
+}
+
+void pyo_tilde_dsp(t_pyo_tilde *x, t_signal **sp) {
+ int i, err;
+ t_sample **dummy = x->in;
+ for (i=0; i<x->chnls; i++)
+ *dummy++ = sp[i]->s_vec;
+ dummy = x->out;
+ for (i=x->chnls; i<x->chnls*2; i++)
+ *dummy++ = sp[i]->s_vec;
+ /* reset pyo only if sampling rate or buffer size have changed */
+ if ((float)sp[0]->s_sr != x->sr || (int)sp[0]->s_n != x->bs) {
+ x->sr = (float)sp[0]->s_sr;
+ x->bs = (int)sp[0]->s_n;
+ pyo_set_server_params(x->interp, x->sr, x->bs);
+ if (x->file != NULL) {
+ err = pyo_exec_file(x->interp, x->file, x->msg, x->add);
+ if (err) {
+ post("Unable to open file < %s >", x->file);
+ x->file = NULL;
+ }
+ }
+ }
+ dsp_add(pyo_tilde_perform, 2, x, sp[0]->s_n);
+}
+
+void *pyo_tilde_new(t_floatarg f) {
+ int i;
+ t_pyo_tilde *x = (t_pyo_tilde *)pd_new(pyo_tilde_class);
+
+ x->chnls = (f) ? f : 2;
+ x->bs = -1;
+ x->sr = -1.0;
+ x->file = NULL;
+ x->add = 0;
+ x->debug = 0;
+
+ /* create signal inlets (first is done in pyo_tilde_setup) */
+ for (i=1; i<x->chnls; i++)
+ inlet_new(&x->obj, &x->obj.ob_pd, &s_signal, &s_signal);
+ /* create signal outlets */
+ for (i=0; i<x->chnls; i++)
+ outlet_new(&x->obj, &s_signal);
+
+ x->in = (t_sample **)getbytes(x->chnls * sizeof(t_sample **));
+ x->out = (t_sample **)getbytes(x->chnls * sizeof(t_sample **));
+ x->msg = (char *)getbytes(262144 * sizeof(char *));
+
+ for (i=0; i<x->chnls; i++)
+ x->in[i] = x->out[i] = 0;
+
+ x->interp = pyo_new_interpreter(x->chnls);
+
+ x->inbuf = (float *)pyo_get_input_buffer_address(x->interp);
+ x->outbuf = (float *)pyo_get_output_buffer_address(x->interp);
+ x->callback = (void *)pyo_get_embedded_callback_address(x->interp);
+ x->id = pyo_get_server_id(x->interp);
+
+ return (void *)x;
+}
+
+void pyo_tilde_free(t_pyo_tilde *x) {
+ freebytes(x->in, sizeof(x->in));
+ freebytes(x->out, sizeof(x->out));
+ freebytes(x->msg, sizeof(x->msg));
+ pyo_end_interpreter(x->interp);
+}
+
+void pyo_tilde_set_value(t_pyo_tilde *x, char *att, int argc, t_atom *argv) {
+ int err, bracket = 0;
+ char fchar[32];
+ t_symbol *c = atom_getsymbol(argv);
+ argc--; argv++;
+ sprintf(x->msg, "%s%s=", c->s_name, att);
+ if (argc > 1) {
+ strcat(x->msg, "[");
+ bracket = 1;
+ }
+ while (argc-- > 0) {
+ if (argv->a_type == A_SYMBOL) {
+ strcat(x->msg, atom_getsymbol(argv)->s_name);
+ }
+ else if (argv->a_type == A_FLOAT) {
+ sprintf(fchar, "%.6f", atom_getfloat(argv));
+ strcat(x->msg, fchar);
+ }
+ if (argc > 0)
+ strcat(x->msg, ",");
+ argv++;
+ }
+ if (bracket)
+ strcat(x->msg, "]");
+ err = pyo_exec_statement(x->interp, x->msg, x->debug);
+ if (err)
+ post("pyo~: %s", x->msg);
+}
+
+void pyo_tilde_value(t_pyo_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+ char *att = ".value";
+ pyo_tilde_set_value(x, att, argc, argv);
+}
+void pyo_tilde_set(t_pyo_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+ char *att = "";
+ pyo_tilde_set_value(x, att, argc, argv);
+}
+
+void pyo_tilde_create(t_pyo_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+ int err;
+ char *varname, *object;
+ char fchar[32];
+ t_symbol *c = atom_getsymbol(argv);
+ varname = c->s_name;
+ argc--; argv++;
+ c = atom_getsymbol(argv);
+ object = c->s_name;
+ argc--; argv++;
+ sprintf(x->msg, "%s=%s(", varname, object);
+ while (argc-- > 0) {
+ if (argv->a_type == A_SYMBOL) {
+ strcat(x->msg, atom_getsymbol(argv)->s_name);
+ }
+ else if (argv->a_type == A_FLOAT) {
+ sprintf(fchar, "%f", atom_getfloat(argv));
+ strcat(x->msg, fchar);
+ }
+ if (argc > 0)
+ strcat(x->msg, ",");
+ argv++;
+ }
+ strcat(x->msg, ")");
+ err = pyo_exec_statement(x->interp, x->msg, x->debug);
+ if (err)
+ post("pyo~: %s", x->msg);
+}
+
+void pyo_tilde_clear(t_pyo_tilde *x) {
+ pyo_server_reboot(x->interp);
+}
+
+void pyo_tilde_debug(t_pyo_tilde *x, t_float debug) {
+ x->debug = debug <= 0 ? 0 : 1;
+}
+
+void pyo_tilde_read(t_pyo_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+ int err;
+ switch (argc) {
+ case 1:
+ x->add = 0;
+ x->file = atom_getsymbol(argv)->s_name;
+ break;
+ case 2:
+ x->add = strcmp(atom_getsymbol(argv++)->s_name, "-a") == 0 ? 1 : 0;
+ x->file = atom_getsymbol(argv)->s_name;
+ break;
+ }
+ if (pyo_is_server_started(x->interp)) {
+ err = pyo_exec_file(x->interp, x->file, x->msg, x->add);
+ if (err) {
+ post("Unable to open file < %s >", x->file);
+ x->file = NULL;
+ }
+ }
+}
+
+void pyo_tilde_call(t_pyo_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+ int err;
+ char fchar[32];
+ sprintf(x->msg, "%s(", atom_getsymbol(argv)->s_name);
+ argc--; argv++;
+ while (argc-- > 0) {
+ if (argv->a_type == A_SYMBOL) {
+ strcat(x->msg, atom_getsymbol(argv)->s_name);
+ }
+ else if (argv->a_type == A_FLOAT) {
+ sprintf(fchar, "%f", atom_getfloat(argv));
+ strcat(x->msg, fchar);
+ }
+ if (argc > 0)
+ strcat(x->msg, ", ");
+ argv++;
+ }
+ strcat(x->msg, ")");
+ err = pyo_exec_statement(x->interp, x->msg, x->debug);
+ if (err)
+ post("pyo~: %s", x->msg);
+}
+
+void pyo_tilde_setup(void) {
+ pyo_tilde_class = class_new(gensym("pyo~"), (t_newmethod)pyo_tilde_new,
+ (t_method)pyo_tilde_free, sizeof(t_pyo_tilde), CLASS_DEFAULT, A_DEFFLOAT, 0);
+ class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_dsp, gensym("dsp"), 0);
+ class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_clear, gensym("clear"), 0);
+ class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_value, gensym("value"),
+ A_GIMME, 0); /* send value(s) to a Sig or SigTo object */
+ class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_set, gensym("set"),
+ A_GIMME, 0); /* send value(s) to any object's attribute */
+ class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_read, gensym("read"),
+ A_GIMME, 0); /* read a script file */
+ class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_call, gensym("call"),
+ A_GIMME, 0); /* call a function or a method */
+ class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_create, gensym("create"),
+ A_GIMME, 0); /* create a python object */
+ class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_debug, gensym("debug"),
+ A_DEFFLOAT, 0); /* set the debug (verbose) mode */
+ CLASS_MAINSIGNALIN(pyo_tilde_class, t_pyo_tilde, f);
+}
diff --git a/examples/utilities/02_osc_scan.py b/examples/utilities/02_osc_scan.py
new file mode 100644
index 0000000..442247e
--- /dev/null
+++ b/examples/utilities/02_osc_scan.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Scan Open Sound Control inputs. Launch this script from a terminal.
+
+"""
+from pyo import *
+import time
+
+port = input("Enter the incoming port number : ")
+
+s = Server().boot().start()
+
+print "Play with your OSC interface..."
+
+go = True
+def pp(address, *args):
+ if go:
+ print "Address =", address
+ print "Values =", args
+ print "---------------"
+
+scan = OscDataReceive(port, "*", pp)
+
+again = "y"
+while again == "y":
+ time.sleep(10)
+ go = False
+ again = raw_input("Do you want to continue ? (y/n) : ")
+ if again == "y":
+ print "Continue..."
+ go = True
+
+s.stop()
+time.sleep(1)
+exit()
+
\ No newline at end of file
diff --git a/examples/utilities/04_batch_processing.py b/examples/utilities/04_batch_processing.py
index fa7b094..fa1f6b6 100644
--- a/examples/utilities/04_batch_processing.py
+++ b/examples/utilities/04_batch_processing.py
@@ -4,37 +4,46 @@
This script demonstrates how to use pyo to do offline batch processing.
"""
-import os
from pyo import *
-s = Server(duplex=0, audio="offline").boot()
-
-# input sound
-sndpath = SNDS_PATH + "/accord.aif"
-# output folder
-recpath = os.path.join(os.path.expanduser("~"), "Desktop", "pyo_batch")
-if not os.path.isdir(recpath):
- os.mkdir(recpath)
-
-# output file duration
-dur = sndinfo(sndpath)[1]
-
-NUM = 10
-for i in range(NUM):
- note = 12 + i
- noteFreq = midiToHz(note)
- s.recordOptions(dur=dur+.1, filename=os.path.join(recpath, "file_%02d.wav" % note), fileformat=0, sampletype=0)
-
- ### processing goes here ###
- osc = Sine(freq=noteFreq, mul=i*0.01+.02, add=1)
- a = SfPlayer(sndpath, speed=osc, loop=False, mul=0.7).mix(2).out()
-
- ############################
-
- s.start() # s.stop() is automatically called when rendering is done
- # do not reboot the server after the last pass
- if i < (NUM-1):
- s.shutdown()
- s.boot()
-
-print "Batch processing done"
+import os
+s = Server(audio="offline")
+
+# path to your sound folder
+folder_path = SNDS_PATH
+# path to the processed sounds folder (user's home directory/batch)
+output_folder = os.path.join(os.path.expanduser("~"), "pyo_batch_fx")
+# create it if it does not exist
+if not os.path.isdir(output_folder):
+ os.mkdir(output_folder)
+
+# get the list of files to process
+sounds = [file for file in os.listdir(folder_path) if sndinfo(os.path.join(folder_path, file)) != None]
+
+# enter the batch processing loop
+for sound in sounds:
+ # retrieve info about the sound
+ path = os.path.join(folder_path, sound)
+ info = sndinfo(path)
+ dur, sr, chnls = info[1], info[2], info[3]
+ fformat = ['WAVE', 'AIFF', 'AU', 'RAW', 'SD2', 'FLAC', 'CAF', 'OGG'].index(info[4])
+ samptype = ['16 bit int', '24 bit int', '32 bit int', '32 bit float',
+ '64 bits float', 'U-Law encoded', 'A-Law encoded'].index(info[5])
+
+ # set server parameters
+ s.setSamplingRate(sr)
+ s.setNchnls(chnls)
+ s.boot()
+ s.recordOptions(dur=dur, filename=os.path.join(output_folder, sound),
+ fileformat=fformat, sampletype=samptype)
+
+ # processing
+ sf = SfPlayer(path)
+ bp = ButBP(sf, 1000, 2)
+ dt = Disto(bp, drive=0.9, slope=0.8)
+ mx = Interp(sf, dt, interp=0.5, mul=0.5).out()
+
+ # start the render
+ s.start()
+ # cleanup
+ s.shutdown()
diff --git a/examples/utilities/04_batch_synthesis.py b/examples/utilities/04_batch_synthesis.py
new file mode 100644
index 0000000..8b32246
--- /dev/null
+++ b/examples/utilities/04_batch_synthesis.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+This script demonstrates how to use pyo to do synthesis batch generation.
+
+"""
+import os
+from pyo import *
+s = Server(duplex=0, audio="offline")
+
+# output folder
+output_folder = os.path.join(os.path.expanduser("~"), "pyo_batch_synth")
+if not os.path.isdir(output_folder):
+ os.mkdir(output_folder)
+
+# output file duration
+dur = 2
+
+NUM = 12
+for i in range(NUM):
+ s.boot()
+ note = 60 + i
+ noteFreq = midiToHz(note)
+ s.recordOptions(dur=dur+.1, filename=os.path.join(output_folder, "file_%02d.wav" % note),
+ fileformat=0, sampletype=0)
+
+ ### processing goes here ###
+ env = Adsr(attack=0.005, decay=0.15, sustain=0.7, release=1.7, dur=dur).play()
+ qenv = Pow(env, 4, mul=0.8)
+ osc1 = SineLoop(freq=noteFreq, feedback=0.075, mul=qenv).out()
+ osc2 = SineLoop(freq=noteFreq*1.01, feedback=0.075, mul=qenv).out(1)
+
+ # start th render
+ s.start()
+ # cleanup
+ s.shutdown()
+
+print "Batch processing done"
+
diff --git a/examples/utilities/07_scope.py b/examples/utilities/07_scope.py
new file mode 100644
index 0000000..4af4ec3
--- /dev/null
+++ b/examples/utilities/07_scope.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Simple scope example.
+
+"""
+from pyo import *
+
+class Scope:
+ def __init__(self, input, length=0.05):
+ self.input = input
+ self.table = NewTable(length=length, chnls=len(input))
+ self.table.view(title="Signal Scope")
+ self.trig = Metro(time=length).play()
+ self.rec = TrigTableRec(self.input, self.trig, self.table)
+ self.trf = TrigFunc(self.trig, function=self.update)
+
+ def start(self, x):
+ if x: self.trig.play()
+ else: self.trig.stop()
+
+ def update(self):
+ self.table.refreshView()
+
+s = Server(duplex=1).boot()
+
+CHNLS = 2
+LENGTH = 0.05
+
+inp = Input(chnl=range(CHNLS))
+scope = Scope(inp, LENGTH)
+
+s.gui(locals())
diff --git a/externals/external-template.py b/externals/external-template.py
index 1ee8e92..3cdca10 100644
--- a/externals/external-template.py
+++ b/externals/external-template.py
@@ -41,12 +41,10 @@ class Gain(PyoObject):
"""
# Do not forget "mul" and "add" attributes.
def __init__(self, input, db=-3, mul=1, add=0):
- PyoObject.__init__(self)
+ PyoObject.__init__(self, mul, add)
# Keep trace of arguments (same name preceded by an underscore)
self._input = input
self._db = db
- self._mul = mul
- self._add = add
# Always use InputFader for the input sound. That allows crossfade on input changes.
self._in_fader = InputFader(input)
# Converts every arguments to lists (for multi-channel expansion).
diff --git a/include/pyomodule.h b/include/pyomodule.h
index ce4ba6c..a8b9c71 100644
--- a/include/pyomodule.h
+++ b/include/pyomodule.h
@@ -21,7 +21,7 @@
#include "Python.h"
#include <math.h>
-#define PYO_VERSION "0.6.8"
+#define PYO_VERSION "0.7.4"
#ifndef __MYFLT_DEF
#define __MYFLT_DEF
@@ -38,6 +38,8 @@
#define TYPE__FII "|fii"
#define TYPE_F_II "f|ii"
#define TYPE__FFF "|fff"
+#define TYPE_F_FFF "f|fff"
+#define TYPE_O_FIFFI "O|fiffi"
#define TYPE_O_F "O|f"
#define TYPE_O_FO "O|fO"
#define TYPE__OF "|Of"
@@ -73,6 +75,7 @@
#define TYPE__OFII "|Ofii"
#define TYPE__FIIOO "|fiiOO"
#define TYPE_O_OFOO "O|OfOO"
+#define TYPE_O_OOOOFF "O|OOOOff"
#define TYPE_O_IFFO "O|iffO"
#define TYPE_O_OOIF "O|OOif"
#define TYPE_O_FFFFIOO "O|ffffiOO"
@@ -105,6 +108,7 @@
#define MYATAN2 atan2f
#define MYEXP expf
#define MYROUND roundf
+#define MYTANH tanhf
#else
#define LIB_BASE_NAME "_pyo64"
@@ -118,6 +122,8 @@
#define TYPE__FII "|dii"
#define TYPE_F_II "d|ii"
#define TYPE__FFF "|ddd"
+#define TYPE_F_FFF "d|ddd"
+#define TYPE_O_FIFFI "O|diddi"
#define TYPE_O_F "O|d"
#define TYPE_O_FO "O|dO"
#define TYPE__OF "|Od"
@@ -153,6 +159,7 @@
#define TYPE__OFII "|Odii"
#define TYPE__FIIOO "|diiOO"
#define TYPE_O_OFOO "O|OdOO"
+#define TYPE_O_OOOOFF "O|OOOOdd"
#define TYPE_O_IFFO "O|iddO"
#define TYPE_O_OOIF "O|OOid"
#define TYPE_O_FFFFIOO "O|ddddiOO"
@@ -185,7 +192,7 @@
#define MYATAN2 atan2
#define MYEXP exp
#define MYROUND round
-
+#define MYTANH tanh
#endif
#endif
@@ -302,6 +309,7 @@ extern PyTypeObject CtlScanType;
extern PyTypeObject CtlScan2Type;
extern PyTypeObject MidiNoteType;
extern PyTypeObject NoteinType;
+extern PyTypeObject NoteinTrigType;
extern PyTypeObject BendinType;
extern PyTypeObject TouchinType;
extern PyTypeObject PrograminType;
@@ -395,6 +403,7 @@ extern PyTypeObject ScaleType;
extern PyTypeObject CentsToTranspoType;
extern PyTypeObject TranspoToCentsType;
extern PyTypeObject MToFType;
+extern PyTypeObject FToMType;
extern PyTypeObject MToTType;
extern PyTypeObject M_SinType;
extern PyTypeObject M_CosType;
@@ -409,6 +418,7 @@ extern PyTypeObject M_Atan2Type;
extern PyTypeObject M_FloorType;
extern PyTypeObject M_CeilType;
extern PyTypeObject M_RoundType;
+extern PyTypeObject M_TanhType;
extern PyTypeObject FFTMainType;
extern PyTypeObject FFTType;
extern PyTypeObject IFFTType;
@@ -455,6 +465,24 @@ extern PyTypeObject PVBufTabLoopsType;
extern PyTypeObject PVMixType;
extern PyTypeObject GranuleType;
extern PyTypeObject TableScaleType;
+extern PyTypeObject TrackHoldType;
+extern PyTypeObject ComplexResType;
+extern PyTypeObject STReverbType;
+extern PyTypeObject STRevType;
+extern PyTypeObject Pointer2Type;
+extern PyTypeObject CentroidType;
+extern PyTypeObject AttackDetectorType;
+extern PyTypeObject SmoothDelayType;
+extern PyTypeObject TrigBursterType;
+extern PyTypeObject TrigBurstType;
+extern PyTypeObject TrigBurstTapStreamType;
+extern PyTypeObject TrigBurstAmpStreamType;
+extern PyTypeObject TrigBurstDurStreamType;
+extern PyTypeObject TrigBurstEndStreamType;
+extern PyTypeObject ScopeType;
+extern PyTypeObject PeakAmpType;
+extern PyTypeObject MainParticleType;
+extern PyTypeObject ParticleType;
/* Constants */
#define E M_E
@@ -492,6 +520,9 @@ extern PyTypeObject TableScaleType;
#define FREEVERB_ID 24
#define XNOISEDUR_ID 25
#define URN_ID 26
+#define GRANULE_ID 27
+#define MAINPARTICLE_ID 28
+/* Do not forget to modify Server_generateSeed function */
/* object headers */
#define pyo_audio_HEAD \
@@ -578,11 +609,8 @@ extern PyTypeObject TableScaleType;
/* INIT INPUT STREAM */
#define INIT_INPUT_STREAM \
if ( PyObject_HasAttrString((PyObject *)inputtmp, "server") == 0 ) { \
- PySys_WriteStderr("TypeError: \"input\" argument must be a PyoObject.\n"); \
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) { \
- PyObject_CallMethod(self->server, "shutdown", NULL); \
- } \
- Py_Exit(1); \
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument must be a PyoObject.\n"); \
+ Py_RETURN_NONE; \
} \
Py_INCREF(inputtmp); \
Py_XDECREF(self->input); \
@@ -637,13 +665,14 @@ extern PyTypeObject TableScaleType;
PyErr_SetString(PyExc_TypeError, "The data must be a list of floats."); \
return PyInt_FromLong(-1); \
} \
- self->size = PyList_Size(arg)-1; \
+ self->size = PyList_Size(arg); \
self->data = (MYFLT *)realloc(self->data, (self->size+1) * sizeof(MYFLT)); \
TableStream_setSize(self->tablestream, self->size+1); \
\
- for (i=0; i<(self->size+1); i++) { \
+ for (i=0; i<(self->size); i++) { \
self->data[i] = PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(arg, i))); \
} \
+ self->data[self->size] = self->data[0]; \
TableStream_setData(self->tablestream, self->data); \
\
Py_INCREF(Py_None); \
@@ -720,21 +749,44 @@ extern PyTypeObject TableScaleType;
return samples;
#define GET_VIEW_TABLE \
- int i, y; \
- int w = 500; \
- int h = 200; \
- int h2 = h/2; \
- int amp = h2 - 2; \
- float step = (float)self->size / (float)(w); \
- PyObject *samples; \
+ int i, y, w, h, h2, amp; \
+ float step; \
+ PyObject *samples, *tuple, *sizetmp = NULL; \
+ \
+ static char *kwlist[] = {"size", NULL}; \
\
- samples = PyList_New(w*4); \
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &sizetmp)) \
+ return PyInt_FromLong(-1); \
+ \
+ if (sizetmp) { \
+ if (PyTuple_Check(sizetmp)) { \
+ w = PyInt_AsLong(PyTuple_GET_ITEM(sizetmp, 0)); \
+ h = PyInt_AsLong(PyTuple_GET_ITEM(sizetmp, 1)); \
+ } \
+ else if (PyList_Check(sizetmp)) { \
+ w = PyInt_AsLong(PyList_GET_ITEM(sizetmp, 0)); \
+ h = PyInt_AsLong(PyList_GET_ITEM(sizetmp, 1)); \
+ } \
+ else { \
+ w = 500; \
+ h = 200; \
+ } \
+ } \
+ else { \
+ w = 500; \
+ h = 200; \
+ } \
+ h2 = h/2; \
+ amp = h2 - 2; \
+ step = (float)self->size / (float)(w); \
+ \
+ samples = PyList_New(w); \
for(i=0; i<w; i++) { \
- y = self->data[(int)(i*step)] * amp + amp; \
- PyList_SetItem(samples, i*4, PyInt_FromLong(i)); \
- PyList_SetItem(samples, i*4+1, PyInt_FromLong(h-y)); \
- PyList_SetItem(samples, i*4+2, PyInt_FromLong(i)); \
- PyList_SetItem(samples, i*4+3, PyInt_FromLong(h-y)); \
+ y = self->data[(int)(i*step)] * amp + amp + 2; \
+ tuple = PyTuple_New(2); \
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong(i)); \
+ PyTuple_SetItem(tuple, 1, PyInt_FromLong(h-y)); \
+ PyList_SetItem(samples, i, tuple); \
} \
\
return samples;
@@ -776,6 +828,128 @@ extern PyTypeObject TableScaleType;
Py_INCREF(Py_None); \
return Py_None; \
+/* Table amplitude reverse */
+#define INVERT \
+ int i; \
+ for (i=0; i<self->size+1; i++) { \
+ self->data[i] = -self->data[i]; \
+ } \
+ Py_INCREF(Py_None); \
+ return Py_None; \
+
+/* Table positive rectify */
+#define RECTIFY \
+ int i; \
+ MYFLT x; \
+ for (i=0; i<self->size+1; i++) { \
+ x = self->data[i]; \
+ if (x < 0) \
+ self->data[i] = -x; \
+ } \
+ Py_INCREF(Py_None); \
+ return Py_None; \
+
+/* Table bipolar gain */
+#define TABLE_BIPOLAR_GAIN \
+ MYFLT gpos = 1.0, gneg = 1.0; \
+ int i; \
+ static char *kwlist[] = {"gpos", "gneg", NULL}; \
+ \
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE__FF, kwlist, &gpos, &gneg)) \
+ return PyInt_FromLong(-1); \
+ \
+ for (i=0; i<self->size+1; i++) { \
+ if (self->data[i] < 0) \
+ self->data[i] *= gneg; \
+ else \
+ self->data[i] *= gpos; \
+ } \
+ \
+ Py_RETURN_NONE;
+
+/* Table power function */
+#define TABLE_POWER \
+ MYFLT x, exp; \
+ int i, sign; \
+ static char *kwlist[] = {"exp", NULL}; \
+ \
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_F, kwlist, &exp)) \
+ return PyInt_FromLong(-1); \
+ \
+ for (i=0; i<self->size+1; i++) { \
+ x = self->data[i]; \
+ sign = 1; \
+ if (x < 0) \
+ sign = -1; \
+ x = MYPOW(x, exp); \
+ if (sign == -1 && x > 0) \
+ x = -x; \
+ self->data[i] = x; \
+ } \
+ \
+ Py_RETURN_NONE;
+
+/* Table one-pole lowpass filter */
+#define TABLE_LOWPASS \
+ MYFLT freq, b, c, x, y; \
+ int i; \
+ double sr = PyFloat_AsDouble(PyObject_CallMethod(PyServer_get_server(), "getSamplingRate", NULL)); \
+ static char *kwlist[] = {"freq", NULL}; \
+ \
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_F, kwlist, &freq)) \
+ return PyInt_FromLong(-1); \
+ \
+ b = 2.0 - MYCOS(TWOPI * freq / sr); \
+ c = b - MYSQRT(b * b - 1.0); \
+ y = 0; \
+ for (i=0; i<self->size+1; i++) { \
+ x = self->data[i]; \
+ self->data[i] = y = x + (y - x) * c; \
+ } \
+ \
+ Py_RETURN_NONE;
+
+/* FADE IN, FADE OUT */
+#define TABLE_FADEIN \
+ MYFLT dur, inc; \
+ int i, samp; \
+ double sr = PyFloat_AsDouble(PyObject_CallMethod(PyServer_get_server(), "getSamplingRate", NULL)); \
+ static char *kwlist[] = {"dur", NULL}; \
+ \
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_F, kwlist, &dur)) \
+ return PyInt_FromLong(-1); \
+ \
+ samp = (int)(dur * sr); \
+ if (samp < 0 || samp >= self->size) \
+ Py_RETURN_NONE; \
+ \
+ inc = 1.0 / samp; \
+ for (i=0; i<samp; i++) { \
+ self->data[i] = self->data[i] * MYSQRT(inc * i); \
+ } \
+ \
+ Py_RETURN_NONE;
+
+#define TABLE_FADEOUT \
+ MYFLT dur, inc; \
+ int i, samp; \
+ double sr = PyFloat_AsDouble(PyObject_CallMethod(PyServer_get_server(), "getSamplingRate", NULL)); \
+ static char *kwlist[] = {"dur", NULL}; \
+ \
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_F, kwlist, &dur)) \
+ return PyInt_FromLong(-1); \
+ \
+ samp = (int)(dur * sr); \
+ if (samp < 0 || samp >= self->size) \
+ Py_RETURN_NONE; \
+ \
+ inc = 1.0 / samp; \
+ for (i=self->size; i>(self->size-samp); i--) { \
+ self->data[i] = self->data[i] * MYSQRT(inc * (self->size - i)); \
+ } \
+ \
+ Py_RETURN_NONE;
+
/* Normalize */
#define NORMALIZE \
int i; \
diff --git a/include/servermodule.h b/include/servermodule.h
index 396ed16..0fedc69 100644
--- a/include/servermodule.h
+++ b/include/servermodule.h
@@ -70,8 +70,12 @@ typedef struct {
char *serverName; /* Only used for jack client name */
int jackautoin; /* jack port auto-connection (on by default) */
int jackautoout; /* jack port auto-connection (on by default) */
- PmStream *in;
- PmStream *out;
+ PyObject *jackAutoConnectInputPorts; /* list of regex to match for jack auto-connection */
+ PyObject *jackAutoConnectOutputPorts; /* list of regex to match for jack auto-connection */
+ PmStream *midiin[64];
+ PmStream *midiout[64];
+ int midiin_count;
+ int midiout_count;
PmEvent midiEvents[200];
int midi_count;
double samplingRate;
diff --git a/installers/osx/PkgResources_i386/License.rtf b/installers/osx/PkgResources_i386/License.rtf
deleted file mode 100755
index 66b2d2a..0000000
--- a/installers/osx/PkgResources_i386/License.rtf
+++ /dev/null
@@ -1,681 +0,0 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
-{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
-{\colortbl;\red255\green255\blue255;}
-\margl1440\margr1440\vieww10100\viewh11340\viewkind0
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
-
-\f0\fs26 \cf0 GNU GENERAL PUBLIC LICENSE\
- Version 3, 29 June 2007\
-\
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\
- Everyone is permitted to copy and distribute verbatim copies\
- of this license document, but changing it is not allowed.\
-\
- Preamble\
-\
- The GNU General Public License is a free, copyleft license for\
-software and other kinds of works.\
-\
- The licenses for most software and other practical works are designed\
-to take away your freedom to share and change the works. By contrast,\
-the GNU General Public License is intended to guarantee your freedom to\
-share and change all versions of a program--to make sure it remains free\
-software for all its users. We, the Free Software Foundation, use the\
-GNU General Public License for most of our software; it applies also to\
-any other work released this way by its authors. You can apply it to\
-your programs, too.\
-\
- When we speak of free software, we are referring to freedom, not\
-price. Our General Public Licenses are designed to make sure that you\
-have the freedom to distribute copies of free software (and charge for\
-them if you wish), that you receive source code or can get it if you\
-want it, that you can change the software or use pieces of it in new\
-free programs, and that you know you can do these things.\
-\
- To protect your rights, we need to prevent others from denying you\
-these rights or asking you to surrender the rights. Therefore, you have\
-certain responsibilities if you distribute copies of the software, or if\
-you modify it: responsibilities to respect the freedom of others.\
-\
- For example, if you distribute copies of such a program, whether\
-gratis or for a fee, you must pass on to the recipients the same\
-freedoms that you received. You must make sure that they, too, receive\
-or can get the source code. And you must show them these terms so they\
-know their rights.\
-\
- Developers that use the GNU GPL protect your rights with two steps:\
-(1) assert copyright on the software, and (2) offer you this License\
-giving you legal permission to copy, distribute and/or modify it.\
-\
- For the developers' and authors' protection, the GPL clearly explains\
-that there is no warranty for this free software. For both users' and\
-authors' sake, the GPL requires that modified versions be marked as\
-changed, so that their problems will not be attributed erroneously to\
-authors of previous versions.\
-\
- Some devices are designed to deny users access to install or run\
-modified versions of the software inside them, although the manufacturer\
-can do so. This is fundamentally incompatible with the aim of\
-protecting users' freedom to change the software. The systematic\
-pattern of such abuse occurs in the area of products for individuals to\
-use, which is precisely where it is most unacceptable. Therefore, we\
-have designed this version of the GPL to prohibit the practice for those\
-products. If such problems arise substantially in other domains, we\
-stand ready to extend this provision to those domains in future versions\
-of the GPL, as needed to protect the freedom of users.\
-\
- Finally, every program is threatened constantly by software patents.\
-States should not allow patents to restrict development and use of\
-software on general-purpose computers, but in those that do, we wish to\
-avoid the special danger that patents applied to a free program could\
-make it effectively proprietary. To prevent this, the GPL assures that\
-patents cannot be used to render the program non-free.\
-\
- The precise terms and conditions for copying, distribution and\
-modification follow.\
-\
- TERMS AND CONDITIONS\
-\
- 0. Definitions.\
-\
- "This License" refers to version 3 of the GNU General Public License.\
-\
- "Copyright" also means copyright-like laws that apply to other kinds of\
-works, such as semiconductor masks.\
-\
- "The Program" refers to any copyrightable work licensed under this\
-License. Each licensee is addressed as "you". "Licensees" and\
-"recipients" may be individuals or organizations.\
-\
- To "modify" a work means to copy from or adapt all or part of the work\
-in a fashion requiring copyright permission, other than the making of an\
-exact copy. The resulting work is called a "modified version" of the\
-earlier work or a work "based on" the earlier work.\
-\
- A "covered work" means either the unmodified Program or a work based\
-on the Program.\
-\
- To "propagate" a work means to do anything with it that, without\
-permission, would make you directly or secondarily liable for\
-infringement under applicable copyright law, except executing it on a\
-computer or modifying a private copy. Propagation includes copying,\
-distribution (with or without modification), making available to the\
-public, and in some countries other activities as well.\
-\
- To "convey" a work means any kind of propagation that enables other\
-parties to make or receive copies. Mere interaction with a user through\
-a computer network, with no transfer of a copy, is not conveying.\
-\
- An interactive user interface displays "Appropriate Legal Notices"\
-to the extent that it includes a convenient and prominently visible\
-feature that (1) displays an appropriate copyright notice, and (2)\
-tells the user that there is no warranty for the work (except to the\
-extent that warranties are provided), that licensees may convey the\
-work under this License, and how to view a copy of this License. If\
-the interface presents a list of user commands or options, such as a\
-menu, a prominent item in the list meets this criterion.\
-\
- 1. Source Code.\
-\
- The "source code" for a work means the preferred form of the work\
-for making modifications to it. "Object code" means any non-source\
-form of a work.\
-\
- A "Standard Interface" means an interface that either is an official\
-standard defined by a recognized standards body, or, in the case of\
-interfaces specified for a particular programming language, one that\
-is widely used among developers working in that language.\
-\
- The "System Libraries" of an executable work include anything, other\
-than the work as a whole, that (a) is included in the normal form of\
-packaging a Major Component, but which is not part of that Major\
-Component, and (b) serves only to enable use of the work with that\
-Major Component, or to implement a Standard Interface for which an\
-implementation is available to the public in source code form. A\
-"Major Component", in this context, means a major essential component\
-(kernel, window system, and so on) of the specific operating system\
-(if any) on which the executable work runs, or a compiler used to\
-produce the work, or an object code interpreter used to run it.\
-\
- The "Corresponding Source" for a work in object code form means all\
-the source code needed to generate, install, and (for an executable\
-work) run the object code and to modify the work, including scripts to\
-control those activities. However, it does not include the work's\
-System Libraries, or general-purpose tools or generally available free\
-programs which are used unmodified in performing those activities but\
-which are not part of the work. For example, Corresponding Source\
-includes interface definition files associated with source files for\
-the work, and the source code for shared libraries and dynamically\
-linked subprograms that the work is specifically designed to require,\
-such as by intimate data communication or control flow between those\
-subprograms and other parts of the work.\
-\
- The Corresponding Source need not include anything that users\
-can regenerate automatically from other parts of the Corresponding\
-Source.\
-\
- The Corresponding Source for a work in source code form is that\
-same work.\
-\
- 2. Basic Permissions.\
-\
- All rights granted under this License are granted for the term of\
-copyright on the Program, and are irrevocable provided the stated\
-conditions are met. This License explicitly affirms your unlimited\
-permission to run the unmodified Program. The output from running a\
-covered work is covered by this License only if the output, given its\
-content, constitutes a covered work. This License acknowledges your\
-rights of fair use or other equivalent, as provided by copyright law.\
-\
- You may make, run and propagate covered works that you do not\
-convey, without conditions so long as your license otherwise remains\
-in force. You may convey covered works to others for the sole purpose\
-of having them make modifications exclusively for you, or provide you\
-with facilities for running those works, provided that you comply with\
-the terms of this License in conveying all material for which you do\
-not control copyright. Those thus making or running the covered works\
-for you must do so exclusively on your behalf, under your direction\
-and control, on terms that prohibit them from making any copies of\
-your copyrighted material outside their relationship with you.\
-\
- Conveying under any other circumstances is permitted solely under\
-the conditions stated below. Sublicensing is not allowed; section 10\
-makes it unnecessary.\
-\
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.\
-\
- No covered work shall be deemed part of an effective technological\
-measure under any applicable law fulfilling obligations under article\
-11 of the WIPO copyright treaty adopted on 20 December 1996, or\
-similar laws prohibiting or restricting circumvention of such\
-measures.\
-\
- When you convey a covered work, you waive any legal power to forbid\
-circumvention of technological measures to the extent such circumvention\
-is effected by exercising rights under this License with respect to\
-the covered work, and you disclaim any intention to limit operation or\
-modification of the work as a means of enforcing, against the work's\
-users, your or third parties' legal rights to forbid circumvention of\
-technological measures.\
-\
- 4. Conveying Verbatim Copies.\
-\
- You may convey verbatim copies of the Program's source code as you\
-receive it, in any medium, provided that you conspicuously and\
-appropriately publish on each copy an appropriate copyright notice;\
-keep intact all notices stating that this License and any\
-non-permissive terms added in accord with section 7 apply to the code;\
-keep intact all notices of the absence of any warranty; and give all\
-recipients a copy of this License along with the Program.\
-\
- You may charge any price or no price for each copy that you convey,\
-and you may offer support or warranty protection for a fee.\
-\
- 5. Conveying Modified Source Versions.\
-\
- You may convey a work based on the Program, or the modifications to\
-produce it from the Program, in the form of source code under the\
-terms of section 4, provided that you also meet all of these conditions:\
-\
- a) The work must carry prominent notices stating that you modified\
- it, and giving a relevant date.\
-\
- b) The work must carry prominent notices stating that it is\
- released under this License and any conditions added under section\
- 7. This requirement modifies the requirement in section 4 to\
- "keep intact all notices".\
-\
- c) You must license the entire work, as a whole, under this\
- License to anyone who comes into possession of a copy. This\
- License will therefore apply, along with any applicable section 7\
- additional terms, to the whole of the work, and all its parts,\
- regardless of how they are packaged. This License gives no\
- permission to license the work in any other way, but it does not\
- invalidate such permission if you have separately received it.\
-\
- d) If the work has interactive user interfaces, each must display\
- Appropriate Legal Notices; however, if the Program has interactive\
- interfaces that do not display Appropriate Legal Notices, your\
- work need not make them do so.\
-\
- A compilation of a covered work with other separate and independent\
-works, which are not by their nature extensions of the covered work,\
-and which are not combined with it such as to form a larger program,\
-in or on a volume of a storage or distribution medium, is called an\
-"aggregate" if the compilation and its resulting copyright are not\
-used to limit the access or legal rights of the compilation's users\
-beyond what the individual works permit. Inclusion of a covered work\
-in an aggregate does not cause this License to apply to the other\
-parts of the aggregate.\
-\
- 6. Conveying Non-Source Forms.\
-\
- You may convey a covered work in object code form under the terms\
-of sections 4 and 5, provided that you also convey the\
-machine-readable Corresponding Source under the terms of this License,\
-in one of these ways:\
-\
- a) Convey the object code in, or embodied in, a physical product\
- (including a physical distribution medium), accompanied by the\
- Corresponding Source fixed on a durable physical medium\
- customarily used for software interchange.\
-\
- b) Convey the object code in, or embodied in, a physical product\
- (including a physical distribution medium), accompanied by a\
- written offer, valid for at least three years and valid for as\
- long as you offer spare parts or customer support for that product\
- model, to give anyone who possesses the object code either (1) a\
- copy of the Corresponding Source for all the software in the\
- product that is covered by this License, on a durable physical\
- medium customarily used for software interchange, for a price no\
- more than your reasonable cost of physically performing this\
- conveying of source, or (2) access to copy the\
- Corresponding Source from a network server at no charge.\
-\
- c) Convey individual copies of the object code with a copy of the\
- written offer to provide the Corresponding Source. This\
- alternative is allowed only occasionally and noncommercially, and\
- only if you received the object code with such an offer, in accord\
- with subsection 6b.\
-\
- d) Convey the object code by offering access from a designated\
- place (gratis or for a charge), and offer equivalent access to the\
- Corresponding Source in the same way through the same place at no\
- further charge. You need not require recipients to copy the\
- Corresponding Source along with the object code. If the place to\
- copy the object code is a network server, the Corresponding Source\
- may be on a different server (operated by you or a third party)\
- that supports equivalent copying facilities, provided you maintain\
- clear directions next to the object code saying where to find the\
- Corresponding Source. Regardless of what server hosts the\
- Corresponding Source, you remain obligated to ensure that it is\
- available for as long as needed to satisfy these requirements.\
-\
- e) Convey the object code using peer-to-peer transmission, provided\
- you inform other peers where the object code and Corresponding\
- Source of the work are being offered to the general public at no\
- charge under subsection 6d.\
-\
- A separable portion of the object code, whose source code is excluded\
-from the Corresponding Source as a System Library, need not be\
-included in conveying the object code work.\
-\
- A "User Product" is either (1) a "consumer product", which means any\
-tangible personal property which is normally used for personal, family,\
-or household purposes, or (2) anything designed or sold for incorporation\
-into a dwelling. In determining whether a product is a consumer product,\
-doubtful cases shall be resolved in favor of coverage. For a particular\
-product received by a particular user, "normally used" refers to a\
-typical or common use of that class of product, regardless of the status\
-of the particular user or of the way in which the particular user\
-actually uses, or expects or is expected to use, the product. A product\
-is a consumer product regardless of whether the product has substantial\
-commercial, industrial or non-consumer uses, unless such uses represent\
-the only significant mode of use of the product.\
-\
- "Installation Information" for a User Product means any methods,\
-procedures, authorization keys, or other information required to install\
-and execute modified versions of a covered work in that User Product from\
-a modified version of its Corresponding Source. The information must\
-suffice to ensure that the continued functioning of the modified object\
-code is in no case prevented or interfered with solely because\
-modification has been made.\
-\
- If you convey an object code work under this section in, or with, or\
-specifically for use in, a User Product, and the conveying occurs as\
-part of a transaction in which the right of possession and use of the\
-User Product is transferred to the recipient in perpetuity or for a\
-fixed term (regardless of how the transaction is characterized), the\
-Corresponding Source conveyed under this section must be accompanied\
-by the Installation Information. But this requirement does not apply\
-if neither you nor any third party retains the ability to install\
-modified object code on the User Product (for example, the work has\
-been installed in ROM).\
-\
- The requirement to provide Installation Information does not include a\
-requirement to continue to provide support service, warranty, or updates\
-for a work that has been modified or installed by the recipient, or for\
-the User Product in which it has been modified or installed. Access to a\
-network may be denied when the modification itself materially and\
-adversely affects the operation of the network or violates the rules and\
-protocols for communication across the network.\
-\
- Corresponding Source conveyed, and Installation Information provided,\
-in accord with this section must be in a format that is publicly\
-documented (and with an implementation available to the public in\
-source code form), and must require no special password or key for\
-unpacking, reading or copying.\
-\
- 7. Additional Terms.\
-\
- "Additional permissions" are terms that supplement the terms of this\
-License by making exceptions from one or more of its conditions.\
-Additional permissions that are applicable to the entire Program shall\
-be treated as though they were included in this License, to the extent\
-that they are valid under applicable law. If additional permissions\
-apply only to part of the Program, that part may be used separately\
-under those permissions, but the entire Program remains governed by\
-this License without regard to the additional permissions.\
-\
- When you convey a copy of a covered work, you may at your option\
-remove any additional permissions from that copy, or from any part of\
-it. (Additional permissions may be written to require their own\
-removal in certain cases when you modify the work.) You may place\
-additional permissions on material, added by you to a covered work,\
-for which you have or can give appropriate copyright permission.\
-\
- Notwithstanding any other provision of this License, for material you\
-add to a covered work, you may (if authorized by the copyright holders of\
-that material) supplement the terms of this License with terms:\
-\
- a) Disclaiming warranty or limiting liability differently from the\
- terms of sections 15 and 16 of this License; or\
-\
- b) Requiring preservation of specified reasonable legal notices or\
- author attributions in that material or in the Appropriate Legal\
- Notices displayed by works containing it; or\
-\
- c) Prohibiting misrepresentation of the origin of that material, or\
- requiring that modified versions of such material be marked in\
- reasonable ways as different from the original version; or\
-\
- d) Limiting the use for publicity purposes of names of licensors or\
- authors of the material; or\
-\
- e) Declining to grant rights under trademark law for use of some\
- trade names, trademarks, or service marks; or\
-\
- f) Requiring indemnification of licensors and authors of that\
- material by anyone who conveys the material (or modified versions of\
- it) with contractual assumptions of liability to the recipient, for\
- any liability that these contractual assumptions directly impose on\
- those licensors and authors.\
-\
- All other non-permissive additional terms are considered "further\
-restrictions" within the meaning of section 10. If the Program as you\
-received it, or any part of it, contains a notice stating that it is\
-governed by this License along with a term that is a further\
-restriction, you may remove that term. If a license document contains\
-a further restriction but permits relicensing or conveying under this\
-License, you may add to a covered work material governed by the terms\
-of that license document, provided that the further restriction does\
-not survive such relicensing or conveying.\
-\
- If you add terms to a covered work in accord with this section, you\
-must place, in the relevant source files, a statement of the\
-additional terms that apply to those files, or a notice indicating\
-where to find the applicable terms.\
-\
- Additional terms, permissive or non-permissive, may be stated in the\
-form of a separately written license, or stated as exceptions;\
-the above requirements apply either way.\
-\
- 8. Termination.\
-\
- You may not propagate or modify a covered work except as expressly\
-provided under this License. Any attempt otherwise to propagate or\
-modify it is void, and will automatically terminate your rights under\
-this License (including any patent licenses granted under the third\
-paragraph of section 11).\
-\
- However, if you cease all violation of this License, then your\
-license from a particular copyright holder is reinstated (a)\
-provisionally, unless and until the copyright holder explicitly and\
-finally terminates your license, and (b) permanently, if the copyright\
-holder fails to notify you of the violation by some reasonable means\
-prior to 60 days after the cessation.\
-\
- Moreover, your license from a particular copyright holder is\
-reinstated permanently if the copyright holder notifies you of the\
-violation by some reasonable means, this is the first time you have\
-received notice of violation of this License (for any work) from that\
-copyright holder, and you cure the violation prior to 30 days after\
-your receipt of the notice.\
-\
- Termination of your rights under this section does not terminate the\
-licenses of parties who have received copies or rights from you under\
-this License. If your rights have been terminated and not permanently\
-reinstated, you do not qualify to receive new licenses for the same\
-material under section 10.\
-\
- 9. Acceptance Not Required for Having Copies.\
-\
- You are not required to accept this License in order to receive or\
-run a copy of the Program. Ancillary propagation of a covered work\
-occurring solely as a consequence of using peer-to-peer transmission\
-to receive a copy likewise does not require acceptance. However,\
-nothing other than this License grants you permission to propagate or\
-modify any covered work. These actions infringe copyright if you do\
-not accept this License. Therefore, by modifying or propagating a\
-covered work, you indicate your acceptance of this License to do so.\
-\
- 10. Automatic Licensing of Downstream Recipients.\
-\
- Each time you convey a covered work, the recipient automatically\
-receives a license from the original licensors, to run, modify and\
-propagate that work, subject to this License. You are not responsible\
-for enforcing compliance by third parties with this License.\
-\
- An "entity transaction" is a transaction transferring control of an\
-organization, or substantially all assets of one, or subdividing an\
-organization, or merging organizations. If propagation of a covered\
-work results from an entity transaction, each party to that\
-transaction who receives a copy of the work also receives whatever\
-licenses to the work the party's predecessor in interest had or could\
-give under the previous paragraph, plus a right to possession of the\
-Corresponding Source of the work from the predecessor in interest, if\
-the predecessor has it or can get it with reasonable efforts.\
-\
- You may not impose any further restrictions on the exercise of the\
-rights granted or affirmed under this License. For example, you may\
-not impose a license fee, royalty, or other charge for exercise of\
-rights granted under this License, and you may not initiate litigation\
-(including a cross-claim or counterclaim in a lawsuit) alleging that\
-any patent claim is infringed by making, using, selling, offering for\
-sale, or importing the Program or any portion of it.\
-\
- 11. Patents.\
-\
- A "contributor" is a copyright holder who authorizes use under this\
-License of the Program or a work on which the Program is based. The\
-work thus licensed is called the contributor's "contributor version".\
-\
- A contributor's "essential patent claims" are all patent claims\
-owned or controlled by the contributor, whether already acquired or\
-hereafter acquired, that would be infringed by some manner, permitted\
-by this License, of making, using, or selling its contributor version,\
-but do not include claims that would be infringed only as a\
-consequence of further modification of the contributor version. For\
-purposes of this definition, "control" includes the right to grant\
-patent sublicenses in a manner consistent with the requirements of\
-this License.\
-\
- Each contributor grants you a non-exclusive, worldwide, royalty-free\
-patent license under the contributor's essential patent claims, to\
-make, use, sell, offer for sale, import and otherwise run, modify and\
-propagate the contents of its contributor version.\
-\
- In the following three paragraphs, a "patent license" is any express\
-agreement or commitment, however denominated, not to enforce a patent\
-(such as an express permission to practice a patent or covenant not to\
-sue for patent infringement). To "grant" such a patent license to a\
-party means to make such an agreement or commitment not to enforce a\
-patent against the party.\
-\
- If you convey a covered work, knowingly relying on a patent license,\
-and the Corresponding Source of the work is not available for anyone\
-to copy, free of charge and under the terms of this License, through a\
-publicly available network server or other readily accessible means,\
-then you must either (1) cause the Corresponding Source to be so\
-available, or (2) arrange to deprive yourself of the benefit of the\
-patent license for this particular work, or (3) arrange, in a manner\
-consistent with the requirements of this License, to extend the patent\
-license to downstream recipients. "Knowingly relying" means you have\
-actual knowledge that, but for the patent license, your conveying the\
-covered work in a country, or your recipient's use of the covered work\
-in a country, would infringe one or more identifiable patents in that\
-country that you have reason to believe are valid.\
-\
- If, pursuant to or in connection with a single transaction or\
-arrangement, you convey, or propagate by procuring conveyance of, a\
-covered work, and grant a patent license to some of the parties\
-receiving the covered work authorizing them to use, propagate, modify\
-or convey a specific copy of the covered work, then the patent license\
-you grant is automatically extended to all recipients of the covered\
-work and works based on it.\
-\
- A patent license is "discriminatory" if it does not include within\
-the scope of its coverage, prohibits the exercise of, or is\
-conditioned on the non-exercise of one or more of the rights that are\
-specifically granted under this License. You may not convey a covered\
-work if you are a party to an arrangement with a third party that is\
-in the business of distributing software, under which you make payment\
-to the third party based on the extent of your activity of conveying\
-the work, and under which the third party grants, to any of the\
-parties who would receive the covered work from you, a discriminatory\
-patent license (a) in connection with copies of the covered work\
-conveyed by you (or copies made from those copies), or (b) primarily\
-for and in connection with specific products or compilations that\
-contain the covered work, unless you entered into that arrangement,\
-or that patent license was granted, prior to 28 March 2007.\
-\
- Nothing in this License shall be construed as excluding or limiting\
-any implied license or other defenses to infringement that may\
-otherwise be available to you under applicable patent law.\
-\
- 12. No Surrender of Others' Freedom.\
-\
- If conditions are imposed on you (whether by court order, agreement or\
-otherwise) that contradict the conditions of this License, they do not\
-excuse you from the conditions of this License. If you cannot convey a\
-covered work so as to satisfy simultaneously your obligations under this\
-License and any other pertinent obligations, then as a consequence you may\
-not convey it at all. For example, if you agree to terms that obligate you\
-to collect a royalty for further conveying from those to whom you convey\
-the Program, the only way you could satisfy both those terms and this\
-License would be to refrain entirely from conveying the Program.\
-\
- 13. Use with the GNU Affero General Public License.\
-\
- Notwithstanding any other provision of this License, you have\
-permission to link or combine any covered work with a work licensed\
-under version 3 of the GNU Affero General Public License into a single\
-combined work, and to convey the resulting work. The terms of this\
-License will continue to apply to the part which is the covered work,\
-but the special requirements of the GNU Affero General Public License,\
-section 13, concerning interaction through a network will apply to the\
-combination as such.\
-\
- 14. Revised Versions of this License.\
-\
- The Free Software Foundation may publish revised and/or new versions of\
-the GNU General Public License from time to time. Such new versions will\
-be similar in spirit to the present version, but may differ in detail to\
-address new problems or concerns.\
-\
- Each version is given a distinguishing version number. If the\
-Program specifies that a certain numbered version of the GNU General\
-Public License "or any later version" applies to it, you have the\
-option of following the terms and conditions either of that numbered\
-version or of any later version published by the Free Software\
-Foundation. If the Program does not specify a version number of the\
-GNU General Public License, you may choose any version ever published\
-by the Free Software Foundation.\
-\
- If the Program specifies that a proxy can decide which future\
-versions of the GNU General Public License can be used, that proxy's\
-public statement of acceptance of a version permanently authorizes you\
-to choose that version for the Program.\
-\
- Later license versions may give you additional or different\
-permissions. However, no additional obligations are imposed on any\
-author or copyright holder as a result of your choosing to follow a\
-later version.\
-\
- 15. Disclaimer of Warranty.\
-\
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY\
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\
-\
- 16. Limitation of Liability.\
-\
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\
-SUCH DAMAGES.\
-\
- 17. Interpretation of Sections 15 and 16.\
-\
- If the disclaimer of warranty and limitation of liability provided\
-above cannot be given local legal effect according to their terms,\
-reviewing courts shall apply local law that most closely approximates\
-an absolute waiver of all civil liability in connection with the\
-Program, unless a warranty or assumption of liability accompanies a\
-copy of the Program in return for a fee.\
-\
- END OF TERMS AND CONDITIONS\
-\
- How to Apply These Terms to Your New Programs\
-\
- If you develop a new program, and you want it to be of the greatest\
-possible use to the public, the best way to achieve this is to make it\
-free software which everyone can redistribute and change under these terms.\
-\
- To do so, attach the following notices to the program. It is safest\
-to attach them to the start of each source file to most effectively\
-state the exclusion of warranty; and each file should have at least\
-the "copyright" line and a pointer to where the full notice is found.\
-\
- <one line to give the program's name and a brief idea of what it does.>\
- Copyright (C) <year> <name of author>\
-\
- This program is free software: you can redistribute it and/or modify\
- it under the terms of the GNU General Public License as published by\
- the Free Software Foundation, either version 3 of the License, or\
- (at your option) any later version.\
-\
- This program is distributed in the hope that it will be useful,\
- but WITHOUT ANY WARRANTY; without even the implied warranty of\
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\
- GNU General Public License for more details.\
-\
- You should have received a copy of the GNU General Public License\
- along with this program. If not, see <http://www.gnu.org/licenses/>.\
-\
-Also add information on how to contact you by electronic and paper mail.\
-\
- If the program does terminal interaction, make it output a short\
-notice like this when it starts in an interactive mode:\
-\
- <program> Copyright (C) <year> <name of author>\
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\
- This is free software, and you are welcome to redistribute it\
- under certain conditions; type `show c' for details.\
-\
-The hypothetical commands `show w' and `show c' should show the appropriate\
-parts of the General Public License. Of course, your program's commands\
-might be different; for a GUI interface, you would use an "about box".\
-\
- You should also get your employer (if you work as a programmer) or school,\
-if any, to sign a "copyright disclaimer" for the program, if necessary.\
-For more information on this, and how to apply and follow the GNU GPL, see\
-<http://www.gnu.org/licenses/>.\
-\
- The GNU General Public License does not permit incorporating your program\
-into proprietary programs. If your program is a subroutine library, you\
-may consider it more useful to permit linking proprietary applications with\
-the library. If this is what you want to do, use the GNU Lesser General\
-Public License instead of this License. But first, please read\
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.\
-}
\ No newline at end of file
diff --git a/installers/osx/PkgResources_i386/ReadMe.rtf b/installers/osx/PkgResources_i386/ReadMe.rtf
deleted file mode 100755
index da986d8..0000000
--- a/installers/osx/PkgResources_i386/ReadMe.rtf
+++ /dev/null
@@ -1,71 +0,0 @@
-{\rtf1\ansi\deff3\adeflang1025
-{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\fswiss\fprq2\fcharset0 Liberation Sans{\*\falt Arial};}{\f5\froman\fprq2\fcharset1 LucidaGrande;}{\f6\froman\fprq0\fcharset1 LucidaGrande;}{\f7\fnil\fprq2\fcharset0 DejaVu Sans;}{\f8\fnil\fprq2\fcharset0 Lohit Hindi;}{\f9\fnil\fprq0\fcharset1 Lohit Hindi;}}
-{\colortbl;\red0\green0\blue0;\red128\green128\blue128;}
-{\stylesheet{\s0\snext0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105 Normal;}
-{\s15\sbasedon0\snext16\sb240\sa120\keepn\dbch\af7\dbch\af8\afs28\loch\f4\fs28 Heading;}
-{\s16\sbasedon0\snext16\sb0\sa120 Text body;}
-{\s17\sbasedon16\snext17\sb0\sa120\dbch\af9 List;}
-{\s18\sbasedon0\snext18\sb120\sa120\noline\i\dbch\af9\afs24\ai\fs24 Caption;}
-{\s19\sbasedon0\snext19\noline\dbch\af9 Index;}
-}{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern3600}}\deftab720
-\viewscale110
-{\*\pgdsctbl
-{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Default;}}
-\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
-\pgndec\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-pyo (version 0.6.}{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-6}{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-)}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-This package installs all the required components to run pyo inside your current Python installation. Python 2.5, 2.6 (preferred) or 2.7 (32-bit Mac OS X Installer) must be already installed on your system.}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-This package is divided into two separate installers. If you do not require one of them, please unselect the package in custom installation mode.}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f6
-1. pyo extension:}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-The following components will be installed in the site-packages folder of the current Python Framework:}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-_pyo.so}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-_pyo64.so}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-pyo.py}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-pyo64.py}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-pyolib (folder)}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f6
-2. Support libraries (i386):}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-This component will install a number of dynamic libraries on which pyo depends. If you already have these, then you can skip this installation.}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f6
-Warning:}{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
- this installation will overwrite any previously installed libraries. These are the libraries that will be installed in your /usr/local/lib directory:}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-liblo.0.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-libportaudio.2.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-libportmidi.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-libsndfile.1.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-Olivier B\u233\'e9langer, 201}{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-3}
-\par }
\ No newline at end of file
diff --git a/installers/osx/PkgResources_i386/Welcome.rtf b/installers/osx/PkgResources_i386/Welcome.rtf
deleted file mode 100755
index b8b9917..0000000
--- a/installers/osx/PkgResources_i386/Welcome.rtf
+++ /dev/null
@@ -1,7 +0,0 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
-{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
-{\colortbl;\red255\green255\blue255;}
-\margl1440\margr1440\vieww10100\viewh11340\viewkind0
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
-
-\f0\fs26 \cf0 You are about to install pyo in your computer. This includes the pyo Python module and support libs.}
\ No newline at end of file
diff --git a/installers/osx/PkgResources_i386/postinstall b/installers/osx/PkgResources_i386/postinstall
deleted file mode 100755
index 21e721a..0000000
--- a/installers/osx/PkgResources_i386/postinstall
+++ /dev/null
@@ -1,106 +0,0 @@
-#! /bin/sh
-
-VERSION=`sw_vers -productVersion | sed -e 's/\.//g'`
-
-if [ $VERSION -ge '1070' ]; then
- echo "Install pyo on OSX 10.7";
-elif [ $VERSION -ge '1060' ]; then
- echo "Install pyo on OSX 10.6";
-else
- echo "Install pyo on OSX 10.5";
-fi
-
-# Removed older versions in the python site-packages builtin directories
-# Removed older versions in the python site-packages from python.org install directories
-PATHS=/Library/Python/2.5/site-packages/:/Library/Python/2.6/site-packages/:/Library/Python/2.7/site-packages/:/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/:/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/:/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
-for path in ${PATHS//:/ }; do
- if cd $path; then
- if [ -f pyo.py ]; then
- sudo rm pyo.py;
- fi
- if [ -f pyo64.py ]; then
- sudo rm pyo64.py;
- fi
- if [ -f pyo.pyc ]; then
- sudo rm pyo.pyc;
- fi
- if [ -f pyo64.pyc ]; then
- sudo rm pyo64.pyc;
- fi
- if [ -f _pyo.so ]; then
- sudo rm _pyo.so;
- fi
- if [ -f _pyo64.so ]; then
- sudo rm _pyo64.so;
- fi
- if [ -d pyolib ]; then
- sudo rm -rf pyolib/;
- fi
- ls -1 pyo*-info > /dev/null 2>&1
- if [ "$?" = "0" ]; then
- sudo rm pyo*-info;
- fi
- fi
-done
-
-# Install pyo in the python site-packages builtin directories
-if [ $VERSION -ge '1070' ]; then
- if cd /Library/Python/2.7/site-packages/; then
- sudo cp -r /tmp/python27/* .
- else
- sudo mkdir -p /Library/Python/2.7/site-packages/
- cd /Library/Python/2.7/site-packages/
- sudo cp -r /tmp/python27/* .
- fi
-else
- if cd /Library/Python/2.6/site-packages/; then
- sudo cp -r /tmp/python26/* .
- else
- sudo mkdir -p /Library/Python/2.6/site-packages/
- cd /Library/Python/2.6/site-packages/
- sudo cp -r /tmp/python26/* .
- fi
-fi
-
-# Install pyo in the python site-packages from python.org install directories
-if cd /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/; then
- sudo cp -r /tmp/python26/* .
-else
- sudo mkdir -p /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/
- cd /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/
- sudo cp -r /tmp/python26/* .
-fi
-
-if cd /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/; then
- sudo cp -r /tmp/python27/* .
-else
- sudo mkdir -p /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
- cd /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
- sudo cp -r /tmp/python27/* .
-fi
-
-sudo rm -rf /tmp/python2*
-
-# Add /usr/local/lib in .bash_profile if not already done
-searchString="/usr/local/lib"
-
-if [ -f ~/.bash_profile ]; then
- if `cat ~/.bash_profile | grep "${searchString}" 1>/dev/null 2>&1`; then
- echo "path already in PATH variable";
- else
- echo "adding path to .bash_profile..."
- echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" >> ~/.bash_profile;
- fi
-else
- echo "creating .bash_profile and adding path to it..."
- echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" > ~/.bash_profile;
-fi
-
-# Add VERSIONER_PYTHON_PREFER_32_BIT in .bash_profile if not already done
-searchString="VERSIONER_PYTHON_PREFER_32_BIT"
-
-if `cat ~/.bash_profile | grep "${searchString}" 1>/dev/null 2>&1`; then
- echo "Variable VERSIONER_PYTHON_PREFER_32_BIT already set.";
-else
- echo "export VERSIONER_PYTHON_PREFER_32_BIT=yes" >> ~/.bash_profile;
-fi
diff --git a/installers/osx/PkgResources_i386/postupgrade b/installers/osx/PkgResources_i386/postupgrade
deleted file mode 100755
index 21e721a..0000000
--- a/installers/osx/PkgResources_i386/postupgrade
+++ /dev/null
@@ -1,106 +0,0 @@
-#! /bin/sh
-
-VERSION=`sw_vers -productVersion | sed -e 's/\.//g'`
-
-if [ $VERSION -ge '1070' ]; then
- echo "Install pyo on OSX 10.7";
-elif [ $VERSION -ge '1060' ]; then
- echo "Install pyo on OSX 10.6";
-else
- echo "Install pyo on OSX 10.5";
-fi
-
-# Removed older versions in the python site-packages builtin directories
-# Removed older versions in the python site-packages from python.org install directories
-PATHS=/Library/Python/2.5/site-packages/:/Library/Python/2.6/site-packages/:/Library/Python/2.7/site-packages/:/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/:/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/:/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
-for path in ${PATHS//:/ }; do
- if cd $path; then
- if [ -f pyo.py ]; then
- sudo rm pyo.py;
- fi
- if [ -f pyo64.py ]; then
- sudo rm pyo64.py;
- fi
- if [ -f pyo.pyc ]; then
- sudo rm pyo.pyc;
- fi
- if [ -f pyo64.pyc ]; then
- sudo rm pyo64.pyc;
- fi
- if [ -f _pyo.so ]; then
- sudo rm _pyo.so;
- fi
- if [ -f _pyo64.so ]; then
- sudo rm _pyo64.so;
- fi
- if [ -d pyolib ]; then
- sudo rm -rf pyolib/;
- fi
- ls -1 pyo*-info > /dev/null 2>&1
- if [ "$?" = "0" ]; then
- sudo rm pyo*-info;
- fi
- fi
-done
-
-# Install pyo in the python site-packages builtin directories
-if [ $VERSION -ge '1070' ]; then
- if cd /Library/Python/2.7/site-packages/; then
- sudo cp -r /tmp/python27/* .
- else
- sudo mkdir -p /Library/Python/2.7/site-packages/
- cd /Library/Python/2.7/site-packages/
- sudo cp -r /tmp/python27/* .
- fi
-else
- if cd /Library/Python/2.6/site-packages/; then
- sudo cp -r /tmp/python26/* .
- else
- sudo mkdir -p /Library/Python/2.6/site-packages/
- cd /Library/Python/2.6/site-packages/
- sudo cp -r /tmp/python26/* .
- fi
-fi
-
-# Install pyo in the python site-packages from python.org install directories
-if cd /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/; then
- sudo cp -r /tmp/python26/* .
-else
- sudo mkdir -p /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/
- cd /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/
- sudo cp -r /tmp/python26/* .
-fi
-
-if cd /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/; then
- sudo cp -r /tmp/python27/* .
-else
- sudo mkdir -p /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
- cd /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
- sudo cp -r /tmp/python27/* .
-fi
-
-sudo rm -rf /tmp/python2*
-
-# Add /usr/local/lib in .bash_profile if not already done
-searchString="/usr/local/lib"
-
-if [ -f ~/.bash_profile ]; then
- if `cat ~/.bash_profile | grep "${searchString}" 1>/dev/null 2>&1`; then
- echo "path already in PATH variable";
- else
- echo "adding path to .bash_profile..."
- echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" >> ~/.bash_profile;
- fi
-else
- echo "creating .bash_profile and adding path to it..."
- echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" > ~/.bash_profile;
-fi
-
-# Add VERSIONER_PYTHON_PREFER_32_BIT in .bash_profile if not already done
-searchString="VERSIONER_PYTHON_PREFER_32_BIT"
-
-if `cat ~/.bash_profile | grep "${searchString}" 1>/dev/null 2>&1`; then
- echo "Variable VERSIONER_PYTHON_PREFER_32_BIT already set.";
-else
- echo "export VERSIONER_PYTHON_PREFER_32_BIT=yes" >> ~/.bash_profile;
-fi
diff --git a/installers/osx/PkgResources_x86_64/ReadMe.rtf b/installers/osx/PkgResources_x86_64/ReadMe.rtf
index d6db53b..7339a3b 100755
--- a/installers/osx/PkgResources_x86_64/ReadMe.rtf
+++ b/installers/osx/PkgResources_x86_64/ReadMe.rtf
@@ -1,75 +1,82 @@
{\rtf1\ansi\deff3\adeflang1025
-{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\fswiss\fprq2\fcharset0 Liberation Sans{\*\falt Arial};}{\f5\froman\fprq2\fcharset1 LucidaGrande;}{\f6\froman\fprq0\fcharset1 LucidaGrande;}{\f7\fnil\fprq2\fcharset0 DejaVu Sans;}{\f8\fnil\fprq2\fcharset0 Lohit Hindi;}{\f9\fnil\fprq0\fcharset1 Lohit Hindi;}}
+{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\fswiss\fprq2\fcharset0 Liberation Sans{\*\falt Arial};}{\f5\froman\fprq2\fcharset0 LucidaGrande;}{\f6\fnil\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f7\fnil\fprq2\fcharset0 FreeSans;}{\f8\fswiss\fprq0\fcharset128 FreeSans;}}
{\colortbl;\red0\green0\blue0;\red128\green128\blue128;}
-{\stylesheet{\s0\snext0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105 Normal;}
-{\s15\sbasedon0\snext16\sb240\sa120\keepn\dbch\af7\dbch\af8\afs28\loch\f4\fs28 Heading;}
-{\s16\sbasedon0\snext16\sb0\sa120 Text body;}
-{\s17\sbasedon16\snext17\sb0\sa120\dbch\af9 List;}
-{\s18\sbasedon0\snext18\sb120\sa120\noline\i\dbch\af9\afs24\ai\fs24 Caption;}
-{\s19\sbasedon0\snext19\noline\dbch\af9 Index;}
-}{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern3600}}\deftab720
-\viewscale110
+{\stylesheet{\s0\snext0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084 Normal;}
+{\s15\sbasedon0\snext16\ql\nowidctlpar\sb240\sa120\keepn\ltrpar\cf1\kerning1\dbch\af7\langfe1081\dbch\af7\afs28\loch\f4\fs28\lang3084 Heading;}
+{\s16\sbasedon0\snext16\sl288\slmult1\ql\nowidctlpar\sb0\sa140\ltrpar\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\loch\f3\fs24\lang3084 Text Body;}
+{\s17\sbasedon16\snext17\sl288\slmult1\ql\nowidctlpar\sb0\sa140\ltrpar\cf1\kerning1\dbch\af7\langfe1081\dbch\af8\afs24\loch\f3\fs24\lang3084 List;}
+{\s18\sbasedon0\snext18\ql\nowidctlpar\sb120\sa120\noline\ltrpar\cf1\i\kerning1\dbch\af7\langfe1081\dbch\af8\afs24\ai\loch\f3\fs24\lang3084 Caption;}
+{\s19\sbasedon0\snext19\ql\nowidctlpar\noline\ltrpar\cf1\kerning1\dbch\af7\langfe1081\dbch\af8\afs24\loch\f3\fs24\lang3084 Index;}
+}{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\author olivier }{\revtim\yr2015\mo1\dy29\hr19\min33}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern67306242}}\deftab720
+\viewscale100
{\*\pgdsctbl
-{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Default;}}
+{\pgdsc0\pgdscuse451\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Default Style;}}
\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
-\pgndec\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-pyo (version 0.6.}{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-6}{\cf1\rtlch \ltrch\loch\fs26\loch\f6
+{\*\ftnsep}\pgndec\pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+Python-pyo (version 0.7.}{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+4}{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
)}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-System requirements : OS X 10.6 or 10.7}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+System requirements : OS X 10.6 to 10.9}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-This package installs all the required components to run pyo inside your current Python installation. Python 2.6 or 2.7 (64-bit) must be already installed on your system.}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+This package installs all the required components to run pyo inside your current Python installation. Python 2.6 or 2.7 (32/64 bit) must be already installed on your system.}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
This package is divided into two separate installers. If you do not require one of them, please unselect the package in custom installation mode.}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
1. pyo extension:}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
The following components will be installed in the site-packages folder of the current Python Framework:}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
_pyo.so}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
_pyo64.so}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
pyo.py}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
pyo64.py}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
pyolib (folder)}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
2. Support libraries (i386 and x86_64):}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
This component will install a number of dynamic libraries on which pyo depends. If you already have these, then you can skip this installation.}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f6
-Warning:}{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+Warning:}{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
this installation will overwrite any previously installed libraries. These are the libraries that will be installed in your /usr/local/lib directory:}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
liblo.7.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
libportaudio.2.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
libportmidi.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
libsndfile.1.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+libFLAC.8.dylib}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+libvorbisenc.2.dylib}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+libvorbis.0.dylib}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+libogg.0.dylib}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-Olivier B\u233\'e9langer, 201}{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-3}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+Olivier B\u233\'e9langer, 2014}
\par }
\ No newline at end of file
diff --git a/installers/osx/PkgResources_x86_64/postinstall b/installers/osx/PkgResources_x86_64/postinstall
index ade04c8..ddcb4ab 100755
--- a/installers/osx/PkgResources_x86_64/postinstall
+++ b/installers/osx/PkgResources_x86_64/postinstall
@@ -1,15 +1,6 @@
#! /bin/sh
-VERSION=`sw_vers -productVersion | sed -e 's/\.//g'`
-
-if [ $VERSION -ge '1070' ]; then
- echo "Install pyo on OSX 10.7";
-else
- echo "Install pyo on OSX 10.6";
-fi
-
-# Removed older versions in the python site-packages builtin directories
-# Removed older versions in the python site-packages from python.org install directories
+# Removed older versions in the python site-packages builtin and in the python site-packages from python.org directories
PATHS=/Library/Python/2.6/site-packages/:/Library/Python/2.7/site-packages/:/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/:/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
for path in ${PATHS//:/ }; do
if cd $path; then
@@ -42,22 +33,20 @@ for path in ${PATHS//:/ }; do
done
# Install pyo in the python site-packages builtin directories
-if [ $VERSION -ge '1070' ]; then
- if cd /Library/Python/2.7/site-packages/; then
- sudo cp -r /tmp/python27/* .
- else
- sudo mkdir -p /Library/Python/2.7/site-packages/
- cd /Library/Python/2.7/site-packages/
- sudo cp -r /tmp/python27/* .
- fi
+if cd /Library/Python/2.7/site-packages/; then
+ sudo cp -r /tmp/python27/* .
else
- if cd /Library/Python/2.6/site-packages/; then
- sudo cp -r /tmp/python26/* .
- else
- sudo mkdir -p /Library/Python/2.6/site-packages/
- cd /Library/Python/2.6/site-packages/
- sudo cp -r /tmp/python26/* .
- fi
+ sudo mkdir -p /Library/Python/2.7/site-packages/
+ cd /Library/Python/2.7/site-packages/
+ sudo cp -r /tmp/python27/* .
+fi
+
+if cd /Library/Python/2.6/site-packages/; then
+ sudo cp -r /tmp/python26/* .
+else
+ sudo mkdir -p /Library/Python/2.6/site-packages/
+ cd /Library/Python/2.6/site-packages/
+ sudo cp -r /tmp/python26/* .
fi
# Install pyo in the python.org site-packages directories
@@ -77,6 +66,15 @@ else
sudo cp -r /tmp/python27/* .
fi
+# Check if anaconda is already installed and copy files to site-packages directory
+if cd ~/anaconda/lib/python2.6/site-packages/; then
+ sudo cp -r /tmp/python26/* .
+fi
+
+if cd ~/anaconda/lib/python2.7/site-packages/; then
+ sudo cp -r /tmp/python27/* .
+fi
+
sudo rm -rf /tmp/python2*
# Add /usr/local/lib in .bash_profile if not already done
diff --git a/installers/osx/PkgResources_x86_64/postupgrade b/installers/osx/PkgResources_x86_64/postupgrade
index ade04c8..ddcb4ab 100755
--- a/installers/osx/PkgResources_x86_64/postupgrade
+++ b/installers/osx/PkgResources_x86_64/postupgrade
@@ -1,15 +1,6 @@
#! /bin/sh
-VERSION=`sw_vers -productVersion | sed -e 's/\.//g'`
-
-if [ $VERSION -ge '1070' ]; then
- echo "Install pyo on OSX 10.7";
-else
- echo "Install pyo on OSX 10.6";
-fi
-
-# Removed older versions in the python site-packages builtin directories
-# Removed older versions in the python site-packages from python.org install directories
+# Removed older versions in the python site-packages builtin and in the python site-packages from python.org directories
PATHS=/Library/Python/2.6/site-packages/:/Library/Python/2.7/site-packages/:/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/:/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
for path in ${PATHS//:/ }; do
if cd $path; then
@@ -42,22 +33,20 @@ for path in ${PATHS//:/ }; do
done
# Install pyo in the python site-packages builtin directories
-if [ $VERSION -ge '1070' ]; then
- if cd /Library/Python/2.7/site-packages/; then
- sudo cp -r /tmp/python27/* .
- else
- sudo mkdir -p /Library/Python/2.7/site-packages/
- cd /Library/Python/2.7/site-packages/
- sudo cp -r /tmp/python27/* .
- fi
+if cd /Library/Python/2.7/site-packages/; then
+ sudo cp -r /tmp/python27/* .
else
- if cd /Library/Python/2.6/site-packages/; then
- sudo cp -r /tmp/python26/* .
- else
- sudo mkdir -p /Library/Python/2.6/site-packages/
- cd /Library/Python/2.6/site-packages/
- sudo cp -r /tmp/python26/* .
- fi
+ sudo mkdir -p /Library/Python/2.7/site-packages/
+ cd /Library/Python/2.7/site-packages/
+ sudo cp -r /tmp/python27/* .
+fi
+
+if cd /Library/Python/2.6/site-packages/; then
+ sudo cp -r /tmp/python26/* .
+else
+ sudo mkdir -p /Library/Python/2.6/site-packages/
+ cd /Library/Python/2.6/site-packages/
+ sudo cp -r /tmp/python26/* .
fi
# Install pyo in the python.org site-packages directories
@@ -77,6 +66,15 @@ else
sudo cp -r /tmp/python27/* .
fi
+# Check if anaconda is already installed and copy files to site-packages directory
+if cd ~/anaconda/lib/python2.6/site-packages/; then
+ sudo cp -r /tmp/python26/* .
+fi
+
+if cd ~/anaconda/lib/python2.7/site-packages/; then
+ sudo cp -r /tmp/python27/* .
+fi
+
sudo rm -rf /tmp/python2*
# Add /usr/local/lib in .bash_profile if not already done
diff --git a/installers/osx/release_i386.sh b/installers/osx/release_i386.sh
deleted file mode 100644
index 7fc5e31..0000000
--- a/installers/osx/release_i386.sh
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/bin/sh
-
-# Need Xcode 3.2.6 or later (pkgbuild and productbuild)
-# 1. install python (and wxpython) 2.6 and 2.7 (32-bit)
-# 2. update pyo sources
-# 3. compile and install pyo float and double
-# 4. cd utils and build E-Pyo
-# 5. cd installer/osx and build the realease
-
-export PACKAGE_NAME=pyo_0.6.8_i386.pkg
-export DMG_DIR="pyo 0.6.8 Intel"
-export DMG_NAME="pyo_0.6.8_OSX-Intel.dmg"
-export INSTALLER_DIR=`pwd`/installer
-export PYO_MODULE_DIR=$INSTALLER_DIR/PyoModule/Package_Contents/tmp
-export SUPPORT_LIBS_DIR=$INSTALLER_DIR/SupportLibs/Package_Contents/usr/local/lib
-export BUILD_RESOURCES=$INSTALLER_DIR/PkgResources/English.lproj
-export PKG_RESOURCES=$INSTALLER_DIR/../PkgResources_i386
-
-mkdir -p $PYO_MODULE_DIR
-mkdir -p $SUPPORT_LIBS_DIR
-mkdir -p $BUILD_RESOURCES
-
-cp $PKG_RESOURCES/License.rtf $BUILD_RESOURCES/License.rtf
-cp $PKG_RESOURCES/Welcome.rtf $BUILD_RESOURCES/Welcome.rtf
-cp $PKG_RESOURCES/ReadMe.rtf $BUILD_RESOURCES/ReadMe.rtf
-
-svn export ../.. installer/pyo-build
-cd installer/pyo-build
-
-echo "building pyo for python 2.6 (32-bit)..."
-sudo /usr/local/bin/python2.6 setup.py install --use-coreaudio --use-double
-
-sudo cp -R build/lib.macosx-10.3-fat-2.6 $PYO_MODULE_DIR/python26
-
-echo "building pyo for python 2.7 (32-bit)..."
-sudo /usr/local/bin/python2.7 setup.py install --use-coreaudio --use-double
-
-sudo cp -R build/lib.macosx-10.3-fat-2.7 $PYO_MODULE_DIR/python27
-
-cd ..
-
-echo "copying support libs..."
-sudo cp /usr/local/lib/liblo.7.dylib $SUPPORT_LIBS_DIR/liblo.7.dylib
-sudo cp /usr/local/lib/libportaudio.2.dylib $SUPPORT_LIBS_DIR/libportaudio.2.dylib
-sudo cp /usr/local/lib/libportmidi.dylib $SUPPORT_LIBS_DIR/libportmidi.dylib
-sudo cp /usr/local/lib/libsndfile.1.dylib $SUPPORT_LIBS_DIR/libsndfile.1.dylib
-sudo cp /usr/local/lib/libFLAC.8.dylib $SUPPORT_LIBS_DIR/libFLAC.8.dylib
-sudo cp /usr/local/lib/libogg.0.dylib $SUPPORT_LIBS_DIR/libogg.0.dylib
-sudo cp /usr/local/lib/libvorbis.0.dylib $SUPPORT_LIBS_DIR/libvorbis.0.dylib
-sudo cp /usr/local/lib/libvorbisenc.2.dylib $SUPPORT_LIBS_DIR/libvorbisenc.2.dylib
-
-echo "setting permissions..."
-
-sudo chgrp -R admin PyoModule/Package_Contents/tmp
-sudo chown -R root PyoModule/Package_Contents/tmp
-sudo chmod -R 755 PyoModule/Package_Contents/tmp
-
-sudo chgrp -R wheel SupportLibs/Package_Contents/usr
-sudo chown -R root SupportLibs/Package_Contents/usr
-sudo chmod -R 755 SupportLibs/Package_Contents/usr
-
-echo "building packages..."
-
-pkgbuild --identifier com.iact.umontreal.ca.pyo.tmp.pkg \
- --root PyoModule/Package_Contents/ \
- --version 1.0 \
- --scripts $PKG_RESOURCES \
- PyoModule.pkg
-
-pkgbuild --identifier com.iact.umontreal.ca.pyo.usr.pkg \
- --root SupportLibs/Package_Contents/ \
- --version 1.0 \
- SupportLibs.pkg
-
-echo "building product..."
-productbuild --distribution ../Distribution.dist --resources $BUILD_RESOURCES $PACKAGE_NAME
-
-echo "assembling DMG..."
-mkdir "$DMG_DIR"
-cd "$DMG_DIR"
-cp ../$PACKAGE_NAME .
-cp -R ../../../../utils/E-Pyo.app .
-ln -s /Applications .
-cd ..
-
-hdiutil create "$DMG_NAME" -srcfolder "$DMG_DIR"
-
-cd ..
-mv installer/$DMG_NAME .
-
-echo "clean up resources..."
-sudo rm -rf installer
-
-
diff --git a/installers/osx/release_x86_64.sh b/installers/osx/release_x86_64.sh
index 4c21d67..c8bcfad 100644
--- a/installers/osx/release_x86_64.sh
+++ b/installers/osx/release_x86_64.sh
@@ -1,8 +1,16 @@
#!/bin/sh
-export PACKAGE_NAME=pyo_0.6.8_x86_64.pkg
-export DMG_DIR="pyo 0.6.8 Universal"
-export DMG_NAME="pyo_0.6.8_OSX-universal.dmg"
+# Need Xcode 3.2.6 or later (pkgbuild and productbuild)
+# 1. install python (and wxpython) 2.6 and 2.7 (32-bit)
+# 2. update pyo sources
+# 3. compile and install pyo float and double
+# 4. cd utils and build E-Pyo
+# 5. install python (and wxpython) 2.7 (64-bit)
+# 6. cd installer/osx and build the realease, only x86_64 version
+
+export PACKAGE_NAME=pyo_0.7.4_x86_64.pkg
+export DMG_DIR="pyo 0.7.4 Universal"
+export DMG_NAME="pyo_0.7.4_OSX-universal.dmg"
export INSTALLER_DIR=`pwd`/installer
export PYO_MODULE_DIR=$INSTALLER_DIR/PyoModule/Package_Contents/tmp
export SUPPORT_LIBS_DIR=$INSTALLER_DIR/SupportLibs/Package_Contents/usr/local/lib
@@ -33,6 +41,11 @@ sudo /usr/local/bin/python2.7 setup.py install --use-coreaudio --use-double
sudo cp -R build/lib.macosx-10.6-intel-2.7 $PYO_MODULE_DIR/python27
+sudo install_name_tool -change libportmidi.dylib /usr/local/lib/libportmidi.dylib $PYO_MODULE_DIR/python26/_pyo.so
+sudo install_name_tool -change libportmidi.dylib /usr/local/lib/libportmidi.dylib $PYO_MODULE_DIR/python26/_pyo64.so
+sudo install_name_tool -change libportmidi.dylib /usr/local/lib/libportmidi.dylib $PYO_MODULE_DIR/python27/_pyo.so
+sudo install_name_tool -change libportmidi.dylib /usr/local/lib/libportmidi.dylib $PYO_MODULE_DIR/python27/_pyo64.so
+
cd ..
echo "copying support libs..."
@@ -41,12 +54,11 @@ sudo cp /usr/local/lib/libportaudio.2.dylib $SUPPORT_LIBS_DIR/libportaudio.2.dyl
sudo cp /usr/local/lib/libportmidi.dylib $SUPPORT_LIBS_DIR/libportmidi.dylib
sudo cp /usr/local/lib/libsndfile.1.dylib $SUPPORT_LIBS_DIR/libsndfile.1.dylib
sudo cp /usr/local/lib/libFLAC.8.dylib $SUPPORT_LIBS_DIR/libFLAC.8.dylib
-sudo cp /usr/local/lib/libogg.0.dylib $SUPPORT_LIBS_DIR/libogg.0.dylib
-sudo cp /usr/local/lib/libvorbis.0.dylib $SUPPORT_LIBS_DIR/libvorbis.0.dylib
sudo cp /usr/local/lib/libvorbisenc.2.dylib $SUPPORT_LIBS_DIR/libvorbisenc.2.dylib
+sudo cp /usr/local/lib/libvorbis.0.dylib $SUPPORT_LIBS_DIR/libvorbis.0.dylib
+sudo cp /usr/local/lib/libogg.0.dylib $SUPPORT_LIBS_DIR/libogg.0.dylib
echo "setting permissions..."
-
sudo chgrp -R admin PyoModule/Package_Contents/tmp
sudo chown -R root PyoModule/Package_Contents/tmp
sudo chmod -R 755 PyoModule/Package_Contents/tmp
diff --git a/installers/win/README-win32-py26.txt b/installers/win/README-win32-py26.txt
index bbe9866..e482de4 100644
--- a/installers/win/README-win32-py26.txt
+++ b/installers/win/README-win32-py26.txt
@@ -4,7 +4,7 @@ Pyo is a Python module written in C to help digital signal processing script cre
http://www.python.org/download/releases/2.6.6/
-To use the WxPython toolkit for widgets, you need to install wxPython2.8-win32-unicode-py26:
+To use the WxPython toolkit for widgets, you need to install wxPython 3.0 for python 2.6:
http://www.wxpython.org/download.php#stable
@@ -13,8 +13,8 @@ it's a good starting point to explore the library!
In a Command Prompt:
-cd Desktop\pyo_examples
-python xnoise_example.py
+cd Desktop\pyo_examples\algorithmic
+python 01_music_box.py
Please, send comments and bugs to:
diff --git a/installers/win/README-win32-py27.txt b/installers/win/README-win32-py27.txt
index 872130e..eddb84d 100644
--- a/installers/win/README-win32-py27.txt
+++ b/installers/win/README-win32-py27.txt
@@ -4,7 +4,7 @@ Pyo is a Python module written in C to help digital signal processing script cre
http://www.python.org/download/
-To use the WxPython toolkit for widgets, you need to install wxPython2.8-win32-unicode-py27:
+To use the WxPython toolkit for widgets, you need to install wxPython 3.0 for python 2.7:
http://www.wxpython.org/download.php#stable
@@ -13,8 +13,8 @@ it's a good starting point to explore the library!
In a Command Prompt:
-cd Desktop\pyo_examples
-python xnoise_example.py
+cd Desktop\pyo_examples\algorithmic
+python 01_music_box.py
Please, send comments and bugs to:
diff --git a/installers/win/win_installer_py26.iss b/installers/win/win_installer_py26.iss
index 1d24ca6..f973793 100644
--- a/installers/win/win_installer_py26.iss
+++ b/installers/win/win_installer_py26.iss
@@ -1,55 +1,63 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
+
+#define appName "pyo"
+#define pyVer "2.6"
+#define appVer "0.7.4"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
-AppId={{4F72B6EF-CFA0-434F-A2B4-B130F94F54EB}
-AppName=Pyo
-AppVersion=0.6.8
-AppPublisher=iACT.umontreal.ca
-AppPublisherURL=http://code.google.com/p/pyo
-AppSupportURL=http://code.google.com/p/pyo
-AppUpdatesURL=http://code.google.com/p/pyo
-DefaultDirName={sd}\Python26
-DisableDirPage=yes
-DefaultGroupName=pyo
-AllowNoIcons=yes
-InfoBeforeFile=C:\Documents and Settings\user\svn\pyo\installers\win\\README-win32-py26.txt
-OutputBaseFilename=pyo_0.6.8_py2.6_setup
+AppId={{AC79C5C4-BE36-419E-B94A-98C6D0DCF4B9}
+AppName={#appName}
+AppVersion={#appVer}
+AppPublisher=iACT.umontreal.ca
+AppPublisherURL=http://code.google.com/p/pyo
+AppSupportURL=http://code.google.com/p/pyo
+AppUpdatesURL=http://code.google.com/p/pyo
+DefaultDirName={code:GetDirName}
+DisableDirPage=no
+AlwaysShowDirOnReadyPage=yes
+DefaultGroupName={#appName}
+AllowNoIcons=yes
+InfoBeforeFile=C:\Users\olipet\svn\pyo\installers\win\\README-win32-py26.txt
+LicenseFile=C:\Users\olipet\svn\pyo\COPYING.txt
+OutputBaseFilename={#appName}_{#appVer}_py{#pyVer}_setup
Compression=lzma
SolidCompression=yes
ChangesAssociations=yes
ChangesEnvironment=yes
+DirExistsWarning=no
+SetupIconFile=C:\Users\olipet\svn\pyo\utils\E-PyoIcon.ico
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
; should use PYTHONPATH variable
[Files]
-Source: "C:\Python26\Lib\site-packages\pyo.py"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\pyo64.py"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\pyolib\*"; DestDir: "{sd}\Python26\Lib\site-packages\pyolib"; Flags: ignoreversion recursesubdirs createallsubdirs
-Source: "C:\Python26\Lib\site-packages\_pyo.pyd"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\_pyo64.pyd"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\libsndfile-1.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\lo.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\portaudio.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\portmidi.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\porttime.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\pthreadVC2.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\msvcr90.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\MinGW\bin\libgcc_s_dw2-1.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\MinGW\bin\libstdc++-6.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\pyo-0.6.8-py2.6.egg-info"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Documents and Settings\user\svn\pyo\examples\*"; DestDir: "{userdesktop}\pyo_examples\"; Flags: ignoreversion recursesubdirs createallsubdirs
-Source: "C:\Documents and Settings\user\svn\pyo\installers\win\README-win32-py26.txt"; DestDir: "{userdesktop}"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\pyo.py"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\pyo64.py"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\pyolib\*"; DestDir: "{app}\Lib\site-packages\pyolib"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Python26\Lib\site-packages\_pyo.pyd"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\_pyo64.pyd"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\libsndfile-1.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\lo.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\portaudio.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\portmidi.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\porttime.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\pthreadVC2.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\msvcr90.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\MinGW\bin\libgcc_s_dw2-1.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\MinGW\bin\libstdc++-6.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\pyo-{#appVer}-py{#pyVer}.egg-info"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olipet\svn\pyo\examples\*"; DestDir: "{userdesktop}\pyo_examples\"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Users\olipet\svn\pyo\installers\win\README-win32-py26.txt"; DestDir: "{userdesktop}"; Flags: ignoreversion
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
; E-Pyo stuff
-Source: "C:\Documents and Settings\user\svn\pyo\utils\E-Pyo_py26\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
-Source: "C:\Documents and Settings\user\svn\pyo\utils\E-Pyo_py26\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Users\olipet\svn\pyo\utils\E-Pyo_py26\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
+Source: "C:\Users\olipet\svn\pyo\utils\E-Pyo_py26\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
@@ -67,9 +75,12 @@ Type: filesandordirs; Name: "{userdocs}\.epyo";
;;;;;;;;;;;;;
[Registry]
-Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "C:\Python26;{olddata}"; Check: NeedsAddPath('C:\Python26')
+Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "C:\Python26;{olddata}"; Check: NeedsAddPath('{app}')
[Code]
+procedure ExitProcess(exitCode:integer);
+ external 'ExitProcess at kernel32.dll stdcall';
+
function NeedsAddPath(Param: string): boolean;
var
OrigPath: string;
@@ -86,6 +97,37 @@ begin
Result := Pos(';' + Param + ';', ';' + OrigPath + ';') = 0;
end;
-
+function GetDirName(Value: string): string;
+var
+ InstallPath: string;
+ reg1 : string;
+ reg2 : string;
+ reg3 : string;
+ reg4 : string;
+begin
+ reg1 := 'SOFTWARE\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+ reg2 := 'SOFTWARE\Wow6432Node\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+ reg3 := 'Software\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+ reg4 := 'Software\Wow6432Node\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+ if RegQueryStringValue(HKLM, reg1, '', InstallPath) then
+ BEGIN
+ Result := InstallPath;
+ END else
+ if RegQueryStringValue(HKCU, reg3, '', InstallPath) then
+ BEGIN
+ Result := InstallPath;
+ END else
+ if RegQueryStringValue(HKLM, reg2, '', InstallPath) then
+ BEGIN
+ Result := InstallPath;
+ END else
+ if RegQueryStringValue(HKCU, reg4, '', InstallPath) then
+ BEGIN
+ Result := InstallPath;
+ END else
+ BEGIN
+ Result := 'C:\Python26';
+ END
+end;
diff --git a/installers/win/win_installer_py27.iss b/installers/win/win_installer_py27.iss
index 6b0cf86..5935569 100644
--- a/installers/win/win_installer_py27.iss
+++ b/installers/win/win_installer_py27.iss
@@ -1,54 +1,61 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
+
+#define appName "pyo"
+#define pyVer "2.7"
+#define appVer "0.7.4"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
-AppId={{244D309A-C251-481A-AD24-0602D392A634}
-AppName=Pyo
-AppVersion=0.6.8
+AppId={{59447873-F994-4BC7-8B1D-0DDCA5B6AFFD}
+AppName={#appName}
+AppVersion={#appVer}
AppPublisher=iACT.umontreal.ca
AppPublisherURL=http://code.google.com/p/pyo
AppSupportURL=http://code.google.com/p/pyo
AppUpdatesURL=http://code.google.com/p/pyo
-DefaultDirName={sd}\Python27
-DisableDirPage=yes
-DefaultGroupName=pyo
+DefaultDirName={code:GetDirName}
+DisableDirPage=no
+AlwaysShowDirOnReadyPage=yes
+DefaultGroupName={#appName}
AllowNoIcons=yes
-InfoBeforeFile=C:\Documents and Settings\user\svn\pyo\installers\win\\README-win32-py27.txt
-OutputBaseFilename=pyo_0.6.8_py2.7_setup
+InfoBeforeFile=C:\Users\olipet\svn\pyo\installers\win\\README-win32-py27.txt
+LicenseFile=C:\Users\olipet\svn\pyo\COPYING.txt
+OutputBaseFilename={#appName}_{#appVer}_py{#pyVer}_setup
Compression=lzma
SolidCompression=yes
ChangesAssociations=yes
-ChangesEnvironment=yes
+ChangesEnvironment=yes
+DirExistsWarning=no
+SetupIconFile=C:\Users\olipet\svn\pyo\utils\E-PyoIcon.ico
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Files]
-Source: "C:\Python27\Lib\site-packages\pyo.py"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\pyo64.py"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\pyolib\*"; DestDir: "{sd}\Python27\Lib\site-packages\pyolib"; Flags: ignoreversion recursesubdirs createallsubdirs
-Source: "C:\Python27\Lib\site-packages\_pyo.pyd"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\_pyo64.pyd"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\libsndfile-1.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\lo.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\portaudio.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\portmidi.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\porttime.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\pthreadVC2.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\msvcr90.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\MinGW\bin\libgcc_s_dw2-1.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\MinGW\bin\libstdc++-6.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\pyo-0.6.8-py2.7.egg-info"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Documents and Settings\user\svn\pyo\examples\*"; DestDir: "{userdesktop}\pyo_examples\"; Flags: ignoreversion recursesubdirs createallsubdirs
-Source: "C:\Documents and Settings\user\svn\pyo\installers\win\README-win32-py27.txt"; DestDir: "{userdesktop}"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\pyo.py"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\pyo64.py"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\pyolib\*"; DestDir: "{app}\Lib\site-packages\pyolib"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Python27\Lib\site-packages\_pyo.pyd"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\_pyo64.pyd"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\libsndfile-1.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\lo.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\portaudio.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\portmidi.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\porttime.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\pthreadVC2.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\msvcr90.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\MinGW\bin\libgcc_s_dw2-1.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\MinGW\bin\libstdc++-6.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\pyo-{#appVer}-py{#pyVer}.egg-info"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olipet\svn\pyo\examples\*"; DestDir: "{userdesktop}\pyo_examples\"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
; E-Pyo stuff
-Source: "C:\Documents and Settings\user\svn\pyo\utils\E-Pyo_py27\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
-Source: "C:\Documents and Settings\user\svn\pyo\utils\E-Pyo_py27\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Users\olipet\svn\pyo\utils\E-Pyo_py27\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
+Source: "C:\Users\olipet\svn\pyo\utils\E-Pyo_py27\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
@@ -66,9 +73,12 @@ Type: filesandordirs; Name: "{userdocs}\.epyo";
;;;;;;;;;;;;;
[Registry]
-Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "C:\Python27;{olddata}"; Check: NeedsAddPath('C:\Python27')
+Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{app};{olddata}"; Check: NeedsAddPath('{app}')
[Code]
+procedure ExitProcess(exitCode:integer);
+ external 'ExitProcess at kernel32.dll stdcall';
+
function NeedsAddPath(Param: string): boolean;
var
OrigPath: string;
@@ -84,3 +94,36 @@ begin
// Pos() returns 0 if not found
Result := Pos(';' + Param + ';', ';' + OrigPath + ';') = 0;
end;
+
+function GetDirName(Value: string): string;
+var
+ InstallPath: string;
+ reg1 : string;
+ reg2 : string;
+ reg3 : string;
+ reg4 : string;
+begin
+ reg1 := 'SOFTWARE\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+ reg2 := 'SOFTWARE\Wow6432Node\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+ reg3 := 'Software\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+ reg4 := 'Software\Wow6432Node\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+ if RegQueryStringValue(HKLM, reg1, '', InstallPath) then
+ BEGIN
+ Result := InstallPath;
+ END else
+ if RegQueryStringValue(HKCU, reg3, '', InstallPath) then
+ BEGIN
+ Result := InstallPath;
+ END else
+ if RegQueryStringValue(HKLM, reg2, '', InstallPath) then
+ BEGIN
+ Result := InstallPath;
+ END else
+ if RegQueryStringValue(HKCU, reg4, '', InstallPath) then
+ BEGIN
+ Result := InstallPath;
+ END else
+ BEGIN
+ Result := 'C:\Python27';
+ END
+end;
\ No newline at end of file
diff --git a/pyo.py b/pyo.py
index f7a865f..02421c5 100644
--- a/pyo.py
+++ b/pyo.py
@@ -99,7 +99,6 @@ if WITH_EXTERNALS:
import pyolib.external as external
from pyolib.external import *
-# Temporary objects, need to be coded in C
class FreqShift(PyoObject):
"""
Frequency shifting using single sideband amplitude modulation.
@@ -110,26 +109,14 @@ class FreqShift(PyoObject):
100, 200, 300, 400 and 500 Hz, shifted up by 50 Hz, will have harmonics
at 150, 250, 350, 450, and 550 Hz.
- Parent class : PyoObject
+ :Parent: :py:class:`PyoObject`
- Parameters:
+ :Args:
- input : PyoObject
- Input signal to process.
- shift : float or PyoObject, optional
- Amount of shifting in Hertz. Defaults to 100.
-
- Methods:
-
- setInput(x, fadetime) : Replace the `input` attribute.
- setShift(x) : Replace the `shift` attribute.
-
- Attributes:
-
- input : PyoObject. Input signal to process.
- shift : float or PyoObject. Amount of shifting in Hertz.
-
- Examples:
+ input : PyoObject
+ Input signal to process.
+ shift : float or PyoObject, optional
+ Amount of shifting in Hertz. Defaults to 100.
>>> s = Server().boot()
>>> s.start()
@@ -141,11 +128,9 @@ class FreqShift(PyoObject):
"""
def __init__(self, input, shift=100, mul=1, add=0):
- PyoObject.__init__(self)
+ PyoObject.__init__(self, mul, add)
self._input = input
self._shift = shift
- self._mul = mul
- self._add = add
self._in_fader = InputFader(input)
in_fader, shift, mul, add, lmax = convertArgsToLists(self._in_fader, shift, mul, add)
@@ -162,25 +147,20 @@ class FreqShift(PyoObject):
mul=wrap(mul,i), add=wrap(add,i)))
self._base_objs.extend(self._mod_objs[-1].getBaseObjects())
- def __dir__(self):
- return ["input", "shift", "mul", "add"]
-
def play(self, dur=0, delay=0):
dur, delay, lmax = convertArgsToLists(dur, delay)
[obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._hilb_objs)]
[obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._sin_objs)]
[obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._cos_objs)]
[obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._mod_objs)]
- self._base_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
- return self
+ return PyoObject.play(self, dur, delay)
def stop(self):
[obj.stop() for obj in self._hilb_objs]
[obj.stop() for obj in self._sin_objs]
[obj.stop() for obj in self._cos_objs]
[obj.stop() for obj in self._mod_objs]
- [obj.stop() for obj in self._base_objs]
- return self
+ return PyoObject.stop(self)
def out(self, chnl=0, inc=1, dur=0, delay=0):
dur, delay, lmax = convertArgsToLists(dur, delay)
@@ -188,14 +168,7 @@ class FreqShift(PyoObject):
[obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._sin_objs)]
[obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._cos_objs)]
[obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._mod_objs)]
- if type(chnl) == ListType:
- self._base_objs = [obj.out(wrap(chnl,i), wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
- else:
- if chnl < 0:
- self._base_objs = [obj.out(i*inc, wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(random.sample(self._base_objs, len(self._base_objs)))]
- else:
- self._base_objs = [obj.out(chnl+i*inc, wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
- return self
+ return PyoObject.out(self, chnl, inc, dur, delay)
def setInput(self, x, fadetime=0.05):
"""
@@ -245,30 +218,123 @@ class FreqShift(PyoObject):
@shift.setter
def shift(self, x): self.setShift(x)
+class PartialTable(PyoTableObject):
+ """
+ Inharmonic waveform generator.
+
+ Generates waveforms made of inharmonic components. Partials are
+ given as a list of 2-values tuple, where the first one is the
+ partial number (can be float) and the second one is the strength
+ of the partial.
+
+ The object uses the first two decimal values of each partial to
+ compute a higher harmonic at a multiple of 100 (so each component
+ is in reality truly harmonic). If the oscillator has a frequency
+ divided by 100, the real desired partials will be restituted.
+
+ The list:
+
+ [(1, 1), (1.1, 0.7), (1.15, 0.5)] will draw a table with:
+
+ harmonic 100 : amplitude = 1
+ harmonic 110 : amplitude = 0.7
+ harmonic 115 : amplitude = 0.5
+
+ To listen to a signal composed of 200, 220 and 230 Hz, one should
+ declared an oscillator like this (frequency of 200Hz divided by 100):
+
+ a = Osc(t, freq=2, mul=0.5).out()
+
+ :Parent: :py:class:`PyoTableObject`
+
+ :Args:
+
+ list : list of tuple, optional
+ List of 2-values tuples. First value is the partial number (float up
+ to two decimal values) and second value is its amplitude (relative to
+ the other harmonics). Defaults to [(1,1), (1.33,0.5),(1.67,0.3)].
+ size : int, optional
+ Table size in samples. Because computed harmonics are very high in
+ frequency, the table size must be bigger than a classic HarmTable.
+ Defaults to 65536.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> t = PartialTable([(1,1), (2.37, 0.5), (4.55, 0.3)]).normalize()
+ >>> # Play with fundamentals 199 and 200 Hz
+ >>> a = Osc(table=t, freq=[1.99,2], mul=.2).out()
+
+ """
+ def __init__(self, list=[(1,1), (1.33,0.5),(1.67,0.3)], size=65536):
+ PyoTableObject.__init__(self, size)
+ self._list = list
+ self._par_table = HarmTable(self._create_list(), size)
+ self._base_objs = self._par_table.getBaseObjects()
+ self.normalize()
+
+ def _create_list(self):
+ # internal method used to compute the harmonics's weight
+ hrms = [(int(x*100.), y) for x, y in self._list]
+ l = []
+ ind = 0
+ for i in range(10000):
+ if i == hrms[ind][0]:
+ l.append(hrms[ind][1])
+ ind += 1
+ if ind == len(hrms):
+ break
+ else:
+ l.append(0)
+ return l
+
+ def replace(self, list):
+ """
+ Redraw the waveform according to a new set of harmonics
+ relative strengths.
+
+ :Args:
+
+ list : list of tuples
+ Each tuple contains the partial number, as a float,
+ and its strength.
+
+ """
+ self._list = list
+ [obj.replace(self._create_list()) for obj in self._base_objs]
+ self.normalize()
+ self.refreshView()
+
+ @property
+ def list(self):
+ """list. List of partial numbers and strength."""
+ return self._list
+ @list.setter
+ def list(self, x): self.replace(x)
OBJECTS_TREE = {'functions': sorted(['pa_count_devices', 'pa_get_default_input', 'pa_get_default_output', 'pm_get_input_devices',
'pa_list_devices', 'pa_count_host_apis', 'pa_list_host_apis', 'pa_get_default_host_api',
'pm_count_devices', 'pm_list_devices', 'sndinfo', 'savefile', 'pa_get_output_devices',
- 'pa_get_input_devices', 'midiToHz', 'sampsToSec', 'secToSamps', 'example', 'class_args',
+ 'pa_get_input_devices', 'midiToHz', 'hzToMidi', 'sampsToSec', 'secToSamps', 'example', 'class_args',
'pm_get_default_input', 'pm_get_output_devices', 'pm_get_default_output', 'midiToTranspo',
'getVersion', 'reducePoints', 'serverCreated', 'serverBooted', 'distanceToSegment', 'rescale',
'upsamp', 'downsamp', 'linToCosCurve', 'convertStringToSysEncoding', 'savefileFromTable',
- 'pa_get_input_max_channels', 'pa_get_output_max_channels', 'pa_get_devices_infos']),
+ 'pa_get_input_max_channels', 'pa_get_output_max_channels', 'pa_get_devices_infos', 'pa_get_version',
+ 'pa_get_version_text', 'floatmap']),
'PyoObjectBase': {
'PyoMatrixObject': sorted(['NewMatrix']),
'PyoTableObject': sorted(['LinTable', 'NewTable', 'SndTable', 'HannTable', 'HarmTable', 'SawTable', 'ParaTable', 'LogTable', 'CosLogTable',
- 'SquareTable', 'ChebyTable', 'CosTable', 'CurveTable', 'ExpTable', 'DataTable', 'WinTable', 'SincTable']),
+ 'SquareTable', 'ChebyTable', 'CosTable', 'CurveTable', 'ExpTable', 'DataTable', 'WinTable', 'SincTable', 'PartialTable']),
'PyoPVObject' : sorted(['PVAnal', 'PVSynth', 'PVTranspose', 'PVVerb', 'PVGate', 'PVAddSynth', 'PVCross', 'PVMult', 'PVMorph', 'PVFilter', 'PVDelay', 'PVBuffer', 'PVShift', 'PVAmpMod', 'PVFreqMod', 'PVBufLoops', 'PVBufTabLoops', 'PVMix']),
- 'PyoObject': {'analysis': sorted(['Follower', 'Follower2', 'ZCross', 'Yin']),
+ 'PyoObject': {'analysis': sorted(['Follower', 'Follower2', 'ZCross', 'Yin', 'Centroid', 'AttackDetector', 'Scope', 'Spectrum', 'PeakAmp']),
'arithmetic': sorted(['Sin', 'Cos', 'Tan', 'Abs', 'Sqrt', 'Log', 'Log2', 'Log10', 'Pow', 'Atan2', 'Floor', 'Round',
- 'Ceil']),
+ 'Ceil', 'Tanh']),
'controls': sorted(['Fader', 'Sig', 'SigTo', 'Adsr', 'Linseg', 'Expseg']),
'dynamics': sorted(['Clip', 'Compress', 'Degrade', 'Mirror', 'Wrap', 'Gate', 'Balance', 'Min', 'Max']),
- 'effects': sorted(['Delay', 'SDelay', 'Disto', 'Freeverb', 'Waveguide', 'Convolve', 'WGVerb',
- 'Harmonizer', 'Chorus', 'AllpassWG', 'FreqShift', 'Vocoder', 'Delay1']),
+ 'effects': sorted(['Delay', 'SDelay', 'Disto', 'Freeverb', 'Waveguide', 'Convolve', 'WGVerb', 'SmoothDelay',
+ 'Harmonizer', 'Chorus', 'AllpassWG', 'FreqShift', 'Vocoder', 'Delay1', 'STRev']),
'filters': sorted(['Biquad', 'BandSplit', 'Port', 'Hilbert', 'Tone', 'DCBlock', 'EQ', 'Allpass',
'Allpass2', 'Phaser', 'Biquadx', 'IRWinSinc', 'IRAverage', 'IRPulse', 'IRFM', 'FourBand',
- 'Biquada', 'Atone', 'SVF', 'Average', 'Reson', 'Resonx', 'ButLP', 'ButHP', 'ButBP', 'ButBR']),
+ 'Biquada', 'Atone', 'SVF', 'Average', 'Reson', 'Resonx', 'ButLP', 'ButHP', 'ButBP', 'ButBR', 'ComplexRes']),
'generators': sorted(['Noise', 'Phasor', 'Sine', 'Input', 'FM', 'SineLoop', 'Blit', 'PinkNoise', 'CrossFM',
'BrownNoise', 'Rossler', 'Lorenz', 'LFO', 'SumOsc', 'SuperSaw', 'RCOsc']),
'internals': sorted(['Dummy', 'InputFader', 'Mix', 'VarPort']),
@@ -278,22 +344,21 @@ OBJECTS_TREE = {'functions': sorted(['pa_count_devices', 'pa_get_default_input',
'pattern': sorted(['Pattern', 'Score', 'CallAfter']),
'randoms': sorted(['Randi', 'Randh', 'Choice', 'RandInt', 'Xnoise', 'XnoiseMidi', 'RandDur', 'XnoiseDur', 'Urn']),
'players': sorted(['SfMarkerShuffler', 'SfPlayer', 'SfMarkerLooper']),
- 'tableprocess': sorted(['TableRec', 'Osc', 'Pointer', 'Lookup', 'Granulator', 'Pulsar', 'OscLoop', 'Granule',
- 'TableRead', 'TableMorph', 'Looper', 'TableIndex', 'OscBank', 'OscTrig', 'TablePut', 'TableScale']),
+ 'tableprocess': sorted(['TableRec', 'Osc', 'Pointer', 'Pointer2', 'Lookup', 'Granulator', 'Pulsar', 'OscLoop', 'Granule',
+ 'TableRead', 'TableMorph', 'Looper', 'TableIndex', 'OscBank', 'OscTrig', 'TablePut', 'TableScale', 'Particle']),
'matrixprocess': sorted(['MatrixRec', 'MatrixPointer', 'MatrixMorph', 'MatrixRecLoop']),
'triggers': sorted(['Metro', 'Beat', 'TrigEnv', 'TrigRand', 'TrigRandInt', 'Select', 'Counter', 'TrigChoice',
'TrigFunc', 'Thresh', 'Cloud', 'Trig', 'TrigXnoise', 'TrigXnoiseMidi', 'Timer', 'Count',
'Change', 'TrigLinseg', 'TrigExpseg', 'Percent', 'Seq', 'TrigTableRec', 'Iter', 'NextTrig',
- 'TrigVal']),
+ 'TrigVal', 'Euclide', 'TrigBurst']),
'utils': sorted(['Clean_objects', 'Print', 'Snap', 'Interp', 'SampHold', 'Compare', 'Record', 'Between', 'Denorm',
'ControlRec', 'ControlRead', 'NoteinRec', 'NoteinRead', 'DBToA', 'AToDB', 'Scale', 'CentsToTranspo',
- 'TranspoToCents', 'MToF', 'MToT']),
- 'fourier': sorted(['FFT', 'IFFT', 'CarToPol', 'PolToCar', 'FrameDelta', 'FrameAccum', 'Vectral', 'CvlVerb', 'Spectrum'])}},
+ 'TranspoToCents', 'MToF', 'FToM', 'MToT', 'TrackHold']),
+ 'fourier': sorted(['FFT', 'IFFT', 'CarToPol', 'PolToCar', 'FrameDelta', 'FrameAccum', 'Vectral', 'CvlVerb'])}},
'Map': {'SLMap': sorted(['SLMapFreq', 'SLMapMul', 'SLMapPhase', 'SLMapQ', 'SLMapDur', 'SLMapPan'])},
'Server': [],
'Stream': [],
'TableStream': []}
DOC_KEYWORDS = ['Attributes', 'Examples', 'Parameters', 'Methods', 'Notes', 'Methods details', 'See also', 'Parentclass']
-
DEMOS_PATH = SNDS_PATH
diff --git a/pyolib/_core.py b/pyolib/_core.py
index 0a643c6..07a9e98 100644
--- a/pyolib/_core.py
+++ b/pyolib/_core.py
@@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License
along with pyo. If not, see <http://www.gnu.org/licenses/>.
"""
-from types import ListType, SliceType, FloatType, StringType, UnicodeType
+from types import ListType, SliceType, FloatType, StringType, UnicodeType, NoneType
import random, os, sys, inspect, tempfile
from subprocess import call
@@ -46,6 +46,7 @@ FILE_FORMATS = {'wav': 0, 'wave': 0, 'aif': 1, 'aiff': 1, 'au': 2, '': 3, 'sd2':
FUNCTIONS_INIT_LINES = {"pa_count_host_apis": "pa_count_host_apis()", "pa_list_host_apis": "pa_list_host_apis()",
"pa_get_default_host_api": "pa_get_default_host_api()", "pa_count_devices": "pa_count_devices()",
"pa_list_devices": "pa_list_devices()", "pa_get_devices_infos": "pa_get_devices_infos()",
+ "pa_get_version": "pa_get_version()", "pa_get_version_text": "pa_get_version_text()",
"pa_get_input_devices": "pa_get_input_devices()", "pa_get_output_devices": "pa_get_output_devices()",
"pa_get_default_input": "pa_get_default_input()", "pa_get_default_output": "pa_get_default_output()",
"pa_get_input_max_channels": "pa_get_input_max_channels(x)", "pa_get_output_max_channels": "pa_get_output_max_channels(x)",
@@ -55,14 +56,14 @@ FUNCTIONS_INIT_LINES = {"pa_count_host_apis": "pa_count_host_apis()", "pa_list_h
"sndinfo": "sndinfo(path, print=False)", "savefile": "savefile(samples, path, sr=44100, channels=1, fileformat=0, sampletype=0)",
"savefileFromTable": "savefileFromTable(table, path, fileformat=0, sampletype=0)",
"upsamp": "upsamp(path, outfile, up=4, order=128)", "downsamp": "downsamp(path, outfile, down=4, order=128)",
- "midiToHz": "midiToHz(x)", "midiToTranspo": "midiToTranspo(x)", "sampsToSec": "sampsToSec(x)",
+ "midiToHz": "midiToHz(x)", "hzToMidi": "hzToMidi(x)", "midiToTranspo": "midiToTranspo(x)", "sampsToSec": "sampsToSec(x)",
"secToSamps": "secToSamps(x)", "linToCosCurve": "linToCosCurve(data, yrange=[0, 1], totaldur=1, points=1024, log=False)",
"rescale": "rescale(data, xmin=0.0, xmax=1.0, ymin=0.0, ymax=1.0, xlog=False, ylog=False)",
"distanceToSegment": "distanceToSegment(p, p1, p2, xmin=0.0, xmax=1.0, ymin=0.0, ymax=1.0, xlog=False, ylog=False)",
"reducePoints": "reducePoints(pointlist, tolerance=0.02)", "serverCreated": "serverCreated()", "serverBooted": "serverBooted()",
"example": "example(cls, dur=5, toprint=True, double=False)", "class_args": "class_args(cls)", "getVersion": "getVersion()",
"convertStringToSysEncoding": "convertStringToSysEncoding(str)", "convertArgsToLists": "convertArgsToLists(*args)",
- "wrap": "wrap(arg, i)"
+ "wrap": "wrap(arg, i)", "floatmap": "floatmap(x, min=0, max=1, exp=1)"
}
def convertStringToSysEncoding(str):
@@ -223,6 +224,9 @@ def getVersion():
major, minor, rev = PYO_VERSION.split('.')
return (int(major), int(minor), int(rev))
+def dumpref():
+ pass
+
class PyoError(Exception):
"""Base class for all pyo exceptions."""
@@ -286,6 +290,20 @@ class PyoObjectBase(object):
"""
return self._base_objs
+ def cleanFuncRefs(self):
+ """
+ Method used to remove internal references to callback functions.
+
+ An internal reference to a callback function (ex. the function
+ called by the TrigFunc object) may prevent the object to be
+ properly deleted when its reference count drop to zero. Calling
+ this function just before deleting the last reference will replace
+ the callback reference by a dump ref.
+
+ """
+ if hasattr(self, "_function"):
+ self.setFunction(dumpref)
+
def __getitem__(self, i):
if i == 'trig':
return self._trig_objs
@@ -768,12 +786,12 @@ class PyoObject(PyoObjectBase):
def setSub(self, x):
"""
- Replace and inverse the `mul` attribute.
+ Replace and inverse the `add` attribute.
:Args:
x : float or PyoObject
- New inversed `mul` attribute.
+ New inversed `add` attribute.
"""
self._add = x
@@ -782,12 +800,12 @@ class PyoObject(PyoObjectBase):
def setDiv(self, x):
"""
- Replace and inverse the `add` attribute.
+ Replace and inverse the `mul` attribute.
:Args:
x : float or PyoObject
- New inversed `add` attribute.
+ New inversed `mul` attribute.
"""
self._mul = x
@@ -899,7 +917,8 @@ class PyoTableObject(PyoObjectBase):
PyoObjectBase.__init__(self)
self._size = size
self.viewFrame = None
-
+ self.graphFrame = None
+
def save(self, path, format=0, sampletype=0):
"""
Writes the content of the table in an audio file.
@@ -1123,13 +1142,103 @@ class PyoTableObject(PyoObjectBase):
def reverse(self):
"""
- Reverse the table's data.
+ Reverse the table's data in time.
"""
[obj.reverse() for obj in self._base_objs]
self.refreshView()
return self
+ def invert(self):
+ """
+ Reverse the table's data in amplitude.
+
+ """
+ [obj.invert() for obj in self._base_objs]
+ self.refreshView()
+ return self
+
+ def rectify(self):
+ """
+ Positive rectification of the table's data.
+
+ """
+ [obj.rectify() for obj in self._base_objs]
+ self.refreshView()
+ return self
+
+ def pow(self, exp=10):
+ """
+ Apply a power function on each sample in the table.
+
+ :Args:
+
+ exp : float, optional
+ Exponent factor. Defaults to 10.
+
+ """
+ [obj.pow(exp) for obj in self._base_objs]
+ self.refreshView()
+ return self
+
+ def bipolarGain(self, gpos=1, gneg=1):
+ """
+ Apply different gain factor for positive and negative samples.
+
+ :Args:
+
+ gpos : float, optional
+ Gain factor for positive samples. Defaults to 1.
+ gneg : float, optional
+ Gain factor for negative samples. Defaults to 1.
+
+ """
+ [obj.bipolarGain(gpos, gneg) for obj in self._base_objs]
+ self.refreshView()
+ return self
+
+ def lowpass(self, freq=1000):
+ """
+ Apply a one-pole lowpass filter on table's samples.
+
+ :Args:
+
+ freq : float, optional
+ Filter's cutoff, in Hertz. Defaults to 1000.
+
+ """
+ [obj.lowpass(freq) for obj in self._base_objs]
+ self.refreshView()
+ return self
+
+ def fadein(self, dur=0.1):
+ """
+ Apply a gradual increase in the level of the table's samples.
+
+ :Args:
+
+ dur : float, optional
+ Fade in duration, in seconds. Defaults to 0.1.
+
+ """
+ [obj.fadein(dur) for obj in self._base_objs]
+ self.refreshView()
+ return self
+
+ def fadeout(self, dur=0.1):
+ """
+ Apply a gradual decrease in the level of the table's samples.
+
+ :Args:
+
+ dur : float, optional
+ Fade out duration, in seconds. Defaults to 0.1.
+
+ """
+ [obj.fadeout(dur) for obj in self._base_objs]
+ self.refreshView()
+ return self
+
def copy(self):
"""
Returns a deep copy of the object.
@@ -1167,11 +1276,14 @@ class PyoTableObject(PyoObjectBase):
the server GUI before showing the controller window.
"""
- samples = self._base_objs[0].getViewTable()
+ samples = self._base_objs[0].getViewTable((500,200))
createViewTableWindow(samples, title, wxnoserver, self.__class__.__name__, self)
def _setViewFrame(self, frame):
self.viewFrame = frame
+
+ def _setGraphFrame(self, frame):
+ self.graphFrame = frame
def refreshView(self):
"""
@@ -1179,9 +1291,12 @@ class PyoTableObject(PyoObjectBase):
"""
if self.viewFrame != None:
- samples = self._base_objs[0].getViewTable()
+ size = self.viewFrame.wavePanel.GetSize()
+ samples = self._base_objs[0].getViewTable((size[0], size[1]))
self.viewFrame.update(samples)
-
+ if self.graphFrame != None:
+ self.graphFrame.update(self.getTable())
+
@property
def size(self):
"""int. Table size in samples."""
@@ -1779,6 +1894,7 @@ class VarPort(PyoObject):
PyoObject.__init__(self, mul, add)
self._value = value
self._time = time
+ self._function = function
value, time, init, function, arg, mul ,add, lmax = convertArgsToLists(value, time, init, function, arg, mul, add)
self._base_objs = [VarPort_base(wrap(value,i), wrap(time,i), wrap(init,i), wrap(function,i), wrap(arg,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
@@ -1810,6 +1926,20 @@ class VarPort(PyoObject):
x, lmax = convertArgsToLists(x)
[obj.setTime(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ def setFunction(self, x):
+ """
+ Replace the `function` attribute.
+
+ :Args:
+
+ x : Python function
+ new `function` attribute.
+
+ """
+ self._function = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setFunction(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
@property
def value(self):
"""float. Numerical value to convert."""
@@ -1824,6 +1954,13 @@ class VarPort(PyoObject):
@time.setter
def time(self, x): self.setTime(x)
+ @property
+ def function(self):
+ """Python callable. Function to be called."""
+ return self._function
+ @function.setter
+ def function(self, x): self.setFunction(x)
+
class Pow(PyoObject):
"""
Performs a power function on audio signal.
@@ -2040,7 +2177,11 @@ class Compare(PyoObject):
def __init__(self, input, comp, mode="<", mul=1, add=0):
PyoObject.__init__(self, mul, add)
self._input = input
- self._comp = comp
+ if type(comp) in [StringType, UnicodeType, NoneType]:
+ print 'TypeError: "comp" argument of %s must be a float or a PyoObject. Set to 0.\n' % self.__class__.__name__
+ comp = self._comp = 0
+ else:
+ self._comp = comp
self._mode = mode
self._in_fader = InputFader(input)
self.comp_dict = {"<": 0, "<=": 1, ">": 2, ">=": 3, "==": 4, "!=": 5}
@@ -2071,10 +2212,13 @@ class Compare(PyoObject):
:Args:
- x : PyoObject
+ x : float or PyoObject
New comparison signal.
"""
+ if type(x) in [StringType, UnicodeType, NoneType]:
+ print >> sys.stderr, 'TypeError: "comp" argument of %s must be a float or a PyoObject.\n' % self.__class__.__name__
+ return
self._comp = x
x, lmax = convertArgsToLists(x)
[obj.setComp(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
diff --git a/pyolib/_maps.py b/pyolib/_maps.py
index 9845c77..7005918 100644
--- a/pyolib/_maps.py
+++ b/pyolib/_maps.py
@@ -158,17 +158,22 @@ class SLMap(Map):
ramp : float, optional
Ramp time, in seconds, used to smooth the signal sent from slider
to object's attribute. Defaults to 0.025.
+ dataOnly : boolean, optional
+ Set this argument to True if the parameter does not accept audio
+ signal as control but discreet values. If True, label will be
+ marked with a star symbol (*). Defaults to False.
>>> s = Server().boot()
+ >>> s.start()
>>> ifs = [350,360,375,388]
>>> maps = [SLMap(20., 2000., 'log', 'freq', ifs), SLMap(0, 0.25, 'lin', 'feedback', 0), SLMapMul(.1)]
>>> a = SineLoop(freq=ifs, mul=.1).out()
>>> a.ctrl(maps)
"""
- def __init__(self, min, max, scale, name, init, res='float', ramp=0.025):
+ def __init__(self, min, max, scale, name, init, res='float', ramp=0.025, dataOnly=False):
Map.__init__(self, min, max, scale)
- self._name, self._init, self._res, self._ramp = name, init, res, ramp
+ self._name, self._init, self._res, self._ramp, self._dataOnly = name, init, res, ramp, dataOnly
@property
def name(self):
@@ -186,6 +191,10 @@ class SLMap(Map):
def ramp(self):
"""float. Ramp time in seconds."""
return self._ramp
+ @property
+ def dataOnly(self):
+ """boolean. True if argument does not accept audio stream."""
+ return self._dataOnly
class SLMapFreq(SLMap):
"""
diff --git a/pyolib/_widgets.py b/pyolib/_widgets.py
index 518299c..40bded2 100644
--- a/pyolib/_widgets.py
+++ b/pyolib/_widgets.py
@@ -15,7 +15,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public Licensehack for OSX display
+You should have received a copy of the GNU General Public License
along with pyo. If not, see <http://www.gnu.org/licenses/>.
"""
from types import ListType, FloatType, IntType
@@ -28,28 +28,39 @@ except:
WITH_PIL = False
try:
- import wxversion
- if (wxversion.checkInstalled("2.8")):
- wxversion.ensureMinimal("2.8")
+ try:
+ import wxversion
+ if (wxversion.checkInstalled("2.8")):
+ wxversion.ensureMinimal("2.8")
+ except:
+ pass
import wx
from _wxwidgets import *
PYO_USE_WX = True
except:
PYO_USE_WX = False
+PYO_USE_TK = False
if not PYO_USE_WX:
try:
from Tkinter import *
from _tkwidgets import *
+ PYO_USE_TK = True
+ print """
+WxPython is not found for the current python version.
+Pyo will use a minimal GUI toolkit written with Tkinter.
+This toolkit has limited functionnalities and is no more
+maintained or updated. If you want to use all of pyo's
+GUI features, you should install WxPython, available here:
+http://www.wxpython.org/
+"""
except:
- if sys.platform == "linux2":
- response = raw_input("""python-tk package is missing! It is needed to use pyo graphical interfaces.
-Do you want to install it? (yes/no): """)
- if response == 'yes':
- os.system('sudo apt-get install python-tk')
- else:
- print "Tkinter is missing! It is needed to use pyo graphical interfaces. Please install it!"
- sys.exit()
+ PYO_USE_TK = False
+ print """
+Neither WxPython nor Tkinter are found for the current python version.
+Pyo's GUI features are disabled. For a complete GUI toolkit, you should
+consider installing WxPython, available here: http://www.wxpython.org/
+"""
X, Y, CURRENT_X, MAX_X, NEXT_Y = 800, 700, 30, 30, 30
WINDOWS = []
@@ -60,8 +71,11 @@ TABLEWINDOWS = []
SNDTABLEWINDOWS = []
MATRIXWINDOWS = []
SPECTRUMWINDOWS = []
+SCOPEWINDOWS = []
+WX_APP = False
def createRootWindow():
+ global WX_APP
if not PYO_USE_WX:
if len(WINDOWS) == 0:
root = Tk()
@@ -70,8 +84,9 @@ def createRootWindow():
else:
return None
else:
- if wx.GetApp() == None:
- win = wx.App(False)
+ if not WX_APP:
+ win = wx.App(False)
+ WX_APP = True
return win
else:
return None
@@ -134,6 +149,7 @@ def wxCreateDelayedGraphWindows():
def wxCreateDelayedDataGraphWindows():
for win in DATAGRAPHWINDOWS:
f = DataTableGrapher(None, win[0], win[1])
+ win[0]._setGraphFrame(f)
if win[2] == None: title = win[0].__class__.__name__
else: title = win[2]
wxDisplayWindow(f, title)
@@ -142,8 +158,7 @@ def wxCreateDelayedTableWindows():
global CURRENT_X, MAX_X, NEXT_Y
for win in TABLEWINDOWS:
object = win[3]
- if WITH_PIL: f = ViewTable_withPIL(None, win[0], win[1], object)
- else: f = ViewTable_withoutPIL(None, win[0], win[1], object)
+ f = ViewTable(None, win[0], win[1], object)
if object != None:
object._setViewFrame(f)
wxDisplayWindow(f, win[2])
@@ -151,8 +166,7 @@ def wxCreateDelayedTableWindows():
def wxCreateDelayedSndTableWindows():
global CURRENT_X, MAX_X, NEXT_Y
for win in SNDTABLEWINDOWS:
- if WITH_PIL: f = SndViewTable_withPIL(None, win[0], win[1], win[3])
- else: f = SndViewTable_withoutPIL(None, win[0], win[1], win[3])
+ f = SndViewTable(None, win[0], win[1], win[3])
win[0]._setViewFrame(f)
wxDisplayWindow(f, win[2])
@@ -174,6 +188,15 @@ def wxCreateDelayedSpectrumWindows():
if win[0] != None:
win[0]._setViewFrame(f)
wxDisplayWindow(f, title)
+
+def wxCreateDelayedScopeWindows():
+ for win in SCOPEWINDOWS:
+ f = ScopeDisplay(None, win[0])
+ if win[1] == None: title = win[0].__class__.__name__
+ else: title = win[1]
+ if win[0] != None:
+ win[0]._setViewFrame(f)
+ wxDisplayWindow(f, title)
def createCtrlWindow(obj, map_list, title, wxnoserver=False):
if not PYO_USE_WX:
@@ -184,7 +207,7 @@ def createCtrlWindow(obj, map_list, title, wxnoserver=False):
if title == None: title = obj.__class__.__name__
win.title(title)
else:
- if wxnoserver or wx.GetApp() != None:
+ if wxnoserver or WX_APP:
root = createRootWindow()
f = PyoObjectControl(None, obj, map_list)
if title == None: title = obj.__class__.__name__
@@ -196,7 +219,7 @@ def createGraphWindow(obj, mode, xlen, yrange, title, wxnoserver=False):
if not PYO_USE_WX:
print "WxPython must be installed to use the 'graph()' method."
else:
- if wxnoserver or wx.GetApp() != None:
+ if wxnoserver or WX_APP:
root = createRootWindow()
f = TableGrapher(None, obj, mode, xlen, yrange)
if title == None: title = obj.__class__.__name__
@@ -208,11 +231,12 @@ def createDataGraphWindow(obj, yrange, title, wxnoserver=False):
if not PYO_USE_WX:
print "WxPython must be installed to use the 'graph()' method."
else:
- if wxnoserver or wx.GetApp() != None:
+ if wxnoserver or WX_APP:
root = createRootWindow()
f = DataTableGrapher(None, obj, yrange)
if title == None: title = obj.__class__.__name__
wxShowWindow(f, title, root)
+ obj._setGraphFrame(f)
else:
DATAGRAPHWINDOWS.append([obj, yrange, title])
@@ -225,10 +249,9 @@ def createViewTableWindow(samples, title="Table waveform", wxnoserver=False, tab
win.resizable(False, False)
win.title(title)
else:
- if wxnoserver or wx.GetApp() != None:
+ if wxnoserver or WX_APP:
root = createRootWindow()
- if WITH_PIL: f = ViewTable_withPIL(None, samples, tableclass)
- else: f = ViewTable_withoutPIL(None, samples, tableclass)
+ f = ViewTable(None, samples, tableclass, object)
wxShowWindow(f, title, root)
if object != None:
object._setViewFrame(f)
@@ -244,10 +267,9 @@ def createSndViewTableWindow(obj, title="Table waveform", wxnoserver=False, tabl
win.resizable(False, False)
win.title(title)
else:
- if wxnoserver or wx.GetApp() != None:
+ if wxnoserver or WX_APP:
root = createRootWindow()
- if WITH_PIL: f = SndViewTable_withPIL(None, obj, tableclass, mouse_callback)
- else: f = SndViewTable_withoutPIL(None, obj, tableclass, mouse_callback)
+ f = SndViewTable(None, obj, tableclass, mouse_callback)
if title == None: title = obj.__class__.__name__
wxShowWindow(f, title, root)
obj._setViewFrame(f)
@@ -265,10 +287,10 @@ It helps a lot to speed up matrix drawing!"""
win.resizable(False, False)
win.title(title)
else:
- if wxnoserver or wx.GetApp() != None:
+ if wxnoserver or WX_APP:
root = createRootWindow()
- if WITH_PIL: f = ViewMatrix_withPIL(None, samples, size)
- else: f = ViewMatrix_withoutPIL(None, samples, size)
+ if WITH_PIL: f = ViewMatrix_withPIL(None, samples, size, object)
+ else: f = ViewMatrix_withoutPIL(None, samples, size, object)
wxShowWindow(f, title, root)
if object != None:
object._setViewFrame(f)
@@ -279,7 +301,7 @@ def createSpectrumWindow(object, title, wxnoserver=False):
if not PYO_USE_WX:
print "WxPython must be installed to use the Spectrum display."
else:
- if wxnoserver or wx.GetApp() != None:
+ if wxnoserver or WX_APP:
root = createRootWindow()
f = SpectrumDisplay(None, object)
if title == None: title = object.__class__.__name__
@@ -288,8 +310,22 @@ def createSpectrumWindow(object, title, wxnoserver=False):
object._setViewFrame(f)
else:
SPECTRUMWINDOWS.append([object, title])
+
+def createScopeWindow(object, title, wxnoserver=False):
+ if not PYO_USE_WX:
+ print "WxPython must be installed to use the Scope display."
+ else:
+ if wxnoserver or WX_APP:
+ root = createRootWindow()
+ f = ScopeDisplay(None, object)
+ if title == None: title = object.__class__.__name__
+ wxShowWindow(f, title, root)
+ if object != None:
+ object._setViewFrame(f)
+ else:
+ SCOPEWINDOWS.append([object, title])
-def createServerGUI(nchnls, start, stop, recstart, recstop, setAmp, started, locals, shutdown, meter, timer, amp):
+def createServerGUI(nchnls, start, stop, recstart, recstop, setAmp, started, locals, shutdown, meter, timer, amp, exit):
global X, Y, MAX_X, NEXT_Y
if not PYO_USE_WX:
createRootWindow()
@@ -299,7 +335,7 @@ def createServerGUI(nchnls, start, stop, recstart, recstop, setAmp, started, loc
f.focus_set()
else:
win = createRootWindow()
- f = ServerGUI(None, nchnls, start, stop, recstart, recstop, setAmp, started, locals, shutdown, meter, timer, amp)
+ f = ServerGUI(None, nchnls, start, stop, recstart, recstop, setAmp, started, locals, shutdown, meter, timer, amp, exit)
f.SetTitle("pyo server")
f.SetPosition((30, 30))
f.Show()
@@ -315,6 +351,7 @@ def createServerGUI(nchnls, start, stop, recstart, recstop, setAmp, started, loc
wx.CallAfter(wxCreateDelayedMatrixWindows)
wx.CallAfter(wxCreateDelayedCtrlWindows)
wx.CallAfter(wxCreateDelayedSpectrumWindows)
+ wx.CallAfter(wxCreateDelayedScopeWindows)
wx.CallAfter(f.Raise)
return f, win
-
\ No newline at end of file
+
diff --git a/pyolib/_wxwidgets.py b/pyolib/_wxwidgets.py
index 4e85080..9fed692 100644
--- a/pyolib/_wxwidgets.py
+++ b/pyolib/_wxwidgets.py
@@ -19,7 +19,6 @@ along with pyo. If not, see <http://www.gnu.org/licenses/>.
import wx, os, sys, math, time, random
from types import ListType, FloatType, IntType
-from wx.lib.embeddedimage import PyEmbeddedImage
try:
from PIL import Image, ImageDraw, ImageTk
@@ -28,93 +27,6 @@ except:
BACKGROUND_COLOUR = "#EBEBEB"
-vu_metre = PyEmbeddedImage(
- "iVBORw0KGgoAAAANSUhEUgAAAMgAAAAFCAIAAACPTDSjAAAAAXNSR0IArs4c6QAAACF0RVh0"
- "U29mdHdhcmUAR3JhcGhpY0NvbnZlcnRlciAoSW50ZWwpd4f6GQAAAMJJREFUeJxiYBgFo4BG"
- "wHWbO1bEKc6JS4pXiddxtTNWKTFLMYspVlilpFyk9WsNsUopR6toF+lglVJP0wDKYpUCmiYX"
- "II9VyqTTFOgSrFI28+0E9YSwSgE9hcfXLNwsZEgBDcQVVkBnAB2DKxi7qg13LHHERIEeMvWF"
- "ulilYoIUM2JUsUoVp2vGKyjsdbDHRH0G+u4SElilZpkYW4uIYJXaaGNtwMDwHxsaTVijCWs0"
- "YY0mrNGENZqwRhMWAAAA//8DAHGDnlocOW36AAAAAElFTkSuQmCC")
-
-vu_metre_dark = PyEmbeddedImage(
- "iVBORw0KGgoAAAANSUhEUgAAAMgAAAAFCAYAAAAALqP0AAAAAXNSR0IArs4c6QAAAAlwSFlz"
- "AAALEgAACxIB0t1+/AAADst0RVh0Q29tbWVudABwclZXIGNodW5rbGVuIDMwMiBpZ25vcmVk"
- "Og1BU0NJSTogeJzt0U1WwjAuwPHpLohUKS5tibG3yM4ude11ei4u4OtdvIE4ky76cOVz+/9l"
- "LuYjaS68f759yKu8nMys6zTPc8rm9Exq1C6nLicuS7UwcS5ljHGMMopEyyQu0S5FJGUuLi4u"
- "Li5Xdb2pd/cuu1pj899y+6ixrTV+lufcktvvLl7p1ut+8C7r9efnUut2Kb/PhOshu5vK9I5l"
- "LtrQtiG0wdmmq3IuT7ffLp1vOt9rLnvfaVjprfSNdo69jvy+P5fPjZbDfunZuSYNSEVYOiA3"
- "ODlDRUREMTRENTZDMjMwMTBDMEYxRTkwNzg4NTQyOTBENkQ4OUIxQjdDOENFMDM3NUVENzU3"
- "QTE5MEZFMEVCNURCQzgxMzg5MzAyRkE3MEU1NzNGQkZGNjUxQUU2MjM2OTE3QkM3RkJFN0RD"
- "OEFCQkM5Q0NDQUNFQjM0Q0Y3M0NBRTZGNDRDNkFENDE4QTcxODI3MTE0QkI1MzA3MTFDNjU4"
- "QzcxOEMzMjhBNDRDQjI0MUFEMTE1NDUyNDY1MDAwMDAwMDAwMA1ta0JGIGNodW5rbGVuIDcy"
- "IGlnbm9yZWQ6DUFTQ0lJOiD63sr+Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u"
- "Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4NSEVYOiBGQURFQ0FGRTAwMDAw"
- "MDA0MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDANbWtUUyBjaHVua2xlbiA4ODg2IGlnbm9yZWQ6DUFT"
- "Q0lJOiB4nO1dWXPbSJLG9ozbLd/unph92C5FbGzsU2twLnwuRVHSWC6HpHy9OHjB1rSPLllW"
- "t5fB/76ZWVUgUCiAOChSni6rW0WiUC6+zPwqqyouOnnWup51ensuM2ve+8cpJKHfLobj+cvj"
- "vXBmzl+x5MVRO5zZtjk/PC6EM2/e2++Hs4Y97/XPLyC7dS4uhPRv3j0+vp61uvBrb3fweWZs"
- "LiNjbLwxusbU+C6fLoz386PTLsi5LjkuIccyfobcLuN3uOP9vNc+LmGVuw1IRVg6IDc4OUNF"
- "RDVENTk3M0RCNDg5MkM2RjY4Q0RCMkRERkVFOUU5ODdERDgxNzQ1NkM2Q0VDNTM2QjcwMTM3"
- "QzE0NDU1MUQyNTgwNzg3QTQ3Q0JEMzg3OEMxRDZCNDhGMUU1OTU2Qjc5N0MxRkZCRTk5NTk1"
- "NTIwNTAyODgwMzgyODUyOUUyRUFCNUI0NUEyNTAwN0JFQ0NGQzJBQUIyQTBCM0E3OUQ2QkE5"
- "RTc1N0E3QjE3MzM2QkRFRkJDNzI5MjRBMURGMDg4NkUzDW1rQlMgY2h1bmtsZW4gMTkwIGln"
- "bm9yZWQ6DUFTQ0lJOiB4nF1Oyy6CMC7szd/wLi6DwFHKq2GrLmoub2hswlWTJmaz/27Lw4Nz"
- "mcnMzmZknS4sLj6iTy5wjS71M11FpjEu91QupdGPLmryVqPj9jLag7S0Lb2AoC6DcOgupnV5"
- "t/GlLkdwlG9kLi5sYC72ZC+2ZT7Jdi452C7PXZPXzshBLi6y/C7dqZg2zfS38NzZ2Z5HlS7D"
- "g1R7LjH2SC77UYlsxEgnOopp0YOOnqvexY9w1WEuJ0SZOi6kLl+6Ll+mDUhFWDogNzg5QzVE"
- "NEVDQjBFODIzMDEwRUNDRERGRjAxMzAwODNDMDUxQ0FBQjYxQUIwNjZBMDQ2RjY4NkNDMjU1"
- "OTMyNjY2QjNGRjZFQ0JDMzgzNzM5OUM5Q0NDRTY2NjQ5RDFBMkMxQTNFQTI0RjFENzA4RDFF"
- "RjUzMzVENDVBNjMxMDhGNzU0MDlBNUQxOEYwMjZBRjI1NkEzRTNGNjMyREE4M0I0QjQyREJE"
- "ODBBMDA3ODM3MEU4MERBNjc1NzlCN0YxQTUwMTQ3NzANbWtCVCBjaHVua2xlbiAxMTQ1IGln"
- "bm9yZWQ6DUFTQ0lJOiD6zsr+Ln84xS4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u"
- "Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4ueJztmolt6zAuLl1ILkkhKSSN"
- "pJAukkZSiD82+GM8bEjZsWT4mi4udJDisctDIrXfK6WUUkoppZRSSv3X9/f3/uvra0qF34Oy"
- "LpdM+y7pX1NVn91uN+Xz83P/+vr6c37LdacuVdYtVb5/eXk52GPr9K+t9P/7+/svSnWseg1I"
- "RVg6IEZBQ0VDQUZFMDA3RjM4QzUwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwNzg5Q0VE"
- "OUE4OTZERUIzMDEwMDU1RDQ4MUE0OTIxMjkyNDhEQTQ5MDE0OTI0NjUyDW1rQlQgY2h1bmts"
- "ZW4gMzM5IGlnbm9yZWQ6DUFTQ0lJOiD6zsr+Ln9ViS4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u"
- "Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4ueJzt1uFpg2Au"
- "hlEucS4ucS4ucS4ucS4usbyBLremIf+KLueBQ5tP++tNbM5TkiRJkiRJkiRJkiRJkiRJkiRJ"
- "LtFxLue+70/nOcu1d/e/uk/3b13Xcy7Hc5qmx8/sLv0s99S9dS7LsjxexzAuf76HdO+yY5V9"
- "s2F2rc37PQ1IRVg6IEZBQ0VDQUZFMDA3RjU1ODkwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwNzg5Q0VERDZFMTY5ODM2MDE0ODY1MTA3NzExMTA3NzExMDE3NzExMDA3NzExMTA3DW1r"
- "QlQgY2h1bmtsZW4gMzc5OSBpZ25vcmVkOg1BU0NJSTog+s7K/i5/n3guLi4uLi4uLi4uLi4u"
- "Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u"
- "Lnic7Z2NkS4pLoUuiC5xIC7EiTguLuJELshe6eo+17tnSUDPz/5Yr2pqZ7tpLi4u0IOel5fB"
- "YDAuLi6DwWAwLi4ug8HgP/z69evl58+ff3ziOveq5+JzpawuZfj3wf9R6fmK/jN8//795dOn"
- "T3984jr3Mnz58uXfzy6+ffsNSEVYOiBGQUNFQ0FGRTAwN0Y5Rjc4MDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDc4OUNFRDlEOEQ5MTFDMjkwQzg1MUQ4ODEzNzEyMDBFQzQ4OTM4MTAw"
- "N0UyNDQxQw1ta0JUIGNodW5rbGVuIDI3NDEgaWdub3JlZDoNQVNDSUk6IPrOyv4uf69+Li4u"
- "Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u"
- "Li4uLi4uLi4uLi54nO2djZHbOC5GU0guSSEpJI2kkC6SRlJIbpCbd/PuLkjJWa8u23gzntXq"
- "h6QuLqIukPr5cy6GYS6GYS6GYS6GYXhJvn///tvvx48u/y67J1WOe5fh2fnw4cNvv69fv/6q"
- "99q+Z/1XOaouw/uBvM/i9vCW/rm7to7Vbyd/DUhFWDogRkFDRUNBRkUwMDdGQUY3RTAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA3ODlDRUQ5RDhEOTFEQjM4MEM0NjUzNDgxQTQ5MjEy"
- "OTI0OERBNDkwMTQ5MjQ2NTINbWtCVCBjaHVua2xlbiAxMDc3NSBpZ25vcmVkOg1BU0NJSTog"
- "+s7K/i5/1PAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u"
- "Li4uLi4uLi4uLi4uLi4uLi4uLi4uLnic7X0ruOwo1vaSSCwuicQikUgkLi6JxCIjkVgkLi6J"
- "jYyMjI0smX9R+5zunp7p+dT/1Ihac+k+VXvXLrAu77suVObnfTaeLtqzkS3G10Zgh6PDLnBd"
- "xS5rLt+FfsPzYi7ggS4uLrYuLtCeJMF33ZPZsYTB8c18c/zxQ28NSEVYOiBGQUNFQ0FGRTAw"
- "N0ZENEYwMDAwMDAwMDEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
- "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDc4OUNFRDdEMkJCOEVDMjhENkY2"
- "OTI0ODJDMTI4OUM0MjI5MTQ4MjQxNjE5ODlDNIWzHPoAAAAhdEVYdFNvZnR3YXJlAEdyYXBo"
- "aWNDb252ZXJ0ZXIgKEludGVsKXeH+hkAAADWSURBVHic7JO7CsJAEEVH95UHpFBEhBUTJIpB"
- "I0GFFDYRBNHSxr/Zn/B/R9c+Ewvt5sLtDswwwwHgcDh06muAVE3Y62TipA+HM80MxgLKoyGZ"
- "kRWw3GmSsbmEealIJi2Ue3Mk4+dMUukopqj1Z2+KqRqDybBPMv4239xRqt8wflbXP/zOfveu"
- "n9VVgLcmam1mJew3hmQWmXJFrklmu9K41to94hjbegoCzKQEirmEIVohSOYeRWiVhud0hm1l"
- "QVgQFoQFYUFYEBaEBWFB/iLICwAA//8DAHqeTXUOgGpTAAAAAElFTkSuQmCC")
-
def interpFloat(t, v1, v2):
"interpolator for a single value; interprets t in [0-1] between v1 and v2"
return (v2-v1)*t + v1
@@ -160,8 +72,12 @@ def GetRoundShape( w, h, r ):
return wx.RegionFromBitmap( GetRoundBitmap(w,h,r) )
class ControlSlider(wx.Panel):
- def __init__(self, parent, minvalue, maxvalue, init=None, pos=(0,0), size=(200,16), log=False, outFunction=None, integer=False, powoftwo=False, backColour=None):
- wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY, pos=pos, size=size, style=wx.NO_BORDER | wx.WANTS_CHARS | wx.EXPAND)
+ def __init__(self, parent, minvalue, maxvalue, init=None, pos=(0,0), size=(200,16), log=False,
+ outFunction=None, integer=False, powoftwo=False, backColour=None, orient=wx.HORIZONTAL):
+ if size == (200,16) and orient == wx.VERTICAL:
+ size = (40, 200)
+ wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY, pos=pos, size=size,
+ style=wx.NO_BORDER | wx.WANTS_CHARS | wx.EXPAND)
self.parent = parent
if backColour:
self.backgroundColour = backColour
@@ -169,10 +85,16 @@ class ControlSlider(wx.Panel):
self.backgroundColour = BACKGROUND_COLOUR
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
self.SetBackgroundColour(self.backgroundColour)
- self.SetMinSize(self.GetSize())
- self.knobSize = 40
- self.knobHalfSize = 20
- self.sliderHeight = size[1] - 5
+ self.orient = orient
+ # self.SetMinSize(self.GetSize())
+ if self.orient == wx.VERTICAL:
+ self.knobSize = 17
+ self.knobHalfSize = 8
+ self.sliderWidth = size[0] - 29
+ else:
+ self.knobSize = 40
+ self.knobHalfSize = 20
+ self.sliderHeight = size[1] - 5
self.outFunction = outFunction
self.integer = integer
self.log = log
@@ -202,8 +124,11 @@ class ControlSlider(wx.Panel):
self.Bind(wx.EVT_SIZE, self.OnResize)
self.Bind(wx.EVT_KEY_DOWN, self.keyDown)
self.Bind(wx.EVT_KILL_FOCUS, self.LooseFocus)
- self.createSliderBitmap()
- self.createKnobBitmap()
+
+ if sys.platform == "win32":
+ self.dcref = wx.BufferedPaintDC
+ else:
+ self.dcref = wx.PaintDC
def setMidiCtl(self, x, propagate=True):
self.propagate = propagate
@@ -229,41 +154,10 @@ class ControlSlider(wx.Panel):
def setSliderHeight(self, height):
self.sliderHeight = height
- self.createSliderBitmap()
- self.createKnobBitmap()
self.Refresh()
- def createSliderBitmap(self):
- w, h = self.GetSize()
- b = wx.EmptyBitmap(w,h)
- dc = wx.MemoryDC(b)
- dc.SetPen(wx.Pen(self.backgroundColour, width=1))
- dc.SetBrush(wx.Brush(self.backgroundColour))
- dc.DrawRectangle(0,0,w,h)
- dc.SetBrush(wx.Brush("#999999"))
- dc.SetPen(wx.Pen(self.backgroundColour, width=1))
- h2 = self.sliderHeight / 4
- dc.DrawRoundedRectangle(0,h2,w,self.sliderHeight,2)
- dc.SelectObject(wx.NullBitmap)
- b.SetMaskColour("#999999")
- self.sliderMask = b
-
- def createKnobBitmap(self):
- w, h = self.knobSize, self.GetSize()[1]
- b = wx.EmptyBitmap(w,h)
- dc = wx.MemoryDC(b)
- rec = wx.Rect(0, 0, w, h)
- dc.SetPen(wx.Pen(self.backgroundColour, width=1))
- dc.SetBrush(wx.Brush(self.backgroundColour))
- dc.DrawRectangleRect(rec)
- h2 = self.sliderHeight / 4
- rec = wx.Rect(0, h2, w, self.sliderHeight)
- dc.GradientFillLinear(rec, "#414753", "#99A7CC", wx.BOTTOM)
- dc.SetBrush(wx.Brush("#999999"))
- dc.DrawRoundedRectangle(0,0,w,h,2)
- dc.SelectObject(wx.NullBitmap)
- b.SetMaskColour("#999999")
- self.knobMask = b
+ def setSliderWidth(self, width):
+ self.sliderWidth = width
def getInit(self):
return self.init
@@ -276,7 +170,11 @@ class ControlSlider(wx.Panel):
return [self.minvalue, self.maxvalue]
def scale(self):
- inter = tFromValue(self.pos, self.knobHalfSize, self.GetSize()[0]-self.knobHalfSize)
+ if self.orient == wx.VERTICAL:
+ h = self.GetSize()[1]
+ inter = tFromValue(h-self.pos, self.knobHalfSize, self.GetSize()[1]-self.knobHalfSize)
+ else:
+ inter = tFromValue(self.pos, self.knobHalfSize, self.GetSize()[0]-self.knobHalfSize)
if not self.integer:
return interpFloat(inter, self.minvalue, self.maxvalue)
elif self.powoftwo:
@@ -348,7 +246,10 @@ class ControlSlider(wx.Panel):
return
if self._enable:
size = self.GetSize()
- self.pos = clamp(evt.GetPosition()[0], self.knobHalfSize, size[0]-self.knobHalfSize)
+ if self.orient == wx.VERTICAL:
+ self.pos = clamp(evt.GetPosition()[1], self.knobHalfSize, size[1]-self.knobHalfSize)
+ else:
+ self.pos = clamp(evt.GetPosition()[0], self.knobHalfSize, size[0]-self.knobHalfSize)
self.value = self.scale()
self.CaptureMouse()
self.selected = False
@@ -363,8 +264,12 @@ class ControlSlider(wx.Panel):
if self._enable:
w, h = self.GetSize()
pos = event.GetPosition()
- if wx.Rect(self.pos-self.knobHalfSize, 0, self.knobSize, h).Contains(pos):
- self.selected = True
+ if self.orient == wx.VERTICAL:
+ if wx.Rect(0, self.pos-self.knobHalfSize, w, self.knobSize).Contains(pos):
+ self.selected = True
+ else:
+ if wx.Rect(self.pos-self.knobHalfSize, 0, self.knobSize, h).Contains(pos):
+ self.selected = True
self.Refresh()
event.Skip()
@@ -372,13 +277,15 @@ class ControlSlider(wx.Panel):
if self._enable:
size = self.GetSize()
if self.HasCapture():
- self.pos = clamp(evt.GetPosition()[0], self.knobHalfSize, size[0]-self.knobHalfSize)
+ if self.orient == wx.VERTICAL:
+ self.pos = clamp(evt.GetPosition()[1], self.knobHalfSize, size[1]-self.knobHalfSize)
+ else:
+ self.pos = clamp(evt.GetPosition()[0], self.knobHalfSize, size[0]-self.knobHalfSize)
self.value = self.scale()
self.selected = False
self.Refresh()
def OnResize(self, evt):
- self.createSliderBitmap()
self.clampPos()
self.Refresh()
@@ -387,20 +294,23 @@ class ControlSlider(wx.Panel):
if self.powoftwo:
val = powOfTwoToInt(self.value)
else:
- val = self.value
- self.pos = tFromValue(val, self.minvalue, self.maxvalue) * (size[0] - self.knobSize) + self.knobHalfSize
- self.pos = clamp(self.pos, self.knobHalfSize, size[0]-self.knobHalfSize)
+ val = self.value
+ if self.orient == wx.VERTICAL:
+ self.pos = tFromValue(val, self.minvalue, self.maxvalue) * (size[1] - self.knobSize) + self.knobHalfSize
+ self.pos = clamp(size[1]-self.pos, self.knobHalfSize, size[1]-self.knobHalfSize)
+ else:
+ self.pos = tFromValue(val, self.minvalue, self.maxvalue) * (size[0] - self.knobSize) + self.knobHalfSize
+ self.pos = clamp(self.pos, self.knobHalfSize, size[0]-self.knobHalfSize)
def setBackgroundColour(self, colour):
self.backgroundColour = colour
self.SetBackgroundColour(self.backgroundColour)
- self.createSliderBitmap()
- self.createKnobBitmap()
self.Refresh()
def OnPaint(self, evt):
w,h = self.GetSize()
- dc = wx.AutoBufferedPaintDC(self)
+ dc = self.dcref(self)
+ gc = wx.GraphicsContext_Create(dc)
dc.SetBrush(wx.Brush(self.backgroundColour, wx.SOLID))
dc.Clear()
@@ -412,10 +322,16 @@ class ControlSlider(wx.Panel):
# Draw inner part
if self._enable: sliderColour = "#99A7CC"
else: sliderColour = "#BBBBBB"
- h2 = self.sliderHeight / 4
- rec = wx.Rect(0, h2, w, self.sliderHeight)
- dc.GradientFillLinear(rec, "#646986", sliderColour, wx.BOTTOM)
- dc.DrawBitmap(self.sliderMask, 0, 0, True)
+ if self.orient == wx.VERTICAL:
+ w2 = (w - self.sliderWidth) / 2
+ rec = wx.Rect(w2, 0, self.sliderWidth, h)
+ brush = gc.CreateLinearGradientBrush(w2, 0, w2+self.sliderWidth, 0, "#646986", sliderColour)
+ else:
+ h2 = self.sliderHeight / 4
+ rec = wx.Rect(0, h2, w, self.sliderHeight)
+ brush = gc.CreateLinearGradientBrush(0, h2, 0, h2+self.sliderHeight, "#646986", sliderColour)
+ gc.SetBrush(brush)
+ gc.DrawRoundedRectangle(rec[0], rec[1], rec[2], rec[3], 2)
if self.midictl != None:
if sys.platform in ['win32', 'linux2']:
@@ -423,21 +339,32 @@ class ControlSlider(wx.Panel):
else:
dc.SetFont(wx.Font(9, wx.ROMAN, wx.NORMAL, wx.NORMAL))
dc.SetTextForeground('#FFFFFF')
- dc.DrawLabel(str(self.midictl), wx.Rect(2,0,h,h), wx.ALIGN_CENTER)
- dc.DrawLabel(str(self.midictl), wx.Rect(w-h,0,h,h), wx.ALIGN_CENTER)
+ if self.orient == wx.VERTICAL:
+ dc.DrawLabel(str(self.midictl), wx.Rect(w2,2,self.sliderWidth,12), wx.ALIGN_CENTER)
+ dc.DrawLabel(str(self.midictl), wx.Rect(w2,h-12,self.sliderWidth,12), wx.ALIGN_CENTER)
+ else:
+ dc.DrawLabel(str(self.midictl), wx.Rect(2,0,h,h), wx.ALIGN_CENTER)
+ dc.DrawLabel(str(self.midictl), wx.Rect(w-h,0,h,h), wx.ALIGN_CENTER)
# Draw knob
if self._enable: knobColour = '#888888'
else: knobColour = "#DDDDDD"
- rec = wx.Rect(self.pos-self.knobHalfSize, 0, self.knobSize, h)
- dc.GradientFillLinear(rec, "#424864", knobColour, wx.RIGHT)
- dc.DrawBitmap(self.knobMask, rec[0], rec[1], True)
-
- if self.selected:
- rec2 = wx.Rect(self.pos-self.knobHalfSize, 0, self.knobSize, h)
- dc.SetBrush(wx.Brush('#333333', wx.SOLID))
- dc.SetPen(wx.Pen('#333333', width=self.borderWidth, style=wx.SOLID))
- dc.DrawRoundedRectangleRect(rec2, 3)
+ if self.orient == wx.VERTICAL:
+ rec = wx.Rect(0, self.pos-self.knobHalfSize, w, self.knobSize-1)
+ if self.selected:
+ brush = wx.Brush('#333333', wx.SOLID)
+ else:
+ brush = gc.CreateLinearGradientBrush(0, 0, w, 0, "#323854", knobColour)
+ gc.SetBrush(brush)
+ gc.DrawRoundedRectangle(rec[0], rec[1], rec[2], rec[3], 3)
+ else:
+ rec = wx.Rect(self.pos-self.knobHalfSize, 0, self.knobSize-1, h)
+ if self.selected:
+ brush = wx.Brush('#333333', wx.SOLID)
+ else:
+ brush = gc.CreateLinearGradientBrush(self.pos-self.knobHalfSize, 0, self.pos+self.knobHalfSize, 0, "#323854", knobColour)
+ gc.SetBrush(brush)
+ gc.DrawRoundedRectangle(rec[0], rec[1], rec[2], rec[3], 3)
if sys.platform in ['win32', 'linux2']:
dc.SetFont(wx.Font(7, wx.ROMAN, wx.NORMAL, wx.NORMAL))
@@ -524,7 +451,10 @@ class MultiSlider(wx.Panel):
slide = pos[1] / self._height
if 0 <= slide < self._nchnls:
self._values[slide] = pos[0] / float(w)
- self._labels = [self._slmap.get(x) for x in self._values]
+ if self._slmap._res == 'int':
+ self._labels = [int(self._slmap.get(x)) for x in self._values]
+ else:
+ self._labels = [self._slmap.get(x) for x in self._values]
self._command(self._key, self._labels)
self.CaptureMouse()
self.Refresh()
@@ -541,45 +471,103 @@ class MultiSlider(wx.Panel):
slide = pos[1] / self._height
if 0 <= slide < self._nchnls:
self._values[slide] = pos[0] / float(w)
- self._labels = [self._slmap.get(x) for x in self._values]
+ if self._slmap._res == 'int':
+ self._labels = [int(self._slmap.get(x)) for x in self._values]
+ else:
+ self._labels = [self._slmap.get(x) for x in self._values]
self._command(self._key, self._labels)
self.Refresh()
class VuMeter(wx.Panel):
- def __init__(self, parent, size=(200,11), numSliders=2):
+ def __init__(self, parent, size=(200,11), numSliders=2, orient=wx.HORIZONTAL):
+ if orient == wx.HORIZONTAL:
+ size = (size[0], numSliders * 5 + 1)
+ else:
+ size = (numSliders * 5 + 1, size[1])
wx.Panel.__init__(self, parent, -1, size=size)
self.parent = parent
+ self.orient = orient
self.SetBackgroundColour("#000000")
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
self.old_nchnls = numSliders
self.numSliders = numSliders
- self.SetMinSize((200,5*self.numSliders+1))
- self.SetSize((200, 5*self.numSliders+1))
- self.bitmap = vu_metre.GetBitmap()
- self.backBitmap = vu_metre_dark.GetBitmap()
self.amplitude = [0] * self.numSliders
+ self.createBitmaps()
self.Bind(wx.EVT_PAINT, self.OnPaint)
+ self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_CLOSE, self.OnClose)
+ def OnSize(self, evt):
+ self.createBitmaps()
+ wx.CallAfter(self.Refresh)
+
+ def createBitmaps(self):
+ w, h = self.GetSize()
+ b = wx.EmptyBitmap(w,h)
+ f = wx.EmptyBitmap(w,h)
+ dcb = wx.MemoryDC(b)
+ dcf = wx.MemoryDC(f)
+ dcb.SetPen(wx.Pen("#000000", width=1))
+ dcf.SetPen(wx.Pen("#000000", width=1))
+ if self.orient == wx.HORIZONTAL:
+ height = 6
+ steps = int(w / 10.0 + 0.5)
+ else:
+ width = 6
+ steps = int(h / 10.0 + 0.5)
+ bounds = int(steps / 6.0)
+ for i in range(steps):
+ if i == (steps - 1):
+ dcb.SetBrush(wx.Brush("#770000"))
+ dcf.SetBrush(wx.Brush("#FF0000"))
+ elif i >= (steps - bounds):
+ dcb.SetBrush(wx.Brush("#440000"))
+ dcf.SetBrush(wx.Brush("#CC0000"))
+ elif i >= (steps - (bounds*2)):
+ dcb.SetBrush(wx.Brush("#444400"))
+ dcf.SetBrush(wx.Brush("#CCCC00"))
+ else:
+ dcb.SetBrush(wx.Brush("#004400"))
+ dcf.SetBrush(wx.Brush("#00CC00"))
+ if self.orient == wx.HORIZONTAL:
+ dcb.DrawRectangle(i*10, 0, 11, height)
+ dcf.DrawRectangle(i*10, 0, 11, height)
+ else:
+ ii = steps - 1 - i
+ dcb.DrawRectangle(0, ii*10, width, 11)
+ dcf.DrawRectangle(0, ii*10, width, 11)
+ if self.orient == wx.HORIZONTAL:
+ dcb.DrawLine(w-1, 0, w-1, height)
+ dcf.DrawLine(w-1, 0, w-1, height)
+ else:
+ dcb.DrawLine(0, 0, width, 0)
+ dcf.DrawLine(0, 0, width, 0)
+ dcb.SelectObject(wx.NullBitmap)
+ dcf.SelectObject(wx.NullBitmap)
+ self.backBitmap = b
+ self.bitmap = f
+
def setNumSliders(self, numSliders):
+ w, h = self.GetSize()
oldChnls = self.old_nchnls
self.numSliders = numSliders
self.amplitude = [0] * self.numSliders
gap = (self.numSliders - oldChnls) * 5
parentSize = self.parent.GetSize()
- if sys.platform == 'linux2':
- self.SetSize((200, 5*self.numSliders+1))
- self.SetMinSize((200, 5*self.numSliders+1))
+ if self.orient == wx.HORIZONTAL:
+ self.SetSize((w, self.numSliders * 5 + 1))
+ self.SetMinSize((w, 5*self.numSliders+1))
self.parent.SetSize((parentSize[0], parentSize[1]+gap))
self.parent.SetMinSize((parentSize[0], parentSize[1]+gap))
else:
- self.SetSize((200, 5*self.numSliders+1))
- self.SetMinSize((200, 5*self.numSliders+1))
- self.parent.SetSize((parentSize[0], parentSize[1]+gap))
- self.parent.SetMinSize((parentSize[0], parentSize[1]+gap))
- self.Refresh()
- self.parent.Layout()
+ self.SetSize((self.numSliders * 5 + 1, h))
+ self.SetMinSize((5*self.numSliders+1, h))
+ self.parent.SetSize((parentSize[0]+gap, parentSize[1]))
+ self.parent.SetMinSize((parentSize[0]+gap, parentSize[1]))
+ wx.CallAfter(self.Refresh)
+ wx.CallAfter(self.parent.Layout)
+ wx.CallAfter(self.parent.Refresh)
def setRms(self, *args):
if args[0] < 0:
@@ -596,13 +584,28 @@ class VuMeter(wx.Panel):
dc.SetBrush(wx.Brush("#000000"))
dc.Clear()
dc.DrawRectangle(0,0,w,h)
- for i in range(self.numSliders):
- db = math.log10(self.amplitude[i]+0.00001) * 0.2 + 1.
- width = int(db*w)
- dc.DrawBitmap(self.backBitmap, 0, i*5)
- dc.SetClippingRegion(0, i*5, width, 5)
- dc.DrawBitmap(self.bitmap, 0, i*5)
- dc.DestroyClippingRegion()
+ if self.orient == wx.HORIZONTAL:
+ height = 6
+ for i in range(self.numSliders):
+ y = i * (height - 1)
+ db = math.log10(self.amplitude[i]+0.00001) * 0.2 + 1.
+ width = int(db*w)
+ dc.DrawBitmap(self.backBitmap, 0, y)
+ if width > 0:
+ dc.SetClippingRegion(0, y, width, height)
+ dc.DrawBitmap(self.bitmap, 0, y)
+ dc.DestroyClippingRegion()
+ else:
+ width = 6
+ for i in range(self.numSliders):
+ y = i * (width - 1)
+ db = math.log10(self.amplitude[i]+0.00001) * 0.2 + 1.
+ height = int(db*h)
+ dc.DrawBitmap(self.backBitmap, y, 0)
+ if height > 0:
+ dc.SetClippingRegion(y, h-height, width, height)
+ dc.DrawBitmap(self.bitmap, y, 0)
+ dc.DestroyClippingRegion()
event.Skip()
def OnClose(self, evt):
@@ -887,14 +890,17 @@ class PyoObjectControl(wx.Frame):
self.box = wx.FlexGridSizer(10,2,5,5)
for i, m in enumerate(self._map_list):
- key, init, mini, maxi, scl, res = m.name, m.init, m.min, m.max, m.scale, m.res
+ key, init, mini, maxi, scl, res, dataOnly = m.name, m.init, m.min, m.max, m.scale, m.res, m.dataOnly
# filters PyoObjects
if type(init) not in [ListType, FloatType, IntType]:
self._excluded.append(key)
else:
self._maps[key] = m
# label (param name)
- label = wx.StaticText(panel, -1, key)
+ if dataOnly:
+ label = wx.StaticText(panel, -1, key+" *")
+ else:
+ label = wx.StaticText(panel, -1, key)
# create and pack slider
if type(init) != ListType:
if scl == 'log': scl = True
@@ -907,15 +913,16 @@ class PyoObjectControl(wx.Frame):
else:
self._sliders.append(MultiSlider(panel, init, key, self.setval, m))
self.box.AddMany([(label, 0, wx.LEFT, 5), (self._sliders[-1], 1, wx.EXPAND | wx.LEFT, 5)])
- # set obj attribute to PyoObject SigTo
- self._values[key] = init
- self._sigs[key] = SigTo(init, .025, init)
- refStream = self._obj.getBaseObjects()[0]._getStream()
- server = self._obj.getBaseObjects()[0].getServer()
- for k in range(len(self._sigs[key].getBaseObjects())):
- curStream = self._sigs[key].getBaseObjects()[k]._getStream()
- server.changeStreamPosition(refStream, curStream)
- setattr(self._obj, key, self._sigs[key])
+ # set obj attribute to PyoObject SigTo
+ if not dataOnly:
+ self._values[key] = init
+ self._sigs[key] = SigTo(init, .025, init)
+ refStream = self._obj.getBaseObjects()[0]._getStream()
+ server = self._obj.getBaseObjects()[0].getServer()
+ for k in range(len(self._sigs[key].getBaseObjects())):
+ curStream = self._sigs[key].getBaseObjects()[k]._getStream()
+ server.changeStreamPosition(refStream, curStream)
+ setattr(self._obj, key, self._sigs[key])
self.box.AddGrowableCol(1, 1)
mainBox.Add(self.box, 1, wx.EXPAND | wx.TOP | wx.BOTTOM | wx.RIGHT, 10)
@@ -927,22 +934,25 @@ class PyoObjectControl(wx.Frame):
def _destroy(self, event):
for m in self._map_list:
key = m.name
- if key not in self._excluded:
+ if key not in self._excluded and key in self._values:
setattr(self._obj, key, self._values[key])
del self._sigs[key]
self.Destroy()
def setval(self, key, x):
- self._values[key] = x
- setattr(self._sigs[key], "value", x)
+ if key in self._values:
+ self._values[key] = x
+ setattr(self._sigs[key], "value", x)
+ else:
+ setattr(self._obj, key, x)
######################################################################
### View window for PyoTableObject
######################################################################
class ViewTable(wx.Frame):
def __init__(self, parent, samples=None, tableclass=None, object=None):
- wx.Frame.__init__(self, parent)
- self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+ wx.Frame.__init__(self, parent, size=(500,200))
+ self.SetMinSize((300, 150))
menubar = wx.MenuBar()
fileMenu = wx.Menu()
closeItem = fileMenu.Append(-1, 'Close\tCtrl+W', kind=wx.ITEM_NORMAL)
@@ -951,77 +961,61 @@ class ViewTable(wx.Frame):
self.SetMenuBar(menubar)
self.tableclass = tableclass
self.object = object
- self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_CLOSE, self._destroy)
- self.width, self.height = 500, 200
- self.half_height = self.height / 2
- self.SetClientSize((self.width+10, self.height+10))
- self.SetMinSize(self.GetSize())
- self.SetMaxSize(self.GetSize())
- self.draw(samples)
+ self.panel = wx.Panel(self)
+ self.panel.SetBackgroundColour(BACKGROUND_COLOUR)
+ self.box = wx.BoxSizer(wx.VERTICAL)
+ self.wavePanel = ViewTablePanel(self.panel, object)
+ self.box.Add(self.wavePanel, 1, wx.EXPAND|wx.ALL, 5)
+ self.panel.SetSizerAndFit(self.box)
+ self.update(samples)
def update(self, samples):
- wx.CallAfter(self.draw, samples)
+ wx.CallAfter(self.wavePanel.draw, samples)
def _destroy(self, evt):
self.object._setViewFrame(None)
self.Destroy()
-
-class ViewTable_withPIL(ViewTable):
- _WITH_PIL = True
- def __init__(self, parent, samples=None, tableclass=None, object=None):
- ViewTable.__init__(self, parent, samples, tableclass, object)
- def draw(self, samples):
- im = Image.new("L", (self.width, self.height), 255)
- draw = ImageDraw.Draw(im)
- draw.line(samples, fill=0, width=1)
- image = wx.EmptyImage(self.width, self.height)
- image.SetData(im.convert("RGB").tostring())
- self.img = wx.BitmapFromImage(image)
- self.Refresh()
-
- def OnPaint(self, evt):
- dc = wx.PaintDC(self)
- dc.DrawBitmap(self.img, 0, 0)
- dc.SetPen(wx.Pen('#BBBBBB', width=1, style=wx.SOLID))
- dc.DrawLine(0, self.half_height+1, self.width, self.half_height+1)
+class ViewTablePanel(wx.Panel):
+ def __init__(self, parent, obj):
+ wx.Panel.__init__(self, parent)
+ self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+ self.obj = obj
+ self.samples = []
+ self.Bind(wx.EVT_PAINT, self.OnPaint)
+ self.Bind(wx.EVT_SIZE, self.OnSize)
+ if sys.platform == "win32":
+ self.dcref = wx.BufferedPaintDC
+ else:
+ self.dcref = wx.PaintDC
-class ViewTable_withoutPIL(ViewTable):
- _WITH_PIL = False
- def __init__(self, parent, samples=None, tableclass=None, object=None):
- ViewTable.__init__(self, parent, samples, tableclass, object)
def draw(self, samples):
- if sys.platform == 'win32':
- if self.tableclass == 'SndTable':
- self.samples = [(samples[i], samples[i+1], samples[i+2], samples[i+3]) for i in range(0, len(samples), 4)]
- else:
- self.samples = [(samples[i], samples[i+1]) for i in range(0, len(samples), 2)]
- else:
- self.samples = [(samples[i], samples[i+1], samples[i+2], samples[i+3]) for i in range(0, len(samples), 4)]
+ self.samples = samples
self.Refresh()
def OnPaint(self, evt):
w,h = self.GetSize()
- dc = wx.AutoBufferedPaintDC(self)
+ dc = self.dcref(self)
+ gc = wx.GraphicsContext_Create(dc)
dc.SetBrush(wx.Brush("#FFFFFF"))
+ dc.SetPen(wx.Pen('#BBBBBB', width=1, style=wx.SOLID))
dc.Clear()
dc.DrawRectangle(0,0,w,h)
- if sys.platform == 'win32':
- if self.tableclass == 'SndTable':
- dc.DrawLineList(self.samples)
- else:
- dc.DrawPointList(self.samples)
- else:
- dc.DrawLineList(self.samples)
- dc.SetPen(wx.Pen('#BBBBBB', width=1, style=wx.SOLID))
- dc.DrawLine(0, self.half_height+1, self.width, self.half_height+1)
+ gc.SetPen(wx.Pen('#000000', width=1, style=wx.SOLID))
+ gc.SetBrush(wx.Brush("#FFFFFF"))
+ if len(self.samples) > 1:
+ gc.DrawLines(self.samples)
+ dc.DrawLine(0, h/2+1, w, h/2+1)
+ def OnSize(self, evt):
+ wx.CallAfter(self.obj.refreshView)
+
class SndViewTable(wx.Frame):
def __init__(self, parent, obj=None, tableclass=None, mouse_callback=None):
wx.Frame.__init__(self, parent, size=(500,250))
- self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+ self.SetMinSize((300, 150))
self.menubar = wx.MenuBar()
self.fileMenu = wx.Menu()
closeItem = self.fileMenu.Append(-1, 'Close\tCtrl+W', kind=wx.ITEM_NORMAL)
@@ -1029,24 +1023,59 @@ class SndViewTable(wx.Frame):
self.menubar.Append(self.fileMenu, "&File")
self.SetMenuBar(self.menubar)
self.Bind(wx.EVT_CLOSE, self._destroy)
- self.Bind(wx.EVT_PAINT, self.OnPaint)
- self.Bind(wx.EVT_SIZE, self.OnSize)
- self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
- self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
- self.Bind(wx.EVT_MOTION, self.OnMotion)
self.obj = obj
self.chnls = len(self.obj)
- self.mouse_callback = mouse_callback
+ self.dur = self.obj.getDur(False)
+ self.panel = wx.Panel(self)
+ self.panel.SetBackgroundColour(BACKGROUND_COLOUR)
+ self.box = wx.BoxSizer(wx.VERTICAL)
+ self.wavePanel = SndViewTablePanel(self.panel, obj, mouse_callback)
+ self.box.Add(self.wavePanel, 1, wx.EXPAND|wx.ALL, 5)
+ self.zoomH = HRangeSlider(self.panel, minvalue=0, maxvalue=1, init=None, pos=(0,0), size=(200,15),
+ valtype='float', log=False, function=self.setZoomH)
+ self.box.Add(self.zoomH, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 5)
+ self.panel.SetSizer(self.box)
+
+ def setZoomH(self, values):
+ self.wavePanel.setBegin(self.dur * values[0])
+ self.wavePanel.setEnd(self.dur * values[1])
+ self.update()
def update(self):
- wx.CallAfter(self.setImage)
+ wx.CallAfter(self.wavePanel.setImage)
def _destroy(self, evt):
self.obj._setViewFrame(None)
self.Destroy()
- def OnSize(self, evt):
+class SndViewTablePanel(wx.Panel):
+ def __init__(self, parent, obj, mouse_callback=None):
+ wx.Panel.__init__(self, parent)
+ self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+ self.Bind(wx.EVT_PAINT, self.OnPaint)
+ self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
+ self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
+ self.Bind(wx.EVT_MOTION, self.OnMotion)
+ self.Bind(wx.EVT_SIZE, self.OnSize)
+ self.obj = obj
+ self.chnls = len(self.obj)
+ self.begin = 0
+ self.end = self.obj.getDur(False)
+ self.mouse_callback = mouse_callback
+ if sys.platform == "win32":
+ self.dcref = wx.BufferedPaintDC
+ else:
+ self.dcref = wx.PaintDC
self.setImage()
+
+ def setBegin(self, x):
+ self.begin = x
+
+ def setEnd(self, x):
+ self.end = x
+
+ def setImage(self):
+ self.img = self.obj.getViewTable(self.GetSize(), self.begin, self.end)
self.Refresh()
def clipPos(self, pos):
@@ -1056,6 +1085,7 @@ class SndViewTable(wx.Frame):
if pos[1] < 0.0: y = 0.0
elif pos[1] > 1.0: y = 1.0
else: y = pos[1]
+ x = x * ((self.end - self.begin) / self.obj.getDur(False)) + (self.begin / self.obj.getDur(False))
return (x, y)
def OnMouseDown(self, evt):
@@ -1086,77 +1116,50 @@ class SndViewTable(wx.Frame):
if self.HasCapture():
self.ReleaseMouse()
-class SndViewTable_withPIL(SndViewTable):
- def __init__(self, parent, obj=None, tableclass=None, mouse_callback=None):
- SndViewTable.__init__(self, parent, obj, tableclass, mouse_callback)
- self.setImage()
-
- def setImage(self):
- w, h = self.GetSize()
- self.img = []
- imgHeight = h/self.chnls
- for i in range(self.chnls):
- im = Image.new("L", (w, imgHeight), 255)
- draw = ImageDraw.Draw(im)
- samples = self.obj._base_objs[i].getViewTable((w, imgHeight))
- draw.line(samples, fill=0, width=1)
- image = wx.EmptyImage(w, imgHeight)
- image.SetData(im.convert("RGB").tostring())
- self.img.append(wx.BitmapFromImage(image))
- self.Refresh()
-
- def OnPaint(self, evt):
- w, h = self.GetSize()
- dc = wx.AutoBufferedPaintDC(self)
- dc.SetPen(wx.Pen('#444444', width=1, style=wx.SHORT_DASH))
- off = h/self.chnls/2
- for i, img in enumerate(self.img):
- y = h/self.chnls*i
- dc.DrawBitmap(img, 0, y)
- dc.DrawLine(0, y+off, w, y+off)
-
-class SndViewTable_withoutPIL(SndViewTable):
- def __init__(self, parent, obj=None, tableclass=None, mouse_callback=None):
- SndViewTable.__init__(self, parent, obj, tableclass, mouse_callback)
- self.tableclass = tableclass
- self.setImage()
-
- def setImage(self):
- w, h = self.GetSize()
- self.img = []
- imgHeight = h/self.chnls
- for j in range(self.chnls):
- off = h/self.chnls*j
- samples = self.obj._base_objs[j].getViewTable((w, imgHeight))
- if sys.platform == 'win32':
- if self.tableclass == 'SndTable':
- samples = [(samples[i], samples[i+1]+off, samples[i+2], samples[i+3]+off) for i in range(0, len(samples), 4)]
- else:
- samples = [(samples[i], samples[i+1]+off) for i in range(0, len(samples), 2)]
- else:
- samples = [(samples[i], samples[i+1]+off, samples[i+2], samples[i+3]+off) for i in range(0, len(samples), 4)]
- self.img.append(samples)
- self.Refresh()
-
def OnPaint(self, evt):
w,h = self.GetSize()
- dc = wx.AutoBufferedPaintDC(self)
+ dc = self.dcref(self)
+ gc = wx.GraphicsContext_Create(dc)
dc.SetBrush(wx.Brush("#FFFFFF"))
dc.Clear()
dc.DrawRectangle(0,0,w,h)
off = h/self.chnls/2
+ gc.SetPen(wx.Pen('#000000', width=1, style=wx.SOLID))
+ gc.SetBrush(wx.Brush("#FFFFFF", style=wx.TRANSPARENT))
+ dc.SetTextForeground("#444444")
+ if sys.platform in "darwin":
+ font, ptsize = dc.GetFont(), dc.GetFont().GetPointSize()
+ font.SetPointSize(ptsize - 3)
+ dc.SetFont(font)
+ elif sys.platform == "win32":
+ font = dc.GetFont()
+ font.SetPointSize(8)
+ dc.SetFont(font)
+ tickstep = w / 10
+ if tickstep < 40:
+ timelabel = "%.1f"
+ elif tickstep < 80:
+ timelabel = "%.2f"
+ elif tickstep < 120:
+ timelabel = "%.3f"
+ else:
+ timelabel = "%.4f"
+ timestep = (self.end - self.begin) * 0.1
for i, samples in enumerate(self.img):
- dc.SetPen(wx.Pen('#000000', width=1, style=wx.SOLID))
y = h/self.chnls*i
- if sys.platform == 'win32':
- if self.tableclass == 'SndTable':
- dc.DrawLineList(samples)
- else:
- dc.DrawPointList(samples)
- else:
- dc.DrawLineList(samples)
- dc.SetPen(wx.Pen('#444444', width=1, style=wx.SHORT_DASH))
+ if len(samples):
+ gc.DrawLines(samples)
+ dc.SetPen(wx.Pen('#888888', width=1, style=wx.DOT))
dc.DrawLine(0, y+off, w, y+off)
+ for j in range(10):
+ dc.SetPen(wx.Pen('#888888', width=1, style=wx.DOT))
+ dc.DrawLine(j*tickstep, 0, j*tickstep, h)
+ dc.DrawText(timelabel % (self.begin+j*timestep), j*tickstep+2, h-y-12)
+ dc.SetPen(wx.Pen('#000000', width=1))
+ dc.DrawLine(0, h-y, w, h-y)
+
+ def OnSize(self, evt):
+ wx.CallAfter(self.setImage)
######################################################################
## View window for PyoMatrixObject
@@ -1298,9 +1301,8 @@ class SpectrumDisplay(wx.Frame):
valtype='float', log=False, function=self.setZoomH)
self.box.Add(self.zoomH, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 5)
self.dispBox.Add(self.box, 1, wx.EXPAND, 0)
- self.gainSlider = wx.Slider(self.panel, -1, 0, -24, 24, style=wx.SL_VERTICAL|wx.SL_INVERSE)
- self.gainSlider.Bind(wx.EVT_SLIDER, self.setGain)
- self.dispBox.Add(self.gainSlider, 0, wx.EXPAND|wx.BOTTOM, 15)
+ self.gainSlider = ControlSlider(self.panel, -24, 24, 0, outFunction=self.setGain, orient=wx.VERTICAL)
+ self.dispBox.Add(self.gainSlider, 0, wx.EXPAND|wx.TOP, 5)
self.dispBox.AddSpacer(5)
self.mainBox.Add(self.dispBox, 1, wx.EXPAND)
self.panel.SetSizer(self.mainBox)
@@ -1334,8 +1336,8 @@ class SpectrumDisplay(wx.Frame):
size = 1 << (evt.GetInt() + 6)
self.obj.size = size
- def setGain(self, evt):
- self.obj.setGain(pow(10.0, evt.GetInt() * 0.05))
+ def setGain(self, gain):
+ self.obj.setGain(pow(10.0, gain * 0.05))
def setZoomH(self, values):
self.spectrumPanel.setLowFreq(self.obj.setLowbound(values[0]))
@@ -1543,6 +1545,164 @@ class SpectrumPanel(wx.Panel):
gc.DrawLines(samples)
######################################################################
+## Spectrum Display
+######################################################################
+class ScopeDisplay(wx.Frame):
+ def __init__(self, parent, obj=None):
+ wx.Frame.__init__(self, parent, size=(600,350))
+ self.SetMinSize((400,240))
+ self.menubar = wx.MenuBar()
+ self.fileMenu = wx.Menu()
+ closeItem = self.fileMenu.Append(-1, 'Close\tCtrl+W', kind=wx.ITEM_NORMAL)
+ self.Bind(wx.EVT_MENU, self._destroy, closeItem)
+ self.menubar.Append(self.fileMenu, "&File")
+ self.SetMenuBar(self.menubar)
+ self.Bind(wx.EVT_CLOSE, self._destroy)
+ self.obj = obj
+ gain = self.obj.gain
+ length = self.obj.length
+ self.panel = wx.Panel(self)
+ self.panel.SetBackgroundColour(BACKGROUND_COLOUR)
+ self.mainBox = wx.BoxSizer(wx.VERTICAL)
+ self.toolBox = wx.BoxSizer(wx.HORIZONTAL)
+ if sys.platform == "darwin":
+ X_OFF = 24
+ else:
+ X_OFF = 16
+ tw, th = self.GetTextExtent("Start")
+ self.activeTog = wx.ToggleButton(self.panel, -1, label="Start", size=(tw+X_OFF, th+10))
+ self.activeTog.SetValue(1)
+ self.activeTog.Bind(wx.EVT_TOGGLEBUTTON, self.activate)
+ self.toolBox.Add(self.activeTog, 0, wx.TOP|wx.LEFT|wx.RIGHT, 5)
+ self.toolBox.AddSpacer(10)
+ self.toolBox.Add(wx.StaticText(self.panel, -1, label="Window length (ms):"), 0, wx.TOP, 11)
+ self.lenSlider = ControlSlider(self.panel, 10, 60, length * 1000, outFunction=self.setLength)
+ self.toolBox.Add(self.lenSlider, 1, wx.TOP|wx.LEFT|wx.RIGHT, 11)
+ self.toolBox.AddSpacer(40)
+ self.mainBox.Add(self.toolBox, 0, wx.EXPAND)
+ self.dispBox = wx.BoxSizer(wx.HORIZONTAL)
+ self.box = wx.BoxSizer(wx.VERTICAL)
+ self.scopePanel = ScopePanel(self.panel, self.obj)
+ self.box.Add(self.scopePanel, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 5)
+ self.dispBox.Add(self.box, 1, wx.EXPAND, 0)
+ self.gainSlider = ControlSlider(self.panel, -24, 24, 20.0 * math.log10(gain), outFunction=self.setGain, orient=wx.VERTICAL)
+ self.dispBox.Add(self.gainSlider, 0, wx.EXPAND)
+ self.dispBox.AddSpacer(5)
+ self.mainBox.Add(self.dispBox, 1, wx.EXPAND)
+ self.panel.SetSizer(self.mainBox)
+
+ def activate(self, evt):
+ self.obj.poll(evt.GetInt())
+
+ def setLength(self, length):
+ length *= 0.001
+ self.obj.setLength(length)
+ self.scopePanel.setLength(length)
+
+ def setGain(self, gain):
+ gain = pow(10.0, gain * 0.05)
+ self.scopePanel.setGain(gain)
+ self.obj.setGain(gain)
+
+ def update(self, points):
+ wx.CallAfter(self.scopePanel.setImage, points)
+
+ def _destroy(self, evt):
+ self.obj._setViewFrame(None)
+ self.Destroy()
+
+class ScopePanel(wx.Panel):
+ def __init__(self, parent, obj):
+ wx.Panel.__init__(self, parent)
+ self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+ self.Bind(wx.EVT_PAINT, self.OnPaint)
+ self.Bind(wx.EVT_SIZE, self.OnSize)
+ self.img = [[]]
+ self.obj = obj
+ self.gain = self.obj.gain
+ self.length = self.obj.length
+ self.chnls = len(self.obj)
+ if self.chnls == 1:
+ self.pens = [wx.Pen(wx.Colour(100,0,0), width=2)]
+ else:
+ self.pens = [wx.Pen(wx.Colour(166,4,0), width=2), wx.Pen(wx.Colour(8,11,116), width=2), wx.Pen(wx.Colour(0,204,0), width=2),
+ wx.Pen(wx.Colour(255,167,0), width=2), wx.Pen(wx.Colour(133,0,75), width=2), wx.Pen(wx.Colour(255,236,0), width=2),
+ wx.Pen(wx.Colour(1,147,154), width=2), wx.Pen(wx.Colour(162,239,0), width=2)]
+
+ if sys.platform == "win32":
+ self.dcref = wx.BufferedPaintDC
+ else:
+ self.dcref = wx.PaintDC
+
+ def OnSize(self, evt):
+ size = self.GetSize()
+ self.obj.setWidth(size[0])
+ self.obj.setHeight(size[1])
+
+ def setGain(self, gain):
+ self.gain = gain
+ print self.gain
+
+ def setLength(self, length):
+ self.length = length
+
+ def setImage(self, points):
+ self.img = points
+ self.Refresh()
+
+ def OnPaint(self, evt):
+ w,h = self.GetSize()
+ dc = self.dcref(self)
+ gc = wx.GraphicsContext_Create(dc)
+ tw, th = dc.GetTextExtent("0")
+ dc.SetBrush(wx.Brush("#FFFFFF"))
+ dc.Clear()
+ dc.DrawRectangle(0,0,w,h)
+ gc.SetPen(wx.Pen('#000000', width=1, style=wx.SOLID))
+ gc.SetBrush(wx.Brush("#FFFFFF", style=wx.TRANSPARENT))
+ dc.SetTextForeground("#444444")
+ if sys.platform in "darwin":
+ font, ptsize = dc.GetFont(), dc.GetFont().GetPointSize()
+ font.SetPointSize(ptsize - 3)
+ dc.SetFont(font)
+ elif sys.platform == "win32":
+ font = dc.GetFont()
+ font.SetPointSize(8)
+ dc.SetFont(font)
+
+ dc.SetPen(wx.Pen('#888888', width=1, style=wx.DOT))
+ # horizontal grid
+ step = h / 6
+ ampstep = 1.0 / 3.0 / self.gain
+ for i in range(1, 6):
+ pos = int(h - i * step)
+ npos = i - 3
+ text = "%.2f" % (ampstep * npos)
+ tw, th = dc.GetTextExtent(text)
+ dc.DrawText(text, w-tw-2, pos-th/2)
+ dc.DrawLine(0, pos, w-tw-10, pos)
+
+ # vertical grid
+ tickstep = w / 4
+ timestep = self.length * 0.25
+ for j in range(4):
+ dc.SetPen(wx.Pen('#888888', width=1, style=wx.DOT))
+ dc.DrawLine(j*tickstep, 0, j*tickstep, h)
+ dc.DrawText("%.3f" % (j*timestep), j*tickstep+2, h-12)
+ # draw waveforms
+ for i, samples in enumerate(self.img):
+ gc.SetPen(self.pens[i])
+ if len(samples):
+ gc.DrawLines(samples)
+
+ # legend
+ last_tw = tw
+ tw, th = dc.GetTextExtent("chan 8")
+ for i in range(self.chnls):
+ dc.SetTextForeground(self.pens[i].GetColour())
+ dc.DrawText("chan %d" % (i+1), w-tw-20-last_tw, i*th+10)
+
+######################################################################
## Grapher window for PyoTableObject control
######################################################################
OFF = 15
@@ -1578,6 +1738,11 @@ class Grapher(wx.Panel):
self.init = [tup for tup in init]
self.points = init
self.outFunction = outFunction
+
+ if sys.platform == "win32":
+ self.dcref = wx.BufferedPaintDC
+ else:
+ self.dcref = wx.PaintDC
self.SetFocus()
@@ -1676,6 +1841,7 @@ class Grapher(wx.Panel):
self.points = [(pt[0], pt[1]-0.002) for pt in self.points]
self.sendValues()
self.Refresh()
+ evt.Skip()
def MouseDown(self, evt):
self.CaptureMouse()
@@ -1714,7 +1880,7 @@ class Grapher(wx.Panel):
if self.mode == 4 and y <= 0:
y = 0.000001
self.points[self.selected] = (x, y)
- self.Refresh()
+ self.Refresh()
def getLogPoints(self, pt1, pt2):
tmp = []
@@ -1850,7 +2016,10 @@ class Grapher(wx.Panel):
def OnPaint(self, evt):
w,h = self.GetSize()
corners = [(OFF,OFF),(w-OFF,OFF),(w-OFF,h-OFF),(OFF,h-OFF)]
- dc = wx.AutoBufferedPaintDC(self)
+ dc = self.dcref(self)
+ gc = wx.GraphicsContext_Create(dc)
+ gc.SetBrush(wx.Brush("#000000"))
+ gc.SetPen(wx.Pen("#000000"))
if sys.platform == "darwin":
font, ptsize = dc.GetFont(), dc.GetFont().GetPointSize()
else:
@@ -1904,44 +2073,44 @@ class Grapher(wx.Panel):
if len(tmp) > 1:
if self.mode == 0:
for i in range(len(tmp)-1):
- dc.DrawLinePoint(tmp[i], tmp[i+1])
+ gc.DrawLines([tmp[i], tmp[i+1]])
elif self.mode == 1:
for i in range(len(tmp)-1):
tmp2 = self.getCosPoints(tmp[i], tmp[i+1])
if i == 0 and len(tmp2) < 2:
- dc.DrawLinePoint(tmp[i], tmp[i+1])
+ gc.DrawLines([tmp[i], tmp[i+1]])
if last_p != None:
- dc.DrawLinePoint(last_p, tmp[i])
+ gc.DrawLines([last_p, tmp[i]])
for j in range(len(tmp2)-1):
- dc.DrawLinePoint(tmp2[j], tmp2[j+1])
+ gc.DrawLines([tmp2[j], tmp2[j+1]])
last_p = tmp2[j+1]
if last_p != None:
- dc.DrawLinePoint(last_p, tmp[-1])
+ gc.DrawLines([last_p, tmp[-1]])
elif self.mode == 2:
for i in range(len(tmp)-1):
tmp2 = self.getExpPoints(tmp[i], tmp[i+1])
if i == 0 and len(tmp2) < 2:
- dc.DrawLinePoint(tmp[i], tmp[i+1])
+ gc.DrawLines([tmp[i], tmp[i+1]])
if last_p != None:
- dc.DrawLinePoint(last_p, tmp[i])
+ gc.DrawLines([last_p, tmp[i]])
for j in range(len(tmp2)-1):
- dc.DrawLinePoint(tmp2[j], tmp2[j+1])
+ gc.DrawLines([tmp2[j], tmp2[j+1]])
last_p = tmp2[j+1]
if last_p != None:
- dc.DrawLinePoint(last_p, tmp[-1])
+ gc.DrawLines([last_p, tmp[-1]])
elif self.mode == 3:
curvetmp = self.addImaginaryPoints(tmp)
for i in range(1, len(curvetmp)-2):
tmp2 = self.getCurvePoints(curvetmp[i-1], curvetmp[i], curvetmp[i+1], curvetmp[i+2])
if i == 1 and len(tmp2) < 2:
- dc.DrawLinePoint(curvetmp[i], curvetmp[i+1])
+ gc.DrawLines([curvetmp[i], curvetmp[i+1]])
if last_p != None:
- dc.DrawLinePoint(last_p, curvetmp[i])
+ gc.DrawLines([last_p, curvetmp[i]])
for j in range(len(tmp2)-1):
- dc.DrawLinePoint(tmp2[j], tmp2[j+1])
+ gc.DrawLines([tmp2[j], tmp2[j+1]])
last_p = tmp2[j+1]
if last_p != None:
- dc.DrawLinePoint(last_p, tmp[-1])
+ gc.DrawLines([last_p, tmp[-1]])
elif self.mode == 4:
back_tmp = [p for p in tmp]
for i in range(len(tmp)):
@@ -1951,14 +2120,14 @@ class Grapher(wx.Panel):
for j in range(len(tmp2)):
tmp2[j] = (tmp2[j][0], int(round((1.0-tmp2[j][1]) * h)) + OFF + RAD)
if i == 0 and len(tmp2) < 2:
- dc.DrawLinePoint(back_tmp[i], back_tmp[i+1])
+ gc.DrawLines([back_tmp[i], back_tmp[i+1]])
if last_p != None:
- dc.DrawLinePoint(last_p, back_tmp[i])
+ gc.DrawLines([last_p, back_tmp[i]])
for j in range(len(tmp2)-1):
- dc.DrawLinePoint(tmp2[j], tmp2[j+1])
+ gc.DrawLines([tmp2[j], tmp2[j+1]])
last_p = tmp2[j+1]
if last_p != None:
- dc.DrawLinePoint(last_p, back_tmp[-1])
+ gc.DrawLines([last_p, back_tmp[-1]])
tmp = [p for p in back_tmp]
elif self.mode == 5:
back_tmp = [p for p in tmp]
@@ -1969,23 +2138,25 @@ class Grapher(wx.Panel):
for j in range(len(tmp2)):
tmp2[j] = (tmp2[j][0], int(round((1.0-tmp2[j][1]) * h)) + OFF + RAD)
if i == 0 and len(tmp2) < 2:
- dc.DrawLinePoint(back_tmp[i], back_tmp[i+1])
+ gc.DrawLines([back_tmp[i], back_tmp[i+1]])
if last_p != None:
- dc.DrawLinePoint(last_p, back_tmp[i])
+ gc.DrawLines([last_p, back_tmp[i]])
for j in range(len(tmp2)-1):
- dc.DrawLinePoint(tmp2[j], tmp2[j+1])
+ gc.DrawLines([tmp2[j], tmp2[j+1]])
last_p = tmp2[j+1]
if last_p != None:
- dc.DrawLinePoint(last_p, back_tmp[-1])
+ gc.DrawLines([last_p, back_tmp[-1]])
tmp = [p for p in back_tmp]
# Draw points
for i,p in enumerate(tmp):
if i == self.selected:
+ gc.SetBrush(wx.Brush("#FFFFFF"))
dc.SetBrush(wx.Brush("#FFFFFF"))
else:
+ gc.SetBrush(wx.Brush("#000000"))
dc.SetBrush(wx.Brush("#000000"))
- dc.DrawCircle(p[0],p[1],RAD)
+ gc.DrawEllipse(p[0]-RAD,p[1]-RAD,RAD2,RAD2)
# Draw position values
font.SetPointSize(ptsize-3)
@@ -2080,7 +2251,11 @@ class DataMultiSlider(wx.Panel):
def OnResize(self, event):
self.Layout()
self.Refresh()
-
+
+ def update(self, points):
+ self.values = points
+ self.Refresh()
+
def OnPaint(self, event):
w,h = self.GetSize()
dc = self.dcref(self)
@@ -2181,10 +2356,13 @@ class DataTableGrapher(wx.Frame):
def close(self, evt):
self.Destroy()
+ def update(self, samples):
+ wx.CallAfter(self.multi.update, samples)
+
class ServerGUI(wx.Frame):
def __init__(self, parent=None, nchnls=2, startf=None, stopf=None, recstartf=None,
- recstopf=None, ampf=None, started=0, locals=None, shutdown=None, meter=True, timer=True, amp=1.):
- wx.Frame.__init__(self, parent)
+ recstopf=None, ampf=None, started=0, locals=None, shutdown=None, meter=True, timer=True, amp=1., exit=True):
+ wx.Frame.__init__(self, parent, style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
self.SetTitle("pyo server")
@@ -2205,6 +2383,7 @@ class ServerGUI(wx.Frame):
self.recstartf = recstartf
self.recstopf = recstopf
self.ampf = ampf
+ self.exit = exit
self._started = False
self._recstarted = False
self._history = []
@@ -2237,7 +2416,7 @@ class ServerGUI(wx.Frame):
box.Add(wx.StaticText(panel, -1, "Amplitude (dB)"), 0, wx.LEFT, leftMargin)
ampBox = wx.BoxSizer(wx.HORIZONTAL)
- self.ampScale = ControlSlider(panel, -60, 18, 20.0 * math.log10(amp), size=(203, 16), outFunction=self.setAmp)
+ self.ampScale = ControlSlider(panel, -60, 18, 20.0 * math.log10(amp), size=(202, 16), outFunction=self.setAmp)
ampBox.Add(self.ampScale, 0, wx.LEFT, leftMargin-10)
box.Add(ampBox, 0, wx.LEFT | wx.RIGHT, 8)
@@ -2259,16 +2438,15 @@ class ServerGUI(wx.Frame):
box.AddSpacer(10)
t = wx.StaticText(panel, -1, "Interpreter")
box.Add(t, 0, wx.LEFT, leftMargin)
- self.text = wx.TextCtrl(panel, -1, "", size=(200, -1), style=wx.TE_PROCESS_ENTER)
+ tw, th = self.GetTextExtent("|")
+ self.text = wx.TextCtrl(panel, -1, "", size=(202, th+8), style=wx.TE_PROCESS_ENTER)
self.text.Bind(wx.EVT_TEXT_ENTER, self.getText)
self.text.Bind(wx.EVT_CHAR, self.onChar)
- box.Add(self.text, 0, wx.LEFT, leftMargin)
+ box.Add(self.text, 0, wx.LEFT, leftMargin-1)
box.AddSpacer(10)
panel.SetSizerAndFit(box)
self.SetClientSize(panel.GetSize())
- self.SetMinSize(self.GetSize())
- self.SetMaxSize(self.GetSize())
if started == 1:
self.start(None, True)
@@ -2281,13 +2459,15 @@ class ServerGUI(wx.Frame):
if not justSet:
self.startf()
self._started = True
- self.startButton.SetLabel('Stop')
- self.quitButton.Disable()
+ wx.CallAfter(self.startButton.SetLabel, 'Stop')
+ if self.exit:
+ wx.CallAfter(self.quitButton.Disable)
else:
- self.stopf()
+ wx.CallLater(100, self.stopf)
self._started = False
- self.startButton.SetLabel('Start')
- self.quitButton.Enable()
+ wx.CallAfter(self.startButton.SetLabel, 'Start')
+ if self.exit:
+ wx.CallAfter(self.quitButton.Enable)
def record(self, evt):
if self._recstarted == False:
@@ -2300,9 +2480,11 @@ class ServerGUI(wx.Frame):
self.recButton.SetLabel('Rec Start')
def on_quit(self, evt):
- self.shutdown()
+ if self.exit:
+ self.shutdown()
self.Destroy()
- sys.exit()
+ if self.exit:
+ sys.exit()
def getPrev(self):
self.text.Clear()
@@ -2332,9 +2514,12 @@ class ServerGUI(wx.Frame):
key = evt.GetKeyCode()
if key == 315:
self.getPrev()
+ evt.StopPropagation()
elif key == 317:
- self.getNext()
- evt.Skip()
+ self.getNext()
+ evt.StopPropagation()
+ else:
+ evt.Skip()
def setAmp(self, value):
self.ampf(math.pow(10.0, float(value) * 0.05))
@@ -2342,12 +2527,3 @@ class ServerGUI(wx.Frame):
def setRms(self, *args):
self.meter.setRms(*args)
-if __name__ == "__main__":
- def pprint(values):
- print values
-
- app = wx.App(False)
- values = [random.uniform(10, 25) for i in range(10)]
- f = DataTableGrapher(init=values, yrange=(2, 50))
- f.Show()
- app.MainLoop()
diff --git a/pyolib/analysis.py b/pyolib/analysis.py
index ffcdc53..6b8316c 100644
--- a/pyolib/analysis.py
+++ b/pyolib/analysis.py
@@ -29,6 +29,8 @@ along with pyo. If not, see <http://www.gnu.org/licenses/>.
from _core import *
from _maps import *
+from _widgets import createSpectrumWindow, createScopeWindow
+from pattern import Pattern
class Follower(PyoObject):
"""
@@ -246,7 +248,7 @@ class ZCross(PyoObject):
The out() method is bypassed. ZCross's signal can not be sent to
audio outs.
- >>> s = Server(duplex=1).boot()
+ >>> s = Server().boot()
>>> s.start()
>>> a = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.4).out()
>>> b = ZCross(a, thresh=.02)
@@ -292,6 +294,10 @@ class ZCross(PyoObject):
def out(self, chnl=0, inc=1, dur=0, delay=0):
return self.play(dur, delay)
+
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0., 0.5, 'lin', 'thresh', self._thresh)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
@@ -440,6 +446,13 @@ class Yin(PyoObject):
def out(self, chnl=0, inc=1, dur=0, delay=0):
return self.play(dur, delay)
+
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0, 1, 'lin', 'tolerance', self._tolerance, dataOnly=True),
+ SLMap(20, 400, 'log', 'minfreq', self._minfreq, dataOnly=True),
+ SLMap(500, 5000, 'log', 'maxfreq', self._maxfreq, dataOnly=True),
+ SLMap(200, 15000, 'log', 'cutoff', self._cutoff, dataOnly=True)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
@@ -475,3 +488,974 @@ class Yin(PyoObject):
return self._cutoff
@cutoff.setter
def cutoff(self, x): self.setCutoff(x)
+
+class Centroid(PyoObject):
+ """
+ Computes the spectral centroid of an input signal.
+
+ Output signal is the spectral centroid, in Hz, of the input signal.
+ It indicates where the "center of mass" of the spectrum is. Perceptually,
+ it has a robust connection with the impression of "brightness" of a sound.
+
+ Centroid does its computation with two overlaps, so a new output value
+ comes every half of the FFT window size.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal to process.
+ size : int, optional
+ Size, as a power-of-two, of the FFT used to compute the centroid.
+
+ Available at initialization time only. Defaults to 1024.
+
+
+ .. note::
+
+ The out() method is bypassed. Centroid's signal can not be sent to
+ audio outs.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> a = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.4).out()
+ >>> b = Centroid(a, 1024)
+ >>> c = Port(b, 0.05, 0.05)
+ >>> d = ButBP(Noise(0.2), freq=c, q=5).out(1)
+
+ """
+ def __init__(self, input, size=1024, mul=1, add=0):
+ PyoObject.__init__(self, mul, add)
+ self._input = input
+ self._size = size
+ self._in_fader = InputFader(input)
+ in_fader, size, mul, add, lmax = convertArgsToLists(self._in_fader, size, mul, add)
+ self._base_objs = [Centroid_base(wrap(in_fader,i), wrap(size,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+
+ def setInput(self, x, fadetime=0.05):
+ """
+ Replace the `input` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New signal to process.
+ fadetime : float, optional
+ Crossfade time between old and new input. Default to 0.05.
+
+ """
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ def out(self, chnl=0, inc=1, dur=0, delay=0):
+ return self.play(dur, delay)
+
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = []
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+ @property
+ def input(self):
+ """PyoObject. Input signal to process."""
+ return self._input
+ @input.setter
+ def input(self, x): self.setInput(x)
+
+class AttackDetector(PyoObject):
+ """
+ Audio signal onset detection.
+
+ AttackDetector anaylises an audio signal in input an output a trigger each
+ time an onset is detected. An onset is a sharp amplitude rising while the
+ signal had previously fall below a minimum threshold. Parameters must be
+ carefully tuned depending on the nature of the analysed signal and the level
+ of the background noise.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal to process.
+ deltime : float, optional
+ Delay time, in seconds, between previous and current rms analysis to compare.
+ Defaults to 0.005.
+ cutoff : float, optional
+ Cutoff frequency, in Hz, of the amplitude follower's lowpass filter.
+ Defaults to 10.
+
+ Higher values are more responsive and also more likely to give false onsets.
+ maxthresh : float, optional
+ Attack threshold in positive dB (current rms must be higher than previous
+ rms + maxthresh to be reported as an attack). Defaults to 3.0.
+ minthresh : float, optional
+ Minimum threshold in dB (signal must fall below this threshold to allow
+ a new attack to be detected). Defaults to -30.0.
+ reltime : float, optional
+ Time, in seconds, to wait before reporting a new attack. Defaults to 0.1.
+
+
+ >>> s = Server(duplex=1).boot()
+ >>> s.start()
+ >>> a = Input()
+ >>> d = AttackDetector(a, deltime=0.005, cutoff=10, maxthresh=4, minthresh=-20, reltime=0.05)
+ >>> exc = TrigEnv(d, HannTable(), dur=0.005, mul=BrownNoise(0.3))
+ >>> wgs = Waveguide(exc, freq=[100,200.1,300.3,400.5], dur=30).out()
+
+ """
+ def __init__(self, input, deltime=0.005, cutoff=10, maxthresh=3, minthresh=-30, reltime=0.1, mul=1, add=0):
+ PyoObject.__init__(self, mul, add)
+ self._input = input
+ self._deltime = deltime
+ self._cutoff = cutoff
+ self._maxthresh = maxthresh
+ self._minthresh = minthresh
+ self._reltime = reltime
+ self._in_fader = InputFader(input)
+ in_fader, deltime, cutoff, maxthresh, minthresh, reltime, mul, add, lmax = convertArgsToLists(self._in_fader, deltime, cutoff, maxthresh, minthresh, reltime, mul, add)
+ self._base_objs = [AttackDetector_base(wrap(in_fader,i), wrap(deltime,i), wrap(cutoff,i), wrap(maxthresh,i), wrap(minthresh,i), wrap(reltime,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+
+ def setInput(self, x, fadetime=0.05):
+ """
+ Replace the `input` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New signal to process.
+ fadetime : float, optional
+ Crossfade time between old and new input. Default to 0.05.
+
+ """
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ def setDeltime(self, x):
+ """
+ Replace the `deltime` attribute.
+
+ :Args:
+
+ x : float
+ New delay between rms analysis.
+
+ """
+ self._deltime = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setDeltime(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setCutoff(self, x):
+ """
+ Replace the `cutoff` attribute.
+
+ :Args:
+
+ x : float
+ New cutoff for the follower lowpass filter.
+
+ """
+ self._cutoff = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setCutoff(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setMaxthresh(self, x):
+ """
+ Replace the `maxthresh` attribute.
+
+ :Args:
+
+ x : float
+ New attack threshold in dB.
+
+ """
+ self._maxthresh = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setMaxthresh(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setMinthresh(self, x):
+ """
+ Replace the `minthresh` attribute.
+
+ :Args:
+
+ x : float
+ New minimum threshold in dB.
+
+ """
+ self._minthresh = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setMinthresh(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setReltime(self, x):
+ """
+ Replace the `reltime` attribute.
+
+ :Args:
+
+ x : float
+ Time, in seconds, to wait before reporting a new attack.
+
+ """
+ self._reltime = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setReltime(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def out(self, chnl=0, inc=1, dur=0, delay=0):
+ return self.play(dur, delay)
+
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0.001, 0.05, 'lin', 'deltime', self._deltime, dataOnly=True),
+ SLMap(1.0, 1000.0, 'log', 'cutoff', self._cutoff, dataOnly=True),
+ SLMap(0.0, 18.0, 'lin', 'maxthresh', self._maxthresh, dataOnly=True),
+ SLMap(-90.0, 0.0, 'lin', 'minthresh', self._minthresh, dataOnly=True),
+ SLMap(0.001, 1.0, 'log', 'reltime', self._reltime, dataOnly=True)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+ @property
+ def input(self):
+ """PyoObject. Input signal to process."""
+ return self._input
+ @input.setter
+ def input(self, x): self.setInput(x)
+
+ @property
+ def deltime(self):
+ """float. Delay between rms analysis."""
+ return self._deltime
+ @deltime.setter
+ def deltime(self, x): self.setDeltime(x)
+
+ @property
+ def cutoff(self):
+ """float. Cutoff for the follower lowpass filter."""
+ return self._cutoff
+ @cutoff.setter
+ def cutoff(self, x): self.setCutoff(x)
+
+ @property
+ def maxthresh(self):
+ """float. Attack threshold in dB."""
+ return self._maxthresh
+ @maxthresh.setter
+ def maxthresh(self, x): self.setMaxthresh(x)
+
+ @property
+ def minthresh(self):
+ """float. Minimum threshold in dB."""
+ return self._minthresh
+ @minthresh.setter
+ def minthresh(self, x): self.setMinthresh(x)
+
+ @property
+ def reltime(self):
+ """float. Time to wait before reporting a new attack."""
+ return self._reltime
+ @reltime.setter
+ def reltime(self, x): self.setReltime(x)
+
+class Spectrum(PyoObject):
+ """
+ Spectrum analyzer and display.
+
+ Spectrum measures the magnitude of an input signal versus frequency
+ within a user defined range. It can show both magnitude and frequency
+ on linear or logarithmic scale.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal to process.
+ size : int {pow-of-two > 4}, optional
+ FFT size. Must be a power of two greater than 4.
+ The FFT size is the number of samples used in each
+ analysis frame. Defaults to 1024.
+ wintype : int, optional
+ Shape of the envelope used to filter each input frame.
+ Possible shapes are :
+ 0. rectangular (no windowing)
+ 1. Hamming
+ 2. Hanning
+ 3. Bartlett (triangular)
+ 4. Blackman 3-term
+ 5. Blackman-Harris 4-term
+ 6. Blackman-Harris 7-term
+ 7. Tuckey (alpha = 0.66)
+ 8. Sine (half-sine window)
+ function : python callable, optional
+ If set, this function will be called with magnitudes (as
+ list of lists, one list per channel). Useful if someone
+ wants to save the analysis data into a text file.
+ Defaults to None.
+
+ .. note::
+
+ Spectrum has no `out` method.
+
+ Spectrum has no `mul` and `add` attributes.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> a = SuperSaw(freq=[500,750], detune=0.6, bal=0.7, mul=0.5).out()
+ >>> spec = Spectrum(a, size=1024)
+
+ """
+ def __init__(self, input, size=1024, wintype=2, function=None):
+ PyoObject.__init__(self)
+ self.points = None
+ self.viewFrame = None
+ self._input = input
+ self._size = size
+ self._wintype = wintype
+ self._function = function
+ self._fscaling = 0
+ self._mscaling = 1
+ self._lowbound = 0
+ self._highbound = 0.5
+ self._width = 500
+ self._height = 400
+ self._gain = 1
+ self._in_fader = InputFader(input)
+ in_fader, size, wintype, lmax = convertArgsToLists(self._in_fader, size, wintype)
+ self._base_objs = [Spectrum_base(wrap(in_fader,i), wrap(size,i), wrap(wintype,i)) for i in range(lmax)]
+ if function == None:
+ self.view()
+ self._timer = Pattern(self.refreshView, 0.05).play()
+
+ def setInput(self, x, fadetime=0.05):
+ """
+ Replace the `input` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New signal to process.
+ fadetime : float, optional
+ Crossfade time between old and new input. Default to 0.05.
+
+ """
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ def setSize(self, x):
+ """
+ Replace the `size` attribute.
+
+ :Args:
+
+ x : int
+ new `size` attribute.
+
+ """
+ self._size = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setSize(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setWinType(self, x):
+ """
+ Replace the `wintype` attribute.
+
+ :Args:
+
+ x : int
+ new `wintype` attribute.
+
+ """
+ self._wintype = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setWinType(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setFunction(self, function):
+ """
+ Sets the function to be called to retrieve the analysis data.
+
+ :Args:
+
+ function : python callable
+ The function called by the internal timer to retrieve the
+ analysis data. The function must be created with one argument
+ and will receive the data as a list of lists (one list per channel).
+
+ """
+ self._function = function
+
+ def poll(self, active):
+ """
+ Turns on and off the analysis polling.
+
+ :Args:
+
+ active : boolean
+ If True, starts the analysis polling, False to stop it.
+ defaults to True.
+
+ """
+ if active:
+ self._timer.play()
+ else:
+ self._timer.stop()
+
+ def polltime(self, time):
+ """
+ Sets the polling time in seconds.
+
+ :Args:
+
+ time : float
+ Adjusts the frequency of the internal timer used to
+ retrieve the current analysis frame. defaults to 0.05.
+
+ """
+ self._timer.time = time
+
+ def setLowbound(self, x):
+ """
+ Sets the lower frequency, as multiplier of sr, returned by the analysis.
+
+ Returns the real low frequency en Hz.
+
+ :Args:
+
+ x : float {0 <= x <= 0.5}
+ new `lowbound` attribute.
+
+ """
+ self._lowbound = x
+ x, lmax = convertArgsToLists(x)
+ tmp = [obj.setLowbound(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ return tmp[0]
+
+ def setHighbound(self, x):
+ """
+ Sets the higher frequency, as multiplier of sr, returned by the analysis.
+
+ Returns the real high frequency en Hz.
+
+ :Args:
+
+ x : float {0 <= x <= 0.5}
+ new `highbound` attribute.
+
+ """
+ self._highbound = x
+ x, lmax = convertArgsToLists(x)
+ tmp = [obj.setHighbound(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ return tmp[0]
+
+ def getLowfreq(self):
+ """
+ Returns the current lower frequency, in Hz, used by the analysis.
+
+ """
+
+ return self._base_objs[0].getLowfreq()
+
+ def getHighfreq(self):
+ """
+ Returns the current higher frequency, in Hz, used by the analysis.
+
+ """
+ return self._base_objs[0].getHighfreq()
+
+ def setWidth(self, x):
+ """
+ Sets the width, in pixels, of the current display.
+
+ Used internally to build the list of points to draw.
+
+ :Args:
+
+ x : int
+ new `width` attribute.
+
+ """
+ self._width = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setWidth(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setHeight(self, x):
+ """
+ Sets the height, in pixels, of the current display.
+
+ Used internally to build the list of points to draw.
+
+ :Args:
+
+ x : int
+ new `height` attribute.
+
+ """
+ self._height = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setHeight(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setFscaling(self, x):
+ """
+ Sets the frequency display to linear or logarithmic.
+
+ :Args:
+
+ x : boolean
+ If True, the frequency display is logarithmic. False turns
+ it back to linear. Defaults to False.
+
+ """
+ self._fscaling = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setFscaling(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ if self.viewFrame != None:
+ self.viewFrame.setFscaling(self._fscaling)
+
+ def setMscaling(self, x):
+ """
+ Sets the magnitude display to linear or logarithmic.
+
+ :Args:
+
+ x : boolean
+ If True, the magnitude display is logarithmic (which means in dB).
+ False turns it back to linear. Defaults to True.
+
+ """
+ self._mscaling = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setMscaling(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ if self.viewFrame != None:
+ self.viewFrame.setMscaling(self._mscaling)
+
+ def getFscaling(self):
+ """
+ Returns the scaling of the frequency display.
+
+ Returns True for logarithmic or False for linear.
+
+ """
+ return self._fscaling
+
+ def getMscaling(self):
+ """
+ Returns the scaling of the magnitude display.
+
+ Returns True for logarithmic or False for linear.
+
+ """
+ return self._mscaling
+
+ def setGain(self, x):
+ """
+ Set the gain of the analysis data. For drawing purpose.
+
+ :Args:
+
+ x : float
+ new `gain` attribute, as linear values.
+
+ """
+ self._gain = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setGain(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def view(self, title="Spectrum", wxnoserver=False):
+ """
+ Opens a window showing the result of the analysis.
+
+ :Args:
+
+ title : string, optional
+ Window title. Defaults to "Spectrum".
+ wxnoserver : boolean, optional
+ With wxPython graphical toolkit, if True, tells the
+ interpreter that there will be no server window.
+
+ If `wxnoserver` is set to True, the interpreter will not wait for
+ the server GUI before showing the controller window.
+
+ """
+ createSpectrumWindow(self, title, wxnoserver)
+
+ def _setViewFrame(self, frame):
+ self.viewFrame = frame
+
+ def refreshView(self):
+ """
+ Updates the graphical display of the spectrum.
+
+ Called automatically by the internal timer.
+
+ """
+ self.points = [obj.display() for obj in self._base_objs]
+ if self._function != None:
+ self._function(self.points)
+ if self.viewFrame != None:
+ self.viewFrame.update(self.points)
+
+
+ @property
+ def input(self):
+ """PyoObject. Input signal to process."""
+ return self._input
+ @input.setter
+ def input(self, x): self.setInput(x)
+
+ @property
+ def size(self):
+ """int. FFT size."""
+ return self._size
+ @size.setter
+ def size(self, x): self.setSize(x)
+
+ @property
+ def wintype(self):
+ """int. Windowing method."""
+ return self._wintype
+ @wintype.setter
+ def wintype(self, x): self.setWinType(x)
+
+ @property
+ def gain(self):
+ """float. Sets the gain of the analysis data."""
+ return self._gain
+ @gain.setter
+ def gain(self, x): self.setGain(x)
+
+ @property
+ def lowbound(self):
+ """float. Lowest frequency (multiplier of sr) to output."""
+ return self._lowbound
+ @lowbound.setter
+ def lowbound(self, x): self.setLowbound(x)
+
+ @property
+ def highbound(self):
+ """float. Highest frequency (multiplier of sr) to output."""
+ return self._highbound
+ @highbound.setter
+ def highbound(self, x): self.setHighbound(x)
+
+ @property
+ def width(self):
+ """int. Width, in pixels, of the current display."""
+ return self._width
+ @width.setter
+ def width(self, x): self.setWidth(x)
+
+ @property
+ def height(self):
+ """int. Height, in pixels, of the current display."""
+ return self._height
+ @height.setter
+ def height(self, x): self.setHeight(x)
+
+ @property
+ def fscaling(self):
+ """boolean. Scaling of the frequency display."""
+ return self._fscaling
+ @fscaling.setter
+ def fscaling(self, x): self.setFscaling(x)
+
+ @property
+ def mscaling(self):
+ """boolean. Scaling of the magnitude display."""
+ return self._mscaling
+ @mscaling.setter
+ def mscaling(self, x): self.setMscaling(x)
+
+class Scope(PyoObject):
+ """
+ Oscilloscope - audio waveform display.
+
+ Oscilloscopes are used to observe the change of an electrical
+ signal over time.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal to process.
+ length : float, optional
+ Length, in seconds, of the displayed window. Can't be a list.
+ Defaults to 0.05.
+ gain : float, optional
+ Linear gain applied to the signal to be displayed.
+ Can't be a list. Defaults to 0.67.
+
+ .. note::
+
+ Scope has no `out` method.
+
+ Scope has no `mul` and `add` attributes.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> a = Sine([100,100.2], mul=0.7)
+ >>> b = Noise(0.1)
+ >>> scope = Scope(a+b)
+
+ """
+ def __init__(self, input, length=0.05, gain=0.67):
+ PyoObject.__init__(self)
+ self.points = None
+ self.viewFrame = None
+ self._input = input
+ self._length = length
+ self._gain = gain
+ self._width = 500
+ self._height = 400
+ self._in_fader = InputFader(input)
+ in_fader, lmax = convertArgsToLists(self._in_fader)
+ self._base_objs = [Scope_base(wrap(in_fader,i), length) for i in range(lmax)]
+ self.view()
+ self._timer = Pattern(self.refreshView, length).play()
+
+ def setInput(self, x, fadetime=0.05):
+ """
+ Replace the `input` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New signal to process.
+ fadetime : float, optional
+ Crossfade time between old and new input. Default to 0.05.
+
+ """
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ def setLength(self, x):
+ """
+ Replace the `length` attribute.
+
+ :Args:
+
+ x : float
+ new `length` attribute.
+
+ """
+ self._length = x
+ self._timer.time = x
+ [obj.setLength(x) for obj in self._base_objs]
+
+ def setGain(self, x):
+ """
+ Set the gain boost applied to the analysed data. For drawing purpose.
+
+ :Args:
+
+ x : float
+ new `gain` attribute, as linear values.
+
+ """
+ self._gain = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setGain(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def poll(self, active):
+ """
+ Turns on and off the analysis polling.
+
+ :Args:
+
+ active : boolean
+ If True, starts the analysis polling, False to stop it.
+ defaults to True.
+
+ """
+ if active:
+ self._timer.play()
+ else:
+ self._timer.stop()
+
+ def setWidth(self, x):
+ """
+ Gives the width of the display to the analyzer.
+
+ The analyzer needs this value to construct the list
+ of points to draw on the display.
+
+ :Args:
+
+ x : int
+ Width of the display in pixel value. The default
+ width is 500.
+
+ """
+ self._width = x
+ [obj.setWidth(x) for obj in self._base_objs]
+
+ def setHeight(self, x):
+ """
+ Gives the height of the display to the analyzer.
+
+ The analyzer needs this value to construct the list
+ of points to draw on the display.
+
+ :Args:
+
+ x : int
+ Height of the display in pixel value. The default
+ height is 400.
+
+ """
+ self._height = x
+ [obj.setHeight(x) for obj in self._base_objs]
+
+ def view(self, title="Scope", wxnoserver=False):
+ """
+ Opens a window showing the result of the analysis.
+
+ :Args:
+
+ title : string, optional
+ Window title. Defaults to "Spectrum".
+ wxnoserver : boolean, optional
+ With wxPython graphical toolkit, if True, tells the
+ interpreter that there will be no server window.
+
+ If `wxnoserver` is set to True, the interpreter will not wait for
+ the server GUI before showing the controller window.
+
+ """
+ createScopeWindow(self, title, wxnoserver)
+
+ def _setViewFrame(self, frame):
+ self.viewFrame = frame
+
+ def refreshView(self):
+ """
+ Updates the graphical display of the scope.
+
+ Called automatically by the internal timer.
+
+ """
+ self.points = [obj.display() for obj in self._base_objs]
+ if self.viewFrame != None:
+ self.viewFrame.update(self.points)
+
+
+ @property
+ def input(self):
+ """PyoObject. Input signal to process."""
+ return self._input
+ @input.setter
+ def input(self, x): self.setInput(x)
+
+ @property
+ def length(self):
+ """float. Window length."""
+ return self._length
+ @length.setter
+ def length(self, x): self.setLength(x)
+
+ @property
+ def gain(self):
+ """float. Sets the gain of the analysis data."""
+ return self._gain
+ @gain.setter
+ def gain(self, x): self.setGain(x)
+
+class PeakAmp(PyoObject):
+ """
+ Peak amplitude follower.
+
+ Output signal is the continuous peak amplitude of an input signal.
+ A new peaking value is computed every buffer size. If `function`
+ argument is not None, it should be a function that will be called
+ every buffer size with a variable-length argument list containing
+ the peaking values of all object's streams. Useful for meter drawing.
+ Function definition must look like this:
+
+ >>> def getValues(*args)
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal to process.
+ function : callable, optional
+ Function that will be called with amplitude values in arguments.
+ Default to None.
+
+ .. note::
+
+ The out() method is bypassed. PeakAmp's signal can not be sent to
+ audio outs.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> sf = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.4).out()
+ >>> amp = PeakAmp(sf)
+ >>> n = Noise(mul=Port(amp)).out(1)
+
+ """
+ def __init__(self, input, function=None, mul=1, add=0):
+ PyoObject.__init__(self, mul, add)
+ self._input = input
+ if callable(function):
+ self._function = function
+ else:
+ self._function = None
+ self._in_fader = InputFader(input)
+ in_fader, mul, add, lmax = convertArgsToLists(self._in_fader, mul, add)
+ self._base_objs = [PeakAmp_base(wrap(in_fader,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+ sr = self._base_objs[0].getServer().getSamplingRate()
+ bs = self._base_objs[0].getServer().getBufferSize()
+ self._timer = Pattern(self._buildList, bs/sr).play()
+
+ def setInput(self, x, fadetime=0.05):
+ """
+ Replace the `input` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New signal to process.
+ fadetime : float, optional
+ Crossfade time between old and new input. Default to 0.05.
+
+ """
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ def setFunction(self, x):
+ """
+ Replace the `function` attribute.
+
+ :Args:
+
+ x : callable
+ New function to call with amplitude values in arguments.
+
+ """
+ if callable(x):
+ self._function = x
+
+ def out(self, chnl=0, inc=1, dur=0, delay=0):
+ return self.play(dur, delay)
+
+ def _buildList(self):
+ if self._function != None:
+ values = [obj.getValue() for obj in self._base_objs]
+ self._function(*values)
+
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = []
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+ @property
+ def input(self):
+ """PyoObject. Input signal to process."""
+ return self._input
+ @input.setter
+ def input(self, x): self.setInput(x)
+
+ @property
+ def function(self):
+ """PyoObject. function signal to process."""
+ return self._function
+ @function.setter
+ def function(self, x): self.setFunction(x)
diff --git a/pyolib/arithmetic.py b/pyolib/arithmetic.py
index bf10013..9bc37bc 100644
--- a/pyolib/arithmetic.py
+++ b/pyolib/arithmetic.py
@@ -673,3 +673,53 @@ class Round(PyoObject):
return self._input
@input.setter
def input(self, x): self.setInput(x)
+
+class Tanh(PyoObject):
+ """
+ Performs a hyperbolic tangent function on audio signal.
+
+ Returns the hyperbolic tangent of audio signal as input.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal, angle in radians.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> import math
+ >>> a = Phasor(250, mul=math.pi*2)
+ >>> b = Tanh(Sin(a, mul=10), mul=0.3).mix(2).out()
+
+ """
+
+ def __init__(self, input, mul=1, add=0):
+ PyoObject.__init__(self, mul, add)
+ self._input = input
+ self._in_fader = InputFader(input)
+ in_fader, mul, add, lmax = convertArgsToLists(self._in_fader, mul, add)
+ self._base_objs = [M_Tanh_base(wrap(in_fader,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+
+ def setInput(self, x, fadetime=0.05):
+ """
+ Replace the `input` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New signal to process.
+ fadetime : float, optional
+ Crossfade time between old and new input. Default to 0.05.
+
+ """
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ @property
+ def input(self):
+ """PyoObject. Input signal to process."""
+ return self._input
+ @input.setter
+ def input(self, x): self.setInput(x)
diff --git a/pyolib/controls.py b/pyolib/controls.py
index d993bbc..a3682bd 100644
--- a/pyolib/controls.py
+++ b/pyolib/controls.py
@@ -129,6 +129,12 @@ class Fader(PyoObject):
x, lmax = convertArgsToLists(x)
[obj.setDur(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0, 10., 'lin', 'fadein', self._fadein, dataOnly=True),
+ SLMap(0, 10., 'lin', 'fadeout', self._fadeout, dataOnly=True),
+ SLMap(0, 20., 'lin', 'dur', self._dur, dataOnly=True)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
@property
def fadein(self):
"""float. Rising time of the envelope in seconds."""
@@ -186,8 +192,6 @@ class Adsr(PyoObject):
The play() method starts the envelope.
The stop() calls the envelope's release phase if `dur` = 0.
-
- Shape of a classical Adsr:
>>> s = Server().boot()
>>> s.start()
@@ -281,6 +285,14 @@ class Adsr(PyoObject):
x, lmax = convertArgsToLists(x)
[obj.setDur(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0, 5, 'lin', 'attack', self._attack, dataOnly=True),
+ SLMap(0, 5, 'lin', 'decay', self._decay, dataOnly=True),
+ SLMap(0, 1, 'lin', 'sustain', self._sustain, dataOnly=True),
+ SLMap(0, 10, 'lin', 'release', self._release, dataOnly=True),
+ SLMap(0, 20., 'lin', 'dur', self._dur, dataOnly=True)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
@property
def attack(self):
"""float. Duration of the attack phase in seconds."""
@@ -749,6 +761,10 @@ class SigTo(PyoObject):
x, lmax = convertArgsToLists(x)
[obj.setTime(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0, 10, 'lin', 'time', self._time, dataOnly=True)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
@property
def value(self):
"""float or PyoObject. Numerical value to convert."""
diff --git a/pyolib/dynamics.py b/pyolib/dynamics.py
index 9e6abd8..f4d6a88 100644
--- a/pyolib/dynamics.py
+++ b/pyolib/dynamics.py
@@ -511,6 +511,8 @@ class Compress(PyoObject):
SLMap(1., 10., 'lin', 'ratio', self._ratio),
SLMap(0.001, .3, 'lin', 'risetime', self._risetime),
SLMap(0.001, .3, 'lin', 'falltime', self._falltime),
+ SLMap(0, 25, 'lin', 'lookahead', self._lookahead, dataOnly=True),
+ SLMap(0, 1, 'lin', 'knee', self._knee, dataOnly=True),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@@ -690,6 +692,7 @@ class Gate(PyoObject):
self._map_list = [SLMap(-100., 0., 'lin', 'thresh', self._thresh),
SLMap(0.0001, .3, 'lin', 'risetime', self._risetime),
SLMap(0.0001, .3, 'lin', 'falltime', self._falltime),
+ SLMap(0, 25, 'lin', 'lookahead', self._lookahead, dataOnly=True),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
diff --git a/pyolib/effects.py b/pyolib/effects.py
index 09024ed..cfde21c 100644
--- a/pyolib/effects.py
+++ b/pyolib/effects.py
@@ -150,6 +150,17 @@ class Delay(PyoObject):
Maximum delay length in seconds. Available only at initialization.
Defaults to 1.
+ .. note::
+
+ The minimum delay time allowed with Delay is one sample. It can be computed
+ with :
+
+ onesamp = 1.0 / s.getSamplingRate()
+
+ .. seealso::
+
+ :py:class:`SDelay`, :py:class:`Waveguide`
+
>>> s = Server().boot()
>>> s.start()
>>> a = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.3).mix(2).out()
@@ -259,6 +270,10 @@ class SDelay(PyoObject):
Maximum delay length in seconds. Available only at initialization.
Defaults to 1.
+ .. seealso::
+
+ :py:class:`Delay`, :py:class:`Delay1`
+
>>> s = Server().boot()
>>> s.start()
>>> srPeriod = 1. / s.getSamplingRate()
@@ -313,7 +328,7 @@ class SDelay(PyoObject):
[obj.reset() for obj in self._base_objs]
def ctrl(self, map_list=None, title=None, wxnoserver=False):
- self._map_list = [SLMap(0.001, self._maxdelay, 'log', 'delay', self._delay),
+ self._map_list = [SLMap(0.0001, self._maxdelay, 'log', 'delay', self._delay),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@@ -1166,6 +1181,7 @@ class Harmonizer(PyoObject):
def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(-24.0, 24.0, 'lin', 'transpo', self._transpo),
SLMap(0., 1., 'lin', 'feedback', self._feedback),
+ SLMap(0.001, 1, 'log', 'winsize', self._winsize, dataOnly=True),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@@ -1247,3 +1263,373 @@ class Delay1(PyoObject):
return self._input
@input.setter
def input(self, x): self.setInput(x)
+
+class STRev(PyoObject):
+ """
+ Stereo reverb.
+
+ Stereo reverb based on WGVerb (8 delay line FDN reverb). A mono
+ input will produce two audio streams, left and right channels.
+ Therefore, a stereo input will produce four audio streams, left
+ and right channels for each input channel. Position of input
+ streams can be set with the `inpos` argument. To achieve a stereo
+ reverb, delay line lengths are slightly differents on both channels,
+ but also, pre-delays length and filter cutoff of both channels will
+ be affected to reflect the input position.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal to process.
+ inpos : float or PyoObject, optional
+ Position of the source, between 0 and 1. 0 means fully left
+ and 1 means fully right. Defaults to 0.5.
+ revtime : float or PyoObject, optional
+ Duration, in seconds, of the reverberated sound, defined as
+ the time needed to the sound to drop 40 dB below its peak.
+ Defaults to 1.
+ cutoff : float or PyoObject, optional
+ cutoff frequency, in Hz, of a first order lowpass filters in the
+ feedback loop of delay lines. Defaults to 5000.
+ bal : float or PyoObject, optional
+ Balance between wet and dry signal, between 0 and 1. 0 means no
+ reverb. Defaults to 0.5.
+ roomSize : float, optional
+ Delay line length scaler, between 0.25 and 4. Values higher than
+ 1 make the delay lines longer and simulate larger rooms. Defaults to 1.
+ firstRefGain : float, optional
+ Gain, in dB, of the first reflexions of the room. Defaults to -3.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> t = SndTable(SNDS_PATH + "/transparent.aif")
+ >>> sf = Looper(t, dur=t.getDur()*2, xfade=0, mul=0.5)
+ >>> rev = STRev(sf, inpos=0.25, revtime=2, cutoff=5000, bal=0.25, roomSize=1).out()
+
+ """
+ def __init__(self, input, inpos=0.5, revtime=1, cutoff=5000, bal=.5, roomSize=1, firstRefGain=-3, mul=1, add=0):
+ PyoObject.__init__(self, mul, add)
+ self._input = input
+ self._inpos = inpos
+ self._revtime = revtime
+ self._cutoff = cutoff
+ self._bal = bal
+ self._roomSize = roomSize
+ self._firstRefGain = firstRefGain
+ self._in_fader = InputFader(input)
+ in_fader, inpos, revtime, cutoff, bal, roomSize, firstRefGain, mul, add, lmax = convertArgsToLists(self._in_fader, inpos, revtime, cutoff, bal, roomSize, firstRefGain, mul, add)
+ self._base_players = [STReverb_base(wrap(in_fader,i), wrap(inpos,i), wrap(revtime,i), wrap(cutoff,i), wrap(bal,i), wrap(roomSize,i), wrap(firstRefGain,i)) for i in range(lmax)]
+ self._base_objs = [STRev_base(wrap(self._base_players,i), j, wrap(mul,i), wrap(add,i)) for i in range(lmax) for j in range(2)]
+
+ def setInput(self, x, fadetime=0.05):
+ """
+ Replace the `input` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New signal to process.
+ fadetime : float, optional
+ Crossfade time between old and new input. Defaults to 0.05.
+
+ """
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ def setInpos(self, x):
+ """
+ Replace the `inpos` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ New `inpos` attribute.
+
+ """
+ self._inpos = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setInpos(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setRevtime(self, x):
+ """
+ Replace the `revtime` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ New `revtime` attribute.
+
+ """
+ self._revtime = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setRevtime(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setCutoff(self, x):
+ """
+ Replace the `cutoff` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ New `cutoff` attribute.
+
+ """
+ self._cutoff = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setCutoff(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setBal(self, x):
+ """
+ Replace the `bal` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ New `bal` attribute.
+
+ """
+ self._bal = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setMix(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setRoomSize(self, x):
+ """
+ Set the room size scaler, between 0.25 and 4.
+
+ :Args:
+
+ x : float
+ Room size scaler, between 0.25 and 4.0.
+
+ """
+ self._roomSize = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setRoomSize(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setFirstRefGain(self, x):
+ """
+ Set the gain of the first reflexions.
+
+ :Args:
+
+ x : float
+ Gain, in dB, of the first reflexions.
+
+ """
+ self._firstRefGain = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setFirstRefGain(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0., 1., 'lin', 'inpos', self._inpos),
+ SLMap(0.01, 120., 'log', 'revtime', self._revtime),
+ SLMap(500., 15000., 'log', 'cutoff', self._cutoff),
+ SLMap(0., 1., 'lin', 'bal', self._bal),
+ SLMap(0.25, 4., 'lin', 'roomSize', self._roomSize, dataOnly=True),
+ SLMap(-48, 12, 'lin', 'firstRefGain', self._firstRefGain, dataOnly=True),
+ SLMapMul(self._mul)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+ @property
+ def input(self):
+ """PyoObject. Input signal to process."""
+ return self._input
+ @input.setter
+ def input(self, x): self.setInput(x)
+
+ @property
+ def inpos(self):
+ """float or PyoObject. Position of the source."""
+ return self._inpos
+ @inpos.setter
+ def inpos(self, x): self.setInpos(x)
+
+ @property
+ def revtime(self):
+ """float or PyoObject. Room size."""
+ return self._revtime
+ @revtime.setter
+ def revtime(self, x): self.setRevtime(x)
+
+ @property
+ def cutoff(self):
+ """float or PyoObject. High frequency damping."""
+ return self._cutoff
+ @cutoff.setter
+ def cutoff(self, x): self.setCutoff(x)
+
+ @property
+ def bal(self):
+ """float or PyoObject. Balance between wet and dry signal."""
+ return self._bal
+ @bal.setter
+ def bal(self, x): self.setBal(x)
+
+ @property
+ def roomSize(self):
+ """float. Room size scaler, between 0.25 and 4.0."""
+ return self._roomSize
+ @roomSize.setter
+ def roomSize(self, x): self.setRoomSize(x)
+
+ @property
+ def firstRefGain(self):
+ """float. Gain, in dB, of the first reflexions."""
+ return self._firstRefGain
+ @firstRefGain.setter
+ def firstRefGain(self, x): self.setFirstRefGain(x)
+
+class SmoothDelay(PyoObject):
+ """
+ Artifact free sweepable recursive delay.
+
+ SmoothDelay implements a delay line that does not produce
+ clicks or pitch shifting when the delay time is changing.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal to delayed.
+ delay : float or PyoObject, optional
+ Delay time in seconds. Defaults to 0.25.
+ feedback : float or PyoObject, optional
+ Amount of output signal sent back into the delay line.
+ Defaults to 0.
+ crossfade : float, optional
+ Crossfade time, in seconds, between overlaped readers.
+ Defaults to 0.05.
+ maxdelay : float, optional
+ Maximum delay length in seconds. Available only at initialization.
+ Defaults to 1.
+
+ .. note::
+
+ The minimum delay time allowed with SmoothDelay is one sample.
+ It can be computed with :
+
+ onesamp = 1.0 / s.getSamplingRate()
+
+ .. seealso::
+
+ :py:class:`Delay`, :py:class:`Waveguide`
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> sf = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=0.3).mix(2).out()
+ >>> lf = Sine(freq=0.1, mul=0.24, add=0.25)
+ >>> sd = SmoothDelay(sf, delay=lf, feedback=0.5, crossfade=0.05, mul=0.7).out()
+
+ """
+ def __init__(self, input, delay=0.25, feedback=0, crossfade=0.05, maxdelay=1, mul=1, add=0):
+ PyoObject.__init__(self, mul, add)
+ self._input = input
+ self._delay = delay
+ self._feedback = feedback
+ self._crossfade = crossfade
+ self._maxdelay = maxdelay
+ self._in_fader = InputFader(input)
+ in_fader, delay, feedback, crossfade, maxdelay, mul, add, lmax = convertArgsToLists(self._in_fader, delay, feedback, crossfade, maxdelay, mul, add)
+ self._base_objs = [SmoothDelay_base(wrap(in_fader,i), wrap(delay,i), wrap(feedback,i), wrap(crossfade,i), wrap(maxdelay,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+
+ def setInput(self, x, fadetime=0.05):
+ """
+ Replace the `input` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New signal to delayed.
+ fadetime : float, optional
+ Crossfade time between old and new input. Defaults to 0.05.
+
+ """
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ def setDelay(self, x):
+ """
+ Replace the `delay` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ New `delay` attribute.
+
+ """
+ self._delay = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setDelay(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setFeedback(self, x):
+ """
+ Replace the `feedback` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ New `feedback` attribute.
+
+ """
+ self._feedback = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setFeedback(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setCrossfade(self, x):
+ """
+ Replace the `crossfade` attribute.
+
+ :Args:
+
+ x : float
+ New `crossfade` attribute.
+
+ """
+ self._crossfade = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setCrossfade(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def reset(self):
+ """
+ Reset the memory buffer to zeros.
+
+ """
+ [obj.reset() for obj in self._base_objs]
+
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0.001, self._maxdelay, 'log', 'delay', self._delay),
+ SLMap(0., 1., 'lin', 'feedback', self._feedback),
+ SLMap(0., self._maxdelay, 'lin', 'crossfade', self._crossfade, dataOnly=True),
+ SLMapMul(self._mul)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+ @property
+ def input(self):
+ """PyoObject. Input signal to delayed."""
+ return self._input
+ @input.setter
+ def input(self, x): self.setInput(x)
+
+ @property
+ def delay(self):
+ """float or PyoObject. Delay time in seconds."""
+ return self._delay
+ @delay.setter
+ def delay(self, x): self.setDelay(x)
+
+ @property
+ def feedback(self):
+ """float or PyoObject. Amount of output signal sent back into the delay line."""
+ return self._feedback
+ @feedback.setter
+ def feedback(self, x): self.setFeedback(x)
+
+ @property
+ def crossfade(self):
+ """float. Crossfade time, in seconds, between overlaps."""
+ return self._crossfade
+ @crossfade.setter
+ def crossfade(self, x): self.setCrossfade(x)
diff --git a/pyolib/filters.py b/pyolib/filters.py
index 1feb485..5442a14 100644
--- a/pyolib/filters.py
+++ b/pyolib/filters.py
@@ -141,7 +141,9 @@ class Biquad(PyoObject):
[obj.setType(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
def ctrl(self, map_list=None, title=None, wxnoserver=False):
- self._map_list = [SLMapFreq(self._freq), SLMapQ(self._q), SLMapMul(self._mul)]
+ self._map_list = [SLMapFreq(self._freq), SLMapQ(self._q),
+ SLMap(0, 4, 'lin', 'type', self._type, res="int", dataOnly=True),
+ SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
@@ -297,7 +299,9 @@ class Biquadx(PyoObject):
[obj.setStages(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
def ctrl(self, map_list=None, title=None, wxnoserver=False):
- self._map_list = [SLMapFreq(self._freq), SLMapQ(self._q), SLMapMul(self._mul)]
+ self._map_list = [SLMapFreq(self._freq), SLMapQ(self._q),
+ SLMap(0, 4, 'lin', 'type', self._type, res="int", dataOnly=True),
+ SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
@@ -684,6 +688,7 @@ class EQ(PyoObject):
def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMapFreq(self._freq), SLMapQ(self._q),
SLMap(-40.0, 40.0, "lin", "boost", self._boost),
+ SLMap(0, 2, 'lin', 'type', self._type, res="int", dataOnly=True),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@@ -1300,8 +1305,8 @@ class Hilbert(PyoObject):
Real and imaginary parts are two separated set of streams.
The user should call :
- Hilbert['real'] to retrieve the real part.
- Hilbert['imag'] to retrieve the imaginary part.
+ | Hilbert['real'] to retrieve the real part.
+ | Hilbert['imag'] to retrieve the imaginary part.
>>> s = Server().boot()
>>> s.start()
@@ -1946,6 +1951,7 @@ class Vocoder(PyoObject):
SLMap(0.25, 2, "lin", "spread", self._spread),
SLMap(0.5, 200, "log", "q", self._q),
SLMap(0, 1, "lin", "slope", self._slope),
+ SLMap(2, 64, 'lin', 'stages', self._stages, res="int", dataOnly=True),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@@ -2125,7 +2131,8 @@ class IRWinSinc(PyoObject):
def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMapFreq(self._freq),
- SLMap(20., 10000., "log", "bw", self._bw)]
+ SLMap(20., 10000., "log", "bw", self._bw),
+ SLMap(0, 3, 'lin', 'type', self._type, res="int", dataOnly=True)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
@@ -2352,7 +2359,8 @@ class IRPulse(PyoObject):
def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMapFreq(self._freq),
- SLMap(20., 10000., "log", "bw", self._bw)]
+ SLMap(20., 10000., "log", "bw", self._bw),
+ SLMap(0, 3, 'lin', 'type', self._type, res="int", dataOnly=True)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
@@ -2738,7 +2746,8 @@ class Average(PyoObject):
[obj.setSize(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
def ctrl(self, map_list=None, title=None, wxnoserver=False):
- self._map_list = [SLMapMul(self._mul)]
+ self._map_list = [SLMap(2, 256, 'lin', 'size', self._size, res="int", dataOnly=True),
+ SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
@@ -3361,3 +3370,109 @@ class ButBR(PyoObject):
return self._q
@q.setter
def q(self, x): self.setQ(x)
+
+class ComplexRes(PyoObject):
+ """
+ Complex one-pole resonator filter.
+
+ ComplexRes implements a resonator derived from a complex
+ multiplication, which is very similar to a digital filter.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal to process.
+ freq : float or PyoObject, optional
+ Center frequency of the filter. Defaults to 1000.
+ decay : float or PyoObject, optional
+ Decay time, in seconds, for the filter's response.
+ Defaults to 0.25.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> env = HannTable()
+ >>> trigs = Metro(.2, poly=4).play()
+ >>> amp = TrigEnv(trigs, table=env, dur=0.005, mul=2)
+ >>> im = Noise(mul=amp)
+ >>> res = ComplexRes(im, freq=[950,530,780,1490], decay=1).out()
+
+ """
+ def __init__(self, input, freq=1000, decay=.25, mul=1, add=0):
+ PyoObject.__init__(self, mul, add)
+ self._input = input
+ self._freq = freq
+ self._decay = decay
+ self._in_fader = InputFader(input)
+ in_fader, freq, decay, mul, add, lmax = convertArgsToLists(self._in_fader, freq, decay, mul, add)
+ self._base_objs = [ComplexRes_base(wrap(in_fader,i), wrap(freq,i), wrap(decay,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+
+ def setInput(self, x, fadetime=0.05):
+ """
+ Replace the `input` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New signal to process.
+ fadetime : float, optional
+ Crossfade time between old and new input. Defaults to 0.05.
+
+ """
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ def setFreq(self, x):
+ """
+ Replace the `freq` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ New `freq` attribute.
+
+ """
+ self._freq = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setFreq(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setDecay(self, x):
+ """
+ Replace the `decay` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ New `decay` attribute.
+
+ """
+ self._decay = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setDecay(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMapFreq(self._freq), SLMap(0.0001, 10, "log", "decay", self._decay),
+ SLMapMul(self._mul)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+ @property
+ def input(self):
+ """PyoObject. Input signal to filter."""
+ return self._input
+ @input.setter
+ def input(self, x): self.setInput(x)
+
+ @property
+ def freq(self):
+ """float or PyoObject. Center frequency of the filter."""
+ return self._freq
+ @freq.setter
+ def freq(self, x): self.setFreq(x)
+
+ @property
+ def decay(self):
+ """float or PyoObject. Decay time of the filter's response."""
+ return self._decay
+ @decay.setter
+ def decay(self, x): self.setDecay(x)
diff --git a/pyolib/fourier.py b/pyolib/fourier.py
index d48b223..9ab0667 100644
--- a/pyolib/fourier.py
+++ b/pyolib/fourier.py
@@ -30,8 +30,6 @@ along with pyo. If not, see <http://www.gnu.org/licenses/>.
"""
from _core import *
from _maps import *
-from _widgets import createSpectrumWindow
-from pattern import Pattern
class FFT(PyoObject):
"""
@@ -84,9 +82,9 @@ class FFT(PyoObject):
Real, imaginary and bin_number parts are three separated set
of audio streams. The user should call :
- FFT['real'] to retrieve the real part.
- FFT['imag'] to retrieve the imaginary part.
- FFT['bin'] to retrieve the bin number part.
+ | FFT['real'] to retrieve the real part.
+ | FFT['imag'] to retrieve the imaginary part.
+ | FFT['bin'] to retrieve the bin number part.
>>> s = Server().boot()
>>> s.start()
@@ -451,8 +449,8 @@ class CarToPol(PyoObject):
Polar coordinates can be retrieve by calling :
- CarToPol['mag'] to retrieve the magnitude part.
- CarToPol['ang'] to retrieve the angle part.
+ | CarToPol['mag'] to retrieve the magnitude part.
+ | CarToPol['ang'] to retrieve the angle part.
CarToPol has no `out` method. Signal must be converted back to time domain,
with IFFT, before being sent to output.
@@ -594,8 +592,8 @@ class PolToCar(PyoObject):
Cartesians coordinates can be retrieve by calling :
- PolToCar['real'] to retrieve the real part.
- CarToPol['imag'] to retrieve the imaginary part.
+ | PolToCar['real'] to retrieve the real part.
+ | CarToPol['imag'] to retrieve the imaginary part.
PolToCar has no `out` method. Signal must be converted back to time domain,
with IFFT, before being sent to output.
@@ -1237,410 +1235,3 @@ class CvlVerb(PyoObject):
return self._bal
@bal.setter
def bal(self, x): self.setBal(x)
-
-class Spectrum(PyoObject):
- """
- Spectrum analyzer and display.
-
- Spectrum measures the magnitude of an input signal versus frequency
- within a user defined range. It can show both magnitude and frequency
- on linear or logarithmic scale.
-
- :Parent: :py:class:`PyoObject`
-
- :Args:
-
- input : PyoObject
- Input signal to process.
- size : int {pow-of-two > 4}, optional
- FFT size. Must be a power of two greater than 4.
- The FFT size is the number of samples used in each
- analysis frame. Defaults to 1024.
- wintype : int, optional
- Shape of the envelope used to filter each input frame.
- Possible shapes are :
- 0. rectangular (no windowing)
- 1. Hamming
- 2. Hanning
- 3. Bartlett (triangular)
- 4. Blackman 3-term
- 5. Blackman-Harris 4-term
- 6. Blackman-Harris 7-term
- 7. Tuckey (alpha = 0.66)
- 8. Sine (half-sine window)
- function : python callable, optional
- If set, this function will be called with magnitudes (as
- list of lists, one list per channel). Useful if someone
- wants to save the analysis data into a text file.
- Defaults to None.
-
- .. note::
-
- Spectrum has no `out` method.
- Spectrum has no `mul` and `add` attributes.
-
- >>> s = Server().boot()
- >>> s.start()
- >>> a = SuperSaw(freq=[500,750], detune=0.6, bal=0.7, mul=0.5).out()
- >>> spec = Spectrum(a, size=1024)
-
- """
- def __init__(self, input, size=1024, wintype=2, function=None):
- PyoObject.__init__(self)
- self.points = None
- self.viewFrame = None
- self._input = input
- self._size = size
- self._wintype = wintype
- self._function = function
- self._fscaling = 0
- self._mscaling = 1
- self._lowbound = 0
- self._highbound = 0.5
- self._width = 500
- self._height = 400
- self._gain = 1
- self._in_fader = InputFader(input)
- in_fader, size, wintype, lmax = convertArgsToLists(self._in_fader, size, wintype)
- self._base_objs = [Spectrum_base(wrap(in_fader,i), wrap(size,i), wrap(wintype,i)) for i in range(lmax)]
- if function == None:
- self.view()
- self._timer = Pattern(self.refreshView, 0.05).play()
-
- def setInput(self, x, fadetime=0.05):
- """
- Replace the `input` attribute.
-
- :Args:
-
- x : PyoObject
- New signal to process.
- fadetime : float, optional
- Crossfade time between old and new input. Default to 0.05.
-
- """
- self._input = x
- self._in_fader.setInput(x, fadetime)
-
- def setSize(self, x):
- """
- Replace the `size` attribute.
-
- :Args:
-
- x : int
- new `size` attribute.
-
- """
- self._size = x
- x, lmax = convertArgsToLists(x)
- [obj.setSize(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-
- def setWinType(self, x):
- """
- Replace the `wintype` attribute.
-
- :Args:
-
- x : int
- new `wintype` attribute.
-
- """
- self._wintype = x
- x, lmax = convertArgsToLists(x)
- [obj.setWinType(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-
- def setFunction(self, function):
- """
- Sets the function to be called to retrieve the analysis data.
-
- :Args:
-
- function : python callable
- The function called by the internal timer to retrieve the
- analysis data. The function must be created with one argument
- and will receive the data as a list of lists (one list per channel).
-
- """
- self._function = function
-
- def poll(self, active):
- """
- Turns on and off the analysis polling.
-
- :Args:
-
- active : boolean
- If True, starts the analysis polling, False to stop it.
- defaults to True.
-
- """
- if active:
- self._timer.play()
- else:
- self._timer.stop()
-
- def polltime(self, time):
- """
- Sets the polling time in seconds.
-
- :Args:
-
- time : float
- Adjusts the frequency of the internal timer used to
- retrieve the current analysis frame. defaults to 0.05.
-
- """
- self._timer.time = time
-
- def setLowbound(self, x):
- """
- Sets the lower frequency, as multiplier of sr, returned by the analysis.
-
- Returns the real low frequency en Hz.
-
- :Args:
-
- x : float {0 <= x <= 0.5}
- new `lowbound` attribute.
-
- """
- self._lowbound = x
- x, lmax = convertArgsToLists(x)
- tmp = [obj.setLowbound(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
- return tmp[0]
-
- def setHighbound(self, x):
- """
- Sets the higher frequency, as multiplier of sr, returned by the analysis.
-
- Returns the real high frequency en Hz.
-
- :Args:
-
- x : float {0 <= x <= 0.5}
- new `highbound` attribute.
-
- """
- self._highbound = x
- x, lmax = convertArgsToLists(x)
- tmp = [obj.setHighbound(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
- return tmp[0]
-
- def getLowfreq(self):
- """
- Returns the current lower frequency, in Hz, used by the analysis.
-
- """
-
- return self._base_objs[0].getLowfreq()
-
- def getHighfreq(self):
- """
- Returns the current higher frequency, in Hz, used by the analysis.
-
- """
- return self._base_objs[0].getHighfreq()
-
- def setWidth(self, x):
- """
- Sets the width, in pixels, of the current display.
-
- Used internally to build the list of points to draw.
-
- :Args:
-
- x : int
- new `width` attribute.
-
- """
- self._width = x
- x, lmax = convertArgsToLists(x)
- [obj.setWidth(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-
- def setHeight(self, x):
- """
- Sets the height, in pixels, of the current display.
-
- Used internally to build the list of points to draw.
-
- :Args:
-
- x : int
- new `height` attribute.
-
- """
- self._height = x
- x, lmax = convertArgsToLists(x)
- [obj.setHeight(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-
- def setFscaling(self, x):
- """
- Sets the frequency display to linear or logarithmic.
-
- :Args:
-
- x : boolean
- If True, the frequency display is logarithmic. False turns
- it back to linear. Defaults to False.
-
- """
- self._fscaling = x
- x, lmax = convertArgsToLists(x)
- [obj.setFscaling(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
- if self.viewFrame != None:
- self.viewFrame.setFscaling(self._fscaling)
-
- def setMscaling(self, x):
- """
- Sets the magnitude display to linear or logarithmic.
-
- :Args:
-
- x : boolean
- If True, the magnitude display is logarithmic (which means in dB).
- False turns it back to linear. Defaults to True.
-
- """
- self._mscaling = x
- x, lmax = convertArgsToLists(x)
- [obj.setMscaling(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
- if self.viewFrame != None:
- self.viewFrame.setMscaling(self._mscaling)
-
- def getFscaling(self):
- """
- Returns the scaling of the frequency display.
-
- Returns True for logarithmic or False for linear.
-
- """
- return self._fscaling
-
- def getMscaling(self):
- """
- Returns the scaling of the magnitude display.
-
- Returns True for logarithmic or False for linear.
-
- """
- return self._mscaling
-
- def setGain(self, x):
- """
- Set the gain of the anaysis data. For drawing purpose.
-
- :Args:
-
- x : float
- new `gain` attribute, as linear values.
-
- """
- self._gain = x
- x, lmax = convertArgsToLists(x)
- [obj.setGain(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-
- def view(self, title="Spectrum", wxnoserver=False):
- """
- Opens a window showing the result of the analysis.
-
- :Args:
-
- title : string, optional
- Window title. Defaults to "Spectrum".
- wxnoserver : boolean, optional
- With wxPython graphical toolkit, if True, tells the
- interpreter that there will be no server window.
-
- If `wxnoserver` is set to True, the interpreter will not wait for
- the server GUI before showing the controller window.
-
- """
- createSpectrumWindow(self, title, wxnoserver)
-
- def _setViewFrame(self, frame):
- self.viewFrame = frame
-
- def refreshView(self):
- """
- Updates the graphical display of the spectrum.
-
- Called automatically by the internal timer.
-
- """
- self.points = [obj.display() for obj in self._base_objs]
- if self._function != None:
- self._function(self.points)
- if self.viewFrame != None:
- self.viewFrame.update(self.points)
-
-
- @property
- def input(self):
- """PyoObject. Input signal to process."""
- return self._input
- @input.setter
- def input(self, x): self.setInput(x)
-
- @property
- def size(self):
- """int. FFT size."""
- return self._size
- @size.setter
- def size(self, x): self.setSize(x)
-
- @property
- def wintype(self):
- """int. Windowing method."""
- return self._wintype
- @wintype.setter
- def wintype(self, x): self.setWinType(x)
-
- @property
- def gain(self):
- """float. Sets the gain of the analysis data."""
- return self._gain
- @gain.setter
- def gain(self, x): self.setGain(x)
-
- @property
- def lowbound(self):
- """float. Lowest frequency (multiplier of sr) to output."""
- return self._lowbound
- @lowbound.setter
- def lowbound(self, x): self.setLowbound(x)
-
- @property
- def highbound(self):
- """float. Highest frequency (multiplier of sr) to output."""
- return self._highbound
- @highbound.setter
- def highbound(self, x): self.setHighbound(x)
-
- @property
- def width(self):
- """int. Width, in pixels, of the current display."""
- return self._width
- @width.setter
- def width(self, x): self.setWidth(x)
-
- @property
- def height(self):
- """int. Height, in pixels, of the current display."""
- return self._height
- @height.setter
- def height(self, x): self.setHeight(x)
-
- @property
- def fscaling(self):
- """boolean. Scaling of the frequency display."""
- return self._fscaling
- @fscaling.setter
- def fscaling(self, x): self.setFscaling(x)
-
- @property
- def mscaling(self):
- """boolean. Scaling of the magnitude display."""
- return self._mscaling
- @mscaling.setter
- def mscaling(self, x): self.setMscaling(x)
diff --git a/pyolib/generators.py b/pyolib/generators.py
index a24bb1e..72fcfc5 100644
--- a/pyolib/generators.py
+++ b/pyolib/generators.py
@@ -1019,10 +1019,9 @@ class LFO(PyoObject):
"""
- if x >= 0 and x < 8:
- self._type = x
- x, lmax = convertArgsToLists(x)
- [obj.setType(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ self._type = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setType(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
def reset(self):
"""
@@ -1033,7 +1032,10 @@ class LFO(PyoObject):
def ctrl(self, map_list=None, title=None, wxnoserver=False):
- self._map_list = [SLMapFreq(self._freq), SLMap(0., 1., "lin", "sharp", self._sharp), SLMapMul(self._mul)]
+ self._map_list = [SLMapFreq(self._freq),
+ SLMap(0., 1., "lin", "sharp", self._sharp),
+ SLMap(0, 7, "lin", "type", self._type, "int", dataOnly=True),
+ SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
diff --git a/pyolib/midi.py b/pyolib/midi.py
index e305ba4..5936021 100644
--- a/pyolib/midi.py
+++ b/pyolib/midi.py
@@ -257,6 +257,13 @@ class CtlScan(PyoObject):
def setDiv(self, x):
pass
+ def reset(self):
+ """
+ Resets the scanner.
+
+ """
+ [obj.reset() for obj in self._base_objs]
+
def setFunction(self, x):
"""
Replace the `function` attribute.
@@ -362,6 +369,13 @@ class CtlScan2(PyoObject):
def setDiv(self, x):
pass
+ def reset(self):
+ """
+ Resets the scanner.
+
+ """
+ [obj.reset() for obj in self._base_objs]
+
def setFunction(self, x):
"""
Replace the `function` attribute.
@@ -442,10 +456,16 @@ class Notein(PyoObject):
Pitch and velocity are two separated set of streams.
The user should call :
- Notein['pitch'] to retrieve pitch streams.
- Notein['velocity'] to retrieve velocity streams.
+ | Notein['pitch'] to retrieve pitch streams.
+ | Notein['velocity'] to retrieve velocity streams.
Velocity is automatically scaled between 0 and 1.
+
+ Notein also outputs trigger streams on noteon and noteoff.
+ These streams can be retrieved with :
+
+ | Notein['trigon'] to retrieve noteon trigger streams.
+ | Notein['trigoff'] to retrieve noteoff trigger streams.
The out() method is bypassed. Notein's signal can not be sent
to audio outs.
@@ -463,6 +483,8 @@ class Notein(PyoObject):
PyoObject.__init__(self, mul, add)
self._pitch_dummy = []
self._velocity_dummy = []
+ self._trigon_dummy = []
+ self._trigoff_dummy = []
self._poly = poly
self._scale = scale
self._first = first
@@ -471,17 +493,26 @@ class Notein(PyoObject):
mul, add, lmax = convertArgsToLists(mul, add)
self._base_handler = MidiNote_base(self._poly, self._scale, self._first, self._last, self._channel)
self._base_objs = []
+ self._trig_objs = []
for i in range(lmax * poly):
self._base_objs.append(Notein_base(self._base_handler, i, 0, 1, 0))
self._base_objs.append(Notein_base(self._base_handler, i, 1, wrap(mul,i), wrap(add,i)))
-
+ self._trig_objs.append(NoteinTrig_base(self._base_handler, i, 0, 1, 0))
+ self._trig_objs.append(NoteinTrig_base(self._base_handler, i, 1, 1, 0))
+
def __getitem__(self, str):
if str == 'pitch':
self._pitch_dummy.append(Dummy([self._base_objs[i*2] for i in range(self._poly)]))
return self._pitch_dummy[-1]
- if str == 'velocity':
+ elif str == 'velocity':
self._velocity_dummy.append(Dummy([self._base_objs[i*2+1] for i in range(self._poly)]))
return self._velocity_dummy[-1]
+ elif str == 'trigon':
+ self._trigon_dummy.append(Dummy([self._trig_objs[i*2] for i in range(self._poly)]))
+ return self._trigon_dummy[-1]
+ elif str == 'trigoff':
+ self._trigoff_dummy.append(Dummy([self._trig_objs[i*2+1] for i in range(self._poly)]))
+ return self._trigoff_dummy[-1]
def setChannel(self, x):
"""
diff --git a/pyolib/pan.py b/pyolib/pan.py
index 54b16d7..f66eb18 100644
--- a/pyolib/pan.py
+++ b/pyolib/pan.py
@@ -39,7 +39,8 @@ class Pan(PyoObject):
input : PyoObject
Input signal to process.
outs : int, optional
- Number of channels on the panning circle. Defaults to 2.
+ Number of channels on the panning circle. Available at
+ initialization time only. Defaults to 2.
pan : float or PyoObject
Position of the sound on the panning circle, between 0 and 1.
Defaults to 0.5.
@@ -149,7 +150,8 @@ class SPan(PyoObject):
input : PyoObject
Input signal to process.
outs : int, optional
- Number of channels on the panning circle. Defaults to 2.
+ Number of channels on the panning circle. Available at
+ initialization time only. Defaults to 2.
pan : float or PyoObject
Position of the sound on the panning circle, between 0 and 1.
Defaults to 0.5.
@@ -238,7 +240,8 @@ class Switch(PyoObject):
input : PyoObject
Input signal to process.
outs : int, optional
- Number of outputs. Defaults to 2.
+ Number of outputs. Available at initialization time only.
+ Defaults to 2.
voice : float or PyoObject
Voice position pointer, between 0 and (outs-1) / len(input).
Defaults to 0.
@@ -684,7 +687,8 @@ class Mixer(PyoObject):
return self._inputs.keys()
def ctrl(self, map_list=None, title=None, wxnoserver=False):
- self._map_list = [SLMapMul(self._mul)]
+ self._map_list = [SLMap(0, 10, 'lin', 'time', self._time, dataOnly=True),
+ SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
diff --git a/pyolib/pattern.py b/pyolib/pattern.py
index 851ad20..e7b2a7c 100644
--- a/pyolib/pattern.py
+++ b/pyolib/pattern.py
@@ -245,7 +245,7 @@ class CallAfter(PyoObject):
CallAfter has no `mul` and `add` attributes.
- The object is not deleted after the call. The User must delete it himself.
+ The object is not deleted after the call. The user must delete it himself.
>>> s = Server().boot()
>>> s.start()
diff --git a/pyolib/phasevoc.py b/pyolib/phasevoc.py
index bb4f5e5..379b934 100644
--- a/pyolib/phasevoc.py
+++ b/pyolib/phasevoc.py
@@ -295,8 +295,8 @@ class PVAddSynth(PyoObject):
>>> s = Server().boot()
>>> s.start()
>>> a = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=0.7)
- >>> pva = PVAnal(a, size=1024, overlaps=4, pitch=2)
- >>> pvs = PVAddSynth(pva, pitch=1.25, num=100, first=0, inc=2)
+ >>> pva = PVAnal(a, size=1024, overlaps=4, wintype=2)
+ >>> pvs = PVAddSynth(pva, pitch=1.25, num=100, first=0, inc=2).out()
"""
def __init__(self, input, pitch=1, num=100, first=0, inc=1, mul=1, add=0):
diff --git a/pyolib/players.py b/pyolib/players.py
index 98992ad..3a1f7a4 100644
--- a/pyolib/players.py
+++ b/pyolib/players.py
@@ -208,7 +208,9 @@ class SfPlayer(PyoObject):
[obj.setInterp(wrap(x,i)) for i, obj in enumerate(self._base_players)]
def ctrl(self, map_list=None, title=None, wxnoserver=False):
- self._map_list = [SLMap(-2., 2., 'lin', 'speed', self._speed), SLMapMul(self._mul)]
+ self._map_list = [SLMap(-2., 2., 'lin', 'speed', self._speed),
+ SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
+ SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
@@ -354,7 +356,9 @@ class SfMarkerShuffler(PyoObject):
return self._markers
def ctrl(self, map_list=None, title=None, wxnoserver=False):
- self._map_list = [SLMap(0.01, 2., 'lin', 'speed', self._speed), SLMapMul(self._mul)]
+ self._map_list = [SLMap(0.01, 2., 'lin', 'speed', self._speed),
+ SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
+ SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
@@ -492,6 +496,7 @@ class SfMarkerLooper(PyoObject):
def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(0.01, 2., 'lin', 'speed', self._speed),
SLMap(0, len(self._markers)-1, 'lin', 'mark', self._mark, 'int'),
+ SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
diff --git a/pyolib/randoms.py b/pyolib/randoms.py
index 695ee21..737a0e6 100644
--- a/pyolib/randoms.py
+++ b/pyolib/randoms.py
@@ -627,7 +627,7 @@ class Xnoise(PyoObject):
new `x2` attribute.
"""
- self._x2= x
+ self._x2 = x
x, lmax = convertArgsToLists(x)
[obj.setX2(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
@@ -645,6 +645,15 @@ class Xnoise(PyoObject):
x, lmax = convertArgsToLists(x)
[obj.setFreq(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0, 12, 'lin', 'dist', self._dist, res="int", dataOnly=True),
+ SLMap(0.001, 200., 'log', 'freq', self._freq),
+ SLMap(0, 1, 'lin', 'x1', self._x1),
+ SLMap(0, 1, 'lin', 'x2', self._x2),
+ SLMap(0, 2500, 'lin', 'mul', self._mul),
+ SLMap(0, 2500, 'lin', 'add', self._add)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
@property
def dist(self):
"""string or int. Distribution type."""
@@ -880,6 +889,14 @@ class XnoiseMidi(PyoObject):
x, lmax = convertArgsToLists(x)
[obj.setFreq(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0, 12, 'lin', 'dist', self._dist, res="int", dataOnly=True),
+ SLMap(0.001, 200., 'log', 'freq', self._freq),
+ SLMap(0, 1, 'lin', 'x1', self._x1),
+ SLMap(0, 1, 'lin', 'x2', self._x2),
+ SLMap(0, 2, 'lin', 'scale', self._scale, res="int", dataOnly=True)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
@property
def dist(self):
"""string or int. Distribution type."""
@@ -1097,6 +1114,14 @@ class XnoiseDur(PyoObject):
x, lmax = convertArgsToLists(x)
[obj.setX2(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0, 12, 'lin', 'dist', self._dist, res="int", dataOnly=True),
+ SLMap(0, 20, 'lin', 'min', self._min),
+ SLMap(0, 20, 'lin', 'max', self._max),
+ SLMap(0, 1, 'lin', 'x1', self._x1),
+ SLMap(0, 1, 'lin', 'x2', self._x2)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
@property
def dist(self):
"""string or int. Distribution type."""
@@ -1208,7 +1233,7 @@ class Urn(PyoObject):
[obj.setFreq(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
def ctrl(self, map_list=None, title=None, wxnoserver=False):
- self._map_list = [SLMap(1., 2., 'lin', 'max', self._max),
+ self._map_list = [SLMap(1, 1000, 'lin', 'max', self._max, res="int", dataOnly=True),
SLMap(0.1, 20., 'lin', 'freq', self._freq),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
diff --git a/pyolib/server.py b/pyolib/server.py
index b7729a0..7c1f134 100644
--- a/pyolib/server.py
+++ b/pyolib/server.py
@@ -98,7 +98,7 @@ class Server(object):
"""
def __init__(self, sr=44100, nchnls=2, buffersize=256, duplex=1, audio='portaudio', jackname='pyo'):
- if os.environ.has_key("PYO_SERVER_AUDIO") and "offline" not in audio:
+ if os.environ.has_key("PYO_SERVER_AUDIO") and "offline" not in audio and "embedded" not in audio:
audio = os.environ["PYO_SERVER_AUDIO"]
self._time = time
self._nchnls = nchnls
@@ -140,7 +140,7 @@ class Server(object):
self._globalseed = 0
self._server.__init__(sr, nchnls, buffersize, duplex, audio, jackname)
- def gui(self, locals=None, meter=True, timer=True):
+ def gui(self, locals=None, meter=True, timer=True, exit=True):
"""
Show the server's user interface.
@@ -155,10 +155,14 @@ class Server(object):
timer : boolean, optional
If True, the interface will show a clock of the current time.
Defaults to True.
+ exit : boolean, optional
+ If True, the python interpreter will exit when the 'Quit' button is pressed,
+ Otherwise, the GUI will be closed leaving the interpreter alive.
+ Defaults to True.
"""
f, win = createServerGUI(self._nchnls, self.start, self.stop, self.recstart, self.recstop,
- self.setAmp, self.getIsStarted(), locals, self.shutdown, meter, timer, self._amp)
+ self.setAmp, self.getIsStarted(), locals, self.shutdown, meter, timer, self._amp, exit)
if meter:
self._server.setAmpCallable(f)
if timer:
@@ -172,6 +176,9 @@ class Server(object):
def setTimeCallable(self, func):
self.setTime = func
self._server.setTimeCallable(self)
+
+ def setMeter(self, meter):
+ self._server.setAmpCallable(meter)
def setInOutDevice(self, x):
"""
@@ -261,6 +268,9 @@ class Server(object):
"""
Set the Midi input device number. See `pm_list_devices()`.
+ A number greater than the highest portmidi device index
+ will opened all available input devices.
+
:Args:
x : int
@@ -349,7 +359,7 @@ class Server(object):
def setJackAuto(self, xin=True, xout=True):
"""
- Tells the server to auto-connect (or not) Jack ports.
+ Tells the server to auto-connect (or not) Jack ports to System ports.
:Args:
@@ -361,6 +371,32 @@ class Server(object):
"""
self._server.setJackAuto(xin, xout)
+ def setJackAutoConnectInputPorts(self, ports):
+ """
+ Tells the server to auto-connect Jack input ports to pre-defined Jack ports.
+
+ :Args:
+
+ ports : string or list of strings
+ Name of the Jack port(s) to auto-connect. Regular Expressions are allowed.
+
+ """
+ ports, lmax = convertArgsToLists(ports)
+ self._server.setJackAutoConnectInputPorts(ports)
+
+ def setJackAutoConnectOutputPorts(self, ports):
+ """
+ Tells the server to auto-connect Jack output ports to pre-defined Jack ports.
+
+ :Args:
+
+ ports : string or list of strings
+ Name of the Jack port(s) to auto-connect. Regular Expressions are allowed.
+
+ """
+ ports, lmax = convertArgsToLists(ports)
+ self._server.setJackAutoConnectOutputPorts(ports)
+
def setGlobalSeed(self, x):
"""
Set the server's global seed used by random objects.
@@ -543,9 +579,12 @@ class Server(object):
"""
self._server.recstop()
- def sendMidiNote(self, pitch, velocity, channel=0, timestamp=0):
+ def noteout(self, pitch, velocity, channel=0, timestamp=0):
"""
- Send a MIDI note message to the selected output device.
+ Send a MIDI note message to the selected midi output device.
+
+ Arguments can be list of values to generate multiple events
+ in one call.
:Args:
@@ -556,10 +595,135 @@ class Server(object):
with a velocity of 0 is equivalent to a note off.
channel : int, optional
The Midi channel, between 1 and 16, on which the
- note is sent. A channel of 0 means all channels.
+ note is sent. A channel of 0 means all channels.
+ Defaults to 0.
+ timestamp : int, optional
+ The delay time, in milliseconds, before the note
+ is sent on the portmidi stream. A value of 0 means
+ to play the note now. Defaults to 0.
+ """
+ pitch, velocity, channel, timestamp, lmax = convertArgsToLists(pitch, velocity, channel, timestamp)
+ [self._server.noteout(wrap(pitch,i), wrap(velocity,i), wrap(channel,i), wrap(timestamp,i)) for i in range(lmax)]
+
+ def afterout(self, pitch, velocity, channel=0, timestamp=0):
+ """
+ Send an aftertouch message to the selected midi output device.
+
+ Arguments can be list of values to generate multiple events
+ in one call.
+
+ :Args:
+
+ pitch : int
+ Midi key pressed down, between 0 and 127.
+ velocity : int
+ Velocity of the pressure, between 0 and 127.
+ channel : int, optional
+ The Midi channel, between 1 and 16, on which the
+ note is sent. A channel of 0 means all channels.
+ Defaults to 0.
+ timestamp : int, optional
+ The delay time, in milliseconds, before the note
+ is sent on the portmidi stream. A value of 0 means
+ to play the note now. Defaults to 0.
+ """
+ pitch, velocity, channel, timestamp, lmax = convertArgsToLists(pitch, velocity, channel, timestamp)
+ [self._server.afterout(wrap(pitch,i), wrap(velocity,i), wrap(channel,i), wrap(timestamp,i)) for i in range(lmax)]
+
+ def ctlout(self, ctlnum, value, channel=0, timestamp=0):
+ """
+ Send a control change message to the selected midi output device.
+
+ Arguments can be list of values to generate multiple events
+ in one call.
+
+ :Args:
+
+ ctlnum : int
+ Controller number, between 0 and 127.
+ value : int
+ Value of the controller, between 0 and 127.
+ channel : int, optional
+ The Midi channel, between 1 and 16, on which the
+ message is sent. A channel of 0 means all channels.
+ Defaults to 0.
+ timestamp : int, optional
+ The delay time, in milliseconds, before the message
+ is sent on the portmidi stream. A value of 0 means
+ to play the message now. Defaults to 0.
+ """
+ ctlnum, value, channel, timestamp, lmax = convertArgsToLists(ctlnum, value, channel, timestamp)
+ [self._server.ctlout(wrap(ctlnum,i), wrap(value,i), wrap(channel,i), wrap(timestamp,i)) for i in range(lmax)]
+
+ def programout(self, value, channel=0, timestamp=0):
+ """
+ Send a program change message to the selected midi output device.
+
+ Arguments can be list of values to generate multiple events
+ in one call.
+
+ :Args:
+
+ value : int
+ New program number, between 0 and 127.
+ channel : int, optional
+ The Midi channel, between 1 and 16, on which the
+ message is sent. A channel of 0 means all channels.
+ Defaults to 0.
+ timestamp : int, optional
+ The delay time, in milliseconds, before the message
+ is sent on the portmidi stream. A value of 0 means
+ to play the message now. Defaults to 0.
+ """
+ value, channel, timestamp, lmax = convertArgsToLists(value, channel, timestamp)
+ [self._server.programout(wrap(value,i), wrap(channel,i), wrap(timestamp,i)) for i in range(lmax)]
+
+ def pressout(self, value, channel=0, timestamp=0):
+ """
+ Send a channel pressure message to the selected midi output device.
+
+ Arguments can be list of values to generate multiple events
+ in one call.
+
+ :Args:
+
+ value : int
+ Single greatest pressure value, between 0 and 127.
+ channel : int, optional
+ The Midi channel, between 1 and 16, on which the
+ message is sent. A channel of 0 means all channels.
+ Defaults to 0.
+ timestamp : int, optional
+ The delay time, in milliseconds, before the message
+ is sent on the portmidi stream. A value of 0 means
+ to play the message now. Defaults to 0.
+ """
+ value, channel, timestamp, lmax = convertArgsToLists(value, channel, timestamp)
+ [self._server.pressout(wrap(value,i), wrap(channel,i), wrap(timestamp,i)) for i in range(lmax)]
+ def bendout(self, value, channel=0, timestamp=0):
"""
- self._server.sendMidiNote(pitch, velocity, channel, timestamp)
+ Send a pitch bend message to the selected midi output device.
+
+ Arguments can be list of values to generate multiple events
+ in one call.
+
+ :Args:
+
+ value : int
+ 14 bits pitch bend value. 8192 is where there is no
+ bending, 0 is full down and 16383 is full up bending.
+ channel : int, optional
+ The Midi channel, between 1 and 16, on which the
+ message is sent. A channel of 0 means all channels.
+ Defaults to 0.
+ timestamp : int, optional
+ The delay time, in milliseconds, before the message
+ is sent on the portmidi stream. A value of 0 means
+ to play the message now. Defaults to 0.
+ """
+ value, channel, timestamp, lmax = convertArgsToLists(value, channel, timestamp)
+ [self._server.bendout(wrap(value,i), wrap(channel,i), wrap(timestamp,i)) for i in range(lmax)]
def getStreams(self):
"""
@@ -637,13 +801,6 @@ class Server(object):
"""
return self._server.setServer()
-
- def flush(self):
- """
- Flush the server objects. Need a shutdown before working. This is useful if want to flush a script without freeing the buffers
-
- """
- return self._server.flush()
def getInputAddr(self):
"""
diff --git a/pyolib/tableprocess.py b/pyolib/tableprocess.py
index 2b4fb7c..a9acdcd 100644
--- a/pyolib/tableprocess.py
+++ b/pyolib/tableprocess.py
@@ -136,6 +136,7 @@ class Osc(PyoObject):
def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMapFreq(self._freq),
SLMapPhase(self._phase),
+ SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@@ -403,6 +404,7 @@ class OscTrig(PyoObject):
def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMapFreq(self._freq),
SLMapPhase(self._phase),
+ SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@@ -854,7 +856,10 @@ class TableRead(PyoObject):
def ctrl(self, map_list=None, title=None, wxnoserver=False):
- self._map_list = [SLMapFreq(self._freq), SLMapMul(self._mul)]
+ self._map_list = [SLMap(0.0001, 1000, 'log', 'freq', self._freq),
+ SLMap(0, 1, 'lin', 'loop', self._loop, res="int", dataOnly=True),
+ SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
+ SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
@@ -1019,7 +1024,11 @@ class Pulsar(PyoObject):
:Args:
x : int {1, 2, 3, 4}
- new `interp` attribute.
+ Choice of the interpolation method.
+ 1. no interpolation
+ 2. linear
+ 3. cosinus
+ 4. cubic
"""
self._interp = x
@@ -1030,6 +1039,7 @@ class Pulsar(PyoObject):
self._map_list = [SLMapFreq(self._freq),
SLMap(0., 1., 'lin', 'frac', self._frac),
SLMapPhase(self._phase),
+ SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@@ -1149,6 +1159,144 @@ class Pointer(PyoObject):
@index.setter
def index(self, x): self.setIndex(x)
+class Pointer2(PyoObject):
+ """
+ High quality table reader with control on the pointer position.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ table : PyoTableObject
+ Table containing the waveform samples.
+ index : PyoObject
+ Normalized position in the table between 0 and 1.
+ interp : int {1, 2, 3, 4}, optional
+ Choice of the interpolation method. Defaults to 4.
+ 1. no interpolation
+ 2. linear
+ 3. cosinus
+ 4. cubic
+ autosmooth : boolean, optional
+ If True, a lowpass filter, following the pitch, is applied on
+
+ the output signal to reduce the quantization noise produced
+
+ by very low transpositions. Defaults to True.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> t = SndTable(SNDS_PATH + '/transparent.aif')
+ >>> freq = t.getRate()
+ >>> p = Phasor(freq=[freq*0.5, freq*0.45])
+ >>> a = Pointer2(table=t, index=p, mul=.3).out()
+
+ """
+ def __init__(self, table, index, interp=4, autosmooth=True, mul=1, add=0):
+ PyoObject.__init__(self, mul, add)
+ self._table = table
+ self._index = index
+ self._interp = interp
+ self._autosmooth = autosmooth
+ table, index, interp, autosmooth, mul, add, lmax = convertArgsToLists(table, index, interp, autosmooth, mul, add)
+ self._base_objs = [Pointer2_base(wrap(table,i), wrap(index,i), wrap(interp,i), wrap(autosmooth,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+
+ def setTable(self, x):
+ """
+ Replace the `table` attribute.
+
+ :Args:
+
+ x : PyoTableObject
+ new `table` attribute.
+
+ """
+ self._table = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setTable(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setIndex(self, x):
+ """
+ Replace the `index` attribute.
+
+ :Args:
+
+ x : PyoObject
+ new `index` attribute.
+
+ """
+ self._index = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setIndex(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setInterp(self, x):
+ """
+ Replace the `interp` attribute.
+
+ :Args:
+
+ x : int {1, 2, 3, 4}
+ new `interp` attribute.
+ 1. no interpolation
+ 2. linear interpolation
+ 3. cosine interpolation
+ 4. cubic interpolation (default)
+
+ """
+ self._interp = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setInterp(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def setAutoSmooth(self, x):
+ """
+ Replace the `autosmooth` attribute.
+
+ If True, a lowpass filter, following the playback speed, is applied on
+ the output signal to reduce the quantization noise produced by very
+ low transpositions.
+
+ :Args:
+
+ x : boolean
+ new `autosmooth` attribute.
+
+ """
+ self._autosmooth = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setAutoSmooth(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMapMul(self._mul)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+ @property
+ def table(self):
+ """PyoTableObject. Table containing the waveform samples."""
+ return self._table
+ @table.setter
+ def table(self, x): self.setTable(x)
+
+ @property
+ def index(self):
+ """PyoObject. Index pointer position in the table."""
+ return self._index
+ @index.setter
+ def index(self, x): self.setIndex(x)
+
+ @property
+ def interp(self):
+ """int {1, 2, 3, 4}. Interpolation method."""
+ return self._interp
+ @interp.setter
+ def interp(self, x): self.setInterp(x)
+
+ @property
+ def autosmooth(self):
+ """boolean. Quantization noise filter."""
+ return self._autosmooth
+ @autosmooth.setter
+ def autosmooth(self, x): self.setAutoSmooth(x)
+
class TableIndex(PyoObject):
"""
Table reader by sample position without interpolation.
@@ -1710,6 +1858,8 @@ class Granulator(PyoObject):
def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(0.1, 2., 'lin', 'pitch', self._pitch),
SLMap(0.01, 1., 'lin', 'dur', self._dur),
+ SLMap(1, 256, 'lin', 'grains', self._grains, res="int", dataOnly=True),
+ SLMap(0.001, 1, 'log', 'basedur', self._basedur, dataOnly=True),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@@ -2128,7 +2278,9 @@ class Looper(PyoObject):
def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(0.1, 2., 'lin', 'pitch', self._pitch),
SLMap(0., self._table.getDur(), 'lin', 'start', self._start),
- SLMap(0.01, 1., 'lin', 'dur', self._dur),
+ SLMap(0.01, self._table.getDur(), 'lin', 'dur', self._dur),
+ SLMap(0, 2, 'lin', 'xfadeshape', self._xfadeshape, res="int", dataOnly=True),
+ SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@@ -2316,6 +2468,9 @@ class Granule(PyoObject):
"""
Another granular synthesis generator.
+ As of pyo 0.7.4, users can call the `setSync` method to change the
+ granulation mode (either synchronous or asynchronous) of the object.
+
:Parent: :py:class:`PyoObject`
:Args:
@@ -2358,6 +2513,7 @@ class Granule(PyoObject):
self._pitch = pitch
self._pos = pos
self._dur = dur
+ self._sync = 1
table, env, dens, pitch, pos, dur, mul, add, lmax = convertArgsToLists(table, env, dens, pitch, pos, dur, mul, add)
self._base_objs = [Granule_base(wrap(table,i), wrap(env,i), wrap(dens,i), wrap(pitch,i), wrap(pos,i), wrap(dur,i),
wrap(mul,i), wrap(add,i)) for i in range(lmax)]
@@ -2446,6 +2602,21 @@ class Granule(PyoObject):
x, lmax = convertArgsToLists(x)
[obj.setDur(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ def setSync(self, x):
+ """
+ Sets the granulation mode, synchronous or asynchronous.
+
+ :Args:
+
+ x : boolean
+ True means synchronous granulation (the default)
+ while False means asynchronous.
+
+ """
+ self._sync = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setSync(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(1, 250, 'lin', 'dens', self._dens),
SLMap(0.25, 2., 'lin', 'pitch', self._pitch),
@@ -2577,3 +2748,260 @@ class TableScale(PyoObject):
return self._outtable
@outtable.setter
def outtable(self, x): self.setOuttable(x)
+
+class Particle(PyoObject):
+ """
+ A full control granular synthesis generator.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ table : PyoTableObject
+ Table containing the waveform samples.
+ env : PyoTableObject
+ Table containing the grain envelope.
+ dens : float or PyoObject, optional
+ Density of grains per second. Defaults to 50.
+ pitch : float or PyoObject, optional
+ Pitch of the grains. Each grain sampled the current value
+ of this stream at the beginning of its envelope and hold
+ it until the end of the grain. Defaults to 1.
+ pos : float or PyoObject, optional
+ Pointer position, in samples, in the waveform table. Each
+ grain sampled the current value of this stream at the beginning
+ of its envelope and hold it until the end of the grain.
+ Defaults to 0.
+ dur : float or PyoObject, optional
+ Duration, in seconds, of the grain. Each grain sampled the
+ current value of this stream at the beginning of its envelope
+ and hold it until the end of the grain. Defaults to 0.1.
+ dev : float or PyoObject, optional
+ Maximum deviation of the starting time of the grain, between 0 and
+ 1 (relative to the current duration of the grain). Each grain sampled
+ the current value of this stream at the beginning of its envelope
+ and hold it until the end of the grain. Defaults to 0.01.
+ pan : float or PyoObject, optional
+ Panning factor of the grain (if chnls=1, this value is skipped).
+ Each grain sampled the current value of this stream at the beginning
+ of its envelope and hold it until the end of the grain. Defaults to 0.5.
+ chnls : integer, optional
+ Number of output channels per audio stream (if chnls=2 and a stereo sound
+ table is given at the table argument, the objet will create 4 output
+ streams, 2 per table channel). Available at initialization only. Defaults to 1.
+
+ .. note::
+
+ Particle object compensate for the difference between sampling rate of the
+ loaded sound and the current sampling rate of the Server.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> snd = SndTable(SNDS_PATH+"/transparent.aif")
+ >>> end = snd.getSize() - s.getSamplingRate() * 0.25
+ >>> env = HannTable()
+ >>> dns = Randi(min=5, max=100, freq=.1)
+ >>> pit = Randh(min=0.99, max=1.01, freq=100)
+ >>> pos = Randi(min=0, max=1, freq=0.25, mul=end)
+ >>> dur = Randi(min=0.01, max=0.25, freq=0.15)
+ >>> dev = Randi(min=0, max=1, freq=0.2)
+ >>> pan = Noise(0.5, 0.5)
+ >>> grn = Particle(snd, env, dns, pit, pos, dur, dev, pan, chnls=2, mul=.2).out()
+
+ """
+ def __init__(self, table, env, dens=50, pitch=1, pos=0, dur=.1, dev=0.01, pan=0.5, chnls=1, mul=1, add=0):
+ PyoObject.__init__(self, mul, add)
+ self._table = table
+ self._env = env
+ self._dens = dens
+ self._pitch = pitch
+ self._pos = pos
+ self._dur = dur
+ self._dev = dev
+ self._pan = pan
+ self._chnls = chnls
+ table, env, dens, pitch, pos, dur, dev, pan, mul, add, lmax = convertArgsToLists(table, env, dens, pitch, pos, dur, dev, pan, mul, add)
+ self._base_players = [MainParticle_base(wrap(table,i), wrap(env,i), wrap(dens,i), wrap(pitch,i), wrap(pos,i), wrap(dur,i), wrap(dev,i), wrap(pan,i), chnls) for i in range(lmax)]
+ self._base_objs = []
+ for i in range(lmax):
+ for j in range(chnls):
+ self._base_objs.append(Particle_base(wrap(self._base_players,i), j, wrap(mul,i), wrap(add,i)))
+
+ def setTable(self, x):
+ """
+ Replace the `table` attribute.
+
+ :Args:
+
+ x : PyoTableObject
+ new `table` attribute.
+
+ """
+ self._table = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setTable(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setEnv(self, x):
+ """
+ Replace the `env` attribute.
+
+ :Args:
+
+ x : PyoTableObject
+ new `env` attribute.
+
+ """
+ self._env = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setEnv(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setDens(self, x):
+ """
+ Replace the `dens` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ new `dens` attribute.
+
+ """
+ self._dens = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setDens(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setPitch(self, x):
+ """
+ Replace the `pitch` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ new `pitch` attribute.
+
+ """
+ self._pitch = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setPitch(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setPos(self, x):
+ """
+ Replace the `pos` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ new `pos` attribute.
+
+ """
+ self._pos = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setPos(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setDur(self, x):
+ """
+ Replace the `dur` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ new `dur` attribute.
+
+ """
+ self._dur = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setDur(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setDev(self, x):
+ """
+ Replace the `dev` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ new `dev` attribute.
+
+ """
+ self._dev = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setDev(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setPan(self, x):
+ """
+ Replace the `pan` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ new `pan` attribute.
+
+ """
+ self._pan = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setPan(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ tablesize = self._table.getSize(False)
+ self._map_list = [SLMap(1, 250, 'lin', 'dens', self._dens),
+ SLMap(0.25, 2., 'lin', 'pitch', self._pitch),
+ SLMap(0, tablesize, 'lin', 'pos', self._pos),
+ SLMap(0.001, 1., 'lin', 'dur', self._dur),
+ SLMap(0., 1., 'lin', 'dev', self._dev),
+ SLMap(0., 1., 'lin', 'pan', self._pan),
+ SLMapMul(self._mul)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+ @property
+ def table(self):
+ """PyoTableObject. Table containing the waveform samples."""
+ return self._table
+ @table.setter
+ def table(self, x): self.setTable(x)
+
+ @property
+ def env(self):
+ """PyoTableObject. Table containing the grain envelope."""
+ return self._env
+ @env.setter
+ def env(self, x): self.setEnv(x)
+
+ @property
+ def dens(self):
+ """float or PyoObject. Density of grains per second."""
+ return self._dens
+ @dens.setter
+ def dens(self, x): self.setDens(x)
+
+ @property
+ def pitch(self):
+ """float or PyoObject. Transposition factor of the grain."""
+ return self._pitch
+ @pitch.setter
+ def pitch(self, x): self.setPitch(x)
+
+ @property
+ def pos(self):
+ """float or PyoObject. Position of the pointer in the sound table."""
+ return self._pos
+ @pos.setter
+ def pos(self, x): self.setPos(x)
+
+ @property
+ def dur(self):
+ """float or PyoObject. Duration, in seconds, of the grain."""
+ return self._dur
+ @dur.setter
+ def dur(self, x): self.setDur(x)
+
+ @property
+ def dev(self):
+ """float or PyoObject. Deviation of the starting point of the grain in the table."""
+ return self._dev
+ @dev.setter
+ def dev(self, x): self.setDev(x)
+
+ @property
+ def pan(self):
+ """float or PyoObject.Panning of the grain."""
+ return self._pan
+ @pan.setter
+ def pan(self, x): self.setPan(x)
diff --git a/pyolib/tables.py b/pyolib/tables.py
index f3a4a3f..7119054 100644
--- a/pyolib/tables.py
+++ b/pyolib/tables.py
@@ -22,6 +22,7 @@ from _maps import *
from _widgets import createGraphWindow, createDataGraphWindow, createSndViewTableWindow
from types import ListType
from math import pi
+import copy
######################################################################
### Tables
@@ -52,8 +53,8 @@ class HarmTable(PyoTableObject):
"""
def __init__(self, list=[1., 0.], size=8192):
PyoTableObject.__init__(self, size)
- self._list = list
- self._base_objs = [HarmTable_base(list, size)]
+ self._list = copy.deepcopy(list)
+ self._base_objs = [HarmTable_base(self._list, size)]
def replace(self, list):
"""
@@ -217,8 +218,8 @@ class ChebyTable(PyoTableObject):
"""
def __init__(self, list=[1., 0.], size=8192):
PyoTableObject.__init__(self, size)
- self._list = list
- self._base_objs = [ChebyTable_base(list, size)]
+ self._list = copy.deepcopy(list)
+ self._base_objs = [ChebyTable_base(self._list, size)]
def replace(self, list):
"""
@@ -466,7 +467,7 @@ class LinTable(PyoTableObject):
print " Increased size to last point position + 1"
size = list[-1][0] + 1
self._size = size
- self._base_objs = [LinTable_base(list, size)]
+ self._base_objs = [LinTable_base(copy.deepcopy(list), size)]
def replace(self, list):
"""
@@ -596,7 +597,7 @@ class LogTable(PyoTableObject):
print " Increased size to last point position + 1"
size = list[-1][0] + 1
self._size = size
- self._base_objs = [LogTable_base(list, size)]
+ self._base_objs = [LogTable_base(copy.deepcopy(list), size)]
def replace(self, list):
"""
@@ -726,7 +727,7 @@ class CosLogTable(PyoTableObject):
print " Increased size to last point position + 1"
size = list[-1][0] + 1
self._size = size
- self._base_objs = [CosLogTable_base(list, size)]
+ self._base_objs = [CosLogTable_base(copy.deepcopy(list), size)]
def replace(self, list):
"""
@@ -855,7 +856,7 @@ class CosTable(PyoTableObject):
print " Increased size to last point position + 1"
size = list[-1][0] + 1
self._size = size
- self._base_objs = [CosTable_base(list, size)]
+ self._base_objs = [CosTable_base(copy.deepcopy(list), size)]
def replace(self, list):
"""
@@ -1002,7 +1003,7 @@ class CurveTable(PyoTableObject):
self._size = size
self._tension = tension
self._bias = bias
- self._base_objs = [CurveTable_base(list, tension, bias, size)]
+ self._base_objs = [CurveTable_base(copy.deepcopy(list), tension, bias, size)]
def setTension(self, x):
"""
@@ -1185,7 +1186,7 @@ class ExpTable(PyoTableObject):
self._size = size
self._exp = exp
self._inverse = inverse
- self._base_objs = [ExpTable_base(list, exp, inverse, size)]
+ self._base_objs = [ExpTable_base(copy.deepcopy(list), exp, inverse, size)]
def setExp(self, x):
"""
@@ -1588,6 +1589,33 @@ class SndTable(PyoTableObject):
else:
return _size
+ def getViewTable(self, size, begin=0, end=0):
+ """
+ Return a list of points (in X, Y pixel values) for each channel in the table.
+ These lists can be draw on a DC (WxPython) with a DrawLines method.
+
+ :Args:
+
+ size : tuple
+ Size, (X, Y) pixel values, of the waveform container window.
+ begin : float, optional
+ First position in the the table, in seconds, where to get samples.
+ Defaults to 0.
+ end : float, optional
+ Last position in the table, in seconds, where to get samples.
+
+ if this value is set to 0, that means the end of the table. Defaults to 0.
+
+ """
+ w, h = size
+ chnls = len(self._base_objs)
+ img = []
+ imgHeight = h/chnls
+ for i in range(chnls):
+ off = h/chnls*i
+ img.append(self._base_objs[i].getViewTable((w, imgHeight), begin, end, off))
+ return img
+
def getEnvelope(self, points):
"""
Return the amplitude envelope of the table.
@@ -1759,10 +1787,13 @@ class NewTable(PyoTableObject):
"""
return self._base_objs[0].getLength()
- def getDur(self):
+ def getDur(self, all=True):
"""
Returns the length of the table in seconds.
+ The `all` argument is there for compatibility with SndTable but
+ is not used for now.
+
"""
return self._base_objs[0].getLength()
@@ -1774,6 +1805,33 @@ class NewTable(PyoTableObject):
"""
return self._base_objs[0].getRate()
+ def getViewTable(self, size, begin=0, end=0):
+ """
+ Return a list of points (in X, Y pixel values) for each channel in the table.
+ These lists can be draw on a DC (WxPython) with a DrawLines method.
+
+ :Args:
+
+ size : tuple
+ Size, (X, Y) pixel values, of the waveform container window.
+ begin : float, optional
+ First position in the the table, in seconds, where to get samples.
+ Defaults to 0.
+ end : float, optional
+ Last position in the table, in seconds, where to get samples.
+
+ if this value is set to 0, that means the end of the table. Defaults to 0.
+
+ """
+ w, h = size
+ chnls = len(self._base_objs)
+ img = []
+ imgHeight = h/chnls
+ for i in range(chnls):
+ off = h/chnls*i
+ img.append(self._base_objs[i].getViewTable((w, imgHeight), begin, end, off))
+ return img
+
def view(self, title="Sound waveform", wxnoserver=False, mouse_callback=None):
"""
Opens a window showing the contents of the table.
diff --git a/pyolib/triggers.py b/pyolib/triggers.py
index dac00f0..a3a88f4 100644
--- a/pyolib/triggers.py
+++ b/pyolib/triggers.py
@@ -408,11 +408,11 @@ class Beat(PyoObject):
Beat outputs many signals identified with a string between brackets:
- obj['tap'] returns audio stream of the current tap of the measure.
- obj['amp'] returns audio stream of the current beat amplitude.
- obj['dur'] returns audio stream of the current beat duration in seconds.
- obj['end'] returns audio stream with a trigger just before the end of the measure.
-
+ | obj['tap'] returns audio stream of the current tap of the measure.
+ | obj['amp'] returns audio stream of the current beat amplitude.
+ | obj['dur'] returns audio stream of the current beat duration in seconds.
+ | obj['end'] returns audio stream with a trigger just before the end of the measure.
+
obj without brackets returns the generated trigger stream of the measure.
The out() method is bypassed. Beat's signal can not be sent to audio outs.
@@ -496,6 +496,13 @@ class Beat(PyoObject):
else:
return [obj._getStream().getValue() for obj in self.__getitem__(identifier).getBaseObjects()]
+ def reset(self):
+ """
+ Reset internal counters to initialization values.
+
+ """
+ [obj.reset() for obj in self._base_players]
+
def new(self):
"""
Generates a new pattern with the current parameters.
@@ -676,7 +683,11 @@ class Beat(PyoObject):
pass
def ctrl(self, map_list=None, title=None, wxnoserver=False):
- self._map_list = [SLMap(0.001, 1., 'lin', 'time', self._time)]
+ self._map_list = [SLMap(0.001, 1., 'lin', 'time', self._time),
+ SLMap(2, 64, 'lin', 'taps', self._taps, res="int", dataOnly=True),
+ SLMap(0, 100, 'lin', 'w1', self._w1, res="int", dataOnly=True),
+ SLMap(0, 100, 'lin', 'w2', self._w2, res="int", dataOnly=True),
+ SLMap(0, 100, 'lin', 'w3', self._w3, res="int", dataOnly=True)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
@@ -2261,6 +2272,14 @@ class Counter(PyoObject):
value, lmax = convertArgsToLists(value)
[obj.reset(wrap(value,i)) for i, obj in enumerate(self._base_objs)]
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0, 100, 'lin', 'min', self._min, res="int", dataOnly=True),
+ SLMap(0, 1000, 'lin', 'max', self._max, res="int", dataOnly=True),
+ SLMap(0, 2, 'lin', 'dir', self._dir, res="int", dataOnly=True),
+ SLMap(0, 1000, 'lin', 'mul', self._mul),
+ SLMap(0, 1000, 'lin', 'add', self._add)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
@property
def input(self):
"""PyoObject. Audio trigger signal."""
@@ -2367,6 +2386,10 @@ class Select(PyoObject):
x, lmax = convertArgsToLists(x)
[obj.setValue(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0, 100, 'lin', 'value', self._value, res="int", dataOnly=True)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
@property
def input(self):
"""PyoObject. Audio signal."""
@@ -2923,6 +2946,12 @@ class Count(PyoObject):
x, lmax = convertArgsToLists(x)
[obj.setMax(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0, 10000, 'lin', 'min', self._min, res="int", dataOnly=True),
+ SLMap(10000, 1000000, 'lin', 'max', self._max, res="int", dataOnly=True),
+ SLMapMul(self._mul)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
@property
def input(self):
"""PyoObject. Trigger signal. Start/Restart the count."""
@@ -3122,3 +3151,526 @@ class TrigVal(PyoObject):
@value.setter
def value(self, x):
self.setValue(x)
+
+class Euclide(PyoObject):
+ """
+ Euclidean rhythm generator.
+
+ This object generates euclidean trigger patterns, resulting in onsets
+ in the rhythm to be as equidistant as possible.
+
+ A trigger is an audio signal with a value of 1 surrounded by 0s.
+
+ The play() method starts the Euclide and is not called at the object
+ creation time.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ time : float or PyoObject, optional
+ Time, in seconds, between each beat of the pattern. Defaults to 0.125.
+ taps : int, optional
+ Number of beats in the generated pattern (measure length), max = 64.
+ Defaults to 16.
+ onsets : int, optional
+ Number of onsets (a positive tap) in the generated pattern.
+ Defaults to 10.
+ poly : int, optional
+ Beat polyphony. Denotes how many independent streams are
+ generated by the object, allowing overlapping processes.
+
+ Available only at initialization. Defaults to 1.
+
+ .. note::
+
+ Euclide outputs many signals identified with a string between brackets:
+
+ | obj['tap'] returns audio stream of the current tap of the measure.
+ | obj['amp'] returns audio stream of the current beat amplitude.
+ | obj['dur'] returns audio stream of the current beat duration in seconds.
+ | obj['end'] returns audio stream with a trigger just before the end of the measure.
+
+ obj without brackets returns the generated trigger stream of the measure.
+
+ The out() method is bypassed. Euclide's signal can not be sent to audio outs.
+
+ Euclide has no `mul` and `add` attributes.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> t = CosTable([(0,0), (100,1), (500,.3), (8191,0)])
+ >>> beat = Euclide(time=.125, taps=16, onsets=[8,7], poly=1).play()
+ >>> trmid = TrigXnoiseMidi(beat, dist=12, mrange=(60, 96))
+ >>> trhz = Snap(trmid, choice=[0,2,3,5,7,8,10], scale=1)
+ >>> tr2 = TrigEnv(beat, table=t, dur=beat['dur'], mul=beat['amp'])
+ >>> a = Sine(freq=trhz, mul=tr2*0.3).out()
+
+ """
+ def __init__(self, time=.125, taps=16, onsets=10, poly=1):
+ PyoObject.__init__(self)
+ self._tap_dummy = []
+ self._amp_dummy = []
+ self._dur_dummy = []
+ self._end_dummy = []
+ self._time = time
+ self._taps = taps
+ self._onsets = onsets
+ self._poly = poly
+ time, taps, onsets, lmax = convertArgsToLists(time, taps, onsets)
+ self._base_players = [Beater_base(wrap(time,i), wrap(taps,i), wrap([100]*lmax,i), poly) for i in range(lmax)]
+ self._base_objs = [Beat_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+ self._tap_objs = [BeatTapStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+ self._amp_objs = [BeatAmpStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+ self._dur_objs = [BeatDurStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+ self._end_objs = [BeatEndStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+ for i in range(lmax):
+ preset = [wrap(taps,i)] + self.__generate__(wrap(onsets,i), wrap(taps,i))
+ self._base_players[i].setPresets([preset])
+ self._base_players[i].recall(0)
+
+ def __generate__(self, m, k):
+ """
+ Generates the euclidean rhythm for `m` onsets
+ in a measure of length `k` (number of taps).
+ Looping implementation, faster than recursive.
+ """
+ if m > k: m = k
+ k -= m
+ mv, kv = [1], [0]
+ while k > 1:
+ if m > k:
+ m, k = k, m-k
+ mv, kv = mv+kv, mv
+ else:
+ m, k = m, k-m
+ mv, kv = mv+kv, kv
+ return mv * m + kv * k
+
+ def __getitem__(self, i):
+ if i == 'tap':
+ self._tap_dummy.append(Dummy([obj for obj in self._tap_objs]))
+ return self._tap_dummy[-1]
+ if i == 'amp':
+ self._amp_dummy.append(Dummy([obj for obj in self._amp_objs]))
+ return self._amp_dummy[-1]
+ if i == 'dur':
+ self._dur_dummy.append(Dummy([obj for obj in self._dur_objs]))
+ return self._dur_dummy[-1]
+ if i == 'end':
+ self._end_dummy.append(Dummy([obj for obj in self._end_objs]))
+ return self._end_dummy[-1]
+ if type(i) == SliceType:
+ return self._base_objs[i]
+ if i < len(self._base_objs):
+ return self._base_objs[i]
+ else:
+ print "'i' too large!"
+
+ def get(self, identifier="amp", all=False):
+ """
+ Return the first sample of the current buffer as a float.
+
+ Can be used to convert audio stream to usable Python data.
+
+ "tap", "amp" or "dur" must be given to `identifier` to specify
+ which stream to get value from.
+
+ :Args:
+
+ identifier : string {"tap", "amp", "dur"}
+ Address string parameter identifying audio stream.
+ Defaults to "amp".
+ all : boolean, optional
+ If True, the first value of each object's stream
+ will be returned as a list.
+
+ If False, only the value of the first object's
+ stream will be returned as a float.
+
+ """
+ if not all:
+ return self.__getitem__(identifier)[0]._getStream().getValue()
+ else:
+ return [obj._getStream().getValue() for obj in self.__getitem__(identifier).getBaseObjects()]
+
+ def setTime(self, x):
+ """
+ Replace the `time` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ New `time` attribute.
+
+ """
+ self._time = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setTime(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setTaps(self, x):
+ """
+ Replace the `taps` attribute.
+
+ :Args:
+
+ x : int
+ New `taps` attribute.
+
+ """
+ self._taps = x
+ x, onsets, lmax = convertArgsToLists(x, self._onsets)
+ for i in range(len(self._base_players)):
+ preset = [wrap(x,i)] + self.__generate__(wrap(onsets,i), wrap(x,i))
+ self._base_players[i].setPresets([preset])
+ self._base_players[i].recall(0)
+
+ def setOnsets(self, x):
+ """
+ Replace the `onsets` attribute.
+
+ :Args:
+
+ x : int
+ New `onsets` attribute.
+
+ """
+ self._onsets = x
+ x, taps, lmax = convertArgsToLists(x, self._taps)
+ for i in range(len(self._base_players)):
+ preset = [wrap(taps,i)] + self.__generate__(wrap(x,i), wrap(taps,i))
+ self._base_players[i].setPresets([preset])
+ self._base_players[i].recall(0)
+
+ def reset(self):
+ """
+ Reset internal counters to initialization values.
+
+ """
+ [obj.reset() for obj in self._base_players]
+
+ def play(self, dur=0, delay=0):
+ dur, delay, lmax = convertArgsToLists(dur, delay)
+ self._tap_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._tap_objs)]
+ self._amp_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._amp_objs)]
+ self._dur_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._dur_objs)]
+ self._end_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._end_objs)]
+ return PyoObject.play(self, dur, delay)
+
+ def stop(self):
+ [obj.stop() for obj in self._tap_objs]
+ [obj.stop() for obj in self._amp_objs]
+ [obj.stop() for obj in self._dur_objs]
+ [obj.stop() for obj in self._end_objs]
+ return PyoObject.stop(self)
+
+ def out(self, chnl=0, inc=1, dur=0, delay=0):
+ return self.play(dur, delay)
+
+ def setMul(self, x):
+ pass
+
+ def setAdd(self, x):
+ pass
+
+ def setSub(self, x):
+ pass
+
+ def setDiv(self, x):
+ pass
+
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0.01, 1., 'lin', 'time', self._time),
+ SLMap(2, 64, 'lin', 'taps', self._taps, res="int", dataOnly=True),
+ SLMap(0, 64, 'lin', 'onsets', self._onsets, res="int", dataOnly=True)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+ @property
+ def time(self):
+ """float or PyoObject. Time, in seconds, between each beat."""
+ return self._time
+ @time.setter
+ def time(self, x): self.setTime(x)
+
+ @property
+ def taps(self):
+ """int. Number of beats in the generated pattern."""
+ return self._taps
+ @taps.setter
+ def taps(self, x): self.setTaps(x)
+
+ @property
+ def onsets(self):
+ """int. Number of onsets in the generated pattern."""
+ return self._onsets
+ @onsets.setter
+ def onsets(self, x): self.setOnsets(x)
+
+class TrigBurst(PyoObject):
+ """
+ Generates a time/amplitude expandable trigger pattern.
+
+ A trigger is an audio signal with a value of 1 surrounded by 0s.
+
+ When TrigBurst receives a trigger in its `input` argument, it starts
+ to output `count` triggers with a variable delay between each trigger
+ of the pattern. If `expand` is less than 1.0, the delay becomes shorter,
+ if it is greater than 1.0, the delay becomes longer.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal sending triggers.
+ time : float or PyoObject, optional
+ Base time, in seconds, between each trig of the serie. Defaults to 0.25.
+ count : int, optional
+ Number of trigs generated (length of the serie). Defaults to 10.
+ expand : float, optional
+ Timing power serie factor. Each delay before the next trig is the
+ current delay (starting with `time`) times `expand` factor. Defaults to 1.0.
+ ampfade : float, optional
+ Amplitude power serie factor. Each amplitude in the serie is the
+ current amplitude (starting at 1) times `ampfade` factor. Defaults to 1.0.
+ poly : int, optional
+ Voice polyphony. Denotes how many independent streams are
+ generated by the object, allowing overlapping processes.
+
+ Available only at initialization. Defaults to 1.
+
+ .. note::
+
+ TrigBurst outputs many signals identified with a string between brackets:
+
+ | obj['tap'] returns audio stream of the current tap of the serie.
+ | obj['amp'] returns audio stream of the current beat amplitude.
+ | obj['dur'] returns audio stream of the current beat duration in seconds.
+ | obj['end'] returns audio stream with a trigger just before the end of the serie.
+
+ obj without brackets returns the generated trigger stream of the serie.
+
+ The out() method is bypassed. TrigBurst's signal can not be sent to audio outs.
+
+ TrigBurst has no `mul` and `add` attributes.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> env = CosTable([(0,0), (100,0.5), (500, 0.3), (4096,0.3), (8192,0)])
+ >>> m = Metro(2).play()
+ >>> tb = TrigBurst(m, time=0.15, count=[15,20], expand=[0.92,0.9], ampfade=0.85)
+ >>> amp = TrigEnv(tb, env, dur=tb["dur"], mul=tb["amp"]*0.3)
+ >>> a = Sine([800,600], mul=amp)
+ >>> rev = STRev(a, inpos=[0,1], revtime=1.5, cutoff=5000, bal=0.1).out()
+
+ """
+ def __init__(self, input, time=.25, count=10, expand=1.0, ampfade=1.0, poly=1):
+ PyoObject.__init__(self)
+ self._tap_dummy = []
+ self._amp_dummy = []
+ self._dur_dummy = []
+ self._end_dummy = []
+ self._input = input
+ self._time = time
+ self._count = count
+ self._expand = expand
+ self._ampfade = ampfade
+ self._poly = poly
+ self._in_fader = InputFader(input)
+ in_fader, time, count, expand, ampfade, lmax = convertArgsToLists(self._in_fader, time, count, expand, ampfade)
+ self._base_players = [TrigBurster_base(wrap(in_fader,i), wrap(time,i), wrap(count,i), wrap(expand,i), wrap(ampfade,i), poly) for i in range(lmax)]
+ self._base_objs = [TrigBurst_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+ self._tap_objs = [TrigBurstTapStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+ self._amp_objs = [TrigBurstAmpStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+ self._dur_objs = [TrigBurstDurStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+ self._end_objs = [TrigBurstEndStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+
+ def __getitem__(self, i):
+ if i == 'tap':
+ self._tap_dummy.append(Dummy([obj for obj in self._tap_objs]))
+ return self._tap_dummy[-1]
+ if i == 'amp':
+ self._amp_dummy.append(Dummy([obj for obj in self._amp_objs]))
+ return self._amp_dummy[-1]
+ if i == 'dur':
+ self._dur_dummy.append(Dummy([obj for obj in self._dur_objs]))
+ return self._dur_dummy[-1]
+ if i == 'end':
+ self._end_dummy.append(Dummy([obj for obj in self._end_objs]))
+ return self._end_dummy[-1]
+ if type(i) == SliceType:
+ return self._base_objs[i]
+ if i < len(self._base_objs):
+ return self._base_objs[i]
+ else:
+ print "'i' too large!"
+
+ def get(self, identifier="amp", all=False):
+ """
+ Return the first sample of the current buffer as a float.
+
+ Can be used to convert audio stream to usable Python data.
+
+ "tap", "amp" or "dur" must be given to `identifier` to specify
+ which stream to get value from.
+
+ :Args:
+
+ identifier : string {"tap", "amp", "dur"}
+ Address string parameter identifying audio stream.
+ Defaults to "amp".
+ all : boolean, optional
+ If True, the first value of each object's stream
+ will be returned as a list.
+
+ If False, only the value of the first object's
+ stream will be returned as a float.
+
+ """
+ if not all:
+ return self.__getitem__(identifier)[0]._getStream().getValue()
+ else:
+ return [obj._getStream().getValue() for obj in self.__getitem__(identifier).getBaseObjects()]
+
+ def setInput(self, x, fadetime=0.05):
+ """
+ Replace the `input` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New signal to process.
+ fadetime : float, optional
+ Crossfade time between old and new input. Defaults to 0.05.
+
+ """
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ def setTime(self, x):
+ """
+ Replace the `time` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ New `time` attribute.
+
+ """
+ self._time = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setTime(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setCount(self, x):
+ """
+ Replace the `count` attribute.
+
+ :Args:
+
+ x : int
+ New `count` attribute.
+
+ """
+ self._count = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setCount(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setExpand(self, x):
+ """
+ Replace the `expand` attribute.
+
+ :Args:
+
+ x : int
+ New `expand` attribute.
+
+ """
+ self._expand = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setExpand(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def setAmpfade(self, x):
+ """
+ Replace the `ampfade` attribute.
+
+ :Args:
+
+ x : int
+ New `ampfade` attribute.
+
+ """
+ self._ampfade = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setAmpfade(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+ def play(self, dur=0, delay=0):
+ dur, delay, lmax = convertArgsToLists(dur, delay)
+ self._tap_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._tap_objs)]
+ self._amp_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._amp_objs)]
+ self._dur_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._dur_objs)]
+ self._end_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._end_objs)]
+ return PyoObject.play(self, dur, delay)
+
+ def stop(self):
+ [obj.stop() for obj in self._tap_objs]
+ [obj.stop() for obj in self._amp_objs]
+ [obj.stop() for obj in self._dur_objs]
+ [obj.stop() for obj in self._end_objs]
+ return PyoObject.stop(self)
+
+ def out(self, chnl=0, inc=1, dur=0, delay=0):
+ return self.play(dur, delay)
+
+ def setMul(self, x):
+ pass
+
+ def setAdd(self, x):
+ pass
+
+ def setSub(self, x):
+ pass
+
+ def setDiv(self, x):
+ pass
+
+ def ctrl(self, map_list=None, title=None, wxnoserver=False):
+ self._map_list = [SLMap(0.1, 1., 'lin', 'time', self._time, dataOnly=True),
+ SLMap(2, 128, 'lin', 'count', self._count, res="int", dataOnly=True),
+ SLMap(0.5, 2.0, 'lin', 'expand', self._expand, dataOnly=True),
+ SLMap(0.5, 1.0, 'lin', 'ampfade', self._ampfade, dataOnly=True)]
+ PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+ @property
+ def input(self):
+ """PyoObject. Audio trigger signal."""
+ return self._input
+ @input.setter
+ def input(self, x): self.setInput(x)
+
+ @property
+ def time(self):
+ """float or PyoObject. Base time, in seconds, between each trig."""
+ return self._time
+ @time.setter
+ def time(self, x): self.setTime(x)
+
+ @property
+ def count(self):
+ """int. Number of triggers in the generated serie."""
+ return self._count
+ @count.setter
+ def count(self, x): self.setCount(x)
+
+ @property
+ def expand(self):
+ """float. Time's power expansion factor."""
+ return self._expand
+ @expand.setter
+ def expand(self, x): self.setExpand(x)
+
+ @property
+ def ampfade(self):
+ """float. Amplitude's power expansion factor."""
+ return self._ampfade
+ @ampfade.setter
+ def ampfade(self, x): self.setAmpfade(x)
diff --git a/pyolib/utils.py b/pyolib/utils.py
index f1de462..fb2cd06 100644
--- a/pyolib/utils.py
+++ b/pyolib/utils.py
@@ -430,7 +430,7 @@ class SampHold(PyoObject):
SampHold performs a sample-and-hold operation on its input according
to the value of `controlsig`. If `controlsig` equals `value`, the input
- is sampled and holded until next sampling.
+ is sampled and held until next sampling.
:Parent: :py:class:`PyoObject`
@@ -441,7 +441,7 @@ class SampHold(PyoObject):
controlsig : PyoObject
Controls when to sample the signal.
value : float or PyoObject, optional
- Sampling targeted value. Default to 0.0.
+ Sampling target value. Default to 0.0.
>>> s = Server().boot()
>>> s.start()
@@ -521,7 +521,7 @@ class SampHold(PyoObject):
@property
def value(self):
- """float or PyoObject. Targeted value."""
+ """float or PyoObject. Target value."""
return self._value
@value.setter
def value(self, x): self.setValue(x)
@@ -1553,6 +1553,61 @@ class MToF(PyoObject):
@input.setter
def input(self, x): self.setInput(x)
+class FToM(PyoObject):
+ """
+ Returns the midi note equivalent to a frequency in Hz.
+
+ Returns the midi note equivalent to a frequency in Hz,
+ 440.0 (hz) = 69.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal as frequency in Hz.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> lfo = Sine([0.2,0.25], mul=300, add=600)
+ >>> src = SineLoop(freq=lfo, feedback=0.05)
+ >>> hz = Yin(src, minfreq=100, maxfreq=1000, cutoff=500)
+ >>> mid = FToM(hz)
+ >>> fr = Snap(mid, choice=[0,2,5,7,9], scale=1)
+ >>> freq = Port(fr, risetime=0.01, falltime=0.01)
+ >>> syn = SineLoop(freq, feedback=0.05, mul=0.3).out()
+
+ """
+
+ def __init__(self, input, mul=1, add=0):
+ PyoObject.__init__(self, mul, add)
+ self._input = input
+ self._in_fader = InputFader(input)
+ in_fader, mul, add, lmax = convertArgsToLists(self._in_fader, mul, add)
+ self._base_objs = [FToM_base(wrap(in_fader,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+
+ def setInput(self, x, fadetime=0.05):
+ """
+ Replace the `input` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New signal to process.
+ fadetime : float, optional
+ Crossfade time between old and new input. Default to 0.05.
+
+ """
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ @property
+ def input(self):
+ """PyoObject. Input signal to process."""
+ return self._input
+ @input.setter
+ def input(self, x): self.setInput(x)
+
class MToT(PyoObject):
"""
Returns the transposition factor equivalent to a midi note.
@@ -1736,3 +1791,105 @@ class Between(PyoObject):
return self._max
@max.setter
def max(self, x): self.setMax(x)
+
+class TrackHold(PyoObject):
+ """
+ Performs a track-and-hold operation on its input.
+
+ TrackHold lets pass the signal in `input` without modification but hold
+ a sample according to the value of `controlsig`. If `controlsig` equals
+ `value`, the input is sampled and held, otherwise, it passes thru.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal.
+ controlsig : PyoObject
+ Controls when to sample the signal.
+ value : float or PyoObject, optional
+ Sampling target value. Default to 0.0.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> ph = Phasor([3,4])
+ >>> lf = Sine(.2, mul=.5, add=.5)
+ >>> th = TrackHold(lf, ph > 0.5, 1, mul=500, add=300)
+ >>> a = Sine(th, mul=.3).out()
+
+ """
+ def __init__(self, input, controlsig, value=0.0, mul=1, add=0):
+ PyoObject.__init__(self, mul, add)
+ self._input = input
+ self._controlsig = controlsig
+ self._value = value
+ self._in_fader = InputFader(input)
+ self._in_fader2 = InputFader(controlsig)
+ in_fader, in_fader2, value, mul, add, lmax = convertArgsToLists(self._in_fader, self._in_fader2, value, mul, add)
+ self._base_objs = [TrackHold_base(wrap(in_fader,i), wrap(in_fader2,i), wrap(value,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+
+ def setInput(self, x, fadetime=0.05):
+ """
+ Replace the `input` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New signal to process.
+ fadetime : float, optional
+ Crossfade time between old and new input. Default to 0.05.
+
+ """
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ def setControlsig(self, x, fadetime=0.05):
+ """
+ Replace the `controlsig` attribute.
+
+ :Args:
+
+ x : PyoObject
+ New control signal.
+ fadetime : float, optional
+ Crossfade time between old and new input. Default to 0.05.
+
+ """
+ self._controlsig = x
+ self._in_fader2.setInput(x, fadetime)
+
+ def setValue(self, x):
+ """
+ Replace the `value` attribute.
+
+ :Args:
+
+ x : float or PyoObject
+ New `value` attribute.
+
+ """
+ self._value = x
+ x, lmax = convertArgsToLists(x)
+ [obj.setValue(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ @property
+ def input(self):
+ """PyoObject. Input signal."""
+ return self._input
+ @input.setter
+ def input(self, x): self.setInput(x)
+
+ @property
+ def controlsig(self):
+ """PyoObject. Control signal."""
+ return self._controlsig
+ @controlsig.setter
+ def controlsig(self, x): self.setControlsig(x)
+
+ @property
+ def value(self):
+ """float or PyoObject. Target value."""
+ return self._value
+ @value.setter
+ def value(self, x): self.setValue(x)
diff --git a/scripts/radiopyo-template.py b/scripts/radiopyo-template.py
new file mode 100644
index 0000000..bb07eec
--- /dev/null
+++ b/scripts/radiopyo-template.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Template for a RadioPyo song (version 1.0).
+
+A RadioPyo song is a musical python script using the python-pyo
+module to create the audio processing chain. You can connect to
+the radio here : http://radiopyo.acaia.ca/
+
+There is only a few rules:
+ 1 - It must be a one-page script.
+ 2 - No soundfile, only synthesis.
+ 3 - The script must be finite in time, with fade-in and fade-out
+ to avoid clicks between pieces. Use the DURATION variable.
+
+belangeo - 2014
+
+"""
+from pyo import *
+
+################### USER-DEFINED VARIABLES ###################
+### READY is used to manage the server behaviour depending ###
+### of the context. Set this variable to True when the ###
+### music is ready for the radio. TITLE and ARTIST are the ###
+### infos shown by the radio player. DURATION set the ###
+### duration of the audio file generated for the streaming.###
+##############################################################
+READY = False # Set to True when ready for the radio
+TITLE = "Song Title" # The title of the music
+ARTIST = "Artist Name" # Your artist name
+DURATION = 300 # The duration of the music in seconds
+##################### These are optional #####################
+GENRE = "Electronic" # Kind of your music, if there is any
+DATE = 2014 # Year of creation
+
+####################### SERVER CREATION ######################
+if READY:
+ s = Server(duplex=0, audio="offline").boot()
+ s.recordOptions(dur=DURATION, filename="radiopyo.ogg", fileformat=7)
+else:
+ s = Server(duplex=0).boot()
+
+
+##################### PROCESSING SECTION #####################
+# global volume (should be used to control the overall sound)
+fade = Fader(fadein=0.001, fadeout=10, dur=DURATION).play()
+
+
+###
+### Insert your algorithms here...
+###
+
+
+#################### START THE PROCESSING ###################
+s.start()
+if not READY:
+ s.gui(locals())
diff --git a/scripts/release_doc_src.sh b/scripts/release_doc_src.sh
index 9b8c344..78c8449 100644
--- a/scripts/release_doc_src.sh
+++ b/scripts/release_doc_src.sh
@@ -6,7 +6,7 @@
# 3. Execute from pyo folder : ./scripts/release_doc_src.sh
#
-version=0.6.8
+version=0.7.4
replace=XXX
doc_rep=pyo_XXX-doc
diff --git a/scripts/win/windows-build-routine.txt b/scripts/win/windows-7-build-routine.txt
similarity index 96%
copy from scripts/win/windows-build-routine.txt
copy to scripts/win/windows-7-build-routine.txt
index 2cac5e2..f2b08c2 100644
--- a/scripts/win/windows-build-routine.txt
+++ b/scripts/win/windows-7-build-routine.txt
@@ -1,12 +1,12 @@
=== STEP 1 ===
---- Install Python (2.5 -> 2.7)
+--- Install Python (2.6 and 2.7)
=== STEP 2 ===
---- Install Slick SVN (Slick-Subversion-1.6.12-win32.msi)
-http://www.sliksvn.com/pub/Slik-Subversion-1.6.12-win32.msi
+--- Install Slick SVN 1.8.10
+http://www.sliksvn.com
=== STEP 3 ===
---- Install scons 2.2.0 in the Python site-packages:
+--- Install scons 2.3.2 in the Python site-packages:
http://www.scons.org/download.php
=== STEP 4 ===
diff --git a/setup.py b/setup.py
index 92bcd39..d67d090 100644
--- a/setup.py
+++ b/setup.py
@@ -23,7 +23,7 @@ from distutils.core import setup, Extension
import os, sys, getopt
import time
-pyo_version = "0.6.8"
+pyo_version = "0.7.4"
build_osx_with_jack_support = False
compile_externals = False
@@ -68,13 +68,14 @@ files = ['pyomodule.c', 'servermodule.c', 'pvstreammodule.c', 'streammodule.c',
source_files = [path + f for f in files]
path = 'src/objects/'
-files = ['phasevocmodule.c', 'fftmodule.c', 'oscilmodule.c', 'randommodule.c', 'oscmodule.c','analysismodule.c',
- 'sfplayermodule.c', 'oscbankmodule.c', 'lfomodule.c', 'tablemodule.c',
+files = ['granulatormodule.c', 'tablemodule.c', 'wgverbmodule.c', 'freeverbmodule.c', 'phasevocmodule.c', 'fftmodule.c',
+ 'oscilmodule.c', 'randommodule.c', 'oscmodule.c','analysismodule.c',
+ 'sfplayermodule.c', 'oscbankmodule.c', 'lfomodule.c',
'matrixmodule.c', 'filtremodule.c', 'noisemodule.c', 'distomodule.c',
- 'inputmodule.c', 'fadermodule.c', 'midimodule.c', 'delaymodule.c','recordmodule.c', 'granulatormodule.c',
+ 'inputmodule.c', 'fadermodule.c', 'midimodule.c', 'delaymodule.c','recordmodule.c',
'metromodule.c', 'trigmodule.c', 'patternmodule.c', 'bandsplitmodule.c', 'hilbertmodule.c', 'panmodule.c',
- 'selectmodule.c', 'freeverbmodule.c', 'compressmodule.c', 'utilsmodule.c',
- 'convolvemodule.c', 'wgverbmodule.c', 'arithmeticmodule.c', 'sigmodule.c',
+ 'selectmodule.c', 'compressmodule.c', 'utilsmodule.c',
+ 'convolvemodule.c', 'arithmeticmodule.c', 'sigmodule.c',
'matrixprocessmodule.c', 'harmonizermodule.c', 'chorusmodule.c']
if compile_externals:
@@ -93,6 +94,8 @@ else:
tsrt = time.strftime('"%d %b %Y %H:%M:%S"', time.localtime())
macros.append(('TIMESTAMP', tsrt))
include_dirs = ['include', '/usr/local/include']
+ if sys.platform == "darwin":
+ include_dirs.append('/opt/local/include')
library_dirs = []
libraries = ['portaudio', 'portmidi', 'sndfile', 'lo']
if build_osx_with_jack_support:
diff --git a/src/engine/inputfadermodule.c b/src/engine/inputfadermodule.c
index 5f6b44e..a8b26f1 100644
--- a/src/engine/inputfadermodule.c
+++ b/src/engine/inputfadermodule.c
@@ -169,11 +169,8 @@ InputFader_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "server") == 0 ) {
- PySys_WriteStderr("TypeError: \"input\" argument must be a PyoObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument must be a PyoObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input1);
diff --git a/src/engine/interpolation.c b/src/engine/interpolation.c
index a9ee2b5..00ee8c2 100644
--- a/src/engine/interpolation.c
+++ b/src/engine/interpolation.c
@@ -38,7 +38,7 @@ MYFLT cosine(MYFLT *buf, int index, MYFLT frac, int size) {
MYFLT x2 = buf[index+1];
frac2 = (1.0 - MYCOS(frac * M_PI)) * 0.5;
- return (x1 * (1.0 - frac2) + x2 * frac2);
+ return (x1 + (x2 - x1) * frac2);
}
MYFLT cubic(MYFLT *buf, int index, MYFLT frac, int size) {
diff --git a/src/engine/pyomodule.c b/src/engine/pyomodule.c
index 208eff1..24c05c5 100644
--- a/src/engine/pyomodule.c
+++ b/src/engine/pyomodule.c
@@ -52,6 +52,28 @@ static void portaudio_assert(PaError ecode, const char* cmdName) {
>>> print c\n\
1\n\n"
+#define portaudio_get_version_info \
+"\nReturns the version number, as an integer, of the current portaudio installation.\n\n\
+>>> v = pa_get_version()\n\
+>>> print v\n\
+1899\n\n"
+
+static PyObject *
+portaudio_get_version() {
+ return PyInt_FromLong(Pa_GetVersion());
+}
+
+#define portaudio_get_version_text_info \
+"\nReturns the textual description of the current portaudio installation.\n\n\
+>>> desc = pa_get_version_text()\n\
+>>> print desc\n\
+PortAudio V19-devel (built Oct 8 2012 16:25:16)\n\n"
+
+static PyObject *
+portaudio_get_version_text() {
+ return PyString_FromString(Pa_GetVersionText());
+}
+
static PyObject *
portaudio_count_host_apis(){
PaError err;
@@ -1296,7 +1318,7 @@ downsamp(PyObject *self, PyObject *args, PyObject *kwds)
for (i=0; i<samples_per_channels; i++) {
for (j=0; j<snd_chnls; j++) {
- if (i < snd_size)
+ if (i*down < snd_size)
downsamples[j][i] = samples[j][i*down];
else
downsamples[j][i] = 0.0;
@@ -1745,9 +1767,10 @@ rescale(PyObject *self, PyObject *args, PyObject *kwds)
type = 0;
else if (PyList_Check(data))
type = 1;
- else
- Py_RETURN_NONE;
-
+ else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
if (xlog == 0 && ylog == 0) {
datascl = xmax - xmin;
curscl = ymax - ymin;
@@ -1832,9 +1855,47 @@ rescale(PyObject *self, PyObject *args, PyObject *kwds)
}
}
else {
- Py_RETURN_NONE;
+ Py_INCREF(Py_None);
+ return Py_None;
}
- Py_RETURN_NONE;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#define floatmap_info \
+"\nConverts values from a 0-1 range to an output range.\n\n\
+This function takes data in the range `0` - `1` and returns corresponding values\nin the range `min` - `max`.\n\n\
+:Argss:\n\n \
+x : float\n Value to convert, in the range 0 to 1.\n \
+min : float, optional\n Minimum value of the output range. Defaults to 0.\n \
+max : float, optional\n Maximum value of the output range. Defaults to 1.\n \
+exp : float, optional\n Power factor (1 (default) is linear, les than 1 is logarithmic, greter than 1 is exponential).\n\n\
+>>> a = 0.5\n\
+>>> b = floatmap(a, 0, 1, 4)\n\
+>>> print b\n\
+0.0625\n\n"
+
+static PyObject *
+floatmap(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ MYFLT x = 0.0;
+ MYFLT min = 0.0;
+ MYFLT max = 1.0;
+ MYFLT exp = 1.0;
+
+ static char *kwlist[] = {"x", "min", "max", "exp", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_F_FFF, kwlist, &x, &min, &max, &exp))
+ return PyInt_FromLong(-1);
+
+ if (x < 0.0)
+ x = 0.0;
+ else if (x > 1.0)
+ x = 1.0;
+ if (exp != 1.0)
+ x = MYPOW(x, exp);
+
+ return Py_BuildValue("d", x * (max - min) + min);
}
/****** Conversion utilities ******/
@@ -1860,13 +1921,58 @@ midiToHz(PyObject *self, PyObject *arg) {
double x = 0.0;
PyObject *newseq = NULL;
if (PyNumber_Check(arg))
- return Py_BuildValue("d", 8.1757989156437 * pow(1.0594630943593, PyFloat_AsDouble(PyNumber_Float(arg))));
+ return Py_BuildValue("d", 440.0 * MYPOW(2.0, (PyFloat_AsDouble(PyNumber_Float(arg)) - 69) / 12.0));
+ else if (PyList_Check(arg)) {
+ count = PyList_Size(arg);
+ newseq = PyList_New(count);
+ for (i=0; i<count; i++) {
+ x = PyFloat_AsDouble(PyNumber_Float(PyList_GET_ITEM(arg, i)));
+ PyList_SET_ITEM(newseq, i, PyFloat_FromDouble(440.0 * MYPOW(2.0, (x - 69) / 12.0)));
+ }
+ return newseq;
+ }
+ else if (PyTuple_Check(arg)) {
+ count = PyTuple_Size(arg);
+ newseq = PyTuple_New(count);
+ for (i=0; i<count; i++) {
+ x = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(arg, i)));
+ PyTuple_SET_ITEM(newseq, i, PyFloat_FromDouble(440.0 * MYPOW(2.0, (x - 69) / 12.0)));
+ }
+ return newseq;
+ }
+ else
+ Py_RETURN_NONE;
+}
+
+#define hzToMidi_info \
+"\nConverts a frequency in Hertz to a midi note value.\n\n:Args:\n\n \
+x : float\n Frequency in Hertz. `x` can be a number, a list or a tuple, otherwise the function returns None.\n\n\
+>>> a = (110.0, 220.0, 440.0, 880.0)\n\
+>>> b = hzToMidi(a)\n\
+>>> print b\n\
+(45.0, 57.0, 69.0, 81.0)\n\
+>>> a = [110.0, 220.0, 440.0, 880.0]\n\
+>>> b = hzToMidi(a)\n\
+>>> print b\n\
+[45.0, 57.0, 69.0, 81.0]\n\
+>>> b = hzToMidi(440.0)\n\
+>>> print b\n\
+69.0\n\n"
+
+static PyObject *
+hzToMidi(PyObject *self, PyObject *arg) {
+ int count = 0;
+ int i = 0;
+ double x = 0.0;
+ PyObject *newseq = NULL;
+ if (PyNumber_Check(arg))
+ return Py_BuildValue("d", 12.0 * MYLOG2(PyFloat_AsDouble(PyNumber_Float(arg)) / 440.0) + 69);
else if (PyList_Check(arg)) {
count = PyList_Size(arg);
newseq = PyList_New(count);
for (i=0; i<count; i++) {
x = PyFloat_AsDouble(PyNumber_Float(PyList_GET_ITEM(arg, i)));
- PyList_SET_ITEM(newseq, i, PyFloat_FromDouble(8.1757989156437 * pow(1.0594630943593, x)));
+ PyList_SET_ITEM(newseq, i, PyFloat_FromDouble(12.0 * MYLOG2(x / 440.0) + 69));
}
return newseq;
}
@@ -1875,7 +1981,7 @@ midiToHz(PyObject *self, PyObject *arg) {
newseq = PyTuple_New(count);
for (i=0; i<count; i++) {
x = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(arg, i)));
- PyTuple_SET_ITEM(newseq, i, PyFloat_FromDouble(8.1757989156437 * pow(1.0594630943593, x)));
+ PyTuple_SET_ITEM(newseq, i, PyFloat_FromDouble(12.0 * MYLOG2(x / 440.0) + 69));
}
return newseq;
}
@@ -2077,6 +2183,8 @@ serverBooted(PyObject *self) {
}
static PyMethodDef pyo_functions[] = {
+{"pa_get_version", (PyCFunction)portaudio_get_version, METH_NOARGS, portaudio_get_version_info},
+{"pa_get_version_text", (PyCFunction)portaudio_get_version_text, METH_NOARGS, portaudio_get_version_text_info},
{"pa_count_devices", (PyCFunction)portaudio_count_devices, METH_NOARGS, portaudio_count_devices_info},
{"pa_count_host_apis", (PyCFunction)portaudio_count_host_apis, METH_NOARGS, portaudio_count_host_apis_info},
{"pa_list_devices", (PyCFunction)portaudio_list_devices, METH_NOARGS, portaudio_list_devices_info},
@@ -2103,8 +2211,10 @@ static PyMethodDef pyo_functions[] = {
{"reducePoints", (PyCFunction)reducePoints, METH_VARARGS|METH_KEYWORDS, reducePoints_info},
{"distanceToSegment", (PyCFunction)distanceToSegment, METH_VARARGS|METH_KEYWORDS, distanceToSegment_info},
{"rescale", (PyCFunction)rescale, METH_VARARGS|METH_KEYWORDS, rescale_info},
+{"floatmap", (PyCFunction)floatmap, METH_VARARGS|METH_KEYWORDS, floatmap_info},
{"linToCosCurve", (PyCFunction)linToCosCurve, METH_VARARGS|METH_KEYWORDS, linToCosCurve_info},
{"midiToHz", (PyCFunction)midiToHz, METH_O, midiToHz_info},
+{"hzToMidi", (PyCFunction)hzToMidi, METH_O, hzToMidi_info},
{"midiToTranspo", (PyCFunction)midiToTranspo, METH_O, midiToTranspo_info},
{"sampsToSec", (PyCFunction)sampsToSec, METH_O, sampsToSec_info},
{"secToSamps", (PyCFunction)secToSamps, METH_O, secToSamps_info},
@@ -2275,6 +2385,7 @@ init_pyo64(void)
module_add_object(m, "CtlScan2_base", &CtlScan2Type);
module_add_object(m, "MidiNote_base", &MidiNoteType);
module_add_object(m, "Notein_base", &NoteinType);
+ module_add_object(m, "NoteinTrig_base", &NoteinTrigType);
module_add_object(m, "Bendin_base", &BendinType);
module_add_object(m, "Touchin_base", &TouchinType);
module_add_object(m, "Programin_base", &PrograminType);
@@ -2352,6 +2463,7 @@ init_pyo64(void)
module_add_object(m, "M_Floor_base", &M_FloorType);
module_add_object(m, "M_Ceil_base", &M_CeilType);
module_add_object(m, "M_Round_base", &M_RoundType);
+ module_add_object(m, "M_Tanh_base", &M_TanhType);
module_add_object(m, "Snap_base", &SnapType);
module_add_object(m, "Interp_base", &InterpType);
module_add_object(m, "SampHold_base", &SampHoldType);
@@ -2361,6 +2473,7 @@ init_pyo64(void)
module_add_object(m, "CentsToTranspo_base", &CentsToTranspoType);
module_add_object(m, "TranspoToCents_base", &TranspoToCentsType);
module_add_object(m, "MToF_base", &MToFType);
+ module_add_object(m, "FToM_base", &FToMType);
module_add_object(m, "MToT_base", &MToTType);
module_add_object(m, "FFTMain_base", &FFTMainType);
module_add_object(m, "FFT_base", &FFTType);
@@ -2408,6 +2521,24 @@ init_pyo64(void)
module_add_object(m, "PVMix_base", &PVMixType);
module_add_object(m, "Granule_base", &GranuleType);
module_add_object(m, "TableScale_base", &TableScaleType);
+ module_add_object(m, "TrackHold_base", &TrackHoldType);
+ module_add_object(m, "ComplexRes_base", &ComplexResType);
+ module_add_object(m, "STReverb_base", &STReverbType);
+ module_add_object(m, "STRev_base", &STRevType);
+ module_add_object(m, "Pointer2_base", &Pointer2Type);
+ module_add_object(m, "Centroid_base", &CentroidType);
+ module_add_object(m, "AttackDetector_base", &AttackDetectorType);
+ module_add_object(m, "SmoothDelay_base", &SmoothDelayType);
+ module_add_object(m, "TrigBurster_base", &TrigBursterType);
+ module_add_object(m, "TrigBurst_base", &TrigBurstType);
+ module_add_object(m, "TrigBurstTapStream_base", &TrigBurstTapStreamType);
+ module_add_object(m, "TrigBurstAmpStream_base", &TrigBurstAmpStreamType);
+ module_add_object(m, "TrigBurstDurStream_base", &TrigBurstDurStreamType);
+ module_add_object(m, "TrigBurstEndStream_base", &TrigBurstEndStreamType);
+ module_add_object(m, "Scope_base", &ScopeType);
+ module_add_object(m, "PeakAmp_base", &PeakAmpType);
+ module_add_object(m, "MainParticle_base", &MainParticleType);
+ module_add_object(m, "Particle_base", &ParticleType);
PyModule_AddStringConstant(m, "PYO_VERSION", PYO_VERSION);
#ifdef COMPILE_EXTERNALS
diff --git a/src/engine/servermodule.c b/src/engine/servermodule.c
index 9148323..373fb3f 100644
--- a/src/engine/servermodule.c
+++ b/src/engine/servermodule.c
@@ -53,11 +53,11 @@ static inline void Server_process_buffers(Server *server);
static int Server_start_rec_internal(Server *self, char *filename);
/* random objects count and multiplier to assign different seed to each instance. */
-#define num_rnd_objs 27
+#define num_rnd_objs 29
-int rnd_objs_count[num_rnd_objs] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+int rnd_objs_count[num_rnd_objs] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int rnd_objs_mult[num_rnd_objs] = {1993,1997,1999,2003,2011,2017,2027,2029,2039,2053,2063,2069,
- 2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153, 2161,2179};
+ 2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153,2161,2179,2203,2207};
#ifdef USE_COREAUDIO
static int coreaudio_stop_callback(Server *self);
@@ -127,17 +127,20 @@ Server_debug(Server *self, char * format, ...)
/* Portmidi get input events */
static void portmidiGetEvents(Server *self)
{
+ int i;
PmError result;
PmEvent buffer;
- do {
- result = Pm_Poll(self->in);
- if (result) {
- if (Pm_Read(self->in, &buffer, 1) == pmBufferOverflow)
- continue;
- self->midiEvents[self->midi_count++] = buffer;
- }
- } while (result);
+ for (i=0; i<self->midiin_count; i++) {
+ do {
+ result = Pm_Poll(self->midiin[i]);
+ if (result) {
+ if (Pm_Read(self->midiin[i], &buffer, 1) == pmBufferOverflow)
+ continue;
+ self->midiEvents[self->midi_count++] = buffer;
+ }
+ } while (result);
+ }
}
/* Portaudio stuff */
@@ -578,19 +581,19 @@ int
Server_jack_autoconnect (Server *self)
{
const char **ports;
- int i, ret = 0;
+ int i, j, num = 0, ret = 0;
PyoJackBackendData *be_data = (PyoJackBackendData *) self->audio_be_data;
if (self->jackautoin) {
- if ((ports = jack_get_ports (be_data->jack_client, NULL, NULL, JackPortIsOutput)) == NULL) {
- Server_error(self, "Jack: Cannot find any physical capture ports\n");
+ if ((ports = jack_get_ports (be_data->jack_client, "system", NULL, JackPortIsOutput)) == NULL) {
+ Server_error(self, "Jack: Cannot find any physical capture ports called 'system'\n");
ret = -1;
}
i=0;
while(ports[i]!=NULL && be_data->jack_in_ports[i] != NULL){
if (jack_connect (be_data->jack_client, ports[i], jack_port_name(be_data->jack_in_ports[i]))) {
- Server_error(self, "Jack: cannot connect input ports\n");
+ Server_error(self, "Jack: cannot connect input ports to 'system'\n");
ret = -1;
}
i++;
@@ -599,21 +602,62 @@ Server_jack_autoconnect (Server *self)
}
if (self->jackautoout) {
- if ((ports = jack_get_ports (be_data->jack_client, NULL, NULL, JackPortIsInput)) == NULL) {
- Server_error(self, "Jack: Cannot find any physical playback ports\n");
+ if ((ports = jack_get_ports (be_data->jack_client, "system", NULL, JackPortIsInput)) == NULL) {
+ Server_error(self, "Jack: Cannot find any physical playback ports called 'system'\n");
ret = -1;
}
i=0;
while(ports[i]!=NULL && be_data->jack_out_ports[i] != NULL){
if (jack_connect (be_data->jack_client, jack_port_name (be_data->jack_out_ports[i]), ports[i])) {
- Server_error(self, "Jack: cannot connect output ports\n");
+ Server_error(self, "Jack: cannot connect output ports to 'system'\n");
ret = -1;
}
i++;
}
free (ports);
}
+
+ num = PyList_Size(self->jackAutoConnectInputPorts);
+ if (num > 0) {
+ for (j=0; j<num; j++) {
+ if ((ports = jack_get_ports (be_data->jack_client, PyString_AsString(PyList_GetItem(self->jackAutoConnectInputPorts, j)), NULL, JackPortIsOutput)) == NULL) {
+ Server_error(self, "Jack: cannot connect input ports to %s\n", PyString_AsString(PyList_GetItem(self->jackAutoConnectInputPorts, j)));
+ }
+ else {
+ i = 0;
+ while(ports[i] != NULL && be_data->jack_in_ports[i] != NULL){
+ if (jack_connect (be_data->jack_client, ports[i], jack_port_name (be_data->jack_in_ports[i]))) {
+ Server_error(self, "Jack: cannot connect input ports\n");
+ ret = -1;
+ }
+ i++;
+ }
+ free (ports);
+ }
+ }
+ }
+
+ num = PyList_Size(self->jackAutoConnectOutputPorts);
+ if (num > 0) {
+ for (j=0; j<num; j++) {
+ if ((ports = jack_get_ports (be_data->jack_client, PyString_AsString(PyList_GetItem(self->jackAutoConnectOutputPorts, j)), NULL, JackPortIsInput)) == NULL) {
+ Server_error(self, "Jack: cannot connect output ports to %s\n", PyString_AsString(PyList_GetItem(self->jackAutoConnectOutputPorts, j)));
+ }
+ else {
+ i = 0;
+ while(ports[i] != NULL && be_data->jack_out_ports[i] != NULL){
+ if (jack_connect (be_data->jack_client, jack_port_name (be_data->jack_out_ports[i]), ports[i])) {
+ Server_error(self, "Jack: cannot connect output ports\n");
+ ret = -1;
+ }
+ i++;
+ }
+ free (ports);
+ }
+ }
+ }
+
return ret;
}
@@ -989,19 +1033,19 @@ Server_coreaudio_init(Server *self)
/* Get output device stream configuration */
count = sizeof(AudioStreamBasicDescription);
- err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDescription);
+ err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDescription);
if (err != kAudioHardwareNoError)
Server_debug(self, "Get kAudioDevicePropertyStreamFormat error %s\n", (char*)&err);
/*
outputStreamDescription.mSampleRate = (Float64)self->samplingRate;
- err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyStreamFormat, count, &outputStreamDescription);
+ err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyStreamFormat, count, &outputStreamDescription);
if (err != kAudioHardwareNoError)
Server_debug(self, "Set kAudioDevicePropertyStreamFormat error %s\n", (char*)&err);
// Print new output stream description
- err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDescription);
+ err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDescription);
if (err != kAudioHardwareNoError)
Server_debug(self, "Get kAudioDevicePropertyStreamFormat error %s\n", (char*)&err);
*/
@@ -1014,7 +1058,7 @@ Server_coreaudio_init(Server *self)
/********* Set input and output callbacks *********/
/**************************************************/
if (self->duplex == 1) {
- err = AudioDeviceAddIOProc(self->input, coreaudio_input_callback, (void *) self); // setup our device with an IO proc
+ err = AudioDeviceAddIOProc(self->input, coreaudio_input_callback, (void *) self); // setup our device with an IO proc
if (err != kAudioHardwareNoError) {
Server_error(self, "Input AudioDeviceAddIOProc failed %d\n", (int)err);
return -1;
@@ -1029,7 +1073,7 @@ Server_coreaudio_init(Server *self)
err = AudioDeviceSetProperty(self->input, &now, 0, true, kAudioDevicePropertyIOProcStreamUsage, propertySize, input_su);
}
- err = AudioDeviceAddIOProc(self->output, coreaudio_output_callback, (void *) self); // setup our device with an IO proc
+ err = AudioDeviceAddIOProc(self->output, coreaudio_output_callback, (void *) self); // setup our device with an IO proc
if (err != kAudioHardwareNoError) {
Server_error(self, "Output AudioDeviceAddIOProc failed %d\n", (int)err);
return -1;
@@ -1219,7 +1263,7 @@ Server_embedded_ni_start(Server *self)
/* Non-Interleaved */
for (i=0; i<self->bufferSize; i++) {
for (j=0; j<=self->nchnls; j++) {
- /* This could probably be more efficient (ob) */
+ /* TODO: This could probably be more efficient (ob) */
self->output_buffer[i+(self->bufferSize*(j+1))-self->bufferSize] = out[(i*self->nchnls)+j];
}
}
@@ -1465,10 +1509,14 @@ Server_shut_down(Server *self)
return Py_None;
}
+/* handling of PyObjects */
static int
Server_traverse(Server *self, visitproc visit, void *arg)
{
+ /* GUI and TIME ? */
Py_VISIT(self->streams);
+ Py_VISIT(self->jackAutoConnectInputPorts);
+ Py_VISIT(self->jackAutoConnectOutputPorts);
return 0;
}
@@ -1476,6 +1524,8 @@ static int
Server_clear(Server *self)
{
Py_CLEAR(self->streams);
+ Py_CLEAR(self->jackAutoConnectInputPorts);
+ Py_CLEAR(self->jackAutoConnectOutputPorts);
return 0;
}
@@ -1511,9 +1561,8 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (strcmp(audioType, "embedded") != 0)
{
if (PyServer_get_server() != NULL) {
- Server_warning((Server *) PyServer_get_server(), "Warning: A Server is already created!\n"
- "If you put this Server in a new variable, please delete it!\n");
- return PyServer_get_server();
+ PyErr_SetString(PyExc_RuntimeError, "Warning: Trying to create a new Server object while one is already created!\n");
+ Py_RETURN_NONE;
}
}
@@ -1524,7 +1573,8 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
}
if(serverID == MAX_NBR_SERVER){
- return PyString_FromString("You are already using the maximum number of server allowed!");
+ PyErr_SetString(PyExc_RuntimeError, "You are already using the maximum number of server allowed!\n");
+ Py_RETURN_NONE;
}
Server *self;
@@ -1534,6 +1584,8 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->serverName = (char *) calloc(32, sizeof(char));
self->jackautoin = 1;
self->jackautoout = 1;
+ self->jackAutoConnectInputPorts = PyList_New(0);
+ self->jackAutoConnectOutputPorts = PyList_New(0);
self->samplingRate = 44100.0;
self->nchnls = 2;
self->record = 0;
@@ -1543,6 +1595,8 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->output = -1;
self->input_offset = 0;
self->output_offset = 0;
+ self->midiin_count = 0;
+ self->midiout_count = 0;
self->midi_input = -1;
self->midi_output = -1;
self->amp = self->resetAmp = 1.;
@@ -1623,7 +1677,7 @@ Server_setInputOffset(Server *self, PyObject *arg)
Py_INCREF(Py_None);
return Py_None;
}
- if (arg != NULL) {
+ if (arg != NULL) {
if (PyInt_Check(arg))
self->input_offset = PyInt_AsLong(arg);
}
@@ -1639,7 +1693,7 @@ Server_setOutputOffset(Server *self, PyObject *arg)
Py_INCREF(Py_None);
return Py_None;
}
- if (arg != NULL) {
+ if (arg != NULL) {
if (PyInt_Check(arg))
self->output_offset = PyInt_AsLong(arg);
}
@@ -1650,7 +1704,7 @@ Server_setOutputOffset(Server *self, PyObject *arg)
static PyObject *
Server_setInputDevice(Server *self, PyObject *arg)
{
- if (arg != NULL) {
+ if (arg != NULL) {
if (PyInt_Check(arg))
self->input = PyInt_AsLong(arg);
}
@@ -1661,7 +1715,7 @@ Server_setInputDevice(Server *self, PyObject *arg)
static PyObject *
Server_setInOutDevice(Server *self, PyObject *arg)
{
- if (arg != NULL) {
+ if (arg != NULL) {
if (PyInt_Check(arg))
self->input = PyInt_AsLong(arg);
self->output = PyInt_AsLong(arg);
@@ -1673,7 +1727,7 @@ Server_setInOutDevice(Server *self, PyObject *arg)
static PyObject *
Server_setOutputDevice(Server *self, PyObject *arg)
{
- if (arg != NULL) {
+ if (arg != NULL) {
if (PyInt_Check(arg))
self->output = PyInt_AsLong(arg);
}
@@ -1684,7 +1738,7 @@ Server_setOutputDevice(Server *self, PyObject *arg)
static PyObject *
Server_setMidiInputDevice(Server *self, PyObject *arg)
{
- if (arg != NULL) {
+ if (arg != NULL) {
if (PyInt_Check(arg))
self->midi_input = PyInt_AsLong(arg);
}
@@ -1695,7 +1749,7 @@ Server_setMidiInputDevice(Server *self, PyObject *arg)
static PyObject *
Server_setMidiOutputDevice(Server *self, PyObject *arg)
{
- if (arg != NULL) {
+ if (arg != NULL) {
if (PyInt_Check(arg))
self->midi_output = PyInt_AsLong(arg);
}
@@ -1791,6 +1845,42 @@ Server_setJackAuto(Server *self, PyObject *args)
}
static PyObject *
+Server_setJackAutoConnectInputPorts(Server *self, PyObject *arg)
+{
+ PyObject *tmp;
+
+ if (arg != NULL) {
+ if (PyList_Check(arg)) {
+ tmp = arg;
+ Py_XDECREF(self->jackAutoConnectInputPorts);
+ Py_INCREF(tmp);
+ self->jackAutoConnectInputPorts = tmp;
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+Server_setJackAutoConnectOutputPorts(Server *self, PyObject *arg)
+{
+ PyObject *tmp;
+
+ if (arg != NULL) {
+ if (PyList_Check(arg)) {
+ tmp = arg;
+ Py_XDECREF(self->jackAutoConnectOutputPorts);
+ Py_INCREF(tmp);
+ self->jackAutoConnectOutputPorts = tmp;
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
Server_setGlobalSeed(Server *self, PyObject *arg)
{
unsigned int tmp;
@@ -1949,6 +2039,7 @@ Server_setStartOffset(Server *self, PyObject *arg)
int
Server_pm_init(Server *self)
{
+ int i = 0;
/* Initializing MIDI */
PmError pmerr;
@@ -1966,61 +2057,123 @@ Server_pm_init(Server *self)
}
if (self->withPortMidi == 1) {
+ self->midiin_count = self->midiout_count = 0;
int num_devices = Pm_CountDevices();
+ Server_debug(self, "Portmidi number of devices: %d.\n", num_devices);
if (num_devices > 0) {
- if (self->midi_input == -1 || self->midi_input >= num_devices)
- self->midi_input = Pm_GetDefaultInputDeviceID();
- Server_debug(self, "Midi input device : %d.\n", self->midi_input);
- const PmDeviceInfo *info = Pm_GetDeviceInfo(self->midi_input);
- if (info != NULL) {
- if (info->input) {
- pmerr = Pm_OpenInput(&self->in, self->midi_input, NULL, 100, NULL, NULL);
- if (pmerr) {
- Server_warning(self,
+ if (self->midi_input < num_devices) {
+ if (self->midi_input == -1)
+ self->midi_input = Pm_GetDefaultInputDeviceID();
+ Server_debug(self, "Midi input device : %d.\n", self->midi_input);
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(self->midi_input);
+ if (info != NULL) {
+ if (info->input) {
+ pmerr = Pm_OpenInput(&self->midiin[0], self->midi_input, NULL, 100, NULL, NULL);
+ if (pmerr) {
+ Server_warning(self,
"Portmidi warning: could not open midi input %d (%s): %s\n",
- 0, info->name, Pm_GetErrorText(pmerr));
+ self->midi_input, info->name, Pm_GetErrorText(pmerr));
+ self->withPortMidi = 0;
+ }
+ else {
+ Server_debug(self, "Midi input (%s) opened.\n", info->name);
+ self->midiin_count = 1;
+ }
+ }
+ else {
+ Server_warning(self, "Portmidi warning: Midi Device (%s), not an input device!\n", info->name);
self->withPortMidi = 0;
- }
- else
- Server_debug(self, "Midi input (%s) opened.\n", info->name);
+ }
}
- else {
- Server_warning(self, "Portmidi warning: something wrong with midi input device!\n");
- self->withPortMidi = 0;
+ }
+ else if (self->midi_input >= num_devices) {
+ Server_debug(self, "Midi input device : all!\n");
+ self->midiin_count = 0;
+ for (i=0; i<num_devices; i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ if (info != NULL) {
+ if (info->input) {
+ pmerr = Pm_OpenInput(&self->midiin[self->midiin_count], i, NULL, 100, NULL, NULL);
+ if (pmerr) {
+ Server_warning(self,
+ "Portmidi warning: could not open midi input %d (%s): %s\n",
+ 0, info->name, Pm_GetErrorText(pmerr));
+ }
+ else {
+ Server_debug(self, "Midi input (%s) opened.\n", info->name);
+ self->midiin_count++;
+ }
+ }
+ }
}
+ if (self->midiin_count == 0)
+ self->withPortMidi = 0;
}
else {
Server_warning(self, "Portmidi warning: no input device!\n");
self->withPortMidi = 0;
}
- if (self->midi_output == -1 || self->midi_output >= num_devices)
- self->midi_output = Pm_GetDefaultOutputDeviceID();
- Server_debug(self, "Midi output device : %d.\n", self->midi_output);
- const PmDeviceInfo *outinfo = Pm_GetDeviceInfo(self->midi_output);
- if (outinfo != NULL) {
- if (outinfo->output) {
- Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
- pmerr = Pm_OpenOutput(&self->out, self->midi_output, NULL, 0, NULL, NULL, 1);
- if (pmerr) {
- Server_warning(self,
- "Portmidi warning: could not open midi output %d (%s): %s\n",
- 0, outinfo->name, Pm_GetErrorText(pmerr));
+ if (self->midi_output < num_devices) {
+ if (self->midi_output == -1)
+ self->midi_output = Pm_GetDefaultOutputDeviceID();
+ Server_debug(self, "Midi output device : %d.\n", self->midi_output);
+ const PmDeviceInfo *outinfo = Pm_GetDeviceInfo(self->midi_output);
+ if (outinfo != NULL) {
+ if (outinfo->output) {
+ Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+ pmerr = Pm_OpenOutput(&self->midiout[0], self->midi_output, NULL, 0, NULL, NULL, 1);
+ if (pmerr) {
+ Server_warning(self,
+ "Portmidi warning: could not open midi output %d (%s): %s\n",
+ self->midi_output, outinfo->name, Pm_GetErrorText(pmerr));
+ self->withPortMidiOut = 0;
+ if (Pt_Started())
+ Pt_Stop();
+ }
+ else {
+ Server_debug(self, "Midi output (%s) opened.\n", outinfo->name);
+ self->midiout_count = 1;
+ }
+ }
+ else {
+ Server_warning(self, "Portmidi warning: Midi Device (%s), not an output device!\n", outinfo->name);
self->withPortMidiOut = 0;
- }
- else
- Server_debug(self, "Midi output (%s) opened.\n", outinfo->name);
+ }
}
- else {
- Server_warning(self, "Portmidi warning: something wrong with midi output device!\n");
+ }
+ else if (self->midi_output >= num_devices) {
+ Server_debug(self, "Midi output device : all!\n");
+ self->midiout_count = 0;
+ Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+ for (i=0; i<num_devices; i++) {
+ const PmDeviceInfo *outinfo = Pm_GetDeviceInfo(i);
+ if (outinfo != NULL) {
+ if (outinfo->output) {
+ pmerr = Pm_OpenOutput(&self->midiout[self->midiout_count], i, NULL, 100, NULL, NULL, 1);
+ if (pmerr) {
+ Server_warning(self,
+ "Portmidi warning: could not open midi output %d (%s): %s\n",
+ 0, outinfo->name, Pm_GetErrorText(pmerr));
+ }
+ else {
+ Server_debug(self, "Midi output (%s) opened.\n", outinfo->name);
+ self->midiout_count++;
+ }
+ }
+ }
+ }
+ if (self->midiout_count == 0) {
+ if (Pt_Started())
+ Pt_Stop();
self->withPortMidiOut = 0;
}
}
else {
Server_warning(self, "Portmidi warning: no output device!\n");
- self->withPortMidi = 0;
+ self->withPortMidiOut = 0;
}
-
+
if (self->withPortMidi == 0 && self->withPortMidiOut == 0) {
Pm_Terminate();
Server_warning(self, "Portmidi closed.\n");
@@ -2035,7 +2188,9 @@ Server_pm_init(Server *self)
}
if (self->withPortMidi == 1) {
self->midi_count = 0;
- Pm_SetFilter(self->in, PM_FILT_ACTIVE | PM_FILT_CLOCK);
+ for (i=0; i<self->midiin_count; i++) {
+ Pm_SetFilter(self->midiin[i], PM_FILT_ACTIVE | PM_FILT_CLOCK);
+ }
}
return 0;
}
@@ -2136,85 +2291,6 @@ Server_boot(Server *self, PyObject *arg)
return Py_None;
}
-/* Like the Server_boot() but without reinitializing the buffers */
-static PyObject *
-Server_flush(Server *self)
-{
- int audioerr = 0;
- int i;
- if (self->server_booted == 1) {
- Server_error(self, "Server already booted!\n");
- Py_INCREF(Py_None);
- return Py_None;
- }
- self->server_started = 0;
- self->stream_count = 0;
- self->elapsedSamples = 0;
-
- self->streams = PyList_New(0);
- switch (self->audio_be_type) {
- case PyoPortaudio:
- audioerr = Server_pa_init(self);
- break;
- case PyoJack:
-#ifdef USE_JACK
- audioerr = Server_jack_init(self);
- if (audioerr < 0) {
- Server_jack_deinit(self);
- }
-#else
- audioerr = -1;
- Server_error(self, "Pyo built without Jack support\n");
-#endif
- break;
- case PyoCoreaudio:
-#ifdef USE_COREAUDIO
- audioerr = Server_coreaudio_init(self);
- if (audioerr < 0) {
- Server_coreaudio_deinit(self);
- }
-#else
- audioerr = -1;
- Server_error(self, "Pyo built without Coreaudio support\n");
-#endif
- break;
- case PyoOffline:
- audioerr = Server_offline_init(self);
- if (audioerr < 0) {
- Server_offline_deinit(self);
- }
- break;
- case PyoOfflineNB:
- audioerr = Server_offline_init(self);
- if (audioerr < 0) {
- Server_offline_deinit(self);
- }
- break;
- case PyoEmbedded:
- audioerr = Server_embedded_init(self);
- if (audioerr < 0) {
- Server_embedded_deinit(self);
- }
- break;
- }
-
- for (i=0; i<self->bufferSize*self->nchnls; i++) {
- self->input_buffer[i] = 0.0;
- self->output_buffer[i] = 0.0;
- }
-
- if (audioerr == 0) {
- self->server_booted = 1;
- }
- else {
- self->server_booted = 0;
- Server_error(self, "\nServer not booted.\n");
- }
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
static PyObject *
Server_start(Server *self)
{
@@ -2240,7 +2316,7 @@ Server_start(Server *self)
self->server_started = 1;
self->timeStep = (int)(0.01 * self->samplingRate);
- if (self->audio_be_type != PyoOffline && self->audio_be_type != PyoOfflineNB) {
+ if (self->audio_be_type != PyoOffline && self->audio_be_type != PyoOfflineNB && self->audio_be_type != PyoEmbedded) {
midierr = Server_pm_init(self);
Server_debug(self, "PortMidi initialization return code : %d.\n", midierr);
}
@@ -2293,6 +2369,7 @@ Server_start(Server *self)
static PyObject *
Server_stop(Server *self)
{
+ int i;
int err = -1;
if (self->server_started == 0) {
Server_warning(self, "The Server must be started!\n");
@@ -2330,12 +2407,18 @@ Server_stop(Server *self)
else {
self->server_stopped = 1;
if (self->withPortMidi == 1) {
- Pm_Close(self->in);
+ for (i=0; i<self->midiin_count; i++) {
+ Pm_Close(self->midiin[i]);
+ }
}
if (self->withPortMidiOut == 1) {
- Pm_Close(self->out);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Close(self->midiout[i]);
+ }
}
if (self->withPortMidi == 1 || self->withPortMidiOut == 1) {
+ if (Pt_Started())
+ Pt_Stop();
Pm_Terminate();
}
self->withPortMidi = 0;
@@ -2550,23 +2633,153 @@ Server_changeStreamPosition(Server *self, PyObject *args)
}
PyObject *
-Server_sendMidiNote(Server *self, PyObject *args)
+Server_noteout(Server *self, PyObject *args)
{
- int pit, vel, chan, curtime;
+ int i, pit, vel, chan, curtime;
PmEvent buffer[1];
PmTimestamp timestamp;
if (! PyArg_ParseTuple(args, "iiii", &pit, &vel, &chan, ×tamp))
return PyInt_FromLong(-1);
- curtime = Pt_Time();
- buffer[0].timestamp = curtime + timestamp;
- if (chan == 0)
- buffer[0].message = Pm_Message(0x90, pit, vel);
- else
- buffer[0].message = Pm_Message(0x90 | (chan - 1), pit, vel);
- Pm_Write(self->out, buffer, 1);
+ if (self->withPortMidiOut) {
+ curtime = Pt_Time();
+ buffer[0].timestamp = curtime + timestamp;
+ if (chan == 0)
+ buffer[0].message = Pm_Message(0x90, pit, vel);
+ else
+ buffer[0].message = Pm_Message(0x90 | (chan - 1), pit, vel);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Write(self->midiout[i], buffer, 1);
+ }
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+PyObject *
+Server_afterout(Server *self, PyObject *args)
+{
+ int i, pit, vel, chan, curtime;
+ PmEvent buffer[1];
+ PmTimestamp timestamp;
+
+ if (! PyArg_ParseTuple(args, "iiii", &pit, &vel, &chan, ×tamp))
+ return PyInt_FromLong(-1);
+
+ if (self->withPortMidiOut) {
+ curtime = Pt_Time();
+ buffer[0].timestamp = curtime + timestamp;
+ if (chan == 0)
+ buffer[0].message = Pm_Message(0xA0, pit, vel);
+ else
+ buffer[0].message = Pm_Message(0xA0 | (chan - 1), pit, vel);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Write(self->midiout[i], buffer, 1);
+ }
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *
+Server_ctlout(Server *self, PyObject *args)
+{
+ int i, ctlnum, value, chan, curtime;
+ PmEvent buffer[1];
+ PmTimestamp timestamp;
+
+ if (! PyArg_ParseTuple(args, "iiii", &ctlnum, &value, &chan, ×tamp))
+ return PyInt_FromLong(-1);
+
+ if (self->withPortMidiOut) {
+ curtime = Pt_Time();
+ buffer[0].timestamp = curtime + timestamp;
+ if (chan == 0)
+ buffer[0].message = Pm_Message(0xB0, ctlnum, value);
+ else
+ buffer[0].message = Pm_Message(0xB0 | (chan - 1), ctlnum, value);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Write(self->midiout[i], buffer, 1);
+ }
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *
+Server_programout(Server *self, PyObject *args)
+{
+ int i, value, chan, curtime;
+ PmEvent buffer[1];
+ PmTimestamp timestamp;
+
+ if (! PyArg_ParseTuple(args, "iii", &value, &chan, ×tamp))
+ return PyInt_FromLong(-1);
+
+ if (self->withPortMidiOut) {
+ curtime = Pt_Time();
+ buffer[0].timestamp = curtime + timestamp;
+ if (chan == 0)
+ buffer[0].message = Pm_Message(0xC0, value, 0);
+ else
+ buffer[0].message = Pm_Message(0xC0 | (chan - 1), value, 0);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Write(self->midiout[i], buffer, 1);
+ }
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *
+Server_pressout(Server *self, PyObject *args)
+{
+ int i, value, chan, curtime;
+ PmEvent buffer[1];
+ PmTimestamp timestamp;
+
+ if (! PyArg_ParseTuple(args, "iii", &value, &chan, ×tamp))
+ return PyInt_FromLong(-1);
+
+ if (self->withPortMidiOut) {
+ curtime = Pt_Time();
+ buffer[0].timestamp = curtime + timestamp;
+ if (chan == 0)
+ buffer[0].message = Pm_Message(0xD0, value, 0);
+ else
+ buffer[0].message = Pm_Message(0xD0 | (chan - 1), value, 0);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Write(self->midiout[i], buffer, 1);
+ }
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *
+Server_bendout(Server *self, PyObject *args)
+{
+ int i, lsb, msb, value, chan, curtime;
+ PmEvent buffer[1];
+ PmTimestamp timestamp;
+
+ if (! PyArg_ParseTuple(args, "iii", &value, &chan, ×tamp))
+ return PyInt_FromLong(-1);
+
+ if (self->withPortMidiOut) {
+ curtime = Pt_Time();
+ buffer[0].timestamp = curtime + timestamp;
+ lsb = value & 0x007F;
+ msb = (value & (0x007F << 7)) >> 7;
+ if (chan == 0)
+ buffer[0].message = Pm_Message(0xE0, lsb, msb);
+ else
+ buffer[0].message = Pm_Message(0xE0 | (chan - 1), lsb, msb);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Write(self->midiout[i], buffer, 1);
+ }
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -2712,6 +2925,8 @@ static PyMethodDef Server_methods[] = {
{"setNchnls", (PyCFunction)Server_setNchnls, METH_O, "Sets the server's number of channels."},
{"setDuplex", (PyCFunction)Server_setDuplex, METH_O, "Sets the server's duplex mode (0 = only out, 1 = in/out)."},
{"setJackAuto", (PyCFunction)Server_setJackAuto, METH_VARARGS, "Tells the server to auto-connect Jack ports (0 = disable, 1 = enable)."},
+ {"setJackAutoConnectInputPorts", (PyCFunction)Server_setJackAutoConnectInputPorts, METH_O, "Sets a list of ports to auto-connect inputs when using Jack."},
+ {"setJackAutoConnectOutputPorts", (PyCFunction)Server_setJackAutoConnectOutputPorts, METH_O, "Sets a list of ports to auto-connect outputs when using Jack."},
{"setGlobalSeed", (PyCFunction)Server_setGlobalSeed, METH_O, "Sets the server's global seed for random objects."},
{"setAmp", (PyCFunction)Server_setAmp, METH_O, "Sets the overall amplitude."},
{"setAmpCallable", (PyCFunction)Server_setAmpCallable, METH_O, "Sets the Server's GUI callable object."},
@@ -2731,7 +2946,12 @@ static PyMethodDef Server_methods[] = {
This is for internal use and must never be called by the user."},
{"changeStreamPosition", (PyCFunction)Server_changeStreamPosition, METH_VARARGS, "Puts an audio stream before another in the stack. \
This is for internal use and must never be called by the user."},
- {"sendMidiNote", (PyCFunction)Server_sendMidiNote, METH_VARARGS, "Send a Midi note to Portmidi output stream."},
+ {"noteout", (PyCFunction)Server_noteout, METH_VARARGS, "Send a Midi note event to Portmidi output stream."},
+ {"afterout", (PyCFunction)Server_afterout, METH_VARARGS, "Send an aftertouch event to Portmidi output stream."},
+ {"ctlout", (PyCFunction)Server_ctlout, METH_VARARGS, "Send a control change event to Portmidi output stream."},
+ {"programout", (PyCFunction)Server_programout, METH_VARARGS, "Send a program change event to Portmidi output stream."},
+ {"pressout", (PyCFunction)Server_pressout, METH_VARARGS, "Send a channel pressure event to Portmidi output stream."},
+ {"bendout", (PyCFunction)Server_bendout, METH_VARARGS, "Send a pitch bend event to Portmidi output stream."},
{"getStreams", (PyCFunction)Server_getStreams, METH_NOARGS, "Returns the list of streams added to the server."},
{"getSamplingRate", (PyCFunction)Server_getSamplingRate, METH_NOARGS, "Returns the server's sampling rate."},
{"getNchnls", (PyCFunction)Server_getNchnls, METH_NOARGS, "Returns the server's current number of channels."},
@@ -2742,7 +2962,6 @@ static PyMethodDef Server_methods[] = {
{"getMidiActive", (PyCFunction)Server_getMidiActive, METH_NOARGS, "Returns 1 if midi callback is active, otherwise returns 0."},
{"_setDefaultRecPath", (PyCFunction)Server_setDefaultRecPath, METH_VARARGS|METH_KEYWORDS, "Sets the default recording path."},
{"setServer", (PyCFunction)Server_setServer, METH_NOARGS, "Sets this server as the one to use for new objects when using the embedded device"},
- {"flush", (PyCFunction)Server_flush, METH_NOARGS, "Flush the server objects"},
{"getInputAddr", (PyCFunction)Server_getInputAddr, METH_NOARGS, "Get the embedded device input buffer memory address"},
{"getOutputAddr", (PyCFunction)Server_getOutputAddr, METH_NOARGS, "Get the embedded device output buffer memory address"},
{"getServerID", (PyCFunction)Server_getServerID, METH_NOARGS, "Get the embedded device server memory address"},
@@ -2781,10 +3000,10 @@ PyTypeObject ServerType = {
"Pyo Server object. Handles communication with Portaudio and processing callback loop.", /* tp_doc */
(traverseproc)Server_traverse, /* tp_traverse */
(inquiry)Server_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
Server_methods, /* tp_methods */
Server_members, /* tp_members */
0, /* tp_getset */
diff --git a/src/objects/analysismodule.c b/src/objects/analysismodule.c
index b4ef933..36509be 100644
--- a/src/objects/analysismodule.c
+++ b/src/objects/analysismodule.c
@@ -25,6 +25,8 @@
#include "servermodule.h"
#include "dummymodule.h"
#include "interpolation.h"
+#include "fft.h"
+#include "wind.h"
/************/
/* Follower */
@@ -1630,4 +1632,1315 @@ Yin_members, /* tp_members */
0, /* tp_init */
0, /* tp_alloc */
Yin_new, /* tp_new */
-};
\ No newline at end of file
+};
+
+/********************/
+/* Centroid */
+/********************/
+
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ int size;
+ int hsize;
+ int incount;
+ MYFLT centroid;
+ MYFLT *inframe;
+ MYFLT *outframe;
+ MYFLT **twiddle;
+ MYFLT *input_buffer;
+ MYFLT *window;
+ int modebuffer[2];
+} Centroid;
+
+static void
+Centroid_alloc_memories(Centroid *self) {
+ int i, n8;
+ self->hsize = self->size / 2;
+ n8 = self->size >> 3;
+ self->inframe = (MYFLT *)realloc(self->inframe, self->size * sizeof(MYFLT));
+ self->outframe = (MYFLT *)realloc(self->outframe, self->size * sizeof(MYFLT));
+ self->input_buffer = (MYFLT *)realloc(self->input_buffer, self->size * sizeof(MYFLT));
+ for (i=0; i<self->size; i++)
+ self->inframe[i] = self->outframe[i] = self->input_buffer[i] = 0.0;
+ self->twiddle = (MYFLT **)realloc(self->twiddle, 4 * sizeof(MYFLT *));
+ for(i=0; i<4; i++)
+ self->twiddle[i] = (MYFLT *)malloc(n8 * sizeof(MYFLT));
+ fft_compute_split_twiddle(self->twiddle, self->size);
+ self->window = (MYFLT *)realloc(self->window, self->size * sizeof(MYFLT));
+ gen_window(self->window, self->size, 2);
+}
+
+static void
+Centroid_process_i(Centroid *self) {
+ int i;
+ MYFLT re, im, tmp, sum1, sum2;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+
+ for (i=0; i<self->bufsize; i++) {
+ self->input_buffer[self->incount] = in[i];
+ self->data[i] = self->centroid;
+
+ self->incount++;
+ if (self->incount == self->size) {
+ self->incount = self->hsize;
+
+ for (i=0; i<self->size; i++) {
+ self->inframe[i] = self->input_buffer[i] * self->window[i];
+ }
+ realfft_split(self->inframe, self->outframe, self->size, self->twiddle);
+ sum1 = sum2 = 0.0;
+ for (i=1; i<self->hsize; i++) {
+ re = self->outframe[i];
+ im = self->outframe[self->size - i];
+ tmp = MYSQRT(re*re + im*im);
+ sum1 += tmp * i;
+ sum2 += tmp;
+ }
+ tmp = sum1 / sum2;
+ self->centroid += tmp * self->sr / self->size;
+ self->centroid *= 0.5;
+ for (i=0; i<self->hsize; i++) {
+ self->input_buffer[i] = self->input_buffer[i + self->hsize];
+ }
+ }
+ }
+}
+
+static void Centroid_postprocessing_ii(Centroid *self) { POST_PROCESSING_II };
+static void Centroid_postprocessing_ai(Centroid *self) { POST_PROCESSING_AI };
+static void Centroid_postprocessing_ia(Centroid *self) { POST_PROCESSING_IA };
+static void Centroid_postprocessing_aa(Centroid *self) { POST_PROCESSING_AA };
+static void Centroid_postprocessing_ireva(Centroid *self) { POST_PROCESSING_IREVA };
+static void Centroid_postprocessing_areva(Centroid *self) { POST_PROCESSING_AREVA };
+static void Centroid_postprocessing_revai(Centroid *self) { POST_PROCESSING_REVAI };
+static void Centroid_postprocessing_revaa(Centroid *self) { POST_PROCESSING_REVAA };
+static void Centroid_postprocessing_revareva(Centroid *self) { POST_PROCESSING_REVAREVA };
+
+static void
+Centroid_setProcMode(Centroid *self)
+{
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ self->proc_func_ptr = Centroid_process_i;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = Centroid_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = Centroid_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = Centroid_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = Centroid_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = Centroid_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = Centroid_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = Centroid_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = Centroid_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = Centroid_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+Centroid_compute_next_data_frame(Centroid *self)
+{
+ (*self->proc_func_ptr)(self);
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+Centroid_traverse(Centroid *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ return 0;
+}
+
+static int
+Centroid_clear(Centroid *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->input_stream);
+ return 0;
+}
+
+static void
+Centroid_dealloc(Centroid* self)
+{
+ int i;
+ pyo_DEALLOC
+ free(self->inframe);
+ free(self->outframe);
+ free(self->input_buffer);
+ for(i=0; i<4; i++) {
+ free(self->twiddle[i]);
+ }
+ free(self->twiddle);
+ free(self->window);
+ Centroid_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+Centroid_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i, k;
+ PyObject *inputtmp, *input_streamtmp, *multmp=NULL, *addtmp=NULL;
+ Centroid *self;
+ self = (Centroid *)type->tp_alloc(type, 0);
+
+ self->centroid = 0;
+ self->size = 1024;
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, Centroid_compute_next_data_frame);
+ self->mode_func_ptr = Centroid_setProcMode;
+
+ static char *kwlist[] = {"input", "size", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|iOO", kwlist, &inputtmp, &self->size, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ if (self->size < self->bufsize) {
+ printf("Warning : Centroid size less than buffer size!\nCentroid size set to buffersize: %d\n", self->bufsize);
+ self->size = self->bufsize;
+ }
+
+ k = 1;
+ while (k < self->size)
+ k <<= 1;
+ self->size = k;
+
+ INIT_INPUT_STREAM
+
+ if (multmp) {
+ PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+ }
+
+ if (addtmp) {
+ PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ Centroid_alloc_memories(self);
+
+ self->incount = self->hsize;
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * Centroid_getServer(Centroid* self) { GET_SERVER };
+static PyObject * Centroid_getStream(Centroid* self) { GET_STREAM };
+static PyObject * Centroid_setMul(Centroid *self, PyObject *arg) { SET_MUL };
+static PyObject * Centroid_setAdd(Centroid *self, PyObject *arg) { SET_ADD };
+static PyObject * Centroid_setSub(Centroid *self, PyObject *arg) { SET_SUB };
+static PyObject * Centroid_setDiv(Centroid *self, PyObject *arg) { SET_DIV };
+
+static PyObject * Centroid_play(Centroid *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * Centroid_stop(Centroid *self) { STOP };
+
+static PyObject * Centroid_multiply(Centroid *self, PyObject *arg) { MULTIPLY };
+static PyObject * Centroid_inplace_multiply(Centroid *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * Centroid_add(Centroid *self, PyObject *arg) { ADD };
+static PyObject * Centroid_inplace_add(Centroid *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * Centroid_sub(Centroid *self, PyObject *arg) { SUB };
+static PyObject * Centroid_inplace_sub(Centroid *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * Centroid_div(Centroid *self, PyObject *arg) { DIV };
+static PyObject * Centroid_inplace_div(Centroid *self, PyObject *arg) { INPLACE_DIV };
+
+
+static PyMemberDef Centroid_members[] = {
+{"server", T_OBJECT_EX, offsetof(Centroid, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(Centroid, stream), 0, "Stream object."},
+{"mul", T_OBJECT_EX, offsetof(Centroid, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(Centroid, add), 0, "Add factor."},
+{"input", T_OBJECT_EX, offsetof(Centroid, input), 0, "Input sound object."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef Centroid_methods[] = {
+{"getServer", (PyCFunction)Centroid_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)Centroid_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)Centroid_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)Centroid_stop, METH_NOARGS, "Stops computing."},
+{"setMul", (PyCFunction)Centroid_setMul, METH_O, "Sets Centroid mul factor."},
+{"setAdd", (PyCFunction)Centroid_setAdd, METH_O, "Sets Centroid add factor."},
+{"setSub", (PyCFunction)Centroid_setSub, METH_O, "Sets Centroid add factor."},
+{"setDiv", (PyCFunction)Centroid_setDiv, METH_O, "Sets Centroid mul factor."},
+{NULL} /* Sentinel */
+};
+
+static PyNumberMethods Centroid_as_number = {
+ (binaryfunc)Centroid_add, /*nb_add*/
+ (binaryfunc)Centroid_sub, /*nb_subtract*/
+ (binaryfunc)Centroid_multiply, /*nb_multiply*/
+ (binaryfunc)Centroid_div, /*nb_divide*/
+ 0, /*nb_remainder*/
+ 0, /*nb_divmod*/
+ 0, /*nb_power*/
+ 0, /*nb_neg*/
+ 0, /*nb_pos*/
+ 0, /*(unaryfunc)array_abs,*/
+ 0, /*nb_nonzero*/
+ 0, /*nb_invert*/
+ 0, /*nb_lshift*/
+ 0, /*nb_rshift*/
+ 0, /*nb_and*/
+ 0, /*nb_xor*/
+ 0, /*nb_or*/
+ 0, /*nb_coerce*/
+ 0, /*nb_int*/
+ 0, /*nb_long*/
+ 0, /*nb_float*/
+ 0, /*nb_oct*/
+ 0, /*nb_hex*/
+ (binaryfunc)Centroid_inplace_add, /*inplace_add*/
+ (binaryfunc)Centroid_inplace_sub, /*inplace_subtract*/
+ (binaryfunc)Centroid_inplace_multiply, /*inplace_multiply*/
+ (binaryfunc)Centroid_inplace_div, /*inplace_divide*/
+ 0, /*inplace_remainder*/
+ 0, /*inplace_power*/
+ 0, /*inplace_lshift*/
+ 0, /*inplace_rshift*/
+ 0, /*inplace_and*/
+ 0, /*inplace_xor*/
+ 0, /*inplace_or*/
+ 0, /*nb_floor_divide*/
+ 0, /*nb_true_divide*/
+ 0, /*nb_inplace_floor_divide*/
+ 0, /*nb_inplace_true_divide*/
+ 0, /* nb_index */
+};
+
+PyTypeObject CentroidType = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.Centroid_base", /*tp_name*/
+sizeof(Centroid), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)Centroid_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+&Centroid_as_number, /*tp_as_number*/
+0, /*tp_as_sequence*/
+0, /*tp_as_mapping*/
+0, /*tp_hash */
+0, /*tp_call*/
+0, /*tp_str*/
+0, /*tp_getattro*/
+0, /*tp_setattro*/
+0, /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"Centroid objects. FFT transform.", /* tp_doc */
+(traverseproc)Centroid_traverse, /* tp_traverse */
+(inquiry)Centroid_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+Centroid_methods, /* tp_methods */
+Centroid_members, /* tp_members */
+0, /* tp_getset */
+0, /* tp_base */
+0, /* tp_dict */
+0, /* tp_descr_get */
+0, /* tp_descr_set */
+0, /* tp_dictoffset */
+0, /* tp_init */
+0, /* tp_alloc */
+Centroid_new, /* tp_new */
+};
+
+/************/
+/* AttackDetector */
+/************/
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ MYFLT deltime;
+ MYFLT cutoff;
+ MYFLT maxthresh;
+ MYFLT minthresh;
+ MYFLT reltime;
+ MYFLT folfactor;
+ MYFLT follow;
+ MYFLT followdb;
+ MYFLT *buffer;
+ MYFLT previous;
+ int memsize;
+ int sampdel;
+ int incount;
+ int overminok;
+ int belowminok;
+ long maxtime;
+ long timer;
+ int modebuffer[2]; // need at least 2 slots for mul & add
+} AttackDetector;
+
+static void
+AttackDetector_process(AttackDetector *self) {
+ int i, ind;
+ MYFLT absin;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = 0.0;
+ absin = in[i];
+ // envelope follower
+ if (absin < 0.0)
+ absin = -absin;
+ self->follow = absin + self->folfactor * (self->follow - absin);
+ // follower in dB
+ if (self->follow <= 0.000001)
+ self->followdb = -120.0;
+ else
+ self->followdb = 20.0 * MYLOG10(self->follow);
+ // previous analysis
+ ind = self->incount - self->sampdel;
+ if (ind < 0)
+ ind += self->memsize;
+ self->previous = self->buffer[ind];
+ self->buffer[self->incount] = self->followdb;
+ self->incount++;
+ if (self->incount >= self->memsize)
+ self->incount = 0;
+ // if release time has past
+ if (self->timer >= self->maxtime) {
+ // if rms is over min threshold
+ if (self->overminok) {
+ // if rms is greater than previous + maxthresh
+ if (self->followdb > (self->previous + self->maxthresh)) {
+ self->data[i] = 1.0;
+ self->overminok = self->belowminok = 0;
+ self->timer = 0;
+ }
+ }
+ }
+ if (self->belowminok == 0 && self->followdb < self->minthresh)
+ self->belowminok = 1;
+ else if (self->belowminok == 1 && self->followdb > self->minthresh)
+ self->overminok = 1;
+ self->timer++;
+ }
+}
+
+static void AttackDetector_postprocessing_ii(AttackDetector *self) { POST_PROCESSING_II };
+static void AttackDetector_postprocessing_ai(AttackDetector *self) { POST_PROCESSING_AI };
+static void AttackDetector_postprocessing_ia(AttackDetector *self) { POST_PROCESSING_IA };
+static void AttackDetector_postprocessing_aa(AttackDetector *self) { POST_PROCESSING_AA };
+static void AttackDetector_postprocessing_ireva(AttackDetector *self) { POST_PROCESSING_IREVA };
+static void AttackDetector_postprocessing_areva(AttackDetector *self) { POST_PROCESSING_AREVA };
+static void AttackDetector_postprocessing_revai(AttackDetector *self) { POST_PROCESSING_REVAI };
+static void AttackDetector_postprocessing_revaa(AttackDetector *self) { POST_PROCESSING_REVAA };
+static void AttackDetector_postprocessing_revareva(AttackDetector *self) { POST_PROCESSING_REVAREVA };
+
+static void
+AttackDetector_setProcMode(AttackDetector *self)
+{
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ self->proc_func_ptr = AttackDetector_process;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = AttackDetector_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = AttackDetector_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = AttackDetector_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = AttackDetector_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = AttackDetector_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = AttackDetector_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = AttackDetector_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = AttackDetector_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = AttackDetector_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+AttackDetector_compute_next_data_frame(AttackDetector *self)
+{
+ (*self->proc_func_ptr)(self);
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+AttackDetector_traverse(AttackDetector *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ return 0;
+}
+
+static int
+AttackDetector_clear(AttackDetector *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->input_stream);
+ return 0;
+}
+
+static void
+AttackDetector_dealloc(AttackDetector* self)
+{
+ pyo_DEALLOC
+ free(self->buffer);
+ AttackDetector_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+AttackDetector_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *inputtmp, *input_streamtmp, *multmp=NULL, *addtmp=NULL;
+ AttackDetector *self;
+ self = (AttackDetector *)type->tp_alloc(type, 0);
+
+ self->deltime = 0.005;
+ self->cutoff = 10.0;
+ self->maxthresh = 3.0;
+ self->minthresh = -30.0;
+ self->reltime = 0.1;
+ self->follow = 0.0;
+ self->followdb = -120.0;
+ self->previous = 0.0;
+ self->incount = 0;
+ self->overminok = 0;
+ self->belowminok = 0;
+ self->timer = 0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, AttackDetector_compute_next_data_frame);
+ self->mode_func_ptr = AttackDetector_setProcMode;
+
+ static char *kwlist[] = {"input", "deltime", "cutoff", "maxthresh", "minthresh", "reltime", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_O_FFFFFOO, kwlist, &inputtmp, &self->deltime, &self->cutoff, &self->maxthresh, &self->minthresh, &self->reltime, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ INIT_INPUT_STREAM
+
+ if (multmp) {
+ PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+ }
+
+ if (addtmp) {
+ PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ self->memsize = (int)(0.055 * self->sr + 0.5);
+ self->buffer = (MYFLT *)realloc(self->buffer, (self->memsize+1) * sizeof(MYFLT));
+ for (i=0; i<(self->memsize+1); i++) {
+ self->buffer[i] = 0.0;
+ }
+
+ if (self->deltime < 0.001) self->deltime = 0.001;
+ else if (self->deltime > 0.05) self->deltime = 0.05;
+ self->sampdel = (int)(self->deltime * self->sr);
+
+ if (self->cutoff < 1.0) self->cutoff = 1.0;
+ else if (self->cutoff > 1000.0) self->cutoff = 1000.0;
+ self->folfactor = MYEXP(-TWOPI * self->cutoff / self->sr);
+
+ if (self->cutoff < 1.0) self->cutoff = 1.0;
+ else if (self->cutoff > 1000.0) self->cutoff = 1000.0;
+
+ if (self->maxthresh < 0.0) self->maxthresh = 0.0;
+ else if (self->maxthresh > 18.0) self->maxthresh = 18.0;
+
+ if (self->minthresh < -90.0) self->minthresh = -90.0;
+ else if (self->minthresh > 0.0) self->minthresh = 0.0;
+
+ if (self->reltime < 0.001) self->reltime = 0.001;
+ self->maxtime = (long)(self->reltime * self->sr + 0.5);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * AttackDetector_getServer(AttackDetector* self) { GET_SERVER };
+static PyObject * AttackDetector_getStream(AttackDetector* self) { GET_STREAM };
+static PyObject * AttackDetector_setMul(AttackDetector *self, PyObject *arg) { SET_MUL };
+static PyObject * AttackDetector_setAdd(AttackDetector *self, PyObject *arg) { SET_ADD };
+static PyObject * AttackDetector_setSub(AttackDetector *self, PyObject *arg) { SET_SUB };
+static PyObject * AttackDetector_setDiv(AttackDetector *self, PyObject *arg) { SET_DIV };
+
+static PyObject * AttackDetector_play(AttackDetector *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * AttackDetector_stop(AttackDetector *self) { STOP };
+
+static PyObject * AttackDetector_multiply(AttackDetector *self, PyObject *arg) { MULTIPLY };
+static PyObject * AttackDetector_inplace_multiply(AttackDetector *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * AttackDetector_add(AttackDetector *self, PyObject *arg) { ADD };
+static PyObject * AttackDetector_inplace_add(AttackDetector *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * AttackDetector_sub(AttackDetector *self, PyObject *arg) { SUB };
+static PyObject * AttackDetector_inplace_sub(AttackDetector *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * AttackDetector_div(AttackDetector *self, PyObject *arg) { DIV };
+static PyObject * AttackDetector_inplace_div(AttackDetector *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+AttackDetector_setDeltime(AttackDetector *self, PyObject *arg)
+{
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ if (isNumber == 1) {
+ self->deltime = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ if (self->deltime < 0.001) self->deltime = 0.001;
+ else if (self->deltime > 0.05) self->deltime = 0.05;
+ self->sampdel = (int)(self->deltime * self->sr);
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+AttackDetector_setCutoff(AttackDetector *self, PyObject *arg)
+{
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ if (isNumber == 1) {
+ self->cutoff = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ if (self->cutoff < 1.0) self->cutoff = 1.0;
+ else if (self->cutoff > 1000.0) self->cutoff = 1000.0;
+ self->folfactor = MYEXP(-TWOPI * self->cutoff / self->sr);
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+AttackDetector_setMaxthresh(AttackDetector *self, PyObject *arg)
+{
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ if (isNumber == 1) {
+ self->maxthresh = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ if (self->maxthresh < 0.0) self->maxthresh = 0.0;
+ else if (self->maxthresh > 18.0) self->maxthresh = 18.0;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+AttackDetector_setMinthresh(AttackDetector *self, PyObject *arg)
+{
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ if (isNumber == 1) {
+ self->minthresh = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ if (self->minthresh < -90.0) self->minthresh = -90.0;
+ else if (self->minthresh > 0.0) self->minthresh = 0.0;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+AttackDetector_setReltime(AttackDetector *self, PyObject *arg)
+{
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ if (isNumber == 1) {
+ self->reltime = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ if (self->reltime < 0.001) self->reltime = 0.001;
+ self->maxtime = (long)(self->reltime * self->sr + 0.5);
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyMemberDef AttackDetector_members[] = {
+{"server", T_OBJECT_EX, offsetof(AttackDetector, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(AttackDetector, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(AttackDetector, input), 0, "Input sound object."},
+{"mul", T_OBJECT_EX, offsetof(AttackDetector, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(AttackDetector, add), 0, "Add factor."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef AttackDetector_methods[] = {
+{"getServer", (PyCFunction)AttackDetector_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)AttackDetector_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)AttackDetector_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)AttackDetector_stop, METH_NOARGS, "Stops computing."},
+{"setDeltime", (PyCFunction)AttackDetector_setDeltime, METH_O, "Sets the delay time between current and previous analysis."},
+{"setCutoff", (PyCFunction)AttackDetector_setCutoff, METH_O, "Sets the frequency of the internal lowpass filter."},
+{"setMaxthresh", (PyCFunction)AttackDetector_setMaxthresh, METH_O, "Sets the higher threshold."},
+{"setMinthresh", (PyCFunction)AttackDetector_setMinthresh, METH_O, "Sets the lower threshold."},
+{"setReltime", (PyCFunction)AttackDetector_setReltime, METH_O, "Sets the release time (min time between two detected attacks)."},
+{"setMul", (PyCFunction)AttackDetector_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)AttackDetector_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)AttackDetector_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)AttackDetector_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL} /* Sentinel */
+};
+
+static PyNumberMethods AttackDetector_as_number = {
+(binaryfunc)AttackDetector_add, /*nb_add*/
+(binaryfunc)AttackDetector_sub, /*nb_subtract*/
+(binaryfunc)AttackDetector_multiply, /*nb_multiply*/
+(binaryfunc)AttackDetector_div, /*nb_divide*/
+0, /*nb_remainder*/
+0, /*nb_divmod*/
+0, /*nb_power*/
+0, /*nb_neg*/
+0, /*nb_pos*/
+0, /*(unaryfunc)array_abs,*/
+0, /*nb_nonzero*/
+0, /*nb_invert*/
+0, /*nb_lshift*/
+0, /*nb_rshift*/
+0, /*nb_and*/
+0, /*nb_xor*/
+0, /*nb_or*/
+0, /*nb_coerce*/
+0, /*nb_int*/
+0, /*nb_long*/
+0, /*nb_float*/
+0, /*nb_oct*/
+0, /*nb_hex*/
+(binaryfunc)AttackDetector_inplace_add, /*inplace_add*/
+(binaryfunc)AttackDetector_inplace_sub, /*inplace_subtract*/
+(binaryfunc)AttackDetector_inplace_multiply, /*inplace_multiply*/
+(binaryfunc)AttackDetector_inplace_div, /*inplace_divide*/
+0, /*inplace_remainder*/
+0, /*inplace_power*/
+0, /*inplace_lshift*/
+0, /*inplace_rshift*/
+0, /*inplace_and*/
+0, /*inplace_xor*/
+0, /*inplace_or*/
+0, /*nb_floor_divide*/
+0, /*nb_true_divide*/
+0, /*nb_inplace_floor_divide*/
+0, /*nb_inplace_true_divide*/
+0, /* nb_index */
+};
+
+PyTypeObject AttackDetectorType = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.AttackDetector_base", /*tp_name*/
+sizeof(AttackDetector), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)AttackDetector_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+&AttackDetector_as_number, /*tp_as_number*/
+0, /*tp_as_sequence*/
+0, /*tp_as_mapping*/
+0, /*tp_hash */
+0, /*tp_call*/
+0, /*tp_str*/
+0, /*tp_getattro*/
+0, /*tp_setattro*/
+0, /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"AttackDetector objects. Audio signal peak detection.", /* tp_doc */
+(traverseproc)AttackDetector_traverse, /* tp_traverse */
+(inquiry)AttackDetector_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+AttackDetector_methods, /* tp_methods */
+AttackDetector_members, /* tp_members */
+0, /* tp_getset */
+0, /* tp_base */
+0, /* tp_dict */
+0, /* tp_descr_get */
+0, /* tp_descr_set */
+0, /* tp_dictoffset */
+0, /* tp_init */
+0, /* tp_alloc */
+AttackDetector_new, /* tp_new */
+};
+
+/*********************************************************************************************/
+/* Scope ********************************************************************************/
+/*********************************************************************************************/
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ int size;
+ int width;
+ int height;
+ int pointer;
+ MYFLT gain;
+ MYFLT *buffer;
+} Scope;
+
+static void
+Scope_generate(Scope *self) {
+ int i;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ for (i=0; i<self->bufsize; i++) {
+ if (self->pointer >= self->size)
+ self->pointer = 0;
+ self->buffer[self->pointer] = in[i];
+ self->pointer++;
+ }
+}
+
+static PyObject *
+Scope_display(Scope *self) {
+ int i, ipos;
+ MYFLT pos, step, mag, h2;
+ PyObject *points, *tuple;
+
+ step = self->size / (MYFLT)(self->width);
+ h2 = self->height * 0.5;
+
+ points = PyList_New(self->width);
+
+ for (i=0; i<self->width; i++) {
+ pos = i * step;
+ ipos = (int)pos;
+ tuple = PyTuple_New(2);
+ mag = ((self->buffer[ipos] + (self->buffer[ipos+1] - self->buffer[ipos]) * (pos - ipos)) * self->gain * h2 + h2);
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(i));
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->height - (int)mag));
+ PyList_SET_ITEM(points, i, tuple);
+ }
+ return points;
+}
+
+static void
+Scope_compute_next_data_frame(Scope *self)
+{
+ Scope_generate(self);
+}
+
+static int
+Scope_traverse(Scope *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ return 0;
+}
+
+static int
+Scope_clear(Scope *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->input_stream);
+ return 0;
+}
+
+static void
+Scope_dealloc(Scope* self)
+{
+ pyo_DEALLOC
+ free(self->buffer);
+ Scope_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+Scope_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i, maxsize;
+ MYFLT length = 0.05;
+ PyObject *inputtmp, *input_streamtmp;
+ Scope *self;
+ self = (Scope *)type->tp_alloc(type, 0);
+
+ self->gain = 1.0;
+ self->width = 500;
+ self->height = 400;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, Scope_compute_next_data_frame);
+
+ static char *kwlist[] = {"input", "length", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_O_F, kwlist, &inputtmp, &length))
+ Py_RETURN_NONE;
+
+ INIT_INPUT_STREAM
+
+ maxsize = (int)(self->sr * 0.25);
+ self->buffer = (MYFLT *)realloc(self->buffer, maxsize * sizeof(MYFLT));
+ self->size = (int)(length * self->sr);
+ if (self->size > maxsize)
+ self->size = maxsize;
+ self->pointer = 0;
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ return (PyObject *)self;
+}
+
+static PyObject * Scope_getServer(Scope* self) { GET_SERVER };
+static PyObject * Scope_getStream(Scope* self) { GET_STREAM };
+
+static PyObject * Scope_play(Scope *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * Scope_stop(Scope *self) { STOP };
+
+static PyObject *
+Scope_setLength(Scope *self, PyObject *arg)
+{
+ MYFLT length;
+ int maxsize = (int)(self->sr * 0.25);
+
+ if (PyNumber_Check(arg)) {
+ length = PyFloat_AsDouble(PyNumber_Float(arg));
+ self->size = (int)(length * self->sr);
+ if (self->size > maxsize)
+ self->size = maxsize;
+ self->pointer = 0;
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+Scope_setGain(Scope *self, PyObject *arg)
+{
+ if (PyNumber_Check(arg)) {
+ self->gain = PyFloat_AsDouble(PyNumber_Float(arg));
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+Scope_setWidth(Scope *self, PyObject *arg)
+{
+ if (PyInt_Check(arg)) {
+ self->width = PyInt_AsLong(arg);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+Scope_setHeight(Scope *self, PyObject *arg)
+{
+ if (PyInt_Check(arg)) {
+ self->height = PyInt_AsLong(arg);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMemberDef Scope_members[] = {
+{"server", T_OBJECT_EX, offsetof(Scope, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(Scope, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(Scope, input), 0, "Input sound object."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef Scope_methods[] = {
+{"getServer", (PyCFunction)Scope_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)Scope_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)Scope_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)Scope_stop, METH_NOARGS, "Stops computing."},
+{"display", (PyCFunction)Scope_display, METH_NOARGS, "Computes the samples to draw."},
+{"setLength", (PyCFunction)Scope_setLength, METH_O, "Sets function's argument."},
+{"setGain", (PyCFunction)Scope_setGain, METH_O, "Sets gain compensation."},
+{"setWidth", (PyCFunction)Scope_setWidth, METH_O, "Sets the width of the display."},
+{"setHeight", (PyCFunction)Scope_setHeight, METH_O, "Sets the height of the display."},
+{NULL} /* Sentinel */
+};
+
+PyTypeObject ScopeType = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.Scope_base", /*tp_name*/
+sizeof(Scope), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)Scope_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+0, /*tp_as_number*/
+0, /*tp_as_sequence*/
+0, /*tp_as_mapping*/
+0, /*tp_hash */
+0, /*tp_call*/
+0, /*tp_str*/
+0, /*tp_getattro*/
+0, /*tp_setattro*/
+0, /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"Scope objects. Show the waveform of an input signal.", /* tp_doc */
+(traverseproc)Scope_traverse, /* tp_traverse */
+(inquiry)Scope_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+Scope_methods, /* tp_methods */
+Scope_members, /* tp_members */
+0, /* tp_getset */
+0, /* tp_base */
+0, /* tp_dict */
+0, /* tp_descr_get */
+0, /* tp_descr_set */
+0, /* tp_dictoffset */
+0, /* tp_init */
+0, /* tp_alloc */
+Scope_new, /* tp_new */
+};
+
+/************/
+/* PeakAmp */
+/************/
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ int modebuffer[2]; // need at least 2 slots for mul & add
+ MYFLT follow;
+} PeakAmp;
+
+static void
+PeakAmp_filters_i(PeakAmp *self) {
+ MYFLT absin, peak;
+ int i;
+
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+
+ peak = 0.0;
+ for (i=0; i<self->bufsize; i++) {
+ absin = in[i];
+ if (absin < 0.0)
+ absin = -absin;
+ if (absin > peak)
+ peak = absin;
+ self->data[i] = self->follow;
+ }
+ self->follow = peak;
+}
+
+static void PeakAmp_postprocessing_ii(PeakAmp *self) { POST_PROCESSING_II };
+static void PeakAmp_postprocessing_ai(PeakAmp *self) { POST_PROCESSING_AI };
+static void PeakAmp_postprocessing_ia(PeakAmp *self) { POST_PROCESSING_IA };
+static void PeakAmp_postprocessing_aa(PeakAmp *self) { POST_PROCESSING_AA };
+static void PeakAmp_postprocessing_ireva(PeakAmp *self) { POST_PROCESSING_IREVA };
+static void PeakAmp_postprocessing_areva(PeakAmp *self) { POST_PROCESSING_AREVA };
+static void PeakAmp_postprocessing_revai(PeakAmp *self) { POST_PROCESSING_REVAI };
+static void PeakAmp_postprocessing_revaa(PeakAmp *self) { POST_PROCESSING_REVAA };
+static void PeakAmp_postprocessing_revareva(PeakAmp *self) { POST_PROCESSING_REVAREVA };
+
+static void
+PeakAmp_setProcMode(PeakAmp *self)
+{
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ self->proc_func_ptr = PeakAmp_filters_i;
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = PeakAmp_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = PeakAmp_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = PeakAmp_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = PeakAmp_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = PeakAmp_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = PeakAmp_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = PeakAmp_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = PeakAmp_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = PeakAmp_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+PeakAmp_compute_next_data_frame(PeakAmp *self)
+{
+ (*self->proc_func_ptr)(self);
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+PeakAmp_traverse(PeakAmp *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ return 0;
+}
+
+static int
+PeakAmp_clear(PeakAmp *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->input_stream);
+ return 0;
+}
+
+static void
+PeakAmp_dealloc(PeakAmp* self)
+{
+ pyo_DEALLOC
+ PeakAmp_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+PeakAmp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *inputtmp, *input_streamtmp, *multmp=NULL, *addtmp=NULL;
+ PeakAmp *self;
+ self = (PeakAmp *)type->tp_alloc(type, 0);
+
+ self->follow = 0.0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, PeakAmp_compute_next_data_frame);
+ self->mode_func_ptr = PeakAmp_setProcMode;
+
+ static char *kwlist[] = {"input", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist, &inputtmp, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ INIT_INPUT_STREAM
+
+ if (multmp) {
+ PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+ }
+
+ if (addtmp) {
+ PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * PeakAmp_getServer(PeakAmp* self) { GET_SERVER };
+static PyObject * PeakAmp_getStream(PeakAmp* self) { GET_STREAM };
+static PyObject * PeakAmp_setMul(PeakAmp *self, PyObject *arg) { SET_MUL };
+static PyObject * PeakAmp_setAdd(PeakAmp *self, PyObject *arg) { SET_ADD };
+static PyObject * PeakAmp_setSub(PeakAmp *self, PyObject *arg) { SET_SUB };
+static PyObject * PeakAmp_setDiv(PeakAmp *self, PyObject *arg) { SET_DIV };
+
+static PyObject * PeakAmp_play(PeakAmp *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * PeakAmp_stop(PeakAmp *self) { STOP };
+
+static PyObject * PeakAmp_multiply(PeakAmp *self, PyObject *arg) { MULTIPLY };
+static PyObject * PeakAmp_inplace_multiply(PeakAmp *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * PeakAmp_add(PeakAmp *self, PyObject *arg) { ADD };
+static PyObject * PeakAmp_inplace_add(PeakAmp *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * PeakAmp_sub(PeakAmp *self, PyObject *arg) { SUB };
+static PyObject * PeakAmp_inplace_sub(PeakAmp *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * PeakAmp_div(PeakAmp *self, PyObject *arg) { DIV };
+static PyObject * PeakAmp_inplace_div(PeakAmp *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+PeakAmp_getValue(PeakAmp *self)
+{
+ return PyFloat_FromDouble(self->follow);
+}
+
+static PyMemberDef PeakAmp_members[] = {
+{"server", T_OBJECT_EX, offsetof(PeakAmp, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(PeakAmp, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(PeakAmp, input), 0, "Input sound object."},
+{"mul", T_OBJECT_EX, offsetof(PeakAmp, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(PeakAmp, add), 0, "Add factor."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef PeakAmp_methods[] = {
+{"getServer", (PyCFunction)PeakAmp_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)PeakAmp_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)PeakAmp_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)PeakAmp_stop, METH_NOARGS, "Stops computing."},
+{"getValue", (PyCFunction)PeakAmp_getValue, METH_NOARGS, "Returns the current peaking value."},
+{"setMul", (PyCFunction)PeakAmp_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)PeakAmp_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)PeakAmp_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)PeakAmp_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL} /* Sentinel */
+};
+
+static PyNumberMethods PeakAmp_as_number = {
+(binaryfunc)PeakAmp_add, /*nb_add*/
+(binaryfunc)PeakAmp_sub, /*nb_subtract*/
+(binaryfunc)PeakAmp_multiply, /*nb_multiply*/
+(binaryfunc)PeakAmp_div, /*nb_divide*/
+0, /*nb_remainder*/
+0, /*nb_divmod*/
+0, /*nb_power*/
+0, /*nb_neg*/
+0, /*nb_pos*/
+0, /*(unaryfunc)array_abs,*/
+0, /*nb_nonzero*/
+0, /*nb_invert*/
+0, /*nb_lshift*/
+0, /*nb_rshift*/
+0, /*nb_and*/
+0, /*nb_xor*/
+0, /*nb_or*/
+0, /*nb_coerce*/
+0, /*nb_int*/
+0, /*nb_long*/
+0, /*nb_float*/
+0, /*nb_oct*/
+0, /*nb_hex*/
+(binaryfunc)PeakAmp_inplace_add, /*inplace_add*/
+(binaryfunc)PeakAmp_inplace_sub, /*inplace_subtract*/
+(binaryfunc)PeakAmp_inplace_multiply, /*inplace_multiply*/
+(binaryfunc)PeakAmp_inplace_div, /*inplace_divide*/
+0, /*inplace_remainder*/
+0, /*inplace_power*/
+0, /*inplace_lshift*/
+0, /*inplace_rshift*/
+0, /*inplace_and*/
+0, /*inplace_xor*/
+0, /*inplace_or*/
+0, /*nb_floor_divide*/
+0, /*nb_true_divide*/
+0, /*nb_inplace_floor_divide*/
+0, /*nb_inplace_true_divide*/
+0, /* nb_index */
+};
+
+PyTypeObject PeakAmpType = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.PeakAmp_base", /*tp_name*/
+sizeof(PeakAmp), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)PeakAmp_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+&PeakAmp_as_number, /*tp_as_number*/
+0, /*tp_as_sequence*/
+0, /*tp_as_mapping*/
+0, /*tp_hash */
+0, /*tp_call*/
+0, /*tp_str*/
+0, /*tp_getattro*/
+0, /*tp_setattro*/
+0, /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"PeakAmp objects. Envelope follower.", /* tp_doc */
+(traverseproc)PeakAmp_traverse, /* tp_traverse */
+(inquiry)PeakAmp_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+PeakAmp_methods, /* tp_methods */
+PeakAmp_members, /* tp_members */
+0, /* tp_getset */
+0, /* tp_base */
+0, /* tp_dict */
+0, /* tp_descr_get */
+0, /* tp_descr_set */
+0, /* tp_dictoffset */
+0, /* tp_init */
+0, /* tp_alloc */
+PeakAmp_new, /* tp_new */
+};
diff --git a/src/objects/arithmeticmodule.c b/src/objects/arithmeticmodule.c
index 1c06284..79157db 100644
--- a/src/objects/arithmeticmodule.c
+++ b/src/objects/arithmeticmodule.c
@@ -3771,3 +3771,268 @@ PyTypeObject M_RoundType = {
0, /* tp_alloc */
M_Round_new, /* tp_new */
};
+
+/************/
+/* M_Tanh */
+/************/
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ int modebuffer[2]; // need at least 2 slots for mul & add
+} M_Tanh;
+
+static void
+M_Tanh_process(M_Tanh *self) {
+ int i;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = MYTANH(in[i]);
+ }
+}
+
+static void M_Tanh_postprocessing_ii(M_Tanh *self) { POST_PROCESSING_II };
+static void M_Tanh_postprocessing_ai(M_Tanh *self) { POST_PROCESSING_AI };
+static void M_Tanh_postprocessing_ia(M_Tanh *self) { POST_PROCESSING_IA };
+static void M_Tanh_postprocessing_aa(M_Tanh *self) { POST_PROCESSING_AA };
+static void M_Tanh_postprocessing_ireva(M_Tanh *self) { POST_PROCESSING_IREVA };
+static void M_Tanh_postprocessing_areva(M_Tanh *self) { POST_PROCESSING_AREVA };
+static void M_Tanh_postprocessing_revai(M_Tanh *self) { POST_PROCESSING_REVAI };
+static void M_Tanh_postprocessing_revaa(M_Tanh *self) { POST_PROCESSING_REVAA };
+static void M_Tanh_postprocessing_revareva(M_Tanh *self) { POST_PROCESSING_REVAREVA };
+
+static void
+M_Tanh_setProcMode(M_Tanh *self)
+{
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ self->proc_func_ptr = M_Tanh_process;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = M_Tanh_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = M_Tanh_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = M_Tanh_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = M_Tanh_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = M_Tanh_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = M_Tanh_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = M_Tanh_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = M_Tanh_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = M_Tanh_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+M_Tanh_compute_next_data_frame(M_Tanh *self)
+{
+ (*self->proc_func_ptr)(self);
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+M_Tanh_traverse(M_Tanh *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ return 0;
+}
+
+static int
+M_Tanh_clear(M_Tanh *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->input_stream);
+ return 0;
+}
+
+static void
+M_Tanh_dealloc(M_Tanh* self)
+{
+ pyo_DEALLOC
+ M_Tanh_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+M_Tanh_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *inputtmp, *input_streamtmp, *multmp=NULL, *addtmp=NULL;
+ M_Tanh *self;
+ self = (M_Tanh *)type->tp_alloc(type, 0);
+
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, M_Tanh_compute_next_data_frame);
+ self->mode_func_ptr = M_Tanh_setProcMode;
+
+ static char *kwlist[] = {"input", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist, &inputtmp, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ INIT_INPUT_STREAM
+
+ if (multmp) {
+ PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+ }
+
+ if (addtmp) {
+ PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * M_Tanh_getServer(M_Tanh* self) { GET_SERVER };
+static PyObject * M_Tanh_getStream(M_Tanh* self) { GET_STREAM };
+static PyObject * M_Tanh_setMul(M_Tanh *self, PyObject *arg) { SET_MUL };
+static PyObject * M_Tanh_setAdd(M_Tanh *self, PyObject *arg) { SET_ADD };
+static PyObject * M_Tanh_setSub(M_Tanh *self, PyObject *arg) { SET_SUB };
+static PyObject * M_Tanh_setDiv(M_Tanh *self, PyObject *arg) { SET_DIV };
+
+static PyObject * M_Tanh_play(M_Tanh *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * M_Tanh_out(M_Tanh *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * M_Tanh_stop(M_Tanh *self) { STOP };
+
+static PyObject * M_Tanh_multiply(M_Tanh *self, PyObject *arg) { MULTIPLY };
+static PyObject * M_Tanh_inplace_multiply(M_Tanh *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * M_Tanh_add(M_Tanh *self, PyObject *arg) { ADD };
+static PyObject * M_Tanh_inplace_add(M_Tanh *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * M_Tanh_sub(M_Tanh *self, PyObject *arg) { SUB };
+static PyObject * M_Tanh_inplace_sub(M_Tanh *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * M_Tanh_div(M_Tanh *self, PyObject *arg) { DIV };
+static PyObject * M_Tanh_inplace_div(M_Tanh *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef M_Tanh_members[] = {
+{"server", T_OBJECT_EX, offsetof(M_Tanh, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(M_Tanh, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(M_Tanh, input), 0, "Input sound object."},
+{"mul", T_OBJECT_EX, offsetof(M_Tanh, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(M_Tanh, add), 0, "Add factor."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef M_Tanh_methods[] = {
+{"getServer", (PyCFunction)M_Tanh_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)M_Tanh_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)M_Tanh_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)M_Tanh_stop, METH_NOARGS, "Stops computing."},
+{"out", (PyCFunction)M_Tanh_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"setMul", (PyCFunction)M_Tanh_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)M_Tanh_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)M_Tanh_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)M_Tanh_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL} /* Sentinel */
+};
+
+static PyNumberMethods M_Tanh_as_number = {
+(binaryfunc)M_Tanh_add, /*nb_add*/
+(binaryfunc)M_Tanh_sub, /*nb_subtract*/
+(binaryfunc)M_Tanh_multiply, /*nb_multiply*/
+(binaryfunc)M_Tanh_div, /*nb_divide*/
+0, /*nb_remainder*/
+0, /*nb_divmod*/
+0, /*nb_power*/
+0, /*nb_neg*/
+0, /*nb_pos*/
+0, /*(unaryfunc)array_abs,*/
+0, /*nb_nonzero*/
+0, /*nb_invert*/
+0, /*nb_lshift*/
+0, /*nb_rshift*/
+0, /*nb_and*/
+0, /*nb_xor*/
+0, /*nb_or*/
+0, /*nb_coerce*/
+0, /*nb_int*/
+0, /*nb_long*/
+0, /*nb_float*/
+0, /*nb_oct*/
+0, /*nb_hex*/
+(binaryfunc)M_Tanh_inplace_add, /*inplace_add*/
+(binaryfunc)M_Tanh_inplace_sub, /*inplace_subtract*/
+(binaryfunc)M_Tanh_inplace_multiply, /*inplace_multiply*/
+(binaryfunc)M_Tanh_inplace_div, /*inplace_divide*/
+0, /*inplace_remainder*/
+0, /*inplace_power*/
+0, /*inplace_lshift*/
+0, /*inplace_rshift*/
+0, /*inplace_and*/
+0, /*inplace_xor*/
+0, /*inplace_or*/
+0, /*nb_floor_divide*/
+0, /*nb_true_divide*/
+0, /*nb_inplace_floor_divide*/
+0, /*nb_inplace_true_divide*/
+0, /* nb_index */
+};
+
+PyTypeObject M_TanhType = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.M_Tanh_base", /*tp_name*/
+sizeof(M_Tanh), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)M_Tanh_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+&M_Tanh_as_number, /*tp_as_number*/
+0, /*tp_as_sequence*/
+0, /*tp_as_mapping*/
+0, /*tp_hash */
+0, /*tp_call*/
+0, /*tp_str*/
+0, /*tp_getattro*/
+0, /*tp_setattro*/
+0, /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"M_Tanh objects. Performs tanh function on audio samples.", /* tp_doc */
+(traverseproc)M_Tanh_traverse, /* tp_traverse */
+(inquiry)M_Tanh_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+M_Tanh_methods, /* tp_methods */
+M_Tanh_members, /* tp_members */
+0, /* tp_getset */
+0, /* tp_base */
+0, /* tp_dict */
+0, /* tp_descr_get */
+0, /* tp_descr_set */
+0, /* tp_dictoffset */
+0, /* tp_init */
+0, /* tp_alloc */
+M_Tanh_new, /* tp_new */
+};
diff --git a/src/objects/convolvemodule.c b/src/objects/convolvemodule.c
index 63b3fc3..f19da5a 100644
--- a/src/objects/convolvemodule.c
+++ b/src/objects/convolvemodule.c
@@ -174,11 +174,8 @@ Convolve_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
INIT_INPUT_STREAM
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of Convolve must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of Convolve must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
diff --git a/src/objects/delaymodule.c b/src/objects/delaymodule.c
index f4a0302..bec9a2b 100644
--- a/src/objects/delaymodule.c
+++ b/src/objects/delaymodule.c
@@ -35,6 +35,7 @@ typedef struct {
PyObject *feedback;
Stream *feedback_stream;
MYFLT maxdelay;
+ MYFLT oneOverSr;
long size;
long in_count;
int modebuffer[4];
@@ -50,8 +51,8 @@ Delay_process_ii(Delay *self) {
MYFLT del = PyFloat_AS_DOUBLE(self->delay);
MYFLT feed = PyFloat_AS_DOUBLE(self->feedback);
- if (del < 0.)
- del = 0.;
+ if (del < self->oneOverSr)
+ del = self->oneOverSr;
else if (del > self->maxdelay)
del = self->maxdelay;
MYFLT sampdel = del * self->sr;
@@ -99,8 +100,8 @@ Delay_process_ai(Delay *self) {
for (i=0; i<self->bufsize; i++) {
del = delobj[i];
- if (del < 0.)
- del = 0.;
+ if (del < self->oneOverSr)
+ del = self->oneOverSr;
else if (del > self->maxdelay)
del = self->maxdelay;
sampdel = del * self->sr;
@@ -130,8 +131,8 @@ Delay_process_ia(Delay *self) {
MYFLT del = PyFloat_AS_DOUBLE(self->delay);
MYFLT *fdb = Stream_getData((Stream *)self->feedback_stream);
- if (del < 0.)
- del = 0.;
+ if (del < self->oneOverSr)
+ del = self->oneOverSr;
else if (del > self->maxdelay)
del = self->maxdelay;
MYFLT sampdel = del * self->sr;
@@ -175,8 +176,8 @@ Delay_process_aa(Delay *self) {
for (i=0; i<self->bufsize; i++) {
del = delobj[i];
- if (del < 0.)
- del = 0.;
+ if (del < self->oneOverSr)
+ del = self->oneOverSr;
else if (del > self->maxdelay)
del = self->maxdelay;
sampdel = del * self->sr;
@@ -325,6 +326,9 @@ Delay_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->modebuffer[3] = 0;
INIT_OBJECT_COMMON
+
+ self->oneOverSr = 1.0 / self->sr;
+
Stream_setFunctionPtr(self->stream, Delay_compute_next_data_frame);
self->mode_func_ptr = Delay_setProcMode;
@@ -615,7 +619,7 @@ SDelay_process_i(SDelay *self) {
for (i=0; i<self->bufsize; i++) {
ind = self->in_count - sampdel;
if (ind < 0)
- ind += (self->size-1);
+ ind += self->size;
self->data[i] = self->buffer[ind];
self->buffer[self->in_count] = in[i];
@@ -648,7 +652,7 @@ SDelay_process_a(SDelay *self) {
else {
ind = self->in_count - sampdel;
if (ind < 0)
- ind += (self->size-1);
+ ind += self->size;
self->data[i] = self->buffer[ind];
}
self->buffer[self->in_count++] = in[i];
@@ -3031,3 +3035,716 @@ Delay1_members, /* tp_members */
0, /* tp_alloc */
Delay1_new, /* tp_new */
};
+
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ PyObject *delay;
+ Stream *delay_stream;
+ PyObject *feedback;
+ Stream *feedback_stream;
+ MYFLT crossfade;
+ MYFLT maxdelay;
+ MYFLT oneOverSr;
+ MYFLT amp1;
+ MYFLT amp2;
+ MYFLT inc1;
+ MYFLT inc2;
+ int current;
+ long timer;
+ long size;
+ long in_count;
+ long sampdel;
+ MYFLT sampdel1;
+ MYFLT sampdel2;
+ int modebuffer[4];
+ MYFLT *buffer; // samples memory
+} SmoothDelay;
+
+static void
+SmoothDelay_process_ii(SmoothDelay *self) {
+ MYFLT val, xind, frac, sum;
+ int i;
+ long ind, xsamps = 0;
+
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT del = PyFloat_AS_DOUBLE(self->delay);
+ MYFLT feed = PyFloat_AS_DOUBLE(self->feedback);
+
+ if (del < self->oneOverSr) del = self->oneOverSr;
+ else if (del > self->maxdelay) del = self->maxdelay;
+
+ if (feed < 0) feed = 0.0;
+ else if (feed > 1) feed = 1.0;
+
+ for (i=0; i<self->bufsize; i++) {
+ if (self->timer == 0) {
+ self->current = (self->current + 1) % 2;
+ self->sampdel = (long)(del * self->sr + 0.5);
+ xsamps = (long)(self->crossfade * self->sr + 0.5);
+ if (xsamps > self->sampdel) xsamps = self->sampdel;
+ if (xsamps <= 0) xsamps = 1;
+ if (self->current == 0) {
+ self->sampdel1 = del * self->sr;
+ self->inc1 = 1.0 / xsamps;
+ self->inc2 = -self->inc1;
+ }
+ else {
+ self->sampdel2 = del * self->sr;
+ self->inc2 = 1.0 / xsamps;
+ self->inc1 = -self->inc2;
+ }
+ }
+
+ xind = self->in_count - self->sampdel1;
+ while (xind < 0)
+ xind += self->size;
+ ind = (long)xind;
+ frac = xind - ind;
+ val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+ sum = val * self->amp1;
+ self->amp1 += self->inc1;
+ if (self->amp1 < 0) self->amp1 = 0.0;
+ else if (self->amp1 > 1) self->amp1 = 1.0;
+
+ xind = self->in_count - self->sampdel2;
+ while (xind < 0)
+ xind += self->size;
+ ind = (long)xind;
+ frac = xind - ind;
+ val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+ sum += val * self->amp2;
+ self->amp2 += self->inc2;
+ if (self->amp2 < 0) self->amp2 = 0.0;
+ else if (self->amp2 > 1) self->amp2 = 1.0;
+
+ self->data[i] = sum;
+
+ self->buffer[self->in_count] = in[i] + (sum * feed);
+ if (self->in_count == 0)
+ self->buffer[self->size] = self->buffer[0];
+ self->in_count++;
+ if (self->in_count >= self->size)
+ self->in_count = 0;
+
+ self->timer++;
+ if (self->timer == self->sampdel)
+ self->timer = 0;
+ }
+}
+
+static void
+SmoothDelay_process_ai(SmoothDelay *self) {
+ MYFLT val, xind, frac, sum, del;
+ int i;
+ long ind, xsamps = 0;
+
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT *dl = Stream_getData((Stream *)self->delay_stream);
+ MYFLT feed = PyFloat_AS_DOUBLE(self->feedback);
+
+ if (feed < 0) feed = 0.0;
+ else if (feed > 1) feed = 1.0;
+
+ for (i=0; i<self->bufsize; i++) {
+ if (self->timer == 0) {
+ del = dl[i];
+ if (del < self->oneOverSr) del = self->oneOverSr;
+ else if (del > self->maxdelay) del = self->maxdelay;
+ self->current = (self->current + 1) % 2;
+ self->sampdel = (long)(del * self->sr + 0.5);
+ xsamps = (long)(self->crossfade * self->sr + 0.5);
+ if (xsamps > self->sampdel) xsamps = self->sampdel;
+ if (xsamps <= 0) xsamps = 1;
+ if (self->current == 0) {
+ self->sampdel1 = del * self->sr;
+ self->inc1 = 1.0 / xsamps;
+ self->inc2 = -self->inc1;
+ }
+ else {
+ self->sampdel2 = del * self->sr;
+ self->inc2 = 1.0 / xsamps;
+ self->inc1 = -self->inc2;
+ }
+ }
+
+ xind = self->in_count - self->sampdel1;
+ while (xind < 0)
+ xind += self->size;
+ ind = (long)xind;
+ frac = xind - ind;
+ val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+ sum = val * self->amp1;
+ self->amp1 += self->inc1;
+ if (self->amp1 < 0) self->amp1 = 0.0;
+ else if (self->amp1 > 1) self->amp1 = 1.0;
+
+ xind = self->in_count - self->sampdel2;
+ while (xind < 0)
+ xind += self->size;
+ ind = (long)xind;
+ frac = xind - ind;
+ val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+ sum += val * self->amp2;
+ self->amp2 += self->inc2;
+ if (self->amp2 < 0) self->amp2 = 0.0;
+ else if (self->amp2 > 1) self->amp2 = 1.0;
+
+ self->data[i] = sum;
+
+ self->buffer[self->in_count] = in[i] + (sum * feed);
+ if (self->in_count == 0)
+ self->buffer[self->size] = self->buffer[0];
+ self->in_count++;
+ if (self->in_count >= self->size)
+ self->in_count = 0;
+
+ self->timer++;
+ if (self->timer == self->sampdel)
+ self->timer = 0;
+ }
+}
+
+static void
+SmoothDelay_process_ia(SmoothDelay *self) {
+ MYFLT val, xind, frac, sum, feed;
+ int i;
+ long ind, xsamps = 0;
+
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT del = PyFloat_AS_DOUBLE(self->delay);
+ MYFLT *fd = Stream_getData((Stream *)self->feedback_stream);
+
+ if (del < self->oneOverSr) del = self->oneOverSr;
+ else if (del > self->maxdelay) del = self->maxdelay;
+
+ for (i=0; i<self->bufsize; i++) {
+ feed = fd[i];
+ if (feed < 0) feed = 0.0;
+ else if (feed > 1) feed = 1.0;
+ if (self->timer == 0) {
+ self->current = (self->current + 1) % 2;
+ self->sampdel = (long)(del * self->sr + 0.5);
+ xsamps = (long)(self->crossfade * self->sr + 0.5);
+ if (xsamps > self->sampdel) xsamps = self->sampdel;
+ if (xsamps <= 0) xsamps = 1;
+ if (self->current == 0) {
+ self->sampdel1 = del * self->sr;
+ self->inc1 = 1.0 / xsamps;
+ self->inc2 = -self->inc1;
+ }
+ else {
+ self->sampdel2 = del * self->sr;
+ self->inc2 = 1.0 / xsamps;
+ self->inc1 = -self->inc2;
+ }
+ }
+
+ xind = self->in_count - self->sampdel1;
+ while (xind < 0)
+ xind += self->size;
+ ind = (long)xind;
+ frac = xind - ind;
+ val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+ sum = val * self->amp1;
+ self->amp1 += self->inc1;
+ if (self->amp1 < 0) self->amp1 = 0.0;
+ else if (self->amp1 > 1) self->amp1 = 1.0;
+
+ xind = self->in_count - self->sampdel2;
+ while (xind < 0)
+ xind += self->size;
+ ind = (long)xind;
+ frac = xind - ind;
+ val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+ sum += val * self->amp2;
+ self->amp2 += self->inc2;
+ if (self->amp2 < 0) self->amp2 = 0.0;
+ else if (self->amp2 > 1) self->amp2 = 1.0;
+
+ self->data[i] = sum;
+
+ self->buffer[self->in_count] = in[i] + (sum * feed);
+ if (self->in_count == 0)
+ self->buffer[self->size] = self->buffer[0];
+ self->in_count++;
+ if (self->in_count >= self->size)
+ self->in_count = 0;
+
+ self->timer++;
+ if (self->timer == self->sampdel)
+ self->timer = 0;
+ }
+}
+
+static void
+SmoothDelay_process_aa(SmoothDelay *self) {
+ MYFLT val, xind, frac, sum, del, feed;
+ int i;
+ long ind, xsamps = 0;
+
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT *dl = Stream_getData((Stream *)self->delay_stream);
+ MYFLT *fd = Stream_getData((Stream *)self->feedback_stream);
+
+ for (i=0; i<self->bufsize; i++) {
+ feed = fd[i];
+ if (feed < 0) feed = 0.0;
+ else if (feed > 1) feed = 1.0;
+ if (self->timer == 0) {
+ del = dl[i];
+ if (del < self->oneOverSr) del = self->oneOverSr;
+ else if (del > self->maxdelay) del = self->maxdelay;
+ self->current = (self->current + 1) % 2;
+ self->sampdel = (long)(del * self->sr + 0.5);
+ xsamps = (long)(self->crossfade * self->sr + 0.5);
+ if (xsamps > self->sampdel) xsamps = self->sampdel;
+ if (xsamps <= 0) xsamps = 1;
+ if (self->current == 0) {
+ self->sampdel1 = del * self->sr;
+ self->inc1 = 1.0 / xsamps;
+ self->inc2 = -self->inc1;
+ }
+ else {
+ self->sampdel2 = del * self->sr;
+ self->inc2 = 1.0 / xsamps;
+ self->inc1 = -self->inc2;
+ }
+ }
+
+ xind = self->in_count - self->sampdel1;
+ while (xind < 0)
+ xind += self->size;
+ ind = (long)xind;
+ frac = xind - ind;
+ val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+ sum = val * self->amp1;
+ self->amp1 += self->inc1;
+ if (self->amp1 < 0) self->amp1 = 0.0;
+ else if (self->amp1 > 1) self->amp1 = 1.0;
+
+ xind = self->in_count - self->sampdel2;
+ while (xind < 0)
+ xind += self->size;
+ ind = (long)xind;
+ frac = xind - ind;
+ val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+ sum += val * self->amp2;
+ self->amp2 += self->inc2;
+ if (self->amp2 < 0) self->amp2 = 0.0;
+ else if (self->amp2 > 1) self->amp2 = 1.0;
+
+ self->data[i] = sum;
+
+ self->buffer[self->in_count] = in[i] + (sum * feed);
+ if (self->in_count == 0)
+ self->buffer[self->size] = self->buffer[0];
+ self->in_count++;
+ if (self->in_count >= self->size)
+ self->in_count = 0;
+
+ self->timer++;
+ if (self->timer == self->sampdel)
+ self->timer = 0;
+ }
+}
+
+static void SmoothDelay_postprocessing_ii(SmoothDelay *self) { POST_PROCESSING_II };
+static void SmoothDelay_postprocessing_ai(SmoothDelay *self) { POST_PROCESSING_AI };
+static void SmoothDelay_postprocessing_ia(SmoothDelay *self) { POST_PROCESSING_IA };
+static void SmoothDelay_postprocessing_aa(SmoothDelay *self) { POST_PROCESSING_AA };
+static void SmoothDelay_postprocessing_ireva(SmoothDelay *self) { POST_PROCESSING_IREVA };
+static void SmoothDelay_postprocessing_areva(SmoothDelay *self) { POST_PROCESSING_AREVA };
+static void SmoothDelay_postprocessing_revai(SmoothDelay *self) { POST_PROCESSING_REVAI };
+static void SmoothDelay_postprocessing_revaa(SmoothDelay *self) { POST_PROCESSING_REVAA };
+static void SmoothDelay_postprocessing_revareva(SmoothDelay *self) { POST_PROCESSING_REVAREVA };
+
+static void
+SmoothDelay_setProcMode(SmoothDelay *self)
+{
+ int procmode, muladdmode;
+ procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ switch (procmode) {
+ case 0:
+ self->proc_func_ptr = SmoothDelay_process_ii;
+ break;
+ case 1:
+ self->proc_func_ptr = SmoothDelay_process_ai;
+ break;
+ case 10:
+ self->proc_func_ptr = SmoothDelay_process_ia;
+ break;
+ case 11:
+ self->proc_func_ptr = SmoothDelay_process_aa;
+ break;
+ }
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = SmoothDelay_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = SmoothDelay_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = SmoothDelay_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = SmoothDelay_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = SmoothDelay_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = SmoothDelay_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = SmoothDelay_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = SmoothDelay_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = SmoothDelay_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+SmoothDelay_compute_next_data_frame(SmoothDelay *self)
+{
+ (*self->proc_func_ptr)(self);
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+SmoothDelay_traverse(SmoothDelay *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ Py_VISIT(self->delay);
+ Py_VISIT(self->delay_stream);
+ Py_VISIT(self->feedback);
+ Py_VISIT(self->feedback_stream);
+ return 0;
+}
+
+static int
+SmoothDelay_clear(SmoothDelay *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->input_stream);
+ Py_CLEAR(self->delay);
+ Py_CLEAR(self->delay_stream);
+ Py_CLEAR(self->feedback);
+ Py_CLEAR(self->feedback_stream);
+ return 0;
+}
+
+static void
+SmoothDelay_dealloc(SmoothDelay* self)
+{
+ pyo_DEALLOC
+ free(self->buffer);
+ SmoothDelay_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+SmoothDelay_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *inputtmp, *input_streamtmp, *delaytmp=NULL, *feedbacktmp=NULL, *multmp=NULL, *addtmp=NULL;
+ SmoothDelay *self;
+ self = (SmoothDelay *)type->tp_alloc(type, 0);
+
+ self->delay = PyFloat_FromDouble(0.25);
+ self->feedback = PyFloat_FromDouble(0);
+ self->crossfade = 0.05;
+ self->maxdelay = 1;
+ self->in_count = 0;
+ self->current = 1;
+ self->timer = 0;
+ self->amp1 = 0.0;
+ self->amp2 = 1.0;
+ self->inc1 = self->inc2 = 0.0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+ self->modebuffer[2] = 0;
+ self->modebuffer[3] = 0;
+
+ INIT_OBJECT_COMMON
+
+ self->oneOverSr = self->sampdel1 = self->sampdel2 = 1.0 / self->sr;
+
+ Stream_setFunctionPtr(self->stream, SmoothDelay_compute_next_data_frame);
+ self->mode_func_ptr = SmoothDelay_setProcMode;
+
+ static char *kwlist[] = {"input", "delay", "feedback", "crossfade", "maxdelay", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_O_OOFFOO, kwlist, &inputtmp, &delaytmp, &feedbacktmp, &self->crossfade, &self->maxdelay, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ INIT_INPUT_STREAM
+
+ if (delaytmp) {
+ PyObject_CallMethod((PyObject *)self, "setDelay", "O", delaytmp);
+ }
+
+ if (feedbacktmp) {
+ PyObject_CallMethod((PyObject *)self, "setFeedback", "O", feedbacktmp);
+ }
+
+ if (multmp) {
+ PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+ }
+
+ if (addtmp) {
+ PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ self->size = (long)(self->maxdelay * self->sr + 0.5);
+
+ self->buffer = (MYFLT *)realloc(self->buffer, (self->size+1) * sizeof(MYFLT));
+ for (i=0; i<(self->size+1); i++) {
+ self->buffer[i] = 0.;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * SmoothDelay_getServer(SmoothDelay* self) { GET_SERVER };
+static PyObject * SmoothDelay_getStream(SmoothDelay* self) { GET_STREAM };
+static PyObject * SmoothDelay_setMul(SmoothDelay *self, PyObject *arg) { SET_MUL };
+static PyObject * SmoothDelay_setAdd(SmoothDelay *self, PyObject *arg) { SET_ADD };
+static PyObject * SmoothDelay_setSub(SmoothDelay *self, PyObject *arg) { SET_SUB };
+static PyObject * SmoothDelay_setDiv(SmoothDelay *self, PyObject *arg) { SET_DIV };
+
+static PyObject * SmoothDelay_play(SmoothDelay *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * SmoothDelay_out(SmoothDelay *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * SmoothDelay_stop(SmoothDelay *self) { STOP };
+
+static PyObject * SmoothDelay_multiply(SmoothDelay *self, PyObject *arg) { MULTIPLY };
+static PyObject * SmoothDelay_inplace_multiply(SmoothDelay *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * SmoothDelay_add(SmoothDelay *self, PyObject *arg) { ADD };
+static PyObject * SmoothDelay_inplace_add(SmoothDelay *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * SmoothDelay_sub(SmoothDelay *self, PyObject *arg) { SUB };
+static PyObject * SmoothDelay_inplace_sub(SmoothDelay *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * SmoothDelay_div(SmoothDelay *self, PyObject *arg) { DIV };
+static PyObject * SmoothDelay_inplace_div(SmoothDelay *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+SmoothDelay_setDelay(SmoothDelay *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->delay);
+ if (isNumber == 1) {
+ self->delay = PyNumber_Float(tmp);
+ self->modebuffer[2] = 0;
+ }
+ else {
+ self->delay = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->delay, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->delay_stream);
+ self->delay_stream = (Stream *)streamtmp;
+ self->modebuffer[2] = 1;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+SmoothDelay_setFeedback(SmoothDelay *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->feedback);
+ if (isNumber == 1) {
+ self->feedback = PyNumber_Float(tmp);
+ self->modebuffer[3] = 0;
+ }
+ else {
+ self->feedback = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->feedback, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->feedback_stream);
+ self->feedback_stream = (Stream *)streamtmp;
+ self->modebuffer[3] = 1;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+SmoothDelay_setCrossfade(SmoothDelay *self, PyObject *arg)
+{
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ if (isNumber == 1) {
+ self->crossfade = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+SmoothDelay_reset(SmoothDelay *self)
+{
+ int i;
+ for (i=0; i<(self->size+1); i++) {
+ self->buffer[i] = 0.;
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMemberDef SmoothDelay_members[] = {
+ {"server", T_OBJECT_EX, offsetof(SmoothDelay, server), 0, "Pyo server."},
+ {"stream", T_OBJECT_EX, offsetof(SmoothDelay, stream), 0, "Stream object."},
+ {"input", T_OBJECT_EX, offsetof(SmoothDelay, input), 0, "Input sound object."},
+ {"delay", T_OBJECT_EX, offsetof(SmoothDelay, delay), 0, "SmoothDelay time in seconds."},
+ {"feedback", T_OBJECT_EX, offsetof(SmoothDelay, feedback), 0, "Feedback value."},
+ {"mul", T_OBJECT_EX, offsetof(SmoothDelay, mul), 0, "Mul factor."},
+ {"add", T_OBJECT_EX, offsetof(SmoothDelay, add), 0, "Add factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef SmoothDelay_methods[] = {
+ {"getServer", (PyCFunction)SmoothDelay_getServer, METH_NOARGS, "Returns server object."},
+ {"_getStream", (PyCFunction)SmoothDelay_getStream, METH_NOARGS, "Returns stream object."},
+ {"play", (PyCFunction)SmoothDelay_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+ {"out", (PyCFunction)SmoothDelay_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+ {"stop", (PyCFunction)SmoothDelay_stop, METH_NOARGS, "Stops computing."},
+ {"setDelay", (PyCFunction)SmoothDelay_setDelay, METH_O, "Sets delay time in seconds."},
+ {"setFeedback", (PyCFunction)SmoothDelay_setFeedback, METH_O, "Sets feedback value between 0 -> 1."},
+ {"setCrossfade", (PyCFunction)SmoothDelay_setCrossfade, METH_O, "Sets crossfade time."},
+ {"reset", (PyCFunction)SmoothDelay_reset, METH_NOARGS, "Resets the memory buffer to zeros."},
+ {"setMul", (PyCFunction)SmoothDelay_setMul, METH_O, "Sets oscillator mul factor."},
+ {"setAdd", (PyCFunction)SmoothDelay_setAdd, METH_O, "Sets oscillator add factor."},
+ {"setSub", (PyCFunction)SmoothDelay_setSub, METH_O, "Sets inverse add factor."},
+ {"setDiv", (PyCFunction)SmoothDelay_setDiv, METH_O, "Sets inverse mul factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyNumberMethods SmoothDelay_as_number = {
+ (binaryfunc)SmoothDelay_add, /*nb_add*/
+ (binaryfunc)SmoothDelay_sub, /*nb_subtract*/
+ (binaryfunc)SmoothDelay_multiply, /*nb_multiply*/
+ (binaryfunc)SmoothDelay_div, /*nb_divide*/
+ 0, /*nb_remainder*/
+ 0, /*nb_divmod*/
+ 0, /*nb_power*/
+ 0, /*nb_neg*/
+ 0, /*nb_pos*/
+ 0, /*(unaryfunc)array_abs,*/
+ 0, /*nb_nonzero*/
+ 0, /*nb_invert*/
+ 0, /*nb_lshift*/
+ 0, /*nb_rshift*/
+ 0, /*nb_and*/
+ 0, /*nb_xor*/
+ 0, /*nb_or*/
+ 0, /*nb_coerce*/
+ 0, /*nb_int*/
+ 0, /*nb_long*/
+ 0, /*nb_float*/
+ 0, /*nb_oct*/
+ 0, /*nb_hex*/
+ (binaryfunc)SmoothDelay_inplace_add, /*inplace_add*/
+ (binaryfunc)SmoothDelay_inplace_sub, /*inplace_subtract*/
+ (binaryfunc)SmoothDelay_inplace_multiply, /*inplace_multiply*/
+ (binaryfunc)SmoothDelay_inplace_div, /*inplace_divide*/
+ 0, /*inplace_remainder*/
+ 0, /*inplace_power*/
+ 0, /*inplace_lshift*/
+ 0, /*inplace_rshift*/
+ 0, /*inplace_and*/
+ 0, /*inplace_xor*/
+ 0, /*inplace_or*/
+ 0, /*nb_floor_divide*/
+ 0, /*nb_true_divide*/
+ 0, /*nb_inplace_floor_divide*/
+ 0, /*nb_inplace_true_divide*/
+ 0, /* nb_index */
+};
+
+PyTypeObject SmoothDelayType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_pyo.SmoothDelay_base", /*tp_name*/
+ sizeof(SmoothDelay), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)SmoothDelay_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ &SmoothDelay_as_number, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "SmoothDelay objects. Delay signal by x samples.", /* tp_doc */
+ (traverseproc)SmoothDelay_traverse, /* tp_traverse */
+ (inquiry)SmoothDelay_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ SmoothDelay_methods, /* tp_methods */
+ SmoothDelay_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ SmoothDelay_new, /* tp_new */
+};
diff --git a/src/objects/fadermodule.c b/src/objects/fadermodule.c
index 906d3c8..bd6310e 100644
--- a/src/objects/fadermodule.c
+++ b/src/objects/fadermodule.c
@@ -29,6 +29,7 @@ typedef struct {
pyo_audio_HEAD
int modebuffer[2];
int fademode;
+ int ended;
MYFLT topValue;
MYFLT attack;
MYFLT release;
@@ -52,11 +53,18 @@ Fader_generate_auto(Fader *self) {
MYFLT val;
int i;
+ if (self->ended == 1) {
+ Fader_internal_stop((Fader *)self);
+ return;
+ }
+
for (i=0; i<self->bufsize; i++) {
if (self->currentTime <= self->attack)
val = self->currentTime / self->attack;
- else if (self->currentTime > self->duration)
+ else if (self->currentTime > self->duration) {
val = 0.;
+ self->ended = 1;
+ }
else if (self->currentTime >= (self->duration - self->release))
val = (self->duration - self->currentTime) / self->release;
else
@@ -71,6 +79,11 @@ static void
Fader_generate_wait(Fader *self) {
MYFLT val;
int i;
+
+ if (self->fademode == 1 && self->currentTime > self->release) {
+ Fader_internal_stop((Fader *)self);
+ return;
+ }
for (i=0; i<self->bufsize; i++) {
if (self->fademode == 0) {
@@ -90,8 +103,6 @@ Fader_generate_wait(Fader *self) {
self->data[i] = val;
self->currentTime += self->sampleToSec;
}
- if (self->fademode == 1 && self->currentTime > self->release)
- Fader_internal_stop((Fader *)self);
}
static void Fader_postprocessing_ii(Fader *self) { POST_PROCESSING_II };
@@ -187,6 +198,7 @@ Fader_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->modebuffer[1] = 0;
self->topValue = 0.0;
self->fademode = 0;
+ self->ended = 0;
self->attack = 0.01;
self->release = 0.1;
self->duration = 0.0;
@@ -230,6 +242,7 @@ static PyObject * Fader_setDiv(Fader *self, PyObject *arg) { SET_DIV };
static PyObject * Fader_play(Fader *self, PyObject *args, PyObject *kwds)
{
self->fademode = 0;
+ self->ended = 0;
self->currentTime = 0.0;
(*self->mode_func_ptr)(self);
PLAY
@@ -427,8 +440,10 @@ Adsr_generate_auto(Adsr *self) {
val = self->currentTime * invatt;
else if (self->currentTime <= (self->attack + self->decay))
val = (self->decay - (self->currentTime - self->attack)) * invdec * (1. - self->sustain) + self->sustain;
- else if (self->currentTime > self->duration)
+ else if (self->currentTime > self->duration) {
val = 0.;
+ Adsr_internal_stop((Adsr *)self);
+ }
else if (self->currentTime >= (self->duration - self->release))
val = (self->duration - self->currentTime) * invrel * self->sustain;
else
diff --git a/src/objects/fftmodule.c b/src/objects/fftmodule.c
index 39ca586..f9e6106 100644
--- a/src/objects/fftmodule.c
+++ b/src/objects/fftmodule.c
@@ -3279,7 +3279,7 @@ CvlVerb_alloc_memories(CvlVerb *self) {
self->inframe = (MYFLT *)realloc(self->inframe, self->size2 * sizeof(MYFLT));
self->outframe = (MYFLT *)realloc(self->outframe, self->size2 * sizeof(MYFLT));
self->last_half_frame = (MYFLT *)realloc(self->last_half_frame, self->size * sizeof(MYFLT));
- self->input_buffer = (MYFLT *)realloc(self->output_buffer, self->size * sizeof(MYFLT));
+ self->input_buffer = (MYFLT *)realloc(self->input_buffer, self->size * sizeof(MYFLT));
self->output_buffer = (MYFLT *)realloc(self->output_buffer, self->size2 * sizeof(MYFLT));
for (i=0; i<self->size2; i++)
self->inframe[i] = self->outframe[i] = self->output_buffer[i] = 0.0;
diff --git a/src/objects/filtremodule.c b/src/objects/filtremodule.c
index d848581..eb8fb7f 100644
--- a/src/objects/filtremodule.c
+++ b/src/objects/filtremodule.c
@@ -5792,6 +5792,7 @@ typedef struct {
MYFLT factor;
int stages;
int last_stages;
+ int flag;
MYFLT nyquist;
MYFLT twoPiOnSr;
int modebuffer[6]; // need at least 2 slots for mul & add
@@ -5829,9 +5830,9 @@ Vocoder_allocate_memories(Vocoder *self)
for (j=0; j<2; j++) {
i2j = i * 2 + j;
self->yy1[i2j] = self->yy2[i2j] = self->y1[i2j] = self->y2[i2j] = 0.0;
-
}
- }
+ }
+ self->flag = 1;
}
static void
@@ -5887,11 +5888,12 @@ Vocoder_filters_iii(Vocoder *self) {
self->factor = MYEXP(-1.0 / (self->sr / ((slope * 48.0) + 2.0)));
}
- if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+ if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
self->last_freq = freq;
self->last_spread = spread;
self->last_q = q;
self->last_stages = self->stages;
+ self->flag = 0;
Vocoder_compute_variables(self, freq, spread, q);
}
@@ -5971,11 +5973,12 @@ Vocoder_filters_aii(Vocoder *self) {
else if (count >= maxcount)
count = 0;
count++;
- if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+ if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
self->last_freq = freq;
self->last_spread = spread;
self->last_q = q;
self->last_stages = self->stages;
+ self->flag = 0;
Vocoder_compute_variables(self, freq, spread, q);
}
output = 0.0;
@@ -6053,11 +6056,12 @@ Vocoder_filters_iai(Vocoder *self) {
else if (count >= maxcount)
count = 0;
count++;
- if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+ if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
self->last_freq = freq;
self->last_spread = spread;
self->last_q = q;
self->last_stages = self->stages;
+ self->flag = 0;
Vocoder_compute_variables(self, freq, spread, q);
}
output = 0.0;
@@ -6138,11 +6142,12 @@ Vocoder_filters_aai(Vocoder *self) {
else if (count >= maxcount)
count = 0;
count++;
- if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+ if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
self->last_freq = freq;
self->last_spread = spread;
self->last_q = q;
self->last_stages = self->stages;
+ self->flag = 0;
Vocoder_compute_variables(self, freq, spread, q);
}
output = 0.0;
@@ -6220,11 +6225,12 @@ Vocoder_filters_iia(Vocoder *self) {
else if (count >= maxcount)
count = 0;
count++;
- if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+ if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
self->last_freq = freq;
self->last_spread = spread;
self->last_q = q;
self->last_stages = self->stages;
+ self->flag = 0;
Vocoder_compute_variables(self, freq, spread, q);
}
output = 0.0;
@@ -6304,11 +6310,12 @@ Vocoder_filters_aia(Vocoder *self) {
else if (count >= maxcount)
count = 0;
count++;
- if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+ if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
self->last_freq = freq;
self->last_spread = spread;
self->last_q = q;
self->last_stages = self->stages;
+ self->flag = 0;
Vocoder_compute_variables(self, freq, spread, q);
}
output = 0.0;
@@ -6388,11 +6395,12 @@ Vocoder_filters_iaa(Vocoder *self) {
else if (count >= maxcount)
count = 0;
count++;
- if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+ if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
self->last_freq = freq;
self->last_spread = spread;
self->last_q = q;
self->last_stages = self->stages;
+ self->flag = 0;
Vocoder_compute_variables(self, freq, spread, q);
}
output = 0.0;
@@ -6474,11 +6482,12 @@ Vocoder_filters_aaa(Vocoder *self) {
else if (count >= maxcount)
count = 0;
count++;
- if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+ if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
self->last_freq = freq;
self->last_spread = spread;
self->last_q = q;
self->last_stages = self->stages;
+ self->flag = 0;
Vocoder_compute_variables(self, freq, spread, q);
}
output = 0.0;
@@ -6674,6 +6683,7 @@ Vocoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->factor = 0.99;
self->stages = 24;
self->last_stages = -1;
+ self->flag = 0;
self->modebuffer[0] = 0;
self->modebuffer[1] = 0;
self->modebuffer[2] = 0;
@@ -6697,11 +6707,8 @@ Vocoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
INIT_INPUT_STREAM
if ( PyObject_HasAttrString((PyObject *)input2tmp, "server") == 0 ) {
- PySys_WriteStderr("TypeError: \"input2\" argument of Vocoder must be a PyoObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input2\" argument of Vocoder must be a PyoObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->input2);
self->input2 = input2tmp;
@@ -11024,3 +11031,510 @@ PyTypeObject ButBRType = {
0, /* tp_alloc */
ButBR_new, /* tp_new */
};
+
+/****************/
+/** ComplexRes **/
+/****************/
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ PyObject *freq;
+ Stream *freq_stream;
+ PyObject *decay;
+ Stream *decay_stream;
+ int modebuffer[4]; // need at least 2 slots for mul & add
+ MYFLT last_freq;
+ MYFLT last_decay;
+ MYFLT oneOnSr;
+ // variables
+ MYFLT res;
+ MYFLT norm;
+ MYFLT coeffx;
+ MYFLT coeffy;
+ // sample memories
+ MYFLT x;
+ MYFLT y;
+} ComplexRes;
+
+static void
+ComplexRes_filters_ii(ComplexRes *self) {
+ int i;
+ MYFLT ang, x, y;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT freq = PyFloat_AS_DOUBLE(self->freq);
+ MYFLT decay = PyFloat_AS_DOUBLE(self->decay);
+
+ if (decay <= 0.0001)
+ decay = 0.0001;
+
+ if (decay != self->last_decay || freq != self->last_freq) {
+ self->res = MYEXP(-1.0/(decay*self->sr));
+ //self->norm = (1.0-self->res*self->res)/self->res;
+ self->last_decay = decay;
+ ang = (freq*self->oneOnSr)*TWOPI;
+ self->coeffx = self->res * MYCOS(ang);
+ self->coeffy = self->res * MYSIN(ang);
+ self->last_freq = freq;
+ }
+
+ for (i=0; i<self->bufsize; i++) {
+ x = self->coeffx * self->x - self->coeffy * self->y + in[i];
+ y = self->coeffy * self->x + self->coeffx * self->y;
+ self->data[i] = y * self->norm;
+ self->x = x;
+ self->y = y;
+ }
+}
+
+static void
+ComplexRes_filters_ai(ComplexRes *self) {
+ int i, check = 0;
+ MYFLT freq, ang, x, y;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
+ MYFLT decay = PyFloat_AS_DOUBLE(self->decay);
+
+ if (decay <= 0.0001)
+ decay = 0.0001;
+
+ if (decay != self->last_decay) {
+ self->res = MYEXP(-1.0/(decay*self->sr));
+ //self->norm = (1.0-self->res*self->res)/self->res;
+ self->last_decay = decay;
+ check = 1;
+ }
+
+ for (i=0; i<self->bufsize; i++) {
+ freq = fr[i];
+ if (freq != self->last_freq || check) {
+ ang = (freq*self->oneOnSr)*TWOPI;
+ self->coeffx = self->res * MYCOS(ang);
+ self->coeffy = self->res * MYSIN(ang);
+ self->last_freq = freq;
+ check = 0;
+ }
+ x = self->coeffx * self->x - self->coeffy * self->y + in[i];
+ y = self->coeffy * self->x + self->coeffx * self->y;
+ self->data[i] = y * self->norm;
+ self->x = x;
+ self->y = y;
+ }
+}
+
+static void
+ComplexRes_filters_ia(ComplexRes *self) {
+ int i;
+ MYFLT decay, ang, x, y;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT freq = PyFloat_AS_DOUBLE(self->freq);
+ MYFLT *dec = Stream_getData((Stream *)self->decay_stream);
+
+ for (i=0; i<self->bufsize; i++) {
+ decay = dec[i];
+ if (decay <= 0.0001)
+ decay = 0.0001;
+ if (freq != self->last_freq || decay != self->last_decay) {
+ self->res = MYEXP(-1.0/(decay*self->sr));
+ //self->norm = (1.0-self->res*self->res)/self->res;
+ self->last_decay = decay;
+ ang = (freq*self->oneOnSr)*TWOPI;
+ self->coeffx = self->res * MYCOS(ang);
+ self->coeffy = self->res * MYSIN(ang);
+ self->last_freq = freq;
+ }
+ x = self->coeffx * self->x - self->coeffy * self->y + in[i];
+ y = self->coeffy * self->x + self->coeffx * self->y;
+ self->data[i] = y * self->norm;
+ self->x = x;
+ self->y = y;
+ }
+}
+
+static void
+ComplexRes_filters_aa(ComplexRes *self) {
+ int i;
+ MYFLT freq, decay, ang, x, y;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
+ MYFLT *dec = Stream_getData((Stream *)self->decay_stream);
+
+ for (i=0; i<self->bufsize; i++) {
+ freq = fr[i];
+ decay = dec[i];
+ if (decay <= 0.0001)
+ decay = 0.0001;
+ if (freq != self->last_freq || decay != self->last_decay) {
+ self->res = MYEXP(-1.0/(decay*self->sr));
+ //self->norm = (1.0-self->res*self->res)/self->res;
+ self->last_decay = decay;
+ ang = (freq*self->oneOnSr)*TWOPI;
+ self->coeffx = self->res * MYCOS(ang);
+ self->coeffy = self->res * MYSIN(ang);
+ self->last_freq = freq;
+ }
+ x = self->coeffx * self->x - self->coeffy * self->y + in[i];
+ y = self->coeffy * self->x + self->coeffx * self->y;
+ self->data[i] = y * self->norm;
+ self->x = x;
+ self->y = y;
+ }
+}
+
+static void ComplexRes_postprocessing_ii(ComplexRes *self) { POST_PROCESSING_II };
+static void ComplexRes_postprocessing_ai(ComplexRes *self) { POST_PROCESSING_AI };
+static void ComplexRes_postprocessing_ia(ComplexRes *self) { POST_PROCESSING_IA };
+static void ComplexRes_postprocessing_aa(ComplexRes *self) { POST_PROCESSING_AA };
+static void ComplexRes_postprocessing_ireva(ComplexRes *self) { POST_PROCESSING_IREVA };
+static void ComplexRes_postprocessing_areva(ComplexRes *self) { POST_PROCESSING_AREVA };
+static void ComplexRes_postprocessing_revai(ComplexRes *self) { POST_PROCESSING_REVAI };
+static void ComplexRes_postprocessing_revaa(ComplexRes *self) { POST_PROCESSING_REVAA };
+static void ComplexRes_postprocessing_revareva(ComplexRes *self) { POST_PROCESSING_REVAREVA };
+
+static void
+ComplexRes_setProcMode(ComplexRes *self)
+{
+ int procmode, muladdmode;
+ procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ switch (procmode) {
+ case 0:
+ self->proc_func_ptr = ComplexRes_filters_ii;
+ break;
+ case 1:
+ self->proc_func_ptr = ComplexRes_filters_ai;
+ break;
+ case 10:
+ self->proc_func_ptr = ComplexRes_filters_ia;
+ break;
+ case 11:
+ self->proc_func_ptr = ComplexRes_filters_aa;
+ break;
+ }
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = ComplexRes_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = ComplexRes_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = ComplexRes_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = ComplexRes_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = ComplexRes_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = ComplexRes_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = ComplexRes_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = ComplexRes_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = ComplexRes_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+ComplexRes_compute_next_data_frame(ComplexRes *self)
+{
+ (*self->proc_func_ptr)(self);
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+ComplexRes_traverse(ComplexRes *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ Py_VISIT(self->freq);
+ Py_VISIT(self->freq_stream);
+ Py_VISIT(self->decay);
+ Py_VISIT(self->decay_stream);
+ return 0;
+}
+
+static int
+ComplexRes_clear(ComplexRes *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->input_stream);
+ Py_CLEAR(self->freq);
+ Py_CLEAR(self->freq_stream);
+ Py_CLEAR(self->decay);
+ Py_CLEAR(self->decay_stream);
+ return 0;
+}
+
+static void
+ComplexRes_dealloc(ComplexRes* self)
+{
+ pyo_DEALLOC
+ ComplexRes_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+ComplexRes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *inputtmp, *input_streamtmp, *freqtmp=NULL, *decaytmp=NULL, *multmp=NULL, *addtmp=NULL;
+ ComplexRes *self;
+ self = (ComplexRes *)type->tp_alloc(type, 0);
+
+ self->freq = PyFloat_FromDouble(1000);
+ self->decay = PyFloat_FromDouble(.25);
+ self->last_freq = self->last_decay = -1.0;
+ self->x = self->y = 0.0;
+ self->res = 1.0;
+ self->norm = 0.01; /* normalization factor fixed at -40 dB */
+ self->coeffx = self->coeffy = 0.0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+ self->modebuffer[2] = 0;
+ self->modebuffer[3] = 0;
+
+ INIT_OBJECT_COMMON
+
+ self->oneOnSr = 1.0 / self->sr;
+
+ Stream_setFunctionPtr(self->stream, ComplexRes_compute_next_data_frame);
+ self->mode_func_ptr = ComplexRes_setProcMode;
+
+ static char *kwlist[] = {"input", "freq", "decay", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OOOO", kwlist, &inputtmp, &freqtmp, &decaytmp, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ INIT_INPUT_STREAM
+
+ if (freqtmp) {
+ PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
+ }
+
+ if (decaytmp) {
+ PyObject_CallMethod((PyObject *)self, "setDecay", "O", decaytmp);
+ }
+
+ if (multmp) {
+ PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+ }
+
+ if (addtmp) {
+ PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * ComplexRes_getServer(ComplexRes* self) { GET_SERVER };
+static PyObject * ComplexRes_getStream(ComplexRes* self) { GET_STREAM };
+static PyObject * ComplexRes_setMul(ComplexRes *self, PyObject *arg) { SET_MUL };
+static PyObject * ComplexRes_setAdd(ComplexRes *self, PyObject *arg) { SET_ADD };
+static PyObject * ComplexRes_setSub(ComplexRes *self, PyObject *arg) { SET_SUB };
+static PyObject * ComplexRes_setDiv(ComplexRes *self, PyObject *arg) { SET_DIV };
+
+static PyObject * ComplexRes_play(ComplexRes *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * ComplexRes_out(ComplexRes *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * ComplexRes_stop(ComplexRes *self) { STOP };
+
+static PyObject * ComplexRes_multiply(ComplexRes *self, PyObject *arg) { MULTIPLY };
+static PyObject * ComplexRes_inplace_multiply(ComplexRes *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * ComplexRes_add(ComplexRes *self, PyObject *arg) { ADD };
+static PyObject * ComplexRes_inplace_add(ComplexRes *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * ComplexRes_sub(ComplexRes *self, PyObject *arg) { SUB };
+static PyObject * ComplexRes_inplace_sub(ComplexRes *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * ComplexRes_div(ComplexRes *self, PyObject *arg) { DIV };
+static PyObject * ComplexRes_inplace_div(ComplexRes *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+ComplexRes_setFreq(ComplexRes *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->freq);
+ if (isNumber == 1) {
+ self->freq = PyNumber_Float(tmp);
+ self->modebuffer[2] = 0;
+ }
+ else {
+ self->freq = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->freq, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->freq_stream);
+ self->freq_stream = (Stream *)streamtmp;
+ self->modebuffer[2] = 1;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+ComplexRes_setDecay(ComplexRes *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->decay);
+ if (isNumber == 1) {
+ self->decay = PyNumber_Float(tmp);
+ self->modebuffer[3] = 0;
+ }
+ else {
+ self->decay = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->decay, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->decay_stream);
+ self->decay_stream = (Stream *)streamtmp;
+ self->modebuffer[3] = 1;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMemberDef ComplexRes_members[] = {
+{"server", T_OBJECT_EX, offsetof(ComplexRes, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(ComplexRes, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(ComplexRes, input), 0, "Input sound object."},
+{"freq", T_OBJECT_EX, offsetof(ComplexRes, freq), 0, "Center frequency in cycle per second."},
+{"decay", T_OBJECT_EX, offsetof(ComplexRes, decay), 0, "Decaying envelope time in seconds."},
+{"mul", T_OBJECT_EX, offsetof(ComplexRes, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(ComplexRes, add), 0, "Add factor."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef ComplexRes_methods[] = {
+{"getServer", (PyCFunction)ComplexRes_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)ComplexRes_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)ComplexRes_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"out", (PyCFunction)ComplexRes_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"stop", (PyCFunction)ComplexRes_stop, METH_NOARGS, "Stops computing."},
+{"setFreq", (PyCFunction)ComplexRes_setFreq, METH_O, "Sets filter center frequency in cycle per second."},
+{"setDecay", (PyCFunction)ComplexRes_setDecay, METH_O, "Sets filter decaying envelope time."},
+{"setMul", (PyCFunction)ComplexRes_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)ComplexRes_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)ComplexRes_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)ComplexRes_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL} /* Sentinel */
+};
+
+static PyNumberMethods ComplexRes_as_number = {
+(binaryfunc)ComplexRes_add, /*nb_add*/
+(binaryfunc)ComplexRes_sub, /*nb_subtract*/
+(binaryfunc)ComplexRes_multiply, /*nb_multiply*/
+(binaryfunc)ComplexRes_div, /*nb_divide*/
+0, /*nb_remainder*/
+0, /*nb_divmod*/
+0, /*nb_power*/
+0, /*nb_neg*/
+0, /*nb_pos*/
+0, /*(unaryfunc)array_abs,*/
+0, /*nb_nonzero*/
+0, /*nb_invert*/
+0, /*nb_lshift*/
+0, /*nb_rshift*/
+0, /*nb_and*/
+0, /*nb_xor*/
+0, /*nb_or*/
+0, /*nb_coerce*/
+0, /*nb_int*/
+0, /*nb_long*/
+0, /*nb_float*/
+0, /*nb_oct*/
+0, /*nb_hex*/
+(binaryfunc)ComplexRes_inplace_add, /*inplace_add*/
+(binaryfunc)ComplexRes_inplace_sub, /*inplace_subtract*/
+(binaryfunc)ComplexRes_inplace_multiply, /*inplace_multiply*/
+(binaryfunc)ComplexRes_inplace_div, /*inplace_divide*/
+0, /*inplace_remainder*/
+0, /*inplace_power*/
+0, /*inplace_lshift*/
+0, /*inplace_rshift*/
+0, /*inplace_and*/
+0, /*inplace_xor*/
+0, /*inplace_or*/
+0, /*nb_floor_divide*/
+0, /*nb_true_divide*/
+0, /*nb_inplace_floor_divide*/
+0, /*nb_inplace_true_divide*/
+0, /* nb_index */
+};
+
+PyTypeObject ComplexResType = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.ComplexRes_base", /*tp_name*/
+sizeof(ComplexRes), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)ComplexRes_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+&ComplexRes_as_number, /*tp_as_number*/
+0, /*tp_as_sequence*/
+0, /*tp_as_mapping*/
+0, /*tp_hash */
+0, /*tp_call*/
+0, /*tp_str*/
+0, /*tp_getattro*/
+0, /*tp_setattro*/
+0, /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"ComplexRes objects. Second order allpass filter.", /* tp_doc */
+(traverseproc)ComplexRes_traverse, /* tp_traverse */
+(inquiry)ComplexRes_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+ComplexRes_methods, /* tp_methods */
+ComplexRes_members, /* tp_members */
+0, /* tp_getset */
+0, /* tp_base */
+0, /* tp_dict */
+0, /* tp_descr_get */
+0, /* tp_descr_set */
+0, /* tp_dictoffset */
+0, /* tp_init */
+0, /* tp_alloc */
+ComplexRes_new, /* tp_new */
+};
diff --git a/src/objects/freeverbmodule.c b/src/objects/freeverbmodule.c
index 8ba510b..9f98523 100644
--- a/src/objects/freeverbmodule.c
+++ b/src/objects/freeverbmodule.c
@@ -50,7 +50,7 @@ static const MYFLT allpass_delays[NUM_ALLPASS] = {
static const MYFLT fixedGain = 0.015;
static const MYFLT scaleDamp = 0.5;
-static const MYFLT scaleRoom = 0.28;
+static const MYFLT scaleRoom = 0.29;
static const MYFLT offsetRoom = 0.7;
static const MYFLT allPassFeedBack = 0.5;
@@ -929,4 +929,3 @@ PyTypeObject FreeverbType = {
0, /* tp_alloc */
Freeverb_new, /* tp_new */
};
-
diff --git a/src/objects/granulatormodule.c b/src/objects/granulatormodule.c
index 44eaf46..a996aea 100644
--- a/src/objects/granulatormodule.c
+++ b/src/objects/granulatormodule.c
@@ -711,21 +711,15 @@ Granulator_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of Granulator must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of Granulator must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
if ( PyObject_HasAttrString((PyObject *)envtmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"env\" argument of Granulator must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"env\" argument of Granulator must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->env);
self->env = PyObject_CallMethod((PyObject *)envtmp, "getTableStream", "");
@@ -1866,11 +1860,8 @@ Looper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of Looper must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of Looper must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -2304,7 +2295,7 @@ PyTypeObject LooperType = {
Looper_new, /* tp_new */
};
-static const MYFLT Granule_MAX_GRAINS = 1024;
+static const MYFLT Granule_MAX_GRAINS = 4096;
typedef struct {
pyo_audio_HEAD
PyObject *table;
@@ -2323,16 +2314,17 @@ typedef struct {
MYFLT *phase;
int *flags;
int num;
+ int sync;
double timer;
MYFLT oneOnSr;
+ MYFLT srOnRandMax;
int modebuffer[6];
} Granule;
static void
Granule_transform_i(Granule *self) {
MYFLT dens, inc, index, amp, phase;
- int i, j, ipart;
- int flag = 0;
+ int i, j, ipart, flag = 0;
MYFLT pit = 0, pos = 0, dur = 0;
MYFLT *tablelist = TableStream_getData(self->table);
@@ -2343,18 +2335,24 @@ Granule_transform_i(Granule *self) {
dens = PyFloat_AS_DOUBLE(self->dens);
if (dens < 0.0)
- dens = -dens;
+ dens = 0.0;
inc = dens * self->oneOnSr;
for (i=0; i<self->bufsize; i++) {
self->data[i] = 0.0;
- /* clocker */
- self->timer += inc;
- if (self->timer >= 1.0) {
- self->timer -= 1.0;
- flag = 1;
+ if (self->sync == 1) {
+ /* synchronous */
+ self->timer += inc;
+ if (self->timer >= 1.0) {
+ self->timer -= 1.0;
+ flag = 1;
+ }
+ } else {
+ /* asynchronous */
+ if ((rand() * self->srOnRandMax) < dens)
+ flag = 1;
}
/* need to start a new grain */
@@ -2376,10 +2374,14 @@ Granule_transform_i(Granule *self) {
dur = PyFloat_AS_DOUBLE(self->dur);
else
dur = Stream_getData((Stream *)self->dur_stream)[i];
+ if (pit < 0.0)
+ pit = -pit;
if (pos < 0.0)
pos = 0.0;
else if (pos >= size)
pos = (MYFLT)size;
+ if (dur < 0.0001)
+ dur = 0.0001;
self->gpos[j] = pos;
self->glen[j] = dur * self->sr * pit;
if ((pos + self->glen[j]) >= size || (pos + self->glen[j]) < 0)
@@ -2395,23 +2397,19 @@ Granule_transform_i(Granule *self) {
for (j=0; j<self->num; j++) {
if (self->flags[j]) {
phase = self->phase[j];
- if (phase >= 0.0 && phase < 1.0) {
- // compute envelope
- index = phase * envsize;
- ipart = (int)index;
- amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
-
- // compute sampling
- index = phase * self->glen[j] + self->gpos[j];
- ipart = (int)index;
- self->data[i] += (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
-
- phase += self->inc[j];
- if (phase >= 1.0)
- self->flags[j] = 0;
- else
- self->phase[j] = phase;
- }
+ /* compute envelope */
+ index = phase * envsize;
+ ipart = (int)index;
+ amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
+ /* compute sampling */
+ index = phase * self->glen[j] + self->gpos[j];
+ ipart = (int)index;
+ self->data[i] += (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
+ phase += self->inc[j];
+ if (phase >= 1.0)
+ self->flags[j] = 0;
+ else
+ self->phase[j] = phase;
}
}
flag = 0;
@@ -2421,8 +2419,7 @@ Granule_transform_i(Granule *self) {
static void
Granule_transform_a(Granule *self) {
MYFLT index, amp, phase;
- int i, j, ipart;
- int flag = 0;
+ int i, j, ipart, flag = 0;
MYFLT pit = 0, pos = 0, dur = 0;
MYFLT *tablelist = TableStream_getData(self->table);
@@ -2436,11 +2433,17 @@ Granule_transform_a(Granule *self) {
for (i=0; i<self->bufsize; i++) {
self->data[i] = 0.0;
- /* clocker */
- self->timer += density[i] * self->oneOnSr;
- if (self->timer >= 1.0) {
- self->timer -= 1.0;
- flag = 1;
+ if (self->sync == 1) {
+ /* synchronous */
+ self->timer += density[i] * self->oneOnSr;
+ if (self->timer >= 1.0) {
+ self->timer -= 1.0;
+ flag = 1;
+ }
+ } else {
+ /* asynchronous */
+ if ((rand() * self->srOnRandMax) < density[i])
+ flag = 1;
}
/* need to start a new grain */
@@ -2462,10 +2465,14 @@ Granule_transform_a(Granule *self) {
dur = PyFloat_AS_DOUBLE(self->dur);
else
dur = Stream_getData((Stream *)self->dur_stream)[i];
+ if (pit < 0.0)
+ pit = -pit;
if (pos < 0.0)
pos = 0.0;
else if (pos >= size)
pos = (MYFLT)size;
+ if (dur < 0.0001)
+ dur = 0.0001;
self->gpos[j] = pos;
self->glen[j] = dur * self->sr * pit;
if ((pos + self->glen[j]) >= size || (pos + self->glen[j]) < 0)
@@ -2481,23 +2488,19 @@ Granule_transform_a(Granule *self) {
for (j=0; j<self->num; j++) {
if (self->flags[j]) {
phase = self->phase[j];
- if (phase >= 0.0 && phase < 1.0) {
- // compute envelope
- index = phase * envsize;
- ipart = (int)index;
- amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
-
- // compute sampling
- index = phase * self->glen[j] + self->gpos[j];
- ipart = (int)index;
- self->data[i] += (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
-
- phase += self->inc[j];
- if (phase >= 1.0)
- self->flags[j] = 0;
- else
- self->phase[j] = phase;
- }
+ // compute envelope
+ index = phase * envsize;
+ ipart = (int)index;
+ amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
+ // compute sampling
+ index = phase * self->glen[j] + self->gpos[j];
+ ipart = (int)index;
+ self->data[i] += (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
+ phase += self->inc[j];
+ if (phase >= 1.0)
+ self->flags[j] = 0;
+ else
+ self->phase[j] = phase;
}
}
flag = 0;
@@ -2628,6 +2631,7 @@ Granule_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->dur = PyFloat_FromDouble(0.1);
self->timer = 1.0;
self->num = 0;
+ self->sync = 1;
self->modebuffer[0] = 0;
self->modebuffer[1] = 0;
self->modebuffer[2] = 0;
@@ -2638,6 +2642,7 @@ Granule_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
INIT_OBJECT_COMMON
self->oneOnSr = 1.0 / self->sr;
+ self->srOnRandMax = self->sr / (MYFLT)RAND_MAX;
Stream_setFunctionPtr(self->stream, Granule_compute_next_data_frame);
self->mode_func_ptr = Granule_setProcMode;
@@ -2648,21 +2653,15 @@ Granule_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of Granule must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of Granule must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
if ( PyObject_HasAttrString((PyObject *)envtmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"env\" argument of Granule must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"env\" argument of Granule must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->env);
self->env = PyObject_CallMethod((PyObject *)envtmp, "getTableStream", "");
@@ -2703,7 +2702,9 @@ Granule_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->gpos[i] = self->glen[i] = self->inc[i] = self->phase[i] = 0.0;
self->flags[i] = 0;
}
-
+
+ Server_generateSeed((Server *)self->server, GRANULE_ID);
+
(*self->mode_func_ptr)(self);
return (PyObject *)self;
@@ -2909,6 +2910,21 @@ Granule_setEnv(Granule *self, PyObject *arg)
return Py_None;
}
+static PyObject *
+Granule_setSync(Granule *self, PyObject *arg)
+{
+ if (PyLong_Check(arg) || PyInt_Check(arg)) {
+ self->sync = PyLong_AsLong(arg);
+ if (self->sync <= 0)
+ self->sync = 0;
+ else
+ self->sync = 1;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
static PyMemberDef Granule_members[] = {
{"server", T_OBJECT_EX, offsetof(Granule, server), 0, "Pyo server."},
{"stream", T_OBJECT_EX, offsetof(Granule, stream), 0, "Stream object."},
@@ -2937,6 +2953,7 @@ static PyMethodDef Granule_methods[] = {
{"setPitch", (PyCFunction)Granule_setPitch, METH_O, "Sets global pitch factor."},
{"setPos", (PyCFunction)Granule_setPos, METH_O, "Sets position in the sound table."},
{"setDur", (PyCFunction)Granule_setDur, METH_O, "Sets the grain duration."},
+ {"setSync", (PyCFunction)Granule_setSync, METH_O, "Sets the granulator mode: synchronous or asynchronous."},
{"setMul", (PyCFunction)Granule_setMul, METH_O, "Sets Granule mul factor."},
{"setAdd", (PyCFunction)Granule_setAdd, METH_O, "Sets Granule add factor."},
{"setSub", (PyCFunction)Granule_setSub, METH_O, "Sets inverse add factor."},
@@ -3028,3 +3045,1289 @@ PyTypeObject GranuleType = {
Granule_new, /* tp_new */
};
+static const MYFLT MAINPARTICLE_MAX_GRAINS = 4096;
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *table;
+ PyObject *env;
+ PyObject *dens;
+ Stream *dens_stream;
+ PyObject *pitch;
+ Stream *pitch_stream;
+ PyObject *pos;
+ Stream *pos_stream;
+ PyObject *dur;
+ Stream *dur_stream;
+ PyObject *dev;
+ Stream *dev_stream;
+ PyObject *pan;
+ Stream *pan_stream;
+ MYFLT *gpos;
+ MYFLT *glen;
+ MYFLT *inc;
+ MYFLT *phase;
+ MYFLT *amp1;
+ MYFLT *amp2;
+ int *flags;
+ int *k1;
+ int *k2;
+ int num;
+ int chnls;
+ double timer;
+ double devFactor;
+ double srScale;
+ MYFLT oneOnSr;
+ MYFLT srOnRandMax;
+ MYFLT *buffer_streams;
+ int modebuffer[6];
+} MainParticle;
+
+static void
+MainParticle_transform_mono_i(MainParticle *self) {
+ MYFLT dens, inc, index, amp, phase, val;
+ int i, j, ipart, flag = 0;
+ MYFLT pit = 0, pos = 0, dur = 0, dev = 0;
+
+ MYFLT *tablelist = TableStream_getData(self->table);
+ int size = TableStream_getSize(self->table);
+
+ MYFLT *envlist = TableStream_getData(self->env);
+ int envsize = TableStream_getSize(self->env);
+
+ dens = PyFloat_AS_DOUBLE(self->dens);
+ if (dens < 0.0)
+ dens = 0.0;
+
+ inc = dens * self->oneOnSr * self->devFactor;
+
+ for (i=0; i<self->bufsize*self->chnls; i++) {
+ self->buffer_streams[i] = 0.0;
+ }
+
+ for (i=0; i<self->bufsize; i++) {
+ self->timer += inc;
+ if (self->timer >= 1.0) {
+ self->timer -= 1.0;
+ flag = 1;
+ }
+
+ /* need to start a new grain */
+ if (flag) {
+ for (j=0; j<MAINPARTICLE_MAX_GRAINS; j++) {
+ if (self->flags[j] == 0) {
+ self->flags[j] = 1;
+ if (j >= self->num)
+ self->num = j + 1;
+ if (self->modebuffer[1] == 0)
+ pit = PyFloat_AS_DOUBLE(self->pitch);
+ else
+ pit = Stream_getData((Stream *)self->pitch_stream)[i];
+ if (self->modebuffer[2] == 0)
+ pos = PyFloat_AS_DOUBLE(self->pos);
+ else
+ pos = Stream_getData((Stream *)self->pos_stream)[i];
+ if (self->modebuffer[3] == 0)
+ dur = PyFloat_AS_DOUBLE(self->dur);
+ else
+ dur = Stream_getData((Stream *)self->dur_stream)[i];
+ if (self->modebuffer[4] == 0)
+ dev = PyFloat_AS_DOUBLE(self->dev);
+ else
+ dev = Stream_getData((Stream *)self->dev_stream)[i];
+ if (pit < 0.0)
+ pit = -pit;
+ if (pos < 0.0)
+ pos = 0.0;
+ else if (pos >= size)
+ pos = (MYFLT)size;
+ if (dur < 0.0001)
+ dur = 0.0001;
+ if (dev < 0.0)
+ dev = 0.0;
+ else if (dev > 1.0)
+ dev = 1.0;
+ self->gpos[j] = pos;
+ self->glen[j] = dur * self->sr * pit * self->srScale;
+ if ((pos + self->glen[j]) >= size || (pos + self->glen[j]) < 0)
+ self->flags[j] = 0;
+ self->phase[j] = 0.0;
+ self->inc[j] = 1.0 / (dur * self->sr);
+ self->devFactor = (rand() / (MYFLT)RAND_MAX * 2.0 - 1.0) * dev + 1.0;
+ break;
+ }
+ }
+ }
+
+ /* compute active grains */
+ for (j=0; j<self->num; j++) {
+ if (self->flags[j]) {
+ phase = self->phase[j];
+ /* compute envelope */
+ index = phase * envsize;
+ ipart = (int)index;
+ amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
+ /* compute sampling */
+ index = phase * self->glen[j] + self->gpos[j];
+ ipart = (int)index;
+ val = (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
+ self->buffer_streams[i] += val;
+ phase += self->inc[j];
+ if (phase >= 1.0)
+ self->flags[j] = 0;
+ else
+ self->phase[j] = phase;
+ }
+ }
+ flag = 0;
+ }
+}
+
+static void
+MainParticle_transform_mono_a(MainParticle *self) {
+ MYFLT dens, index, amp, phase, val;
+ int i, j, ipart, flag = 0;
+ MYFLT pit = 0, pos = 0, dur = 0, dev = 0;
+
+ MYFLT *tablelist = TableStream_getData(self->table);
+ int size = TableStream_getSize(self->table);
+
+ MYFLT *envlist = TableStream_getData(self->env);
+ int envsize = TableStream_getSize(self->env);
+
+ MYFLT *density = Stream_getData((Stream *)self->dens_stream);
+
+ for (i=0; i<self->bufsize*self->chnls; i++) {
+ self->buffer_streams[i] = 0.0;
+ }
+
+ for (i=0; i<self->bufsize; i++) {
+ if (density[i] < 0.0)
+ dens = 0.0;
+ else
+ dens = density[i];
+ self->timer += dens * self->oneOnSr * self->devFactor;
+ if (self->timer >= 1.0) {
+ self->timer -= 1.0;
+ flag = 1;
+ }
+
+ /* need to start a new grain */
+ if (flag) {
+ for (j=0; j<MAINPARTICLE_MAX_GRAINS; j++) {
+ if (self->flags[j] == 0) {
+ self->flags[j] = 1;
+ if (j >= self->num)
+ self->num = j + 1;
+ if (self->modebuffer[1] == 0)
+ pit = PyFloat_AS_DOUBLE(self->pitch);
+ else
+ pit = Stream_getData((Stream *)self->pitch_stream)[i];
+ if (self->modebuffer[2] == 0)
+ pos = PyFloat_AS_DOUBLE(self->pos);
+ else
+ pos = Stream_getData((Stream *)self->pos_stream)[i];
+ if (self->modebuffer[3] == 0)
+ dur = PyFloat_AS_DOUBLE(self->dur);
+ else
+ dur = Stream_getData((Stream *)self->dur_stream)[i];
+ if (self->modebuffer[4] == 0)
+ dev = PyFloat_AS_DOUBLE(self->dev);
+ else
+ dev = Stream_getData((Stream *)self->dev_stream)[i];
+ if (pit < 0.0)
+ pit = -pit;
+ if (pos < 0.0)
+ pos = 0.0;
+ else if (pos >= size)
+ pos = (MYFLT)size;
+ if (dur < 0.0001)
+ dur = 0.0001;
+ if (dev < 0.0)
+ dev = 0.0;
+ else if (dev > 1.0)
+ dev = 1.0;
+ self->gpos[j] = pos;
+ self->glen[j] = dur * self->sr * pit * self->srScale;
+ if ((pos + self->glen[j]) >= size || (pos + self->glen[j]) < 0)
+ self->flags[j] = 0;
+ self->phase[j] = 0.0;
+ self->inc[j] = 1.0 / (dur * self->sr);
+ self->devFactor = (rand() / (MYFLT)RAND_MAX * 2.0 - 1.0) * dev + 1.0;
+ break;
+ }
+ }
+ }
+
+ /* compute active grains */
+ for (j=0; j<self->num; j++) {
+ if (self->flags[j]) {
+ phase = self->phase[j];
+ /* compute envelope */
+ index = phase * envsize;
+ ipart = (int)index;
+ amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
+ /* compute sampling */
+ index = phase * self->glen[j] + self->gpos[j];
+ ipart = (int)index;
+ val = (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
+ self->buffer_streams[i] += val;
+ phase += self->inc[j];
+ if (phase >= 1.0)
+ self->flags[j] = 0;
+ else
+ self->phase[j] = phase;
+ }
+ }
+ flag = 0;
+ }
+}
+
+static void
+MainParticle_transform_i(MainParticle *self) {
+ MYFLT dens, inc, index, amp, phase, val, min = 0;
+ int i, j, l, l1, ipart, flag = 0;
+ MYFLT pit = 0, pos = 0, dur = 0, dev = 0, pan = 0;
+
+ MYFLT *tablelist = TableStream_getData(self->table);
+ int size = TableStream_getSize(self->table);
+
+ MYFLT *envlist = TableStream_getData(self->env);
+ int envsize = TableStream_getSize(self->env);
+
+ dens = PyFloat_AS_DOUBLE(self->dens);
+ if (dens < 0.0)
+ dens = 0.0;
+
+ inc = dens * self->oneOnSr * self->devFactor;
+
+ for (i=0; i<self->bufsize*self->chnls; i++) {
+ self->buffer_streams[i] = 0.0;
+ }
+
+ for (i=0; i<self->bufsize; i++) {
+ self->timer += inc;
+ if (self->timer >= 1.0) {
+ self->timer -= 1.0;
+ flag = 1;
+ }
+
+ /* need to start a new grain */
+ if (flag) {
+ for (j=0; j<MAINPARTICLE_MAX_GRAINS; j++) {
+ if (self->flags[j] == 0) {
+ self->flags[j] = 1;
+ if (j >= self->num)
+ self->num = j + 1;
+ if (self->modebuffer[1] == 0)
+ pit = PyFloat_AS_DOUBLE(self->pitch);
+ else
+ pit = Stream_getData((Stream *)self->pitch_stream)[i];
+ if (self->modebuffer[2] == 0)
+ pos = PyFloat_AS_DOUBLE(self->pos);
+ else
+ pos = Stream_getData((Stream *)self->pos_stream)[i];
+ if (self->modebuffer[3] == 0)
+ dur = PyFloat_AS_DOUBLE(self->dur);
+ else
+ dur = Stream_getData((Stream *)self->dur_stream)[i];
+ if (self->modebuffer[4] == 0)
+ dev = PyFloat_AS_DOUBLE(self->dev);
+ else
+ dev = Stream_getData((Stream *)self->dev_stream)[i];
+ if (self->modebuffer[5] == 0)
+ pan = PyFloat_AS_DOUBLE(self->pan);
+ else
+ pan = Stream_getData((Stream *)self->pan_stream)[i];
+ if (pit < 0.0)
+ pit = -pit;
+ if (pos < 0.0)
+ pos = 0.0;
+ else if (pos >= size)
+ pos = (MYFLT)size;
+ if (dur < 0.0001)
+ dur = 0.0001;
+ if (dev < 0.0)
+ dev = 0.0;
+ else if (dev > 1.0)
+ dev = 1.0;
+ if (pan < 0.0)
+ pan = 0.0;
+ else if (pan > 1.0)
+ pan = 1.0;
+ self->gpos[j] = pos;
+ self->glen[j] = dur * self->sr * pit * self->srScale;
+ if ((pos + self->glen[j]) >= size || (pos + self->glen[j]) < 0)
+ self->flags[j] = 0;
+ self->phase[j] = 0.0;
+ self->inc[j] = 1.0 / (dur * self->sr);
+ self->devFactor = (rand() / (MYFLT)RAND_MAX * 2.0 - 1.0) * dev + 1.0;
+ if (self->chnls == 2) {
+ self->k1[j] = 0;
+ self->k2[j] = self->bufsize;
+ self->amp1[j] = MYSQRT(1.0 - pan);
+ self->amp2[j] = MYSQRT(pan);
+ }
+ else {
+ self->amp1[j] = MYSQRT(1.0 - pan);
+ self->amp2[j] = MYSQRT(pan);
+ min = 0;
+ self->k1[j] = 0;
+ self->k2[j] = self->bufsize;
+ for (l=self->chnls; l>0; l--) {
+ l1 = l - 1;
+ min = l1 / (MYFLT)self->chnls;
+ if (pan > min) {
+ self->k1[j] = l1 * self->bufsize;
+ if (l == self->chnls)
+ self->k2[j] = 0;
+ else
+ self->k2[j] = l * self->bufsize;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ /* compute active grains */
+ for (j=0; j<self->num; j++) {
+ if (self->flags[j]) {
+ phase = self->phase[j];
+ /* compute envelope */
+ index = phase * envsize;
+ ipart = (int)index;
+ amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
+ /* compute sampling */
+ index = phase * self->glen[j] + self->gpos[j];
+ ipart = (int)index;
+ val = (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
+ self->buffer_streams[i+self->k1[j]] += val * self->amp1[j];
+ self->buffer_streams[i+self->k2[j]] += val * self->amp2[j];
+ phase += self->inc[j];
+ if (phase >= 1.0)
+ self->flags[j] = 0;
+ else
+ self->phase[j] = phase;
+ }
+ }
+ flag = 0;
+ }
+}
+
+static void
+MainParticle_transform_a(MainParticle *self) {
+ MYFLT dens, index, amp, phase, val, min = 0;
+ int i, j, l, l1, ipart, flag = 0;
+ MYFLT pit = 0, pos = 0, dur = 0, dev = 0, pan = 0;
+
+ MYFLT *tablelist = TableStream_getData(self->table);
+ int size = TableStream_getSize(self->table);
+
+ MYFLT *envlist = TableStream_getData(self->env);
+ int envsize = TableStream_getSize(self->env);
+
+ MYFLT *density = Stream_getData((Stream *)self->dens_stream);
+
+ for (i=0; i<self->bufsize*self->chnls; i++) {
+ self->buffer_streams[i] = 0.0;
+ }
+
+ for (i=0; i<self->bufsize; i++) {
+ if (density[i] < 0.0)
+ dens = 0.0;
+ else
+ dens = density[i];
+ self->timer += dens * self->oneOnSr * self->devFactor;
+ if (self->timer >= 1.0) {
+ self->timer -= 1.0;
+ flag = 1;
+ }
+
+ /* need to start a new grain */
+ if (flag) {
+ for (j=0; j<MAINPARTICLE_MAX_GRAINS; j++) {
+ if (self->flags[j] == 0) {
+ self->flags[j] = 1;
+ if (j >= self->num)
+ self->num = j + 1;
+ if (self->modebuffer[1] == 0)
+ pit = PyFloat_AS_DOUBLE(self->pitch);
+ else
+ pit = Stream_getData((Stream *)self->pitch_stream)[i];
+ if (self->modebuffer[2] == 0)
+ pos = PyFloat_AS_DOUBLE(self->pos);
+ else
+ pos = Stream_getData((Stream *)self->pos_stream)[i];
+ if (self->modebuffer[3] == 0)
+ dur = PyFloat_AS_DOUBLE(self->dur);
+ else
+ dur = Stream_getData((Stream *)self->dur_stream)[i];
+ if (self->modebuffer[4] == 0)
+ dev = PyFloat_AS_DOUBLE(self->dev);
+ else
+ dev = Stream_getData((Stream *)self->dev_stream)[i];
+ if (self->modebuffer[5] == 0)
+ pan = PyFloat_AS_DOUBLE(self->pan);
+ else
+ pan = Stream_getData((Stream *)self->pan_stream)[i];
+ if (pit < 0.0)
+ pit = -pit;
+ if (pos < 0.0)
+ pos = 0.0;
+ else if (pos >= size)
+ pos = (MYFLT)size;
+ if (dur < 0.0001)
+ dur = 0.0001;
+ if (dev < 0.0)
+ dev = 0.0;
+ else if (dev > 1.0)
+ dev = 1.0;
+ if (pan < 0.0)
+ pan = 0.0;
+ else if (pan > 1.0)
+ pan = 1.0;
+ self->gpos[j] = pos;
+ self->glen[j] = dur * self->sr * pit * self->srScale;
+ if ((pos + self->glen[j]) >= size || (pos + self->glen[j]) < 0)
+ self->flags[j] = 0;
+ self->phase[j] = 0.0;
+ self->inc[j] = 1.0 / (dur * self->sr);
+ self->devFactor = (rand() / (MYFLT)RAND_MAX * 2.0 - 1.0) * dev + 1.0;
+ if (self->chnls == 2) {
+ self->k1[j] = 0;
+ self->k2[j] = self->bufsize;
+ self->amp1[j] = MYSQRT(1.0 - pan);
+ self->amp2[j] = MYSQRT(pan);
+ }
+ else {
+ self->amp1[j] = MYSQRT(1.0 - pan);
+ self->amp2[j] = MYSQRT(pan);
+ min = 0;
+ self->k1[j] = 0;
+ self->k2[j] = self->bufsize;
+ for (l=self->chnls; l>0; l--) {
+ l1 = l - 1;
+ min = l1 / (MYFLT)self->chnls;
+ if (pan > min) {
+ self->k1[j] = l1 * self->bufsize;
+ if (l == self->chnls)
+ self->k2[j] = 0;
+ else
+ self->k2[j] = l * self->bufsize;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ /* compute active grains */
+ for (j=0; j<self->num; j++) {
+ if (self->flags[j]) {
+ phase = self->phase[j];
+ /* compute envelope */
+ index = phase * envsize;
+ ipart = (int)index;
+ amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
+ /* compute sampling */
+ index = phase * self->glen[j] + self->gpos[j];
+ ipart = (int)index;
+ val = (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
+ self->buffer_streams[i+self->k1[j]] += val * self->amp1[j];
+ self->buffer_streams[i+self->k2[j]] += val * self->amp2[j];
+ phase += self->inc[j];
+ if (phase >= 1.0)
+ self->flags[j] = 0;
+ else
+ self->phase[j] = phase;
+ }
+ }
+ flag = 0;
+ }
+}
+
+static void
+MainParticle_setProcMode(MainParticle *self)
+{
+ int procmode = self->modebuffer[0];
+
+ switch (procmode) {
+ case 0:
+ if (self->chnls == 1)
+ self->proc_func_ptr = MainParticle_transform_mono_i;
+ else
+ self->proc_func_ptr = MainParticle_transform_i;
+ break;
+ case 1:
+ if (self->chnls == 1)
+ self->proc_func_ptr = MainParticle_transform_mono_a;
+ else
+ self->proc_func_ptr = MainParticle_transform_a;
+ break;
+ }
+}
+
+static void
+MainParticle_compute_next_data_frame(MainParticle *self)
+{
+ (*self->proc_func_ptr)(self);
+}
+
+static int
+MainParticle_traverse(MainParticle *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->table);
+ Py_VISIT(self->env);
+ Py_VISIT(self->dens);
+ Py_VISIT(self->dens_stream);
+ Py_VISIT(self->pitch);
+ Py_VISIT(self->pitch_stream);
+ Py_VISIT(self->pos);
+ Py_VISIT(self->pos_stream);
+ Py_VISIT(self->dur);
+ Py_VISIT(self->dur_stream);
+ Py_VISIT(self->dev);
+ Py_VISIT(self->dev_stream);
+ Py_VISIT(self->pan);
+ Py_VISIT(self->pan_stream);
+ return 0;
+}
+
+static int
+MainParticle_clear(MainParticle *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->table);
+ Py_CLEAR(self->env);
+ Py_CLEAR(self->dens);
+ Py_CLEAR(self->dens_stream);
+ Py_CLEAR(self->pitch);
+ Py_CLEAR(self->pitch_stream);
+ Py_CLEAR(self->pos);
+ Py_CLEAR(self->pos_stream);
+ Py_CLEAR(self->dur);
+ Py_CLEAR(self->dur_stream);
+ Py_CLEAR(self->dev);
+ Py_CLEAR(self->dev_stream);
+ Py_CLEAR(self->pan);
+ Py_CLEAR(self->pan_stream);
+ return 0;
+}
+
+static void
+MainParticle_dealloc(MainParticle* self)
+{
+ pyo_DEALLOC
+ free(self->gpos);
+ free(self->glen);
+ free(self->inc);
+ free(self->flags);
+ free(self->k1);
+ free(self->k2);
+ free(self->phase);
+ free(self->amp1);
+ free(self->amp2);
+ free(self->buffer_streams);
+ MainParticle_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+MYFLT *
+MainParticle_getSamplesBuffer(MainParticle *self)
+{
+ return (MYFLT *)self->buffer_streams;
+}
+
+static PyObject *
+MainParticle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *tabletmp, *envtmp, *denstmp=NULL, *pitchtmp=NULL, *postmp=NULL, *durtmp=NULL, *devtmp=NULL, *pantmp=NULL;
+ MainParticle *self;
+ self = (MainParticle *)type->tp_alloc(type, 0);
+
+ self->dens = PyFloat_FromDouble(50);
+ self->pitch = PyFloat_FromDouble(1);
+ self->pos = PyFloat_FromDouble(0.0);
+ self->dur = PyFloat_FromDouble(0.1);
+ self->dev = PyFloat_FromDouble(0);
+ self->pan = PyFloat_FromDouble(0.5);
+ self->timer = self->devFactor = 1.0;
+ self->srScale = 1.0;
+ self->num = 0;
+ self->chnls = 1;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+ self->modebuffer[2] = 0;
+ self->modebuffer[3] = 0;
+ self->modebuffer[4] = 0;
+ self->modebuffer[5] = 0;
+
+ INIT_OBJECT_COMMON
+
+ self->oneOnSr = 1.0 / self->sr;
+ self->srOnRandMax = self->sr / (MYFLT)RAND_MAX;
+
+ Stream_setFunctionPtr(self->stream, MainParticle_compute_next_data_frame);
+ self->mode_func_ptr = MainParticle_setProcMode;
+
+ static char *kwlist[] = {"table", "env", "dens", "pitch", "pos", "dur", "dev", "pan", "chnls", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OOOOOOi", kwlist, &tabletmp, &envtmp, &denstmp, &pitchtmp, &postmp, &durtmp, &devtmp, &pantmp, &self->chnls))
+ Py_RETURN_NONE;
+
+ if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of MainParticle must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
+ }
+ Py_XDECREF(self->table);
+ self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
+ self->srScale = TableStream_getSamplingRate(self->table) / self->sr;
+
+ if ( PyObject_HasAttrString((PyObject *)envtmp, "getTableStream") == 0 ) {
+ PyErr_SetString(PyExc_TypeError, "\"env\" argument of MainParticle must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
+ }
+ Py_XDECREF(self->env);
+ self->env = PyObject_CallMethod((PyObject *)envtmp, "getTableStream", "");
+
+ if (denstmp) {
+ PyObject_CallMethod((PyObject *)self, "setDens", "O", denstmp);
+ }
+
+ if (pitchtmp) {
+ PyObject_CallMethod((PyObject *)self, "setPitch", "O", pitchtmp);
+ }
+
+ if (postmp) {
+ PyObject_CallMethod((PyObject *)self, "setPos", "O", postmp);
+ }
+
+ if (durtmp) {
+ PyObject_CallMethod((PyObject *)self, "setDur", "O", durtmp);
+ }
+
+ if (devtmp) {
+ PyObject_CallMethod((PyObject *)self, "setDev", "O", devtmp);
+ }
+
+ if (pantmp) {
+ PyObject_CallMethod((PyObject *)self, "setPan", "O", pantmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ if (self->chnls < 1)
+ self->chnls = 1;
+
+ self->gpos = (MYFLT *)realloc(self->gpos, MAINPARTICLE_MAX_GRAINS * sizeof(MYFLT));
+ self->glen = (MYFLT *)realloc(self->glen, MAINPARTICLE_MAX_GRAINS * sizeof(MYFLT));
+ self->inc = (MYFLT *)realloc(self->inc, MAINPARTICLE_MAX_GRAINS * sizeof(MYFLT));
+ self->phase = (MYFLT *)realloc(self->phase, MAINPARTICLE_MAX_GRAINS * sizeof(MYFLT));
+ self->amp1 = (MYFLT *)realloc(self->amp1, MAINPARTICLE_MAX_GRAINS * sizeof(MYFLT));
+ self->amp2 = (MYFLT *)realloc(self->amp2, MAINPARTICLE_MAX_GRAINS * sizeof(MYFLT));
+ self->flags = (int *)realloc(self->flags, MAINPARTICLE_MAX_GRAINS * sizeof(int));
+ self->k1 = (int *)realloc(self->k1, MAINPARTICLE_MAX_GRAINS * sizeof(int));
+ self->k2 = (int *)realloc(self->k2, MAINPARTICLE_MAX_GRAINS * sizeof(int));
+
+ for (i=0; i<MAINPARTICLE_MAX_GRAINS; i++) {
+ self->gpos[i] = self->glen[i] = self->inc[i] = self->phase[i] = self->amp1[i] = self->amp2[i] = 0.0;
+ self->flags[i] = self->k1[i] = self->k2[i] = 0;
+ }
+
+ self->buffer_streams = (MYFLT *)realloc(self->buffer_streams, self->bufsize * self->chnls * sizeof(MYFLT));
+ for (i=0; i<self->bufsize*self->chnls; i++) {
+ self->buffer_streams[i] = 0.0;
+ }
+
+ Server_generateSeed((Server *)self->server, MAINPARTICLE_ID);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * MainParticle_getServer(MainParticle* self) { GET_SERVER };
+static PyObject * MainParticle_getStream(MainParticle* self) { GET_STREAM };
+
+static PyObject * MainParticle_play(MainParticle *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * MainParticle_stop(MainParticle *self) { STOP };
+
+static PyObject *
+MainParticle_setDens(MainParticle *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->dens);
+ if (isNumber == 1) {
+ self->dens = PyNumber_Float(tmp);
+ self->modebuffer[0] = 0;
+ }
+ else {
+ self->dens = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->dens, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->dens_stream);
+ self->dens_stream = (Stream *)streamtmp;
+ self->modebuffer[0] = 1;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+MainParticle_setPitch(MainParticle *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->pitch);
+ if (isNumber == 1) {
+ self->pitch = PyNumber_Float(tmp);
+ self->modebuffer[1] = 0;
+ }
+ else {
+ self->pitch = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->pitch, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->pitch_stream);
+ self->pitch_stream = (Stream *)streamtmp;
+ self->modebuffer[1] = 1;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+MainParticle_setPos(MainParticle *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->pos);
+ if (isNumber == 1) {
+ self->pos = PyNumber_Float(tmp);
+ self->modebuffer[2] = 0;
+ }
+ else {
+ self->pos = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->pos, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->pos_stream);
+ self->pos_stream = (Stream *)streamtmp;
+ self->modebuffer[2] = 1;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+MainParticle_setDur(MainParticle *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->dur);
+ if (isNumber == 1) {
+ self->dur = PyNumber_Float(tmp);
+ self->modebuffer[3] = 0;
+ }
+ else {
+ self->dur = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->dur, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->dur_stream);
+ self->dur_stream = (Stream *)streamtmp;
+ self->modebuffer[3] = 1;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+MainParticle_setDev(MainParticle *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->dev);
+ if (isNumber == 1) {
+ self->dev = PyNumber_Float(tmp);
+ self->modebuffer[4] = 0;
+ }
+ else {
+ self->dev = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->dev, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->dev_stream);
+ self->dev_stream = (Stream *)streamtmp;
+ self->modebuffer[4] = 1;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+MainParticle_setPan(MainParticle *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->pan);
+ if (isNumber == 1) {
+ self->pan = PyNumber_Float(tmp);
+ self->modebuffer[5] = 0;
+ }
+ else {
+ self->pan = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->pan, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->pan_stream);
+ self->pan_stream = (Stream *)streamtmp;
+ self->modebuffer[5] = 1;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+MainParticle_getTable(MainParticle* self)
+{
+ Py_INCREF(self->table);
+ return self->table;
+};
+
+static PyObject *
+MainParticle_setTable(MainParticle *self, PyObject *arg)
+{
+ PyObject *tmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ tmp = arg;
+ Py_DECREF(self->table);
+ self->table = PyObject_CallMethod((PyObject *)tmp, "getTableStream", "");
+ self->srScale = TableStream_getSamplingRate(self->table) / self->sr;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+MainParticle_getEnv(MainParticle* self)
+{
+ Py_INCREF(self->env);
+ return self->env;
+};
+
+static PyObject *
+MainParticle_setEnv(MainParticle *self, PyObject *arg)
+{
+ PyObject *tmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ tmp = arg;
+ Py_DECREF(self->env);
+ self->env = PyObject_CallMethod((PyObject *)tmp, "getTableStream", "");
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMemberDef MainParticle_members[] = {
+ {"server", T_OBJECT_EX, offsetof(MainParticle, server), 0, "Pyo server."},
+ {"stream", T_OBJECT_EX, offsetof(MainParticle, stream), 0, "Stream object."},
+ {"table", T_OBJECT_EX, offsetof(MainParticle, table), 0, "Sound table."},
+ {"env", T_OBJECT_EX, offsetof(MainParticle, env), 0, "Envelope table."},
+ {"dens", T_OBJECT_EX, offsetof(MainParticle, dens), 0, "Density of grains per second."},
+ {"pitch", T_OBJECT_EX, offsetof(MainParticle, pitch), 0, "Speed of the reading pointer."},
+ {"pos", T_OBJECT_EX, offsetof(MainParticle, pos), 0, "Position in the sound table."},
+ {"dur", T_OBJECT_EX, offsetof(MainParticle, dur), 0, "Duration of each grains."},
+ {"dev", T_OBJECT_EX, offsetof(MainParticle, dev), 0, "Grain start point deviation factor."},
+ {"pan", T_OBJECT_EX, offsetof(MainParticle, pan), 0, "Grain panning factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef MainParticle_methods[] = {
+ {"getTable", (PyCFunction)MainParticle_getTable, METH_NOARGS, "Returns sound table object."},
+ {"setTable", (PyCFunction)MainParticle_setTable, METH_O, "Sets sound table."},
+ {"getEnv", (PyCFunction)MainParticle_getEnv, METH_NOARGS, "Returns envelope table object."},
+ {"setEnv", (PyCFunction)MainParticle_setEnv, METH_O, "Sets envelope table."},
+ {"getServer", (PyCFunction)MainParticle_getServer, METH_NOARGS, "Returns server object."},
+ {"_getStream", (PyCFunction)MainParticle_getStream, METH_NOARGS, "Returns stream object."},
+ {"play", (PyCFunction)MainParticle_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+ {"stop", (PyCFunction)MainParticle_stop, METH_NOARGS, "Stops computing."},
+ {"setDens", (PyCFunction)MainParticle_setDens, METH_O, "Sets the density of grains per second."},
+ {"setPitch", (PyCFunction)MainParticle_setPitch, METH_O, "Sets global pitch factor."},
+ {"setPos", (PyCFunction)MainParticle_setPos, METH_O, "Sets position in the sound table."},
+ {"setDur", (PyCFunction)MainParticle_setDur, METH_O, "Sets the grain duration."},
+ {"setDev", (PyCFunction)MainParticle_setDev, METH_O, "Sets grain start point deviation factor."},
+ {"setPan", (PyCFunction)MainParticle_setPan, METH_O, "Sets grain panning factor."},
+ {NULL} /* Sentinel */
+};
+
+PyTypeObject MainParticleType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_pitch*/
+ "_pyo.MainParticle_base", /*tp_name*/
+ sizeof(MainParticle), /*tp_basicpitch*/
+ 0, /*tp_itempitch*/
+ (destructor)MainParticle_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "MainParticle objects. Accumulation of multiples grains of sound.", /* tp_doc */
+ (traverseproc)MainParticle_traverse, /* tp_traverse */
+ (inquiry)MainParticle_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ MainParticle_methods, /* tp_methods */
+ MainParticle_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ MainParticle_new, /* tp_new */
+};
+
+typedef struct {
+ pyo_audio_HEAD
+ MainParticle *mainSplitter;
+ int modebuffer[2];
+ int chnl; // panning order
+} Particle;
+
+static void Particle_postprocessing_ii(Particle *self) { POST_PROCESSING_II };
+static void Particle_postprocessing_ai(Particle *self) { POST_PROCESSING_AI };
+static void Particle_postprocessing_ia(Particle *self) { POST_PROCESSING_IA };
+static void Particle_postprocessing_aa(Particle *self) { POST_PROCESSING_AA };
+static void Particle_postprocessing_ireva(Particle *self) { POST_PROCESSING_IREVA };
+static void Particle_postprocessing_areva(Particle *self) { POST_PROCESSING_AREVA };
+static void Particle_postprocessing_revai(Particle *self) { POST_PROCESSING_REVAI };
+static void Particle_postprocessing_revaa(Particle *self) { POST_PROCESSING_REVAA };
+static void Particle_postprocessing_revareva(Particle *self) { POST_PROCESSING_REVAREVA };
+
+static void
+Particle_setProcMode(Particle *self)
+{
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = Particle_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = Particle_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = Particle_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = Particle_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = Particle_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = Particle_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = Particle_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = Particle_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = Particle_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+Particle_compute_next_data_frame(Particle *self)
+{
+ int i;
+ MYFLT *tmp;
+ int offset = self->chnl * self->bufsize;
+ tmp = MainParticle_getSamplesBuffer((MainParticle *)self->mainSplitter);
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = tmp[i + offset];
+ }
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+Particle_traverse(Particle *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->mainSplitter);
+ return 0;
+}
+
+static int
+Particle_clear(Particle *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->mainSplitter);
+ return 0;
+}
+
+static void
+Particle_dealloc(Particle* self)
+{
+ pyo_DEALLOC
+ Particle_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+Particle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *maintmp=NULL, *multmp=NULL, *addtmp=NULL;
+ Particle *self;
+ self = (Particle *)type->tp_alloc(type, 0);
+
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, Particle_compute_next_data_frame);
+ self->mode_func_ptr = Particle_setProcMode;
+
+ static char *kwlist[] = {"mainSplitter", "chnl", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi|OO", kwlist, &maintmp, &self->chnl, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ Py_XDECREF(self->mainSplitter);
+ Py_INCREF(maintmp);
+ self->mainSplitter = (MainParticle *)maintmp;
+
+ if (multmp) {
+ PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+ }
+
+ if (addtmp) {
+ PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * Particle_getServer(Particle* self) { GET_SERVER };
+static PyObject * Particle_getStream(Particle* self) { GET_STREAM };
+static PyObject * Particle_setMul(Particle *self, PyObject *arg) { SET_MUL };
+static PyObject * Particle_setAdd(Particle *self, PyObject *arg) { SET_ADD };
+static PyObject * Particle_setSub(Particle *self, PyObject *arg) { SET_SUB };
+static PyObject * Particle_setDiv(Particle *self, PyObject *arg) { SET_DIV };
+
+static PyObject * Particle_play(Particle *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * Particle_out(Particle *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * Particle_stop(Particle *self) { STOP };
+
+static PyObject * Particle_multiply(Particle *self, PyObject *arg) { MULTIPLY };
+static PyObject * Particle_inplace_multiply(Particle *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * Particle_add(Particle *self, PyObject *arg) { ADD };
+static PyObject * Particle_inplace_add(Particle *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * Particle_sub(Particle *self, PyObject *arg) { SUB };
+static PyObject * Particle_inplace_sub(Particle *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * Particle_div(Particle *self, PyObject *arg) { DIV };
+static PyObject * Particle_inplace_div(Particle *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef Particle_members[] = {
+{"server", T_OBJECT_EX, offsetof(Particle, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(Particle, stream), 0, "Stream object."},
+{"mul", T_OBJECT_EX, offsetof(Particle, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(Particle, add), 0, "Add factor."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef Particle_methods[] = {
+{"getServer", (PyCFunction)Particle_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)Particle_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)Particle_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"out", (PyCFunction)Particle_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"stop", (PyCFunction)Particle_stop, METH_NOARGS, "Stops computing."},
+{"setMul", (PyCFunction)Particle_setMul, METH_O, "Sets Particle mul factor."},
+{"setAdd", (PyCFunction)Particle_setAdd, METH_O, "Sets Particle add factor."},
+{"setSub", (PyCFunction)Particle_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)Particle_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL} /* Sentinel */
+};
+
+static PyNumberMethods Particle_as_number = {
+(binaryfunc)Particle_add, /*nb_add*/
+(binaryfunc)Particle_sub, /*nb_subtract*/
+(binaryfunc)Particle_multiply, /*nb_multiply*/
+(binaryfunc)Particle_div, /*nb_divide*/
+0, /*nb_remainder*/
+0, /*nb_divmod*/
+0, /*nb_power*/
+0, /*nb_neg*/
+0, /*nb_pos*/
+0, /*(unaryfunc)array_abs,*/
+0, /*nb_nonzero*/
+0, /*nb_invert*/
+0, /*nb_lshift*/
+0, /*nb_rshift*/
+0, /*nb_and*/
+0, /*nb_xor*/
+0, /*nb_or*/
+0, /*nb_coerce*/
+0, /*nb_int*/
+0, /*nb_long*/
+0, /*nb_float*/
+0, /*nb_oct*/
+0, /*nb_hex*/
+(binaryfunc)Particle_inplace_add, /*inplace_add*/
+(binaryfunc)Particle_inplace_sub, /*inplace_subtract*/
+(binaryfunc)Particle_inplace_multiply, /*inplace_multiply*/
+(binaryfunc)Particle_inplace_div, /*inplace_divide*/
+0, /*inplace_remainder*/
+0, /*inplace_power*/
+0, /*inplace_lshift*/
+0, /*inplace_rshift*/
+0, /*inplace_and*/
+0, /*inplace_xor*/
+0, /*inplace_or*/
+0, /*nb_floor_divide*/
+0, /*nb_true_divide*/
+0, /*nb_inplace_floor_divide*/
+0, /*nb_inplace_true_divide*/
+0, /* nb_index */
+};
+
+PyTypeObject ParticleType = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.Particle_base", /*tp_name*/
+sizeof(Particle), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)Particle_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+&Particle_as_number, /*tp_as_number*/
+0, /*tp_as_sequence*/
+0, /*tp_as_mapping*/
+0, /*tp_hash */
+0, /*tp_call*/
+0, /*tp_str*/
+0, /*tp_getattro*/
+0, /*tp_setattro*/
+0, /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"Particle objects. Reads one band from a MainParticle object.", /* tp_doc */
+(traverseproc)Particle_traverse, /* tp_traverse */
+(inquiry)Particle_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+Particle_methods, /* tp_methods */
+Particle_members, /* tp_members */
+0, /* tp_getset */
+0, /* tp_base */
+0, /* tp_dict */
+0, /* tp_descr_get */
+0, /* tp_descr_set */
+0, /* tp_dictoffset */
+0, /* tp_init */
+0, /* tp_alloc */
+Particle_new, /* tp_new */
+};
diff --git a/src/objects/matrixmodule.c b/src/objects/matrixmodule.c
index dc1a8d6..9178518 100644
--- a/src/objects/matrixmodule.c
+++ b/src/objects/matrixmodule.c
@@ -595,6 +595,7 @@ MatrixRec_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
INIT_INPUT_STREAM
Py_XDECREF(self->matrix);
+ Py_INCREF(matrixtmp);
self->matrix = (NewMatrix *)matrixtmp;
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
@@ -801,6 +802,7 @@ MatrixRecLoop_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
INIT_INPUT_STREAM
Py_XDECREF(self->matrix);
+ Py_INCREF(matrixtmp);
self->matrix = (NewMatrix *)matrixtmp;
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
@@ -1013,6 +1015,7 @@ MatrixMorph_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
INIT_INPUT_STREAM
Py_XDECREF(self->matrix);
+ Py_INCREF(matrixtmp);
self->matrix = (PyObject *)matrixtmp;
width = NewMatrix_getWidth((NewMatrix *)self->matrix);
@@ -1021,6 +1024,7 @@ MatrixMorph_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->buffer = (MYFLT *)realloc(self->buffer, (numsamps) * sizeof(MYFLT));
Py_XDECREF(self->sources);
+ Py_INCREF(sourcestmp);
self->sources = (PyObject *)sourcestmp;
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
diff --git a/src/objects/matrixprocessmodule.c b/src/objects/matrixprocessmodule.c
index 19a5018..ef30191 100644
--- a/src/objects/matrixprocessmodule.c
+++ b/src/objects/matrixprocessmodule.c
@@ -159,6 +159,10 @@ MatrixPointer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OOO|OO", kwlist, &matrixtmp, &xtmp, &ytmp, &multmp, &addtmp))
Py_RETURN_NONE;
+ if ( PyObject_HasAttrString((PyObject *)matrixtmp, "getMatrixStream") == 0 ) {
+ PyErr_SetString(PyExc_TypeError, "\"matrix\" argument of MatrixPointer must be a PyoMatrixObject.\n");
+ Py_RETURN_NONE;
+ }
Py_XDECREF(self->matrix);
self->matrix = PyObject_CallMethod((PyObject *)matrixtmp, "getMatrixStream", "");
@@ -221,6 +225,11 @@ MatrixPointer_setMatrix(MatrixPointer *self, PyObject *arg)
}
tmp = arg;
+ if ( PyObject_HasAttrString((PyObject *)tmp, "getMatrixStream") == 0 ) {
+ PyErr_SetString(PyExc_TypeError, "\"matrix\" argument of MatrixPointer must be a PyoMatrixObject.\n");
+ Py_RETURN_NONE;
+ }
+
Py_DECREF(self->matrix);
self->matrix = PyObject_CallMethod((PyObject *)tmp, "getMatrixStream", "");
@@ -238,16 +247,13 @@ MatrixPointer_setX(MatrixPointer *self, PyObject *arg)
return Py_None;
}
- int isNumber = PyNumber_Check(arg);
- if (isNumber == 1) {
- PySys_WriteStderr("MatrixPointer x attributes must be a PyoObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ tmp = arg;
+
+ if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+ PyErr_SetString(PyExc_TypeError, "\"x\" attribute of MatrixPointer must be a PyoObject.\n");
+ Py_RETURN_NONE;
}
- tmp = arg;
Py_INCREF(tmp);
Py_XDECREF(self->x);
@@ -271,16 +277,13 @@ MatrixPointer_setY(MatrixPointer *self, PyObject *arg)
return Py_None;
}
- int isNumber = PyNumber_Check(arg);
- if (isNumber == 1) {
- PySys_WriteStderr("MatrixPointer y attributes must be a PyoObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ tmp = arg;
+
+ if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+ PyErr_SetString(PyExc_TypeError, "\"y\" attribute of MatrixPointer must be a PyoObject.\n");
+ Py_RETURN_NONE;
}
- tmp = arg;
Py_INCREF(tmp);
Py_XDECREF(self->y);
diff --git a/src/objects/metromodule.c b/src/objects/metromodule.c
index 2279b70..2deeb00 100644
--- a/src/objects/metromodule.c
+++ b/src/objects/metromodule.c
@@ -1987,7 +1987,7 @@ Beater_generate_i(Beater *self) {
self->dur_buffer_streams[i + self->voiceCount * self->bufsize] = self->durations[self->tapCount];
if (self->currentTime >= tm) {
self->currentTime -= tm;
- if (self->tapCount == (self->last_taps-1))
+ if (self->tapCount == (self->last_taps-2))
self->end_buffer_streams[i + self->voiceCount * self->bufsize] = 1.0;
if (self->sequence[self->tapCount] == 1) {
self->currentTap = self->tapCount;
@@ -2057,7 +2057,7 @@ Beater_generate_a(Beater *self) {
self->dur_buffer_streams[i + self->voiceCount * self->bufsize] = self->durations[self->tapCount];
if (self->currentTime >= tm) {
self->currentTime -= tm;
- if (self->tapCount == (self->last_taps-1))
+ if (self->tapCount == (self->last_taps-2))
self->end_buffer_streams[i + self->voiceCount * self->bufsize] = 1.0;
if (self->sequence[self->tapCount] == 1) {
self->currentTap = self->tapCount;
@@ -2301,6 +2301,17 @@ Beater_setTime(Beater *self, PyObject *arg)
}
static PyObject *
+Beater_reset(Beater *self)
+{
+ self->voiceCount = 0;
+ self->tapCount = 0;
+ self->currentTap = 0;
+ self->currentTime = -1.0;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
Beater_setTaps(Beater *self, PyObject *arg)
{
if (PyInt_Check(arg))
@@ -2449,6 +2460,7 @@ static PyMethodDef Beater_methods[] = {
{"recall", (PyCFunction)Beater_recallPreset, METH_O, "Recall a pattern previously stored in a memory slot."},
{"getPresets", (PyCFunction)Beater_getPresets, METH_NOARGS, "Returns the list of stored presets."},
{"setPresets", (PyCFunction)Beater_setPresets, METH_O, "Store a list of presets."},
+ {"reset", (PyCFunction)Beater_reset, METH_NOARGS, "Resets counters to 0."},
{NULL} /* Sentinel */
};
@@ -3743,3 +3755,1582 @@ PyTypeObject BeatEndStreamType = {
0, /* tp_alloc */
BeatEndStream_new, /* tp_new */
};
+
+/****************/
+/**** TrigBurster *****/
+/****************/
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ int modebuffer[1];
+ int poly;
+ int voiceCount;
+ MYFLT time;
+ MYFLT a_time;
+ int count;
+ int a_count;
+ MYFLT expand;
+ MYFLT a_expand;
+ MYFLT ampfade;
+ MYFLT a_ampfade;
+ int flag;
+ double sampleToSec;
+ double currentTime;
+ double targetTime;
+ int currentCount;
+ int *currentTap;
+ MYFLT *currentAmp;
+ MYFLT *currentDur;
+ MYFLT *buffer_streams;
+ MYFLT *tap_buffer_streams;
+ MYFLT *amp_buffer_streams;
+ MYFLT *dur_buffer_streams;
+ MYFLT *end_buffer_streams;
+} TrigBurster;
+
+static void
+TrigBurster_generate_i(TrigBurster *self) {
+ int i, j;
+
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+
+ for (i=0; i<(self->poly*self->bufsize); i++) {
+ self->buffer_streams[i] = self->end_buffer_streams[i] = 0.0;
+ }
+
+ for (i=0; i<self->bufsize; i++) {
+ if (in[i] == 1.0) {
+ self->flag = 1;
+ self->currentCount = 0;
+ self->a_time = self->targetTime = self->currentTime = self->time;
+ self->a_count = self->count;
+ self->a_expand = self->expand;
+ self->a_ampfade = self->ampfade;
+ }
+ if (self->flag == 1) {
+ if (self->currentTime >= self->targetTime) {
+ self->currentTime -= self->targetTime;
+ self->targetTime = self->a_time * MYPOW(self->a_expand, self->currentCount);
+ self->currentTap[self->voiceCount] = self->currentCount;
+ self->currentAmp[self->voiceCount] = MYPOW(self->a_ampfade, self->currentCount);
+ self->currentDur[self->voiceCount] = self->targetTime;
+ self->buffer_streams[i + self->voiceCount * self->bufsize] = 1.0;
+ self->currentCount++;
+ if (self->currentCount == (self->a_count - 1))
+ self->end_buffer_streams[i + self->voiceCount * self->bufsize] = 1.0;
+ if (self->currentCount == self->a_count)
+ self->flag = 0;
+ self->voiceCount++;
+ if (self->voiceCount == self->poly)
+ self->voiceCount = 0;
+ }
+ self->currentTime += self->sampleToSec;
+ }
+ for (j=0; j<self->poly; j++) {
+ self->tap_buffer_streams[i + j * self->bufsize] = (MYFLT)self->currentTap[j];
+ self->amp_buffer_streams[i + j * self->bufsize] = self->currentAmp[j];
+ self->dur_buffer_streams[i + j * self->bufsize] = self->currentDur[j];
+ }
+ }
+}
+
+MYFLT *
+TrigBurster_getSamplesBuffer(TrigBurster *self)
+{
+ return (MYFLT *)self->buffer_streams;
+}
+
+MYFLT *
+TrigBurster_getTapBuffer(TrigBurster *self)
+{
+ return (MYFLT *)self->tap_buffer_streams;
+}
+
+MYFLT *
+TrigBurster_getAmpBuffer(TrigBurster *self)
+{
+ return (MYFLT *)self->amp_buffer_streams;
+}
+
+MYFLT *
+TrigBurster_getDurBuffer(TrigBurster *self)
+{
+ return (MYFLT *)self->dur_buffer_streams;
+}
+
+MYFLT *
+TrigBurster_getEndBuffer(TrigBurster *self)
+{
+ return (MYFLT *)self->end_buffer_streams;
+}
+
+static void
+TrigBurster_setProcMode(TrigBurster *self)
+{
+ self->proc_func_ptr = TrigBurster_generate_i;
+}
+
+static void
+TrigBurster_compute_next_data_frame(TrigBurster *self)
+{
+ (*self->proc_func_ptr)(self);
+}
+
+static int
+TrigBurster_traverse(TrigBurster *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ return 0;
+}
+
+static int
+TrigBurster_clear(TrigBurster *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->input_stream);
+ return 0;
+}
+
+static void
+TrigBurster_dealloc(TrigBurster* self)
+{
+ pyo_DEALLOC
+ free(self->buffer_streams);
+ free(self->tap_buffer_streams);
+ free(self->amp_buffer_streams);
+ free(self->dur_buffer_streams);
+ free(self->end_buffer_streams);
+ free(self->currentTap);
+ free(self->currentAmp);
+ free(self->currentDur);
+ TrigBurster_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrigBurster_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *inputtmp, *input_streamtmp;
+ TrigBurster *self;
+ self = (TrigBurster *)type->tp_alloc(type, 0);
+
+
+ self->poly = 1;
+ self->voiceCount = 0;
+ self->time = self->a_time = 0.25;
+ self->count = self->a_count = 10;
+ self->expand = self->a_expand = 1.0;
+ self->ampfade = self->a_ampfade = 1.0;
+ self->currentCount = 0;
+ self->targetTime = 0.0;
+ self->currentTime = -1.0;
+ self->flag = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, TrigBurster_compute_next_data_frame);
+ self->mode_func_ptr = TrigBurster_setProcMode;
+
+ self->sampleToSec = 1. / self->sr;
+
+ Stream_setStreamActive(self->stream, 1);
+
+ static char *kwlist[] = {"input", "time", "count", "expand", "ampfade", "poly", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_O_FIFFI, kwlist, &inputtmp, &self->time, &self->count, &self->expand, &self->ampfade, &self->poly))
+ Py_RETURN_NONE;
+
+ INIT_INPUT_STREAM
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ self->buffer_streams = (MYFLT *)realloc(self->buffer_streams, self->poly * self->bufsize * sizeof(MYFLT));
+ self->tap_buffer_streams = (MYFLT *)realloc(self->tap_buffer_streams, self->poly * self->bufsize * sizeof(MYFLT));
+ self->amp_buffer_streams = (MYFLT *)realloc(self->amp_buffer_streams, self->poly * self->bufsize * sizeof(MYFLT));
+ self->dur_buffer_streams = (MYFLT *)realloc(self->dur_buffer_streams, self->poly * self->bufsize * sizeof(MYFLT));
+ self->end_buffer_streams = (MYFLT *)realloc(self->end_buffer_streams, self->poly * self->bufsize * sizeof(MYFLT));
+ for (i=0; i<(self->poly*self->bufsize); i++) {
+ self->buffer_streams[i] = self->tap_buffer_streams[i] = self->amp_buffer_streams[i] = self->dur_buffer_streams[i] = self->end_buffer_streams[i] = 0.0;
+ }
+
+ self->currentTap = (int *)realloc(self->currentTap, self->poly * sizeof(int));
+ self->currentAmp = (MYFLT *)realloc(self->currentAmp, self->poly * sizeof(MYFLT));
+ self->currentDur = (MYFLT *)realloc(self->currentDur, self->poly * sizeof(MYFLT));
+ for (i=0; i<(self->poly); i++) {
+ self->currentTap[i] = 0;
+ self->currentAmp[i] = self->currentDur[i] = 0.0;
+ }
+
+ return (PyObject *)self;
+}
+
+static PyObject * TrigBurster_getServer(TrigBurster* self) { GET_SERVER };
+static PyObject * TrigBurster_getStream(TrigBurster* self) { GET_STREAM };
+
+static PyObject * TrigBurster_play(TrigBurster *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrigBurster_stop(TrigBurster *self) { STOP };
+
+static PyObject *
+TrigBurster_setTime(TrigBurster *self, PyObject *arg)
+{
+ if (PyNumber_Check(arg))
+ self->time = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ if (self->time <= 0.01)
+ self->time = 0.01;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+TrigBurster_setCount(TrigBurster *self, PyObject *arg)
+{
+ if (PyInt_Check(arg))
+ self->count = PyInt_AS_LONG(arg);
+ if (self->count < 1)
+ self->count = 1;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+TrigBurster_setExpand(TrigBurster *self, PyObject *arg)
+{
+ if (PyNumber_Check(arg))
+ self->expand = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ if (self->expand <= 0.1)
+ self->expand = 0.1;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+TrigBurster_setAmpfade(TrigBurster *self, PyObject *arg)
+{
+ if (PyNumber_Check(arg))
+ self->ampfade = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ if (self->ampfade <= 0.1)
+ self->ampfade = 0.1;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMemberDef TrigBurster_members[] = {
+ {"server", T_OBJECT_EX, offsetof(TrigBurster, server), 0, "Pyo server."},
+ {"stream", T_OBJECT_EX, offsetof(TrigBurster, stream), 0, "Stream object."},
+ {"input", T_OBJECT_EX, offsetof(TrigBurster, input), 0, "Input sound object."},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef TrigBurster_methods[] = {
+ {"getServer", (PyCFunction)TrigBurster_getServer, METH_NOARGS, "Returns server object."},
+ {"_getStream", (PyCFunction)TrigBurster_getStream, METH_NOARGS, "Returns stream object."},
+ {"play", (PyCFunction)TrigBurster_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+ {"stop", (PyCFunction)TrigBurster_stop, METH_NOARGS, "Stops computing."},
+ {"setTime", (PyCFunction)TrigBurster_setTime, METH_O, "Sets the base time of the serie."},
+ {"setCount", (PyCFunction)TrigBurster_setCount, METH_O, "Sets the number of trigs in the serie."},
+ {"setExpand", (PyCFunction)TrigBurster_setExpand, METH_O, "Sets the time's expansion factor of the serie."},
+ {"setAmpfade", (PyCFunction)TrigBurster_setAmpfade, METH_O, "Sets the amplitude's expansion factor of the serie."},
+ {NULL} /* Sentinel */
+};
+
+PyTypeObject TrigBursterType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_pyo.TrigBurster_base", /*tp_name*/
+ sizeof(TrigBurster), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)TrigBurster_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "TrigBurster objects. Create an algorithmic beat sequence.", /* tp_doc */
+ (traverseproc)TrigBurster_traverse, /* tp_traverse */
+ (inquiry)TrigBurster_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ TrigBurster_methods, /* tp_methods */
+ TrigBurster_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ TrigBurster_new, /* tp_new */
+};
+
+/************************************************************************************************/
+/* TrigBurst streamer object per channel */
+/************************************************************************************************/
+typedef struct {
+ pyo_audio_HEAD
+ TrigBurster *mainPlayer;
+ int chnl;
+ int modebuffer[2];
+} TrigBurst;
+
+static void TrigBurst_postprocessing_ii(TrigBurst *self) { POST_PROCESSING_II };
+static void TrigBurst_postprocessing_ai(TrigBurst *self) { POST_PROCESSING_AI };
+static void TrigBurst_postprocessing_ia(TrigBurst *self) { POST_PROCESSING_IA };
+static void TrigBurst_postprocessing_aa(TrigBurst *self) { POST_PROCESSING_AA };
+static void TrigBurst_postprocessing_ireva(TrigBurst *self) { POST_PROCESSING_IREVA };
+static void TrigBurst_postprocessing_areva(TrigBurst *self) { POST_PROCESSING_AREVA };
+static void TrigBurst_postprocessing_revai(TrigBurst *self) { POST_PROCESSING_REVAI };
+static void TrigBurst_postprocessing_revaa(TrigBurst *self) { POST_PROCESSING_REVAA };
+static void TrigBurst_postprocessing_revareva(TrigBurst *self) { POST_PROCESSING_REVAREVA };
+
+static void
+TrigBurst_setProcMode(TrigBurst *self) {
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = TrigBurst_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = TrigBurst_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = TrigBurst_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = TrigBurst_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = TrigBurst_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = TrigBurst_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = TrigBurst_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = TrigBurst_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = TrigBurst_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+TrigBurst_compute_next_data_frame(TrigBurst *self)
+{
+ int i;
+ MYFLT *tmp;
+ int offset = self->chnl * self->bufsize;
+ tmp = TrigBurster_getSamplesBuffer((TrigBurster *)self->mainPlayer);
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = tmp[i + offset];
+ }
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+TrigBurst_traverse(TrigBurst *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->mainPlayer);
+ return 0;
+}
+
+static int
+TrigBurst_clear(TrigBurst *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->mainPlayer);
+ return 0;
+}
+
+static void
+TrigBurst_dealloc(TrigBurst* self)
+{
+ pyo_DEALLOC
+ TrigBurst_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrigBurst_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *maintmp=NULL;
+ TrigBurst *self;
+ self = (TrigBurst *)type->tp_alloc(type, 0);
+
+ self->chnl = 0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, TrigBurst_compute_next_data_frame);
+ self->mode_func_ptr = TrigBurst_setProcMode;
+
+ static char *kwlist[] = {"mainPlayer", "chnl", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &maintmp, &self->chnl))
+ Py_RETURN_NONE;
+
+ Py_XDECREF(self->mainPlayer);
+ Py_INCREF(maintmp);
+ self->mainPlayer = (TrigBurster *)maintmp;
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * TrigBurst_getServer(TrigBurst* self) { GET_SERVER };
+static PyObject * TrigBurst_getStream(TrigBurst* self) { GET_STREAM };
+static PyObject * TrigBurst_setMul(TrigBurst *self, PyObject *arg) { SET_MUL };
+static PyObject * TrigBurst_setAdd(TrigBurst *self, PyObject *arg) { SET_ADD };
+static PyObject * TrigBurst_setSub(TrigBurst *self, PyObject *arg) { SET_SUB };
+static PyObject * TrigBurst_setDiv(TrigBurst *self, PyObject *arg) { SET_DIV };
+
+static PyObject * TrigBurst_play(TrigBurst *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrigBurst_out(TrigBurst *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * TrigBurst_stop(TrigBurst *self) { STOP };
+
+static PyObject * TrigBurst_multiply(TrigBurst *self, PyObject *arg) { MULTIPLY };
+static PyObject * TrigBurst_inplace_multiply(TrigBurst *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * TrigBurst_add(TrigBurst *self, PyObject *arg) { ADD };
+static PyObject * TrigBurst_inplace_add(TrigBurst *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * TrigBurst_sub(TrigBurst *self, PyObject *arg) { SUB };
+static PyObject * TrigBurst_inplace_sub(TrigBurst *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * TrigBurst_div(TrigBurst *self, PyObject *arg) { DIV };
+static PyObject * TrigBurst_inplace_div(TrigBurst *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef TrigBurst_members[] = {
+ {"server", T_OBJECT_EX, offsetof(TrigBurst, server), 0, "Pyo server."},
+ {"stream", T_OBJECT_EX, offsetof(TrigBurst, stream), 0, "Stream object."},
+ {"mul", T_OBJECT_EX, offsetof(TrigBurst, mul), 0, "Mul factor."},
+ {"add", T_OBJECT_EX, offsetof(TrigBurst, add), 0, "Add factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef TrigBurst_methods[] = {
+ {"getServer", (PyCFunction)TrigBurst_getServer, METH_NOARGS, "Returns server object."},
+ {"_getStream", (PyCFunction)TrigBurst_getStream, METH_NOARGS, "Returns stream object."},
+ {"play", (PyCFunction)TrigBurst_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+ {"out", (PyCFunction)TrigBurst_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+ {"stop", (PyCFunction)TrigBurst_stop, METH_NOARGS, "Stops computing."},
+ {"setMul", (PyCFunction)TrigBurst_setMul, METH_O, "Sets oscillator mul factor."},
+ {"setAdd", (PyCFunction)TrigBurst_setAdd, METH_O, "Sets oscillator add factor."},
+ {"setSub", (PyCFunction)TrigBurst_setSub, METH_O, "Sets inverse add factor."},
+ {"setDiv", (PyCFunction)TrigBurst_setDiv, METH_O, "Sets inverse mul factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyNumberMethods TrigBurst_as_number = {
+ (binaryfunc)TrigBurst_add, /*nb_add*/
+ (binaryfunc)TrigBurst_sub, /*nb_subtract*/
+ (binaryfunc)TrigBurst_multiply, /*nb_multiply*/
+ (binaryfunc)TrigBurst_div, /*nb_divide*/
+ 0, /*nb_remainder*/
+ 0, /*nb_divmod*/
+ 0, /*nb_power*/
+ 0, /*nb_neg*/
+ 0, /*nb_pos*/
+ 0, /*(unaryfunc)array_abs,*/
+ 0, /*nb_nonzero*/
+ 0, /*nb_invert*/
+ 0, /*nb_lshift*/
+ 0, /*nb_rshift*/
+ 0, /*nb_and*/
+ 0, /*nb_xor*/
+ 0, /*nb_or*/
+ 0, /*nb_coerce*/
+ 0, /*nb_int*/
+ 0, /*nb_long*/
+ 0, /*nb_float*/
+ 0, /*nb_oct*/
+ 0, /*nb_hex*/
+ (binaryfunc)TrigBurst_inplace_add, /*inplace_add*/
+ (binaryfunc)TrigBurst_inplace_sub, /*inplace_subtract*/
+ (binaryfunc)TrigBurst_inplace_multiply, /*inplace_multiply*/
+ (binaryfunc)TrigBurst_inplace_div, /*inplace_divide*/
+ 0, /*inplace_remainder*/
+ 0, /*inplace_power*/
+ 0, /*inplace_lshift*/
+ 0, /*inplace_rshift*/
+ 0, /*inplace_and*/
+ 0, /*inplace_xor*/
+ 0, /*inplace_or*/
+ 0, /*nb_floor_divide*/
+ 0, /*nb_true_divide*/
+ 0, /*nb_inplace_floor_divide*/
+ 0, /*nb_inplace_true_divide*/
+ 0, /* nb_index */
+};
+
+PyTypeObject TrigBurstType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_pyo.TrigBurst_base", /*tp_name*/
+ sizeof(TrigBurst), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)TrigBurst_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ &TrigBurst_as_number, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "TrigBurst objects. Reads a channel from a TrigBurster.", /* tp_doc */
+ (traverseproc)TrigBurst_traverse, /* tp_traverse */
+ (inquiry)TrigBurst_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ TrigBurst_methods, /* tp_methods */
+ TrigBurst_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ TrigBurst_new, /* tp_new */
+};
+
+/************************************************************************************************/
+/* TrigBurstTapStream object per channel */
+/************************************************************************************************/
+typedef struct {
+ pyo_audio_HEAD
+ TrigBurster *mainPlayer;
+ int chnl;
+ int modebuffer[2];
+} TrigBurstTapStream;
+
+static void TrigBurstTapStream_postprocessing_ii(TrigBurstTapStream *self) { POST_PROCESSING_II };
+static void TrigBurstTapStream_postprocessing_ai(TrigBurstTapStream *self) { POST_PROCESSING_AI };
+static void TrigBurstTapStream_postprocessing_ia(TrigBurstTapStream *self) { POST_PROCESSING_IA };
+static void TrigBurstTapStream_postprocessing_aa(TrigBurstTapStream *self) { POST_PROCESSING_AA };
+static void TrigBurstTapStream_postprocessing_ireva(TrigBurstTapStream *self) { POST_PROCESSING_IREVA };
+static void TrigBurstTapStream_postprocessing_areva(TrigBurstTapStream *self) { POST_PROCESSING_AREVA };
+static void TrigBurstTapStream_postprocessing_revai(TrigBurstTapStream *self) { POST_PROCESSING_REVAI };
+static void TrigBurstTapStream_postprocessing_revaa(TrigBurstTapStream *self) { POST_PROCESSING_REVAA };
+static void TrigBurstTapStream_postprocessing_revareva(TrigBurstTapStream *self) { POST_PROCESSING_REVAREVA };
+
+static void
+TrigBurstTapStream_setProcMode(TrigBurstTapStream *self) {
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = TrigBurstTapStream_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = TrigBurstTapStream_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = TrigBurstTapStream_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = TrigBurstTapStream_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = TrigBurstTapStream_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = TrigBurstTapStream_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = TrigBurstTapStream_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = TrigBurstTapStream_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = TrigBurstTapStream_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+TrigBurstTapStream_compute_next_data_frame(TrigBurstTapStream *self)
+{
+ int i;
+ MYFLT *tmp;
+ int offset = self->chnl * self->bufsize;
+ tmp = TrigBurster_getTapBuffer((TrigBurster *)self->mainPlayer);
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = tmp[i + offset];
+ }
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+TrigBurstTapStream_traverse(TrigBurstTapStream *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->mainPlayer);
+ return 0;
+}
+
+static int
+TrigBurstTapStream_clear(TrigBurstTapStream *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->mainPlayer);
+ return 0;
+}
+
+static void
+TrigBurstTapStream_dealloc(TrigBurstTapStream* self)
+{
+ pyo_DEALLOC
+ TrigBurstTapStream_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrigBurstTapStream_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *maintmp=NULL;
+ TrigBurstTapStream *self;
+ self = (TrigBurstTapStream *)type->tp_alloc(type, 0);
+
+ self->chnl = 0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, TrigBurstTapStream_compute_next_data_frame);
+ self->mode_func_ptr = TrigBurstTapStream_setProcMode;
+
+ static char *kwlist[] = {"mainPlayer", "chnl", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &maintmp, &self->chnl))
+ Py_RETURN_NONE;
+
+ Py_XDECREF(self->mainPlayer);
+ Py_INCREF(maintmp);
+ self->mainPlayer = (TrigBurster *)maintmp;
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * TrigBurstTapStream_getServer(TrigBurstTapStream* self) { GET_SERVER };
+static PyObject * TrigBurstTapStream_getStream(TrigBurstTapStream* self) { GET_STREAM };
+static PyObject * TrigBurstTapStream_setMul(TrigBurstTapStream *self, PyObject *arg) { SET_MUL };
+static PyObject * TrigBurstTapStream_setAdd(TrigBurstTapStream *self, PyObject *arg) { SET_ADD };
+static PyObject * TrigBurstTapStream_setSub(TrigBurstTapStream *self, PyObject *arg) { SET_SUB };
+static PyObject * TrigBurstTapStream_setDiv(TrigBurstTapStream *self, PyObject *arg) { SET_DIV };
+
+static PyObject * TrigBurstTapStream_play(TrigBurstTapStream *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrigBurstTapStream_out(TrigBurstTapStream *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * TrigBurstTapStream_stop(TrigBurstTapStream *self) { STOP };
+
+static PyObject * TrigBurstTapStream_multiply(TrigBurstTapStream *self, PyObject *arg) { MULTIPLY };
+static PyObject * TrigBurstTapStream_inplace_multiply(TrigBurstTapStream *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * TrigBurstTapStream_add(TrigBurstTapStream *self, PyObject *arg) { ADD };
+static PyObject * TrigBurstTapStream_inplace_add(TrigBurstTapStream *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * TrigBurstTapStream_sub(TrigBurstTapStream *self, PyObject *arg) { SUB };
+static PyObject * TrigBurstTapStream_inplace_sub(TrigBurstTapStream *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * TrigBurstTapStream_div(TrigBurstTapStream *self, PyObject *arg) { DIV };
+static PyObject * TrigBurstTapStream_inplace_div(TrigBurstTapStream *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef TrigBurstTapStream_members[] = {
+ {"server", T_OBJECT_EX, offsetof(TrigBurstTapStream, server), 0, "Pyo server."},
+ {"stream", T_OBJECT_EX, offsetof(TrigBurstTapStream, stream), 0, "Stream object."},
+ {"mul", T_OBJECT_EX, offsetof(TrigBurstTapStream, mul), 0, "Mul factor."},
+ {"add", T_OBJECT_EX, offsetof(TrigBurstTapStream, add), 0, "Add factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef TrigBurstTapStream_methods[] = {
+ {"getServer", (PyCFunction)TrigBurstTapStream_getServer, METH_NOARGS, "Returns server object."},
+ {"_getStream", (PyCFunction)TrigBurstTapStream_getStream, METH_NOARGS, "Returns stream object."},
+ {"play", (PyCFunction)TrigBurstTapStream_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+ {"out", (PyCFunction)TrigBurstTapStream_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+ {"stop", (PyCFunction)TrigBurstTapStream_stop, METH_NOARGS, "Stops computing."},
+ {"setMul", (PyCFunction)TrigBurstTapStream_setMul, METH_O, "Sets oscillator mul factor."},
+ {"setAdd", (PyCFunction)TrigBurstTapStream_setAdd, METH_O, "Sets oscillator add factor."},
+ {"setSub", (PyCFunction)TrigBurstTapStream_setSub, METH_O, "Sets inverse add factor."},
+ {"setDiv", (PyCFunction)TrigBurstTapStream_setDiv, METH_O, "Sets inverse mul factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyNumberMethods TrigBurstTapStream_as_number = {
+ (binaryfunc)TrigBurstTapStream_add, /*nb_add*/
+ (binaryfunc)TrigBurstTapStream_sub, /*nb_subtract*/
+ (binaryfunc)TrigBurstTapStream_multiply, /*nb_multiply*/
+ (binaryfunc)TrigBurstTapStream_div, /*nb_divide*/
+ 0, /*nb_remainder*/
+ 0, /*nb_divmod*/
+ 0, /*nb_power*/
+ 0, /*nb_neg*/
+ 0, /*nb_pos*/
+ 0, /*(unaryfunc)array_abs,*/
+ 0, /*nb_nonzero*/
+ 0, /*nb_invert*/
+ 0, /*nb_lshift*/
+ 0, /*nb_rshift*/
+ 0, /*nb_and*/
+ 0, /*nb_xor*/
+ 0, /*nb_or*/
+ 0, /*nb_coerce*/
+ 0, /*nb_int*/
+ 0, /*nb_long*/
+ 0, /*nb_float*/
+ 0, /*nb_oct*/
+ 0, /*nb_hex*/
+ (binaryfunc)TrigBurstTapStream_inplace_add, /*inplace_add*/
+ (binaryfunc)TrigBurstTapStream_inplace_sub, /*inplace_subtract*/
+ (binaryfunc)TrigBurstTapStream_inplace_multiply, /*inplace_multiply*/
+ (binaryfunc)TrigBurstTapStream_inplace_div, /*inplace_divide*/
+ 0, /*inplace_remainder*/
+ 0, /*inplace_power*/
+ 0, /*inplace_lshift*/
+ 0, /*inplace_rshift*/
+ 0, /*inplace_and*/
+ 0, /*inplace_xor*/
+ 0, /*inplace_or*/
+ 0, /*nb_floor_divide*/
+ 0, /*nb_true_divide*/
+ 0, /*nb_inplace_floor_divide*/
+ 0, /*nb_inplace_true_divide*/
+ 0, /* nb_index */
+};
+
+PyTypeObject TrigBurstTapStreamType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_pyo.TrigBurstTapStream_base", /*tp_name*/
+ sizeof(TrigBurstTapStream), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)TrigBurstTapStream_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ &TrigBurstTapStream_as_number, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "TrigBurstTapStream objects. Reads the current tap from a TrigBurster object.", /* tp_doc */
+ (traverseproc)TrigBurstTapStream_traverse, /* tp_traverse */
+ (inquiry)TrigBurstTapStream_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ TrigBurstTapStream_methods, /* tp_methods */
+ TrigBurstTapStream_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ TrigBurstTapStream_new, /* tp_new */
+};
+
+/************************************************************************************************/
+/* TrigBurstAmpStream object per channel */
+/************************************************************************************************/
+typedef struct {
+ pyo_audio_HEAD
+ TrigBurster *mainPlayer;
+ int chnl;
+ int modebuffer[2];
+} TrigBurstAmpStream;
+
+static void TrigBurstAmpStream_postprocessing_ii(TrigBurstAmpStream *self) { POST_PROCESSING_II };
+static void TrigBurstAmpStream_postprocessing_ai(TrigBurstAmpStream *self) { POST_PROCESSING_AI };
+static void TrigBurstAmpStream_postprocessing_ia(TrigBurstAmpStream *self) { POST_PROCESSING_IA };
+static void TrigBurstAmpStream_postprocessing_aa(TrigBurstAmpStream *self) { POST_PROCESSING_AA };
+static void TrigBurstAmpStream_postprocessing_ireva(TrigBurstAmpStream *self) { POST_PROCESSING_IREVA };
+static void TrigBurstAmpStream_postprocessing_areva(TrigBurstAmpStream *self) { POST_PROCESSING_AREVA };
+static void TrigBurstAmpStream_postprocessing_revai(TrigBurstAmpStream *self) { POST_PROCESSING_REVAI };
+static void TrigBurstAmpStream_postprocessing_revaa(TrigBurstAmpStream *self) { POST_PROCESSING_REVAA };
+static void TrigBurstAmpStream_postprocessing_revareva(TrigBurstAmpStream *self) { POST_PROCESSING_REVAREVA };
+
+static void
+TrigBurstAmpStream_setProcMode(TrigBurstAmpStream *self) {
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+TrigBurstAmpStream_compute_next_data_frame(TrigBurstAmpStream *self)
+{
+ int i;
+ MYFLT *tmp;
+ int offset = self->chnl * self->bufsize;
+ tmp = TrigBurster_getAmpBuffer((TrigBurster *)self->mainPlayer);
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = tmp[i + offset];
+ }
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+TrigBurstAmpStream_traverse(TrigBurstAmpStream *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->mainPlayer);
+ return 0;
+}
+
+static int
+TrigBurstAmpStream_clear(TrigBurstAmpStream *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->mainPlayer);
+ return 0;
+}
+
+static void
+TrigBurstAmpStream_dealloc(TrigBurstAmpStream* self)
+{
+ pyo_DEALLOC
+ TrigBurstAmpStream_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrigBurstAmpStream_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *maintmp=NULL;
+ TrigBurstAmpStream *self;
+ self = (TrigBurstAmpStream *)type->tp_alloc(type, 0);
+
+ self->chnl = 0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, TrigBurstAmpStream_compute_next_data_frame);
+ self->mode_func_ptr = TrigBurstAmpStream_setProcMode;
+
+ static char *kwlist[] = {"mainPlayer", "chnl", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &maintmp, &self->chnl))
+ Py_RETURN_NONE;
+
+ Py_XDECREF(self->mainPlayer);
+ Py_INCREF(maintmp);
+ self->mainPlayer = (TrigBurster *)maintmp;
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * TrigBurstAmpStream_getServer(TrigBurstAmpStream* self) { GET_SERVER };
+static PyObject * TrigBurstAmpStream_getStream(TrigBurstAmpStream* self) { GET_STREAM };
+static PyObject * TrigBurstAmpStream_setMul(TrigBurstAmpStream *self, PyObject *arg) { SET_MUL };
+static PyObject * TrigBurstAmpStream_setAdd(TrigBurstAmpStream *self, PyObject *arg) { SET_ADD };
+static PyObject * TrigBurstAmpStream_setSub(TrigBurstAmpStream *self, PyObject *arg) { SET_SUB };
+static PyObject * TrigBurstAmpStream_setDiv(TrigBurstAmpStream *self, PyObject *arg) { SET_DIV };
+
+static PyObject * TrigBurstAmpStream_play(TrigBurstAmpStream *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrigBurstAmpStream_out(TrigBurstAmpStream *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * TrigBurstAmpStream_stop(TrigBurstAmpStream *self) { STOP };
+
+static PyObject * TrigBurstAmpStream_multiply(TrigBurstAmpStream *self, PyObject *arg) { MULTIPLY };
+static PyObject * TrigBurstAmpStream_inplace_multiply(TrigBurstAmpStream *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * TrigBurstAmpStream_add(TrigBurstAmpStream *self, PyObject *arg) { ADD };
+static PyObject * TrigBurstAmpStream_inplace_add(TrigBurstAmpStream *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * TrigBurstAmpStream_sub(TrigBurstAmpStream *self, PyObject *arg) { SUB };
+static PyObject * TrigBurstAmpStream_inplace_sub(TrigBurstAmpStream *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * TrigBurstAmpStream_div(TrigBurstAmpStream *self, PyObject *arg) { DIV };
+static PyObject * TrigBurstAmpStream_inplace_div(TrigBurstAmpStream *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef TrigBurstAmpStream_members[] = {
+ {"server", T_OBJECT_EX, offsetof(TrigBurstAmpStream, server), 0, "Pyo server."},
+ {"stream", T_OBJECT_EX, offsetof(TrigBurstAmpStream, stream), 0, "Stream object."},
+ {"mul", T_OBJECT_EX, offsetof(TrigBurstAmpStream, mul), 0, "Mul factor."},
+ {"add", T_OBJECT_EX, offsetof(TrigBurstAmpStream, add), 0, "Add factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef TrigBurstAmpStream_methods[] = {
+ {"getServer", (PyCFunction)TrigBurstAmpStream_getServer, METH_NOARGS, "Returns server object."},
+ {"_getStream", (PyCFunction)TrigBurstAmpStream_getStream, METH_NOARGS, "Returns stream object."},
+ {"play", (PyCFunction)TrigBurstAmpStream_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+ {"out", (PyCFunction)TrigBurstAmpStream_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+ {"stop", (PyCFunction)TrigBurstAmpStream_stop, METH_NOARGS, "Stops computing."},
+ {"setMul", (PyCFunction)TrigBurstAmpStream_setMul, METH_O, "Sets oscillator mul factor."},
+ {"setAdd", (PyCFunction)TrigBurstAmpStream_setAdd, METH_O, "Sets oscillator add factor."},
+ {"setSub", (PyCFunction)TrigBurstAmpStream_setSub, METH_O, "Sets inverse add factor."},
+ {"setDiv", (PyCFunction)TrigBurstAmpStream_setDiv, METH_O, "Sets inverse mul factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyNumberMethods TrigBurstAmpStream_as_number = {
+ (binaryfunc)TrigBurstAmpStream_add, /*nb_add*/
+ (binaryfunc)TrigBurstAmpStream_sub, /*nb_subtract*/
+ (binaryfunc)TrigBurstAmpStream_multiply, /*nb_multiply*/
+ (binaryfunc)TrigBurstAmpStream_div, /*nb_divide*/
+ 0, /*nb_remainder*/
+ 0, /*nb_divmod*/
+ 0, /*nb_power*/
+ 0, /*nb_neg*/
+ 0, /*nb_pos*/
+ 0, /*(unaryfunc)array_abs,*/
+ 0, /*nb_nonzero*/
+ 0, /*nb_invert*/
+ 0, /*nb_lshift*/
+ 0, /*nb_rshift*/
+ 0, /*nb_and*/
+ 0, /*nb_xor*/
+ 0, /*nb_or*/
+ 0, /*nb_coerce*/
+ 0, /*nb_int*/
+ 0, /*nb_long*/
+ 0, /*nb_float*/
+ 0, /*nb_oct*/
+ 0, /*nb_hex*/
+ (binaryfunc)TrigBurstAmpStream_inplace_add, /*inplace_add*/
+ (binaryfunc)TrigBurstAmpStream_inplace_sub, /*inplace_subtract*/
+ (binaryfunc)TrigBurstAmpStream_inplace_multiply, /*inplace_multiply*/
+ (binaryfunc)TrigBurstAmpStream_inplace_div, /*inplace_divide*/
+ 0, /*inplace_remainder*/
+ 0, /*inplace_power*/
+ 0, /*inplace_lshift*/
+ 0, /*inplace_rshift*/
+ 0, /*inplace_and*/
+ 0, /*inplace_xor*/
+ 0, /*inplace_or*/
+ 0, /*nb_floor_divide*/
+ 0, /*nb_true_divide*/
+ 0, /*nb_inplace_floor_divide*/
+ 0, /*nb_inplace_true_divide*/
+ 0, /* nb_index */
+};
+
+PyTypeObject TrigBurstAmpStreamType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_pyo.TrigBurstAmpStream_base", /*tp_name*/
+ sizeof(TrigBurstAmpStream), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)TrigBurstAmpStream_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ &TrigBurstAmpStream_as_number, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "TrigBurstAmpStream objects. Reads a amplitude channel from a TrigBurster object.", /* tp_doc */
+ (traverseproc)TrigBurstAmpStream_traverse, /* tp_traverse */
+ (inquiry)TrigBurstAmpStream_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ TrigBurstAmpStream_methods, /* tp_methods */
+ TrigBurstAmpStream_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ TrigBurstAmpStream_new, /* tp_new */
+};
+
+/************************************************************************************************/
+/* TrigBurstDurStream object per channel */
+/************************************************************************************************/
+typedef struct {
+ pyo_audio_HEAD
+ TrigBurster *mainPlayer;
+ int chnl;
+ int modebuffer[2];
+} TrigBurstDurStream;
+
+static void TrigBurstDurStream_postprocessing_ii(TrigBurstDurStream *self) { POST_PROCESSING_II };
+static void TrigBurstDurStream_postprocessing_ai(TrigBurstDurStream *self) { POST_PROCESSING_AI };
+static void TrigBurstDurStream_postprocessing_ia(TrigBurstDurStream *self) { POST_PROCESSING_IA };
+static void TrigBurstDurStream_postprocessing_aa(TrigBurstDurStream *self) { POST_PROCESSING_AA };
+static void TrigBurstDurStream_postprocessing_ireva(TrigBurstDurStream *self) { POST_PROCESSING_IREVA };
+static void TrigBurstDurStream_postprocessing_areva(TrigBurstDurStream *self) { POST_PROCESSING_AREVA };
+static void TrigBurstDurStream_postprocessing_revai(TrigBurstDurStream *self) { POST_PROCESSING_REVAI };
+static void TrigBurstDurStream_postprocessing_revaa(TrigBurstDurStream *self) { POST_PROCESSING_REVAA };
+static void TrigBurstDurStream_postprocessing_revareva(TrigBurstDurStream *self) { POST_PROCESSING_REVAREVA };
+
+static void
+TrigBurstDurStream_setProcMode(TrigBurstDurStream *self) {
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = TrigBurstDurStream_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = TrigBurstDurStream_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = TrigBurstDurStream_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = TrigBurstDurStream_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = TrigBurstDurStream_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = TrigBurstDurStream_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = TrigBurstDurStream_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = TrigBurstDurStream_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = TrigBurstDurStream_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+TrigBurstDurStream_compute_next_data_frame(TrigBurstDurStream *self)
+{
+ int i;
+ MYFLT *tmp;
+ int offset = self->chnl * self->bufsize;
+ tmp = TrigBurster_getDurBuffer((TrigBurster *)self->mainPlayer);
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = tmp[i + offset];
+ }
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+TrigBurstDurStream_traverse(TrigBurstDurStream *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->mainPlayer);
+ return 0;
+}
+
+static int
+TrigBurstDurStream_clear(TrigBurstDurStream *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->mainPlayer);
+ return 0;
+}
+
+static void
+TrigBurstDurStream_dealloc(TrigBurstDurStream* self)
+{
+ pyo_DEALLOC
+ TrigBurstDurStream_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrigBurstDurStream_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *maintmp=NULL;
+ TrigBurstDurStream *self;
+ self = (TrigBurstDurStream *)type->tp_alloc(type, 0);
+
+ self->chnl = 0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, TrigBurstDurStream_compute_next_data_frame);
+ self->mode_func_ptr = TrigBurstDurStream_setProcMode;
+
+ static char *kwlist[] = {"mainPlayer", "chnl", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &maintmp, &self->chnl))
+ Py_RETURN_NONE;
+
+ Py_XDECREF(self->mainPlayer);
+ Py_INCREF(maintmp);
+ self->mainPlayer = (TrigBurster *)maintmp;
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * TrigBurstDurStream_getServer(TrigBurstDurStream* self) { GET_SERVER };
+static PyObject * TrigBurstDurStream_getStream(TrigBurstDurStream* self) { GET_STREAM };
+static PyObject * TrigBurstDurStream_setMul(TrigBurstDurStream *self, PyObject *arg) { SET_MUL };
+static PyObject * TrigBurstDurStream_setAdd(TrigBurstDurStream *self, PyObject *arg) { SET_ADD };
+static PyObject * TrigBurstDurStream_setSub(TrigBurstDurStream *self, PyObject *arg) { SET_SUB };
+static PyObject * TrigBurstDurStream_setDiv(TrigBurstDurStream *self, PyObject *arg) { SET_DIV };
+
+static PyObject * TrigBurstDurStream_play(TrigBurstDurStream *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrigBurstDurStream_out(TrigBurstDurStream *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * TrigBurstDurStream_stop(TrigBurstDurStream *self) { STOP };
+
+static PyObject * TrigBurstDurStream_multiply(TrigBurstDurStream *self, PyObject *arg) { MULTIPLY };
+static PyObject * TrigBurstDurStream_inplace_multiply(TrigBurstDurStream *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * TrigBurstDurStream_add(TrigBurstDurStream *self, PyObject *arg) { ADD };
+static PyObject * TrigBurstDurStream_inplace_add(TrigBurstDurStream *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * TrigBurstDurStream_sub(TrigBurstDurStream *self, PyObject *arg) { SUB };
+static PyObject * TrigBurstDurStream_inplace_sub(TrigBurstDurStream *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * TrigBurstDurStream_div(TrigBurstDurStream *self, PyObject *arg) { DIV };
+static PyObject * TrigBurstDurStream_inplace_div(TrigBurstDurStream *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef TrigBurstDurStream_members[] = {
+ {"server", T_OBJECT_EX, offsetof(TrigBurstDurStream, server), 0, "Pyo server."},
+ {"stream", T_OBJECT_EX, offsetof(TrigBurstDurStream, stream), 0, "Stream object."},
+ {"mul", T_OBJECT_EX, offsetof(TrigBurstDurStream, mul), 0, "Mul factor."},
+ {"add", T_OBJECT_EX, offsetof(TrigBurstDurStream, add), 0, "Add factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef TrigBurstDurStream_methods[] = {
+ {"getServer", (PyCFunction)TrigBurstDurStream_getServer, METH_NOARGS, "Returns server object."},
+ {"_getStream", (PyCFunction)TrigBurstDurStream_getStream, METH_NOARGS, "Returns stream object."},
+ {"play", (PyCFunction)TrigBurstDurStream_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+ {"out", (PyCFunction)TrigBurstDurStream_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+ {"stop", (PyCFunction)TrigBurstDurStream_stop, METH_NOARGS, "Stops computing."},
+ {"setMul", (PyCFunction)TrigBurstDurStream_setMul, METH_O, "Sets oscillator mul factor."},
+ {"setAdd", (PyCFunction)TrigBurstDurStream_setAdd, METH_O, "Sets oscillator add factor."},
+ {"setSub", (PyCFunction)TrigBurstDurStream_setSub, METH_O, "Sets inverse add factor."},
+ {"setDiv", (PyCFunction)TrigBurstDurStream_setDiv, METH_O, "Sets inverse mul factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyNumberMethods TrigBurstDurStream_as_number = {
+ (binaryfunc)TrigBurstDurStream_add, /*nb_add*/
+ (binaryfunc)TrigBurstDurStream_sub, /*nb_subtract*/
+ (binaryfunc)TrigBurstDurStream_multiply, /*nb_multiply*/
+ (binaryfunc)TrigBurstDurStream_div, /*nb_divide*/
+ 0, /*nb_remainder*/
+ 0, /*nb_divmod*/
+ 0, /*nb_power*/
+ 0, /*nb_neg*/
+ 0, /*nb_pos*/
+ 0, /*(unaryfunc)array_abs,*/
+ 0, /*nb_nonzero*/
+ 0, /*nb_invert*/
+ 0, /*nb_lshift*/
+ 0, /*nb_rshift*/
+ 0, /*nb_and*/
+ 0, /*nb_xor*/
+ 0, /*nb_or*/
+ 0, /*nb_coerce*/
+ 0, /*nb_int*/
+ 0, /*nb_long*/
+ 0, /*nb_float*/
+ 0, /*nb_oct*/
+ 0, /*nb_hex*/
+ (binaryfunc)TrigBurstDurStream_inplace_add, /*inplace_add*/
+ (binaryfunc)TrigBurstDurStream_inplace_sub, /*inplace_subtract*/
+ (binaryfunc)TrigBurstDurStream_inplace_multiply, /*inplace_multiply*/
+ (binaryfunc)TrigBurstDurStream_inplace_div, /*inplace_divide*/
+ 0, /*inplace_remainder*/
+ 0, /*inplace_power*/
+ 0, /*inplace_lshift*/
+ 0, /*inplace_rshift*/
+ 0, /*inplace_and*/
+ 0, /*inplace_xor*/
+ 0, /*inplace_or*/
+ 0, /*nb_floor_divide*/
+ 0, /*nb_true_divide*/
+ 0, /*nb_inplace_floor_divide*/
+ 0, /*nb_inplace_true_divide*/
+ 0, /* nb_index */
+};
+
+PyTypeObject TrigBurstDurStreamType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_pyo.TrigBurstDurStream_base", /*tp_name*/
+ sizeof(TrigBurstDurStream), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)TrigBurstDurStream_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ &TrigBurstDurStream_as_number, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "TrigBurstDurStream objects. Reads a duration channel from a TrigBurster object.", /* tp_doc */
+ (traverseproc)TrigBurstDurStream_traverse, /* tp_traverse */
+ (inquiry)TrigBurstDurStream_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ TrigBurstDurStream_methods, /* tp_methods */
+ TrigBurstDurStream_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ TrigBurstDurStream_new, /* tp_new */
+};
+
+/************************************************************************************************/
+/* TrigBurstEndStream object per channel */
+/************************************************************************************************/
+typedef struct {
+ pyo_audio_HEAD
+ TrigBurster *mainPlayer;
+ int chnl;
+ int modebuffer[2];
+} TrigBurstEndStream;
+
+static void TrigBurstEndStream_postprocessing_ii(TrigBurstEndStream *self) { POST_PROCESSING_II };
+static void TrigBurstEndStream_postprocessing_ai(TrigBurstEndStream *self) { POST_PROCESSING_AI };
+static void TrigBurstEndStream_postprocessing_ia(TrigBurstEndStream *self) { POST_PROCESSING_IA };
+static void TrigBurstEndStream_postprocessing_aa(TrigBurstEndStream *self) { POST_PROCESSING_AA };
+static void TrigBurstEndStream_postprocessing_ireva(TrigBurstEndStream *self) { POST_PROCESSING_IREVA };
+static void TrigBurstEndStream_postprocessing_areva(TrigBurstEndStream *self) { POST_PROCESSING_AREVA };
+static void TrigBurstEndStream_postprocessing_revai(TrigBurstEndStream *self) { POST_PROCESSING_REVAI };
+static void TrigBurstEndStream_postprocessing_revaa(TrigBurstEndStream *self) { POST_PROCESSING_REVAA };
+static void TrigBurstEndStream_postprocessing_revareva(TrigBurstEndStream *self) { POST_PROCESSING_REVAREVA };
+
+static void
+TrigBurstEndStream_setProcMode(TrigBurstEndStream *self) {
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = TrigBurstEndStream_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = TrigBurstEndStream_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = TrigBurstEndStream_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = TrigBurstEndStream_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = TrigBurstEndStream_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = TrigBurstEndStream_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = TrigBurstEndStream_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = TrigBurstEndStream_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = TrigBurstEndStream_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+TrigBurstEndStream_compute_next_data_frame(TrigBurstEndStream *self)
+{
+ int i;
+ MYFLT *tmp;
+ int offset = self->chnl * self->bufsize;
+ tmp = TrigBurster_getEndBuffer((TrigBurster *)self->mainPlayer);
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = tmp[i + offset];
+ }
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+TrigBurstEndStream_traverse(TrigBurstEndStream *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->mainPlayer);
+ return 0;
+}
+
+static int
+TrigBurstEndStream_clear(TrigBurstEndStream *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->mainPlayer);
+ return 0;
+}
+
+static void
+TrigBurstEndStream_dealloc(TrigBurstEndStream* self)
+{
+ pyo_DEALLOC
+ TrigBurstEndStream_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrigBurstEndStream_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *maintmp=NULL;
+ TrigBurstEndStream *self;
+ self = (TrigBurstEndStream *)type->tp_alloc(type, 0);
+
+ self->chnl = 0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, TrigBurstEndStream_compute_next_data_frame);
+ self->mode_func_ptr = TrigBurstEndStream_setProcMode;
+
+ static char *kwlist[] = {"mainPlayer", "chnl", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &maintmp, &self->chnl))
+ Py_RETURN_NONE;
+
+ Py_XDECREF(self->mainPlayer);
+ Py_INCREF(maintmp);
+ self->mainPlayer = (TrigBurster *)maintmp;
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * TrigBurstEndStream_getServer(TrigBurstEndStream* self) { GET_SERVER };
+static PyObject * TrigBurstEndStream_getStream(TrigBurstEndStream* self) { GET_STREAM };
+static PyObject * TrigBurstEndStream_setMul(TrigBurstEndStream *self, PyObject *arg) { SET_MUL };
+static PyObject * TrigBurstEndStream_setAdd(TrigBurstEndStream *self, PyObject *arg) { SET_ADD };
+static PyObject * TrigBurstEndStream_setSub(TrigBurstEndStream *self, PyObject *arg) { SET_SUB };
+static PyObject * TrigBurstEndStream_setDiv(TrigBurstEndStream *self, PyObject *arg) { SET_DIV };
+
+static PyObject * TrigBurstEndStream_play(TrigBurstEndStream *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrigBurstEndStream_out(TrigBurstEndStream *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * TrigBurstEndStream_stop(TrigBurstEndStream *self) { STOP };
+
+static PyObject * TrigBurstEndStream_multiply(TrigBurstEndStream *self, PyObject *arg) { MULTIPLY };
+static PyObject * TrigBurstEndStream_inplace_multiply(TrigBurstEndStream *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * TrigBurstEndStream_add(TrigBurstEndStream *self, PyObject *arg) { ADD };
+static PyObject * TrigBurstEndStream_inplace_add(TrigBurstEndStream *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * TrigBurstEndStream_sub(TrigBurstEndStream *self, PyObject *arg) { SUB };
+static PyObject * TrigBurstEndStream_inplace_sub(TrigBurstEndStream *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * TrigBurstEndStream_div(TrigBurstEndStream *self, PyObject *arg) { DIV };
+static PyObject * TrigBurstEndStream_inplace_div(TrigBurstEndStream *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef TrigBurstEndStream_members[] = {
+ {"server", T_OBJECT_EX, offsetof(TrigBurstEndStream, server), 0, "Pyo server."},
+ {"stream", T_OBJECT_EX, offsetof(TrigBurstEndStream, stream), 0, "Stream object."},
+ {"mul", T_OBJECT_EX, offsetof(TrigBurstEndStream, mul), 0, "Mul factor."},
+ {"add", T_OBJECT_EX, offsetof(TrigBurstEndStream, add), 0, "Add factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef TrigBurstEndStream_methods[] = {
+ {"getServer", (PyCFunction)TrigBurstEndStream_getServer, METH_NOARGS, "Returns server object."},
+ {"_getStream", (PyCFunction)TrigBurstEndStream_getStream, METH_NOARGS, "Returns stream object."},
+ {"play", (PyCFunction)TrigBurstEndStream_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+ {"out", (PyCFunction)TrigBurstEndStream_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+ {"stop", (PyCFunction)TrigBurstEndStream_stop, METH_NOARGS, "Stops computing."},
+ {"setMul", (PyCFunction)TrigBurstEndStream_setMul, METH_O, "Sets oscillator mul factor."},
+ {"setAdd", (PyCFunction)TrigBurstEndStream_setAdd, METH_O, "Sets oscillator add factor."},
+ {"setSub", (PyCFunction)TrigBurstEndStream_setSub, METH_O, "Sets inverse add factor."},
+ {"setDiv", (PyCFunction)TrigBurstEndStream_setDiv, METH_O, "Sets inverse mul factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyNumberMethods TrigBurstEndStream_as_number = {
+ (binaryfunc)TrigBurstEndStream_add, /*nb_add*/
+ (binaryfunc)TrigBurstEndStream_sub, /*nb_subtract*/
+ (binaryfunc)TrigBurstEndStream_multiply, /*nb_multiply*/
+ (binaryfunc)TrigBurstEndStream_div, /*nb_divide*/
+ 0, /*nb_remainder*/
+ 0, /*nb_divmod*/
+ 0, /*nb_power*/
+ 0, /*nb_neg*/
+ 0, /*nb_pos*/
+ 0, /*(unaryfunc)array_abs,*/
+ 0, /*nb_nonzero*/
+ 0, /*nb_invert*/
+ 0, /*nb_lshift*/
+ 0, /*nb_rshift*/
+ 0, /*nb_and*/
+ 0, /*nb_xor*/
+ 0, /*nb_or*/
+ 0, /*nb_coerce*/
+ 0, /*nb_int*/
+ 0, /*nb_long*/
+ 0, /*nb_float*/
+ 0, /*nb_oct*/
+ 0, /*nb_hex*/
+ (binaryfunc)TrigBurstEndStream_inplace_add, /*inplace_add*/
+ (binaryfunc)TrigBurstEndStream_inplace_sub, /*inplace_subtract*/
+ (binaryfunc)TrigBurstEndStream_inplace_multiply, /*inplace_multiply*/
+ (binaryfunc)TrigBurstEndStream_inplace_div, /*inplace_divide*/
+ 0, /*inplace_remainder*/
+ 0, /*inplace_power*/
+ 0, /*inplace_lshift*/
+ 0, /*inplace_rshift*/
+ 0, /*inplace_and*/
+ 0, /*inplace_xor*/
+ 0, /*inplace_or*/
+ 0, /*nb_floor_divide*/
+ 0, /*nb_true_divide*/
+ 0, /*nb_inplace_floor_divide*/
+ 0, /*nb_inplace_true_divide*/
+ 0, /* nb_index */
+};
+
+PyTypeObject TrigBurstEndStreamType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_pyo.TrigBurstEndStream_base", /*tp_name*/
+ sizeof(TrigBurstEndStream), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)TrigBurstEndStream_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ &TrigBurstEndStream_as_number, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "TrigBurstEndStream objects. Reads a duration channel from a TrigBurster object.", /* tp_doc */
+ (traverseproc)TrigBurstEndStream_traverse, /* tp_traverse */
+ (inquiry)TrigBurstEndStream_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ TrigBurstEndStream_methods, /* tp_methods */
+ TrigBurstEndStream_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ TrigBurstEndStream_new, /* tp_new */
+};
diff --git a/src/objects/midimodule.c b/src/objects/midimodule.c
index cc35226..f9be648 100644
--- a/src/objects/midimodule.c
+++ b/src/objects/midimodule.c
@@ -126,6 +126,14 @@ static PyObject * CtlScan_getStream(CtlScan* self) { GET_STREAM };
static PyObject * CtlScan_play(CtlScan *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * CtlScan_stop(CtlScan *self) { STOP };
+static PyObject *
+CtlScan_reset(CtlScan *self)
+{
+ self->ctlnumber = -1;
+ Py_INCREF(Py_None);
+ return Py_None;
+};
+
static PyObject *
CtlScan_setFunction(CtlScan *self, PyObject *arg)
{
@@ -168,6 +176,7 @@ static PyMethodDef CtlScan_methods[] = {
{"_getStream", (PyCFunction)CtlScan_getStream, METH_NOARGS, "Returns stream object."},
{"play", (PyCFunction)CtlScan_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
{"stop", (PyCFunction)CtlScan_stop, METH_NOARGS, "Stops computing."},
+ {"reset", (PyCFunction)CtlScan_reset, METH_NOARGS, "Resets the scanned number."},
{"setFunction", (PyCFunction)CtlScan_setFunction, METH_O, "Sets the function to be called."},
{"setToprint", (PyCFunction)CtlScan_setToprint, METH_O, "If True, print values to the console."},
{NULL} /* Sentinel */
@@ -318,6 +327,14 @@ static PyObject * CtlScan2_getStream(CtlScan2* self) { GET_STREAM };
static PyObject * CtlScan2_play(CtlScan2 *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * CtlScan2_stop(CtlScan2 *self) { STOP };
+static PyObject *
+CtlScan2_reset(CtlScan2 *self)
+{
+ self->ctlnumber = self->midichnl = -1;
+ Py_INCREF(Py_None);
+ return Py_None;
+};
+
static PyObject *
CtlScan2_setFunction(CtlScan2 *self, PyObject *arg)
{
@@ -360,6 +377,7 @@ static PyMethodDef CtlScan2_methods[] = {
{"_getStream", (PyCFunction)CtlScan2_getStream, METH_NOARGS, "Returns stream object."},
{"play", (PyCFunction)CtlScan2_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
{"stop", (PyCFunction)CtlScan2_stop, METH_NOARGS, "Stops computing."},
+ {"reset", (PyCFunction)CtlScan2_reset, METH_NOARGS, "Reset scanned numbers."},
{"setFunction", (PyCFunction)CtlScan2_setFunction, METH_O, "Sets the function to be called."},
{"setToprint", (PyCFunction)CtlScan2_setToprint, METH_O, "If True, print values to the console."},
{NULL} /* Sentinel */
@@ -1905,6 +1923,7 @@ typedef struct {
int centralkey;
int channel;
int stealing;
+ MYFLT *trigger_streams;
} MidiNote;
static void
@@ -2000,12 +2019,14 @@ void grabMidiNotes(MidiNote *self, PmEvent *buffer, int count)
self->vcount = voice;
self->notebuf[voice*2] = pitch;
self->notebuf[voice*2+1] = velocity;
+ self->trigger_streams[self->bufsize*(self->vcount*2)] = 1.0;
}
}
else {
self->vcount = (self->vcount + 1) % self->voices;
self->notebuf[self->vcount*2] = pitch;
self->notebuf[self->vcount*2+1] = velocity;
+ self->trigger_streams[self->bufsize*(self->vcount*2)] = 1.0;
}
}
else if (pitchIsIn(self->notebuf, pitch, self->voices) == 1 && kind == 0 && pitch >= self->first && pitch <= self->last) {
@@ -2013,6 +2034,7 @@ void grabMidiNotes(MidiNote *self, PmEvent *buffer, int count)
voice = whichVoice(self->notebuf, pitch, self->voices);
self->notebuf[voice*2] = -1;
self->notebuf[voice*2+1] = 0.;
+ self->trigger_streams[self->bufsize*(voice*2+1)] = 1.0;
}
}
}
@@ -2022,7 +2044,11 @@ static void
MidiNote_compute_next_data_frame(MidiNote *self)
{
PmEvent *tmp;
- int count;
+ int i, count;
+
+ for (i=0; i<self->bufsize*self->voices*2; i++) {
+ self->trigger_streams[i] = 0.0;
+ }
tmp = Server_getMidiEventBuffer((Server *)self->server);
count = Server_getMidiEventCount((Server *)self->server);
@@ -2049,10 +2075,17 @@ MidiNote_dealloc(MidiNote* self)
{
pyo_DEALLOC
free(self->notebuf);
+ free(self->trigger_streams);
MidiNote_clear(self);
self->ob_type->tp_free((PyObject*)self);
}
+static MYFLT *
+MidiNote_get_trigger_buffer(MidiNote *self)
+{
+ return self->trigger_streams;
+}
+
static PyObject *
MidiNote_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
@@ -2081,6 +2114,11 @@ MidiNote_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
self->notebuf = (int *)realloc(self->notebuf, self->voices * 2 * sizeof(int));
+ self->trigger_streams = (MYFLT *)realloc(self->trigger_streams, self->bufsize * self->voices * 2 * sizeof(MYFLT));
+
+ for (i=0; i<self->bufsize*self->voices*2; i++) {
+ self->trigger_streams[i] = 0.0;
+ }
for (i=0; i<self->voices; i++) {
self->notebuf[i*2] = -1;
@@ -2503,6 +2541,262 @@ Notein_members, /* tp_members */
Notein_new, /* tp_new */
};
+/* NoteinTrig trig streamer */
+typedef struct {
+ pyo_audio_HEAD
+ MidiNote *handler;
+ int modebuffer[2];
+ int voice;
+ int mode; /* 0 = noteon, 1 = noteoff */
+} NoteinTrig;
+
+static void NoteinTrig_postprocessing_ii(NoteinTrig *self) { POST_PROCESSING_II };
+static void NoteinTrig_postprocessing_ai(NoteinTrig *self) { POST_PROCESSING_AI };
+static void NoteinTrig_postprocessing_ia(NoteinTrig *self) { POST_PROCESSING_IA };
+static void NoteinTrig_postprocessing_aa(NoteinTrig *self) { POST_PROCESSING_AA };
+static void NoteinTrig_postprocessing_ireva(NoteinTrig *self) { POST_PROCESSING_IREVA };
+static void NoteinTrig_postprocessing_areva(NoteinTrig *self) { POST_PROCESSING_AREVA };
+static void NoteinTrig_postprocessing_revai(NoteinTrig *self) { POST_PROCESSING_REVAI };
+static void NoteinTrig_postprocessing_revaa(NoteinTrig *self) { POST_PROCESSING_REVAA };
+static void NoteinTrig_postprocessing_revareva(NoteinTrig *self) { POST_PROCESSING_REVAREVA };
+
+static void
+NoteinTrig_setProcMode(NoteinTrig *self)
+{
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = NoteinTrig_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = NoteinTrig_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = NoteinTrig_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = NoteinTrig_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = NoteinTrig_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = NoteinTrig_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = NoteinTrig_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = NoteinTrig_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = NoteinTrig_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+NoteinTrig_compute_next_data_frame(NoteinTrig *self)
+{
+ int i;
+ MYFLT *tmp = MidiNote_get_trigger_buffer(self->handler);
+
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = tmp[self->bufsize*(self->voice*2+self->mode)+i];
+ }
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+NoteinTrig_traverse(NoteinTrig *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->handler);
+ return 0;
+}
+
+static int
+NoteinTrig_clear(NoteinTrig *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->handler);
+ return 0;
+}
+
+static void
+NoteinTrig_dealloc(NoteinTrig* self)
+{
+ pyo_DEALLOC
+ NoteinTrig_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+NoteinTrig_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *handlertmp=NULL, *multmp=NULL, *addtmp=NULL;
+ NoteinTrig *self;
+ self = (NoteinTrig *)type->tp_alloc(type, 0);
+
+ self->voice = 0;
+ self->mode = 0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, NoteinTrig_compute_next_data_frame);
+ self->mode_func_ptr = NoteinTrig_setProcMode;
+
+ static char *kwlist[] = {"handler", "voice", "mode", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|iiOO", kwlist, &handlertmp, &self->voice, &self->mode, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ Py_XDECREF(self->handler);
+ Py_INCREF(handlertmp);
+ self->handler = (MidiNote *)handlertmp;
+
+ if (multmp) {
+ PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+ }
+
+ if (addtmp) {
+ PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * NoteinTrig_getServer(NoteinTrig* self) { GET_SERVER };
+static PyObject * NoteinTrig_getStream(NoteinTrig* self) { GET_STREAM };
+static PyObject * NoteinTrig_setMul(NoteinTrig *self, PyObject *arg) { SET_MUL };
+static PyObject * NoteinTrig_setAdd(NoteinTrig *self, PyObject *arg) { SET_ADD };
+static PyObject * NoteinTrig_setSub(NoteinTrig *self, PyObject *arg) { SET_SUB };
+static PyObject * NoteinTrig_setDiv(NoteinTrig *self, PyObject *arg) { SET_DIV };
+
+static PyObject * NoteinTrig_play(NoteinTrig *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * NoteinTrig_stop(NoteinTrig *self) { STOP };
+
+static PyObject * NoteinTrig_multiply(NoteinTrig *self, PyObject *arg) { MULTIPLY };
+static PyObject * NoteinTrig_inplace_multiply(NoteinTrig *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * NoteinTrig_add(NoteinTrig *self, PyObject *arg) { ADD };
+static PyObject * NoteinTrig_inplace_add(NoteinTrig *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * NoteinTrig_sub(NoteinTrig *self, PyObject *arg) { SUB };
+static PyObject * NoteinTrig_inplace_sub(NoteinTrig *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * NoteinTrig_div(NoteinTrig *self, PyObject *arg) { DIV };
+static PyObject * NoteinTrig_inplace_div(NoteinTrig *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef NoteinTrig_members[] = {
+{"server", T_OBJECT_EX, offsetof(NoteinTrig, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(NoteinTrig, stream), 0, "Stream object."},
+{"mul", T_OBJECT_EX, offsetof(NoteinTrig, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(NoteinTrig, add), 0, "Add factor."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef NoteinTrig_methods[] = {
+{"getServer", (PyCFunction)NoteinTrig_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)NoteinTrig_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)NoteinTrig_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)NoteinTrig_stop, METH_NOARGS, "Stops computing."},
+{"setMul", (PyCFunction)NoteinTrig_setMul, METH_O, "Sets NoteinTrig mul factor."},
+{"setAdd", (PyCFunction)NoteinTrig_setAdd, METH_O, "Sets NoteinTrig add factor."},
+{"setSub", (PyCFunction)NoteinTrig_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)NoteinTrig_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL} /* Sentinel */
+};
+
+static PyNumberMethods NoteinTrig_as_number = {
+(binaryfunc)NoteinTrig_add, /*nb_add*/
+(binaryfunc)NoteinTrig_sub, /*nb_subtract*/
+(binaryfunc)NoteinTrig_multiply, /*nb_multiply*/
+(binaryfunc)NoteinTrig_div, /*nb_divide*/
+0, /*nb_remainder*/
+0, /*nb_divmod*/
+0, /*nb_power*/
+0, /*nb_neg*/
+0, /*nb_pos*/
+0, /*(unaryfunc)array_abs,*/
+0, /*nb_nonzero*/
+0, /*nb_invert*/
+0, /*nb_lshift*/
+0, /*nb_rshift*/
+0, /*nb_and*/
+0, /*nb_xor*/
+0, /*nb_or*/
+0, /*nb_coerce*/
+0, /*nb_int*/
+0, /*nb_long*/
+0, /*nb_float*/
+0, /*nb_oct*/
+0, /*nb_hex*/
+(binaryfunc)NoteinTrig_inplace_add, /*inplace_add*/
+(binaryfunc)NoteinTrig_inplace_sub, /*inplace_subtract*/
+(binaryfunc)NoteinTrig_inplace_multiply, /*inplace_multiply*/
+(binaryfunc)NoteinTrig_inplace_div, /*inplace_divide*/
+0, /*inplace_remainder*/
+0, /*inplace_power*/
+0, /*inplace_lshift*/
+0, /*inplace_rshift*/
+0, /*inplace_and*/
+0, /*inplace_xor*/
+0, /*inplace_or*/
+0, /*nb_floor_divide*/
+0, /*nb_true_divide*/
+0, /*nb_inplace_floor_divide*/
+0, /*nb_inplace_true_divide*/
+0, /* nb_index */
+};
+
+PyTypeObject NoteinTrigType = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.NoteinTrig_base", /*tp_name*/
+sizeof(NoteinTrig), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)NoteinTrig_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+&NoteinTrig_as_number, /*tp_as_number*/
+0, /*tp_as_sequence*/
+0, /*tp_as_mapping*/
+0, /*tp_hash */
+0, /*tp_call*/
+0, /*tp_str*/
+0, /*tp_getattro*/
+0, /*tp_setattro*/
+0, /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"NoteinTrig objects. Stream noteon or noteoff trigger from a Notein voice.", /* tp_doc */
+(traverseproc)NoteinTrig_traverse, /* tp_traverse */
+(inquiry)NoteinTrig_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+NoteinTrig_methods, /* tp_methods */
+NoteinTrig_members, /* tp_members */
+0, /* tp_getset */
+0, /* tp_base */
+0, /* tp_dict */
+0, /* tp_descr_get */
+0, /* tp_descr_set */
+0, /* tp_dictoffset */
+0, /* tp_init */
+0, /* tp_alloc */
+NoteinTrig_new, /* tp_new */
+};
+
typedef struct {
pyo_audio_HEAD
PyObject *input;
diff --git a/src/objects/oscbankmodule.c b/src/objects/oscbankmodule.c
index b8b4cd3..9f98380 100644
--- a/src/objects/oscbankmodule.c
+++ b/src/objects/oscbankmodule.c
@@ -452,11 +452,8 @@ OscBank_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of OscBank must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of OscBank must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
diff --git a/src/objects/oscilmodule.c b/src/objects/oscilmodule.c
index 5c7f1e0..722521e 100644
--- a/src/objects/oscilmodule.c
+++ b/src/objects/oscilmodule.c
@@ -1207,11 +1207,8 @@ Osc_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of Osc must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of Osc must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -1742,11 +1739,8 @@ OscLoop_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of OscLoop must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of OscLoop must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -2268,11 +2262,8 @@ OscTrig_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of OscTrig must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of OscTrig must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -3084,13 +3075,12 @@ Pointer_readframes_a(Pointer *self) {
int size = TableStream_getSize(self->table);
MYFLT *pha = Stream_getData((Stream *)self->index_stream);
-
+
for (i=0; i<self->bufsize; i++) {
- ph = Osc_clip(pha[i] * size, size);
-
+ ph = Osc_clip(pha[i] * size, size);
ipart = (int)ph;
fpart = ph - ipart;
- self->data[i] = tablelist[ipart] * (1.0 - fpart) + tablelist[ipart+1] * fpart;
+ self->data[i] = tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * fpart;
}
}
@@ -3199,11 +3189,8 @@ Pointer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of Pointer must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of Pointer must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -3221,7 +3208,7 @@ Pointer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
(*self->mode_func_ptr)(self);
-
+
return (PyObject *)self;
}
@@ -3280,16 +3267,12 @@ Pointer_setIndex(Pointer *self, PyObject *arg)
return Py_None;
}
- int isNumber = PyNumber_Check(arg);
- if (isNumber == 1) {
- PySys_WriteStderr("TypeError: \"index\" attribute of Pointer must be a PyoObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ tmp = arg;
+ if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+ PyErr_SetString(PyExc_TypeError, "\"index\" argument of Pointer must be a PyoObject.\n");
+ Py_RETURN_NONE;
}
- tmp = arg;
Py_INCREF(tmp);
Py_XDECREF(self->index);
@@ -3414,6 +3397,421 @@ Pointer_new, /* tp_new */
};
/**************/
+/* Pointer2 object */
+/**************/
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *table;
+ PyObject *index;
+ Stream *index_stream;
+ int modebuffer[2];
+ int interp; /* 0 = default to 2, 1 = nointerp, 2 = linear, 3 = cos, 4 = cubic */
+ int autosmooth; /* 0 = off, > 0 = on */
+ MYFLT y1;
+ MYFLT y2;
+ MYFLT c;
+ MYFLT lastPh;
+ MYFLT (*interp_func_ptr)(MYFLT *, int, MYFLT, int);
+} Pointer2;
+
+static void
+Pointer2_readframes_a(Pointer2 *self) {
+ MYFLT fpart, phdiff, b, fr;
+ double ph;
+ int i, ipart;
+ MYFLT *tablelist = TableStream_getData(self->table);
+ int size = TableStream_getSize(self->table);
+ double tableSr = TableStream_getSamplingRate(self->table);
+
+ MYFLT *pha = Stream_getData((Stream *)self->index_stream);
+
+ if (!self->autosmooth) {
+ for (i=0; i<self->bufsize; i++) {
+ ph = Osc_clip(pha[i] * size, size);
+ ipart = (int)ph;
+ fpart = ph - ipart;
+ self->y1 = self->y2 = self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
+ }
+ }
+ else {
+ for (i=0; i<self->bufsize; i++) {
+ ph = Osc_clip(pha[i] * size, size);
+ ipart = (int)ph;
+ fpart = ph - ipart;
+ self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
+ phdiff = MYFABS(ph - self->lastPh);
+ self->lastPh = ph;
+ if (phdiff < 1) {
+ fr = phdiff * tableSr * 0.45;
+ b = 2.0 - MYCOS(TWOPI * fr / self->sr);
+ self->c = (b - MYSQRT(b * b - 1.0));
+ self->y1 = self->data[i] + (self->y1 - self->data[i]) * self->c;
+ self->data[i] = self->y2 = self->y1 + (self->y2 - self->y1) * self->c;
+ }
+ else
+ self->y1 = self->y2 = self->data[i];
+ }
+ }
+}
+
+static void Pointer2_postprocessing_ii(Pointer2 *self) { POST_PROCESSING_II };
+static void Pointer2_postprocessing_ai(Pointer2 *self) { POST_PROCESSING_AI };
+static void Pointer2_postprocessing_ia(Pointer2 *self) { POST_PROCESSING_IA };
+static void Pointer2_postprocessing_aa(Pointer2 *self) { POST_PROCESSING_AA };
+static void Pointer2_postprocessing_ireva(Pointer2 *self) { POST_PROCESSING_IREVA };
+static void Pointer2_postprocessing_areva(Pointer2 *self) { POST_PROCESSING_AREVA };
+static void Pointer2_postprocessing_revai(Pointer2 *self) { POST_PROCESSING_REVAI };
+static void Pointer2_postprocessing_revaa(Pointer2 *self) { POST_PROCESSING_REVAA };
+static void Pointer2_postprocessing_revareva(Pointer2 *self) { POST_PROCESSING_REVAREVA };
+
+static void
+Pointer2_setProcMode(Pointer2 *self)
+{
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ self->proc_func_ptr = Pointer2_readframes_a;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = Pointer2_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = Pointer2_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = Pointer2_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = Pointer2_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = Pointer2_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = Pointer2_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = Pointer2_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = Pointer2_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = Pointer2_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+Pointer2_compute_next_data_frame(Pointer2 *self)
+{
+ (*self->proc_func_ptr)(self);
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+Pointer2_traverse(Pointer2 *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->table);
+ Py_VISIT(self->index);
+ Py_VISIT(self->index_stream);
+ return 0;
+}
+
+static int
+Pointer2_clear(Pointer2 *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->table);
+ Py_CLEAR(self->index);
+ Py_CLEAR(self->index_stream);
+ return 0;
+}
+
+static void
+Pointer2_dealloc(Pointer2* self)
+{
+ pyo_DEALLOC
+ Pointer2_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+Pointer2_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *tabletmp, *indextmp, *multmp=NULL, *addtmp=NULL;
+ Pointer2 *self;
+ self = (Pointer2 *)type->tp_alloc(type, 0);
+
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+ self->interp = 4;
+ self->autosmooth = 1;
+ self->y1 = self->y2 = self->c = self->lastPh = 0.0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, Pointer2_compute_next_data_frame);
+ self->mode_func_ptr = Pointer2_setProcMode;
+
+ static char *kwlist[] = {"table", "index", "interp", "autosmooth", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|iiOO", kwlist, &tabletmp, &indextmp, &self->interp, &self->autosmooth, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of Pointer2 must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
+ }
+ Py_XDECREF(self->table);
+ self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
+
+ if (indextmp) {
+ PyObject_CallMethod((PyObject *)self, "setIndex", "O", indextmp);
+ }
+
+ PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+
+ if (addtmp) {
+ PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ SET_INTERP_POINTER
+
+ return (PyObject *)self;
+}
+
+static PyObject * Pointer2_getServer(Pointer2* self) { GET_SERVER };
+static PyObject * Pointer2_getStream(Pointer2* self) { GET_STREAM };
+static PyObject * Pointer2_setMul(Pointer2 *self, PyObject *arg) { SET_MUL };
+static PyObject * Pointer2_setAdd(Pointer2 *self, PyObject *arg) { SET_ADD };
+static PyObject * Pointer2_setSub(Pointer2 *self, PyObject *arg) { SET_SUB };
+static PyObject * Pointer2_setDiv(Pointer2 *self, PyObject *arg) { SET_DIV };
+
+static PyObject * Pointer2_play(Pointer2 *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * Pointer2_out(Pointer2 *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * Pointer2_stop(Pointer2 *self) { STOP };
+
+static PyObject * Pointer2_multiply(Pointer2 *self, PyObject *arg) { MULTIPLY };
+static PyObject * Pointer2_inplace_multiply(Pointer2 *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * Pointer2_add(Pointer2 *self, PyObject *arg) { ADD };
+static PyObject * Pointer2_inplace_add(Pointer2 *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * Pointer2_sub(Pointer2 *self, PyObject *arg) { SUB };
+static PyObject * Pointer2_inplace_sub(Pointer2 *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * Pointer2_div(Pointer2 *self, PyObject *arg) { DIV };
+static PyObject * Pointer2_inplace_div(Pointer2 *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+Pointer2_getTable(Pointer2* self)
+{
+ Py_INCREF(self->table);
+ return self->table;
+};
+
+static PyObject *
+Pointer2_setTable(Pointer2 *self, PyObject *arg)
+{
+ PyObject *tmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ tmp = arg;
+ Py_DECREF(self->table);
+ self->table = PyObject_CallMethod((PyObject *)tmp, "getTableStream", "");
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+Pointer2_setIndex(Pointer2 *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ tmp = arg;
+ if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+ PyErr_SetString(PyExc_TypeError, "\"index\" argument of Pointer2 must be a PyoObject.\n");
+ Py_RETURN_NONE;
+ }
+
+ Py_INCREF(tmp);
+ Py_XDECREF(self->index);
+
+ self->index = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->index, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->index_stream);
+ self->index_stream = (Stream *)streamtmp;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+Pointer2_setInterp(Pointer2 *self, PyObject *arg)
+{
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ if (isNumber == 1) {
+ self->interp = PyInt_AsLong(PyNumber_Int(arg));
+ }
+
+ SET_INTERP_POINTER
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+Pointer2_setAutoSmooth(Pointer2 *self, PyObject *arg)
+{
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ if (isNumber == 1) {
+ self->autosmooth = PyInt_AsLong(PyNumber_Int(arg));
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMemberDef Pointer2_members[] = {
+{"server", T_OBJECT_EX, offsetof(Pointer2, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(Pointer2, stream), 0, "Stream object."},
+{"table", T_OBJECT_EX, offsetof(Pointer2, table), 0, "Waveform table."},
+{"index", T_OBJECT_EX, offsetof(Pointer2, index), 0, "Reader index."},
+{"mul", T_OBJECT_EX, offsetof(Pointer2, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(Pointer2, add), 0, "Add factor."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef Pointer2_methods[] = {
+{"getTable", (PyCFunction)Pointer2_getTable, METH_NOARGS, "Returns waveform table object."},
+{"getServer", (PyCFunction)Pointer2_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)Pointer2_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)Pointer2_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"out", (PyCFunction)Pointer2_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"stop", (PyCFunction)Pointer2_stop, METH_NOARGS, "Stops computing."},
+{"setTable", (PyCFunction)Pointer2_setTable, METH_O, "Sets oscillator table."},
+{"setIndex", (PyCFunction)Pointer2_setIndex, METH_O, "Sets reader index."},
+{"setInterp", (PyCFunction)Pointer2_setInterp, METH_O, "Sets oscillator interpolation mode."},
+{"setAutoSmooth", (PyCFunction)Pointer2_setAutoSmooth, METH_O, "Activates auto smoother filter."},
+{"setMul", (PyCFunction)Pointer2_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)Pointer2_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)Pointer2_setSub, METH_O, "Sets oscillator inverse add factor."},
+{"setDiv", (PyCFunction)Pointer2_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL} /* Sentinel */
+};
+
+static PyNumberMethods Pointer2_as_number = {
+(binaryfunc)Pointer2_add, /*nb_add*/
+(binaryfunc)Pointer2_sub, /*nb_subtract*/
+(binaryfunc)Pointer2_multiply, /*nb_multiply*/
+(binaryfunc)Pointer2_div, /*nb_divide*/
+0, /*nb_remainder*/
+0, /*nb_divmod*/
+0, /*nb_power*/
+0, /*nb_neg*/
+0, /*nb_pos*/
+0, /*(unaryfunc)array_abs,*/
+0, /*nb_nonzero*/
+0, /*nb_invert*/
+0, /*nb_lshift*/
+0, /*nb_rshift*/
+0, /*nb_and*/
+0, /*nb_xor*/
+0, /*nb_or*/
+0, /*nb_coerce*/
+0, /*nb_int*/
+0, /*nb_long*/
+0, /*nb_float*/
+0, /*nb_oct*/
+0, /*nb_hex*/
+(binaryfunc)Pointer2_inplace_add, /*inplace_add*/
+(binaryfunc)Pointer2_inplace_sub, /*inplace_subtract*/
+(binaryfunc)Pointer2_inplace_multiply, /*inplace_multiply*/
+(binaryfunc)Pointer2_inplace_div, /*inplace_divide*/
+0, /*inplace_remainder*/
+0, /*inplace_power*/
+0, /*inplace_lshift*/
+0, /*inplace_rshift*/
+0, /*inplace_and*/
+0, /*inplace_xor*/
+0, /*inplace_or*/
+0, /*nb_floor_divide*/
+0, /*nb_true_divide*/
+0, /*nb_inplace_floor_divide*/
+0, /*nb_inplace_true_divide*/
+0, /* nb_index */
+};
+
+PyTypeObject Pointer2Type = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.Pointer2_base", /*tp_name*/
+sizeof(Pointer2), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)Pointer2_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+&Pointer2_as_number, /*tp_as_number*/
+0, /*tp_as_sequence*/
+0, /*tp_as_mapping*/
+0, /*tp_hash */
+0, /*tp_call*/
+0, /*tp_str*/
+0, /*tp_getattro*/
+0, /*tp_setattro*/
+0, /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"Pointer2 objects. High quality table reader with a pointer index.", /* tp_doc */
+(traverseproc)Pointer2_traverse, /* tp_traverse */
+(inquiry)Pointer2_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+Pointer2_methods, /* tp_methods */
+Pointer2_members, /* tp_members */
+0, /* tp_getset */
+0, /* tp_base */
+0, /* tp_dict */
+0, /* tp_descr_get */
+0, /* tp_descr_set */
+0, /* tp_dictoffset */
+0, /* tp_init */
+0, /* tp_alloc */
+Pointer2_new, /* tp_new */
+};
+
+/**************/
/* TableIndex object */
/**************/
typedef struct {
@@ -3548,11 +3946,8 @@ TableIndex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of TableIndex must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableIndex must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -3629,16 +4024,12 @@ TableIndex_setIndex(TableIndex *self, PyObject *arg)
return Py_None;
}
- int isNumber = PyNumber_Check(arg);
- if (isNumber == 1) {
- PySys_WriteStderr("TypeError: \"index\" attribute of TableIndex must be a PyoObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ tmp = arg;
+ if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+ PyErr_SetString(PyExc_TypeError, "\"index\" argument of TableIndex must be a PyoObject.\n");
+ Py_RETURN_NONE;
}
- tmp = arg;
Py_INCREF(tmp);
Py_XDECREF(self->index);
@@ -3905,11 +4296,8 @@ Lookup_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of Lookup must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of Lookup must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -3986,16 +4374,12 @@ Lookup_setIndex(Lookup *self, PyObject *arg)
return Py_None;
}
- int isNumber = PyNumber_Check(arg);
- if (isNumber == 1) {
- PySys_WriteStderr("TypeError: \"index\" attribute of Lookup must be a PyoObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
- }
-
tmp = arg;
+ if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+ PyErr_SetString(PyExc_TypeError, "\"index\" argument of Lookup must be a PyoObject.\n");
+ Py_RETURN_NONE;
+ }
+
Py_INCREF(tmp);
Py_XDECREF(self->index);
@@ -4634,21 +5018,15 @@ Pulsar_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of Pulsar must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of Pulsar must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
if ( PyObject_HasAttrString((PyObject *)envtmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"env\" argument of Pulsar must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"env\" argument of Pulsar must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->env);
self->env = PyObject_CallMethod((PyObject *)envtmp, "getTableStream", "");
@@ -5216,11 +5594,8 @@ TableRead_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of TableRead must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableRead must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -10976,21 +11351,15 @@ TableScale_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of TableScale must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableScale must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
if ( PyObject_HasAttrString((PyObject *)outtabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"outtable\" argument of TableScale must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"outtable\" argument of TableScale must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->outtable);
self->outtable = PyObject_CallMethod((PyObject *)outtabletmp, "getTableStream", "");
diff --git a/src/objects/oscmodule.c b/src/objects/oscmodule.c
index a8e8f05..65cd201 100644
--- a/src/objects/oscmodule.c
+++ b/src/objects/oscmodule.c
@@ -937,7 +937,7 @@ int OscDataReceive_handler(const char *path, const char *types, lo_arg **argv, i
void *data, void *user_data)
{
OscDataReceive *self = user_data;
- PyObject *tup, *result;
+ PyObject *tup, *result=NULL;
tup = PyTuple_New(argc+1);
int i, ok = 0;
@@ -976,6 +976,8 @@ int OscDataReceive_handler(const char *path, const char *types, lo_arg **argv, i
if (result == NULL)
PyErr_Print();
}
+ Py_XDECREF(tup);
+ Py_XDECREF(result);
return 0;
}
@@ -1054,6 +1056,8 @@ OscDataReceive_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static PyObject * OscDataReceive_getServer(OscDataReceive* self) { GET_SERVER };
static PyObject * OscDataReceive_getStream(OscDataReceive* self) { GET_STREAM };
+static PyObject * OscDataReceive_play(OscDataReceive *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * OscDataReceive_stop(OscDataReceive *self) { STOP };
static PyObject *
OscDataReceive_addAddress(OscDataReceive *self, PyObject *arg) {
@@ -1094,6 +1098,8 @@ static PyMemberDef OscDataReceive_members[] = {
static PyMethodDef OscDataReceive_methods[] = {
{"getServer", (PyCFunction)OscDataReceive_getServer, METH_NOARGS, "Returns server object."},
{"_getStream", (PyCFunction)OscDataReceive_getStream, METH_NOARGS, "Returns stream object."},
+ {"play", (PyCFunction)OscDataReceive_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+ {"stop", (PyCFunction)OscDataReceive_stop, METH_NOARGS, "Stops computing."},
{"addAddress", (PyCFunction)OscDataReceive_addAddress, METH_O, "Add new paths to the object."},
{"delAddress", (PyCFunction)OscDataReceive_delAddress, METH_O, "Remove path from the object."},
{NULL} /* Sentinel */
diff --git a/src/objects/phasevocmodule.c b/src/objects/phasevocmodule.c
index af5d3dc..5ed4bb0 100644
--- a/src/objects/phasevocmodule.c
+++ b/src/objects/phasevocmodule.c
@@ -612,11 +612,8 @@ PVSynth_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVSynth \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVSynth must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -653,9 +650,8 @@ PVSynth_setInput(PVSynth *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVSynth \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVSynth must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -1087,11 +1083,8 @@ PVAddSynth_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVAddSynth \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVAddSynth must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -1137,9 +1130,8 @@ PVAddSynth_setInput(PVAddSynth *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVAddSynth \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVAddSynth must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -1573,11 +1565,8 @@ PVTranspose_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVTranspose \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVTranspose must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -1621,9 +1610,8 @@ PVTranspose_setInput(PVTranspose *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVTranspose \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVTranspose must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -1752,6 +1740,7 @@ typedef struct {
int hopsize;
int overcount;
MYFLT *l_magn;
+ MYFLT *l_freq;
MYFLT **magn;
MYFLT **freq;
int *count;
@@ -1766,8 +1755,9 @@ PVVerb_realloc_memories(PVVerb *self) {
inputLatency = self->size - self->hopsize;
self->overcount = 0;
self->l_magn = (MYFLT *)realloc(self->l_magn, self->hsize * sizeof(MYFLT));
+ self->l_freq = (MYFLT *)realloc(self->l_freq, self->hsize * sizeof(MYFLT));
for (i=0; i<self->hsize; i++)
- self->l_magn[i] = 0.0;
+ self->l_magn[i] = self->l_freq[i] = 0.0;
self->magn = (MYFLT **)realloc(self->magn, self->olaps * sizeof(MYFLT *));
self->freq = (MYFLT **)realloc(self->freq, self->olaps * sizeof(MYFLT *));
for (i=0; i<self->olaps; i++) {
@@ -1788,7 +1778,7 @@ PVVerb_realloc_memories(PVVerb *self) {
static void
PVVerb_process_ii(PVVerb *self) {
int i, k;
- MYFLT revtime, damp, mag, amp;
+ MYFLT revtime, damp, mag, amp, fre;
MYFLT **magn = PVStream_getMagn((PVStream *)self->input_stream);
MYFLT **freq = PVStream_getFreq((PVStream *)self->input_stream);
int *count = PVStream_getCount((PVStream *)self->input_stream);
@@ -1819,11 +1809,15 @@ PVVerb_process_ii(PVVerb *self) {
amp = 1.0;
for (k=0; k<self->hsize; k++) {
mag = magn[self->overcount][k];
- if (mag > self->l_magn[k])
+ fre = freq[self->overcount][k];
+ if (mag > self->l_magn[k]) {
self->magn[self->overcount][k] = self->l_magn[k] = mag;
- else
+ self->freq[self->overcount][k] = self->l_freq[k] = fre;
+ }
+ else {
self->magn[self->overcount][k] = self->l_magn[k] = mag + (self->l_magn[k] - mag) * revtime * amp;
- self->freq[self->overcount][k] = freq[self->overcount][k];
+ self->freq[self->overcount][k] = self->l_freq[k] = fre + (self->l_freq[k] - fre) * revtime * amp;
+ }
amp *= damp;
}
self->overcount++;
@@ -1836,7 +1830,7 @@ PVVerb_process_ii(PVVerb *self) {
static void
PVVerb_process_ai(PVVerb *self) {
int i, k;
- MYFLT revtime, damp, mag, amp;
+ MYFLT revtime, damp, mag, amp, fre;
MYFLT **magn = PVStream_getMagn((PVStream *)self->input_stream);
MYFLT **freq = PVStream_getFreq((PVStream *)self->input_stream);
int *count = PVStream_getCount((PVStream *)self->input_stream);
@@ -1868,11 +1862,15 @@ PVVerb_process_ai(PVVerb *self) {
amp = 1.0;
for (k=0; k<self->hsize; k++) {
mag = magn[self->overcount][k];
- if (mag > self->l_magn[k])
+ fre = freq[self->overcount][k];
+ if (mag > self->l_magn[k]) {
self->magn[self->overcount][k] = self->l_magn[k] = mag;
- else
+ self->freq[self->overcount][k] = self->l_freq[k] = fre;
+ }
+ else {
self->magn[self->overcount][k] = self->l_magn[k] = mag + (self->l_magn[k] - mag) * revtime * amp;
- self->freq[self->overcount][k] = freq[self->overcount][k];
+ self->freq[self->overcount][k] = self->l_freq[k] = fre + (self->l_freq[k] - fre) * revtime * amp;
+ }
amp *= damp;
}
self->overcount++;
@@ -1885,7 +1883,7 @@ PVVerb_process_ai(PVVerb *self) {
static void
PVVerb_process_ia(PVVerb *self) {
int i, k;
- MYFLT revtime, damp, mag, amp;
+ MYFLT revtime, damp, mag, amp, fre;
MYFLT **magn = PVStream_getMagn((PVStream *)self->input_stream);
MYFLT **freq = PVStream_getFreq((PVStream *)self->input_stream);
int *count = PVStream_getCount((PVStream *)self->input_stream);
@@ -1917,11 +1915,15 @@ PVVerb_process_ia(PVVerb *self) {
amp = 1.0;
for (k=0; k<self->hsize; k++) {
mag = magn[self->overcount][k];
- if (mag > self->l_magn[k])
+ fre = freq[self->overcount][k];
+ if (mag > self->l_magn[k]) {
self->magn[self->overcount][k] = self->l_magn[k] = mag;
- else
+ self->freq[self->overcount][k] = self->l_freq[k] = fre;
+ }
+ else {
self->magn[self->overcount][k] = self->l_magn[k] = mag + (self->l_magn[k] - mag) * revtime * amp;
- self->freq[self->overcount][k] = freq[self->overcount][k];
+ self->freq[self->overcount][k] = self->l_freq[k] = fre + (self->l_freq[k] - fre) * revtime * amp;
+ }
amp *= damp;
}
self->overcount++;
@@ -1934,7 +1936,7 @@ PVVerb_process_ia(PVVerb *self) {
static void
PVVerb_process_aa(PVVerb *self) {
int i, k;
- MYFLT revtime, damp, mag, amp;
+ MYFLT revtime, damp, mag, amp, fre;
MYFLT **magn = PVStream_getMagn((PVStream *)self->input_stream);
MYFLT **freq = PVStream_getFreq((PVStream *)self->input_stream);
int *count = PVStream_getCount((PVStream *)self->input_stream);
@@ -1967,11 +1969,15 @@ PVVerb_process_aa(PVVerb *self) {
amp = 1.0;
for (k=0; k<self->hsize; k++) {
mag = magn[self->overcount][k];
- if (mag > self->l_magn[k])
+ fre = freq[self->overcount][k];
+ if (mag > self->l_magn[k]) {
self->magn[self->overcount][k] = self->l_magn[k] = mag;
- else
+ self->freq[self->overcount][k] = self->l_freq[k] = fre;
+ }
+ else {
self->magn[self->overcount][k] = self->l_magn[k] = mag + (self->l_magn[k] - mag) * revtime * amp;
- self->freq[self->overcount][k] = freq[self->overcount][k];
+ self->freq[self->overcount][k] = self->l_freq[k] = fre + (self->l_freq[k] - fre) * revtime * amp;
+ }
amp *= damp;
}
self->overcount++;
@@ -2049,6 +2055,7 @@ PVVerb_dealloc(PVVerb* self)
free(self->magn);
free(self->freq);
free(self->l_magn);
+ free(self->l_freq);
free(self->count);
PVVerb_clear(self);
self->ob_type->tp_free((PyObject*)self);
@@ -2076,11 +2083,8 @@ PVVerb_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVVerb \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVVerb must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -2128,9 +2132,8 @@ PVVerb_setInput(PVVerb *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVVerb \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVVerb must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -2570,11 +2573,8 @@ PVGate_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVGate \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVGate must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -2622,9 +2622,8 @@ PVGate_setInput(PVGate *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVGate \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVGate must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -2970,11 +2969,8 @@ PVCross_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVCross \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVCross must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -2985,11 +2981,8 @@ PVCross_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->input_stream = (PVStream *)input_streamtmp;
if ( PyObject_HasAttrString((PyObject *)input2tmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVCross \"input2\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVCross must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(input2tmp);
Py_XDECREF(self->input2);
@@ -3033,9 +3026,8 @@ PVCross_setInput(PVCross *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVCross \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVCross must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -3057,9 +3049,8 @@ PVCross_setInput2(PVCross *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVCross \"input2\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVCross must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -3318,11 +3309,8 @@ PVMult_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVMult \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVMult must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -3333,11 +3321,8 @@ PVMult_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->input_stream = (PVStream *)input_streamtmp;
if ( PyObject_HasAttrString((PyObject *)input2tmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVMult \"input2\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVMult must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(input2tmp);
Py_XDECREF(self->input2);
@@ -3377,9 +3362,8 @@ PVMult_setInput(PVMult *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVMult \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVMult must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -3401,9 +3385,8 @@ PVMult_setInput2(PVMult *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVMult \"input2\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVMult must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -3689,11 +3672,8 @@ PVMorph_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVMorph \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVMorph must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -3704,11 +3684,8 @@ PVMorph_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->input_stream = (PVStream *)input_streamtmp;
if ( PyObject_HasAttrString((PyObject *)input2tmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVMorph \"input2\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVMorph must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(input2tmp);
Py_XDECREF(self->input2);
@@ -3752,9 +3729,8 @@ PVMorph_setInput(PVMorph *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVMorph \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVMorph must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -3776,9 +3752,8 @@ PVMorph_setInput2(PVMorph *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVMorph \"input2\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVMorph must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -4138,11 +4113,8 @@ PVFilter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVFilter \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVFilter must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -4189,9 +4161,8 @@ PVFilter_setInput(PVFilter *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVFilter \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVFilter must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -4624,11 +4595,8 @@ PVDelay_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVDelay \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVDelay must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -4675,9 +4643,8 @@ PVDelay_setInput(PVDelay *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVDelay \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVDelay must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -5088,11 +5055,8 @@ PVBuffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVBuffer \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVBuffer must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -5144,9 +5108,8 @@ PVBuffer_setInput(PVBuffer *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVBuffer \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVBuffer must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -5171,16 +5134,12 @@ PVBuffer_setIndex(PVBuffer *self, PyObject *arg)
return Py_None;
}
- int isNumber = PyNumber_Check(arg);
- if (isNumber == 1) {
- PySys_WriteStderr("TypeError: \"index\" attribute of PVBuffer must be a PyoObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ tmp = arg;
+ if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+ PyErr_SetString(PyExc_TypeError, "\"index\" argument of PVBuffer must be a PyoObject.\n");
+ Py_RETURN_NONE;
}
- tmp = arg;
Py_INCREF(tmp);
Py_XDECREF(self->index);
@@ -5501,11 +5460,8 @@ PVShift_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVShift \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVShift must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -5549,9 +5505,8 @@ PVShift_setInput(PVShift *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVShift \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVShift must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -5980,11 +5935,8 @@ PVAmpMod_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVAmpMod \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVAmpMod must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -6037,9 +5989,8 @@ PVAmpMod_setInput(PVAmpMod *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVAmpMod \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVAmpMod must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -6589,11 +6540,8 @@ PVFreqMod_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVFreqMod \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVFreqMod must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -6650,9 +6598,8 @@ PVFreqMod_setInput(PVFreqMod *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVFreqMod \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVFreqMod must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -7137,11 +7084,8 @@ PVBufLoops_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVBufLoops \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVBufLoops must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -7196,9 +7140,8 @@ PVBufLoops_setInput(PVBufLoops *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVBufLoops \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVBufLoops must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -7570,11 +7513,8 @@ PVBufTabLoops_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVBufTabLoops \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVBufTabLoops must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -7624,9 +7564,8 @@ PVBufTabLoops_setInput(PVBufTabLoops *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVBufTabLoops \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVBufTabLoops must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -7884,11 +7823,8 @@ PVMix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVMix \"input\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVMix must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
Py_XDECREF(self->input);
@@ -7899,11 +7835,8 @@ PVMix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->input_stream = (PVStream *)input_streamtmp;
if ( PyObject_HasAttrString((PyObject *)input2tmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVMix \"input2\" argument must be a PyoPVObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVMix must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(input2tmp);
Py_XDECREF(self->input2);
@@ -7943,9 +7876,8 @@ PVMix_setInput(PVMix *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVMix \"input\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVMix must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
@@ -7967,9 +7899,8 @@ PVMix_setInput2(PVMix *self, PyObject *arg)
inputtmp = arg;
if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
- PySys_WriteStderr("TypeError: PVMix \"input2\" argument must be a PyoPVObject.\n");
- Py_INCREF(Py_None);
- return Py_None;
+ PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVMix must be a PyoPVObject.\n");
+ Py_RETURN_NONE;
}
Py_INCREF(inputtmp);
diff --git a/src/objects/sigmodule.c b/src/objects/sigmodule.c
index 93e295e..7cd4cf0 100644
--- a/src/objects/sigmodule.c
+++ b/src/objects/sigmodule.c
@@ -333,9 +333,9 @@ typedef struct {
pyo_audio_HEAD
PyObject *value;
Stream *value_stream;
- MYFLT time;
MYFLT lastValue;
MYFLT currentValue;
+ MYFLT time;
long timeStep;
MYFLT stepVal;
long timeCount;
@@ -346,20 +346,19 @@ static void
SigTo_generates_i(SigTo *self) {
int i;
MYFLT value;
-
if (self->modebuffer[2] == 0) {
value = PyFloat_AS_DOUBLE(self->value);
+ if (value != self->lastValue) {
+ self->timeCount = 0;
+ self->timeStep = (long)(self->time * self->sr);
+ self->stepVal = (value - self->currentValue) / self->timeStep;
+ self->lastValue = value;
+ }
if (self->timeStep <= 0) {
for (i=0; i<self->bufsize; i++)
self->data[i] = self->currentValue = self->lastValue = value;
}
- else {
- if (value != self->lastValue) {
- self->timeCount = 0;
- self->stepVal = (value - self->currentValue) / self->timeStep;
- self->lastValue = value;
- }
-
+ else {
for (i=0; i<self->bufsize; i++) {
if (self->timeCount == (self->timeStep - 1)) {
self->currentValue = value;
@@ -386,6 +385,7 @@ SigTo_generates_i(SigTo *self) {
value = vals[i];
if (value != self->lastValue) {
self->timeCount = 0;
+ self->timeStep = (long)(self->time * self->sr);
self->stepVal = (value - self->currentValue) / self->timeStep;
self->lastValue = value;
}
@@ -497,7 +497,6 @@ SigTo_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->value = PyFloat_FromDouble(0.0);
self->time = 0.025;
- self->timeStep = (long)(self->time * self->sr);
self->timeCount = 0;
self->stepVal = 0.0;
self->modebuffer[0] = 0;
@@ -532,6 +531,7 @@ SigTo_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
self->lastValue = self->currentValue = inittmp;
+ self->timeStep = (long)(self->time * self->sr);
(*self->mode_func_ptr)(self);
@@ -590,7 +590,6 @@ SigTo_setTime(SigTo *self, PyObject *arg)
Py_INCREF(tmp);
if (isNumber == 1) {
self->time = PyFloat_AS_DOUBLE(PyNumber_Float(tmp));
- self->timeStep = (long)(self->time * self->sr);
}
Py_INCREF(Py_None);
@@ -992,6 +991,26 @@ VarPort_setTime(VarPort *self, PyObject *arg)
return Py_None;
}
+static PyObject *
+VarPort_setFunction(VarPort *self, PyObject *arg)
+{
+ PyObject *tmp;
+
+ if (! PyCallable_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, "The function attribute must be callable.");
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ tmp = arg;
+ Py_XDECREF(self->callable);
+ Py_INCREF(tmp);
+ self->callable = tmp;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
static PyObject * VarPort_getServer(VarPort* self) { GET_SERVER };
static PyObject * VarPort_getStream(VarPort* self) { GET_STREAM };
static PyObject * VarPort_setMul(VarPort *self, PyObject *arg) { SET_MUL };
@@ -1026,6 +1045,7 @@ static PyMethodDef VarPort_methods[] = {
{"stop", (PyCFunction)VarPort_stop, METH_NOARGS, "Stops computing."},
{"setValue", (PyCFunction)VarPort_setValue, METH_O, "Sets VarPort value."},
{"setTime", (PyCFunction)VarPort_setTime, METH_O, "Sets ramp time in seconds."},
+ {"setFunction", (PyCFunction)VarPort_setFunction, METH_O, "Sets function to be called."},
{"setMul", (PyCFunction)VarPort_setMul, METH_O, "Sets VarPort mul factor."},
{"setAdd", (PyCFunction)VarPort_setAdd, METH_O, "Sets VarPort add factor."},
{"setSub", (PyCFunction)VarPort_setSub, METH_O, "Sets inverse add factor."},
diff --git a/src/objects/tablemodule.c b/src/objects/tablemodule.c
index 0be9ea5..3852057 100644
--- a/src/objects/tablemodule.c
+++ b/src/objects/tablemodule.c
@@ -231,10 +231,17 @@ static PyObject * HarmTable_reset(HarmTable *self) { TABLE_RESET };
static PyObject * HarmTable_normalize(HarmTable *self) { NORMALIZE };
static PyObject * HarmTable_removeDC(HarmTable *self) { REMOVE_DC };
static PyObject * HarmTable_reverse(HarmTable *self) { REVERSE };
+static PyObject * HarmTable_invert(HarmTable *self) { INVERT };
+static PyObject * HarmTable_rectify(HarmTable *self) { RECTIFY };
+static PyObject * HarmTable_bipolarGain(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * HarmTable_lowpass(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * HarmTable_fadein(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * HarmTable_fadeout(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * HarmTable_pow(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * HarmTable_copy(HarmTable *self, PyObject *arg) { COPY };
static PyObject * HarmTable_setTable(HarmTable *self, PyObject *arg) { SET_TABLE };
static PyObject * HarmTable_getTable(HarmTable *self) { GET_TABLE };
-static PyObject * HarmTable_getViewTable(HarmTable *self) { GET_VIEW_TABLE };
+static PyObject * HarmTable_getViewTable(HarmTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * HarmTable_put(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * HarmTable_get(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -302,12 +309,19 @@ static PyMethodDef HarmTable_methods[] = {
{"getServer", (PyCFunction)HarmTable_getServer, METH_NOARGS, "Returns server object."},
{"setTable", (PyCFunction)HarmTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)HarmTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)HarmTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)HarmTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)HarmTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"normalize", (PyCFunction)HarmTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
{"reset", (PyCFunction)HarmTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)HarmTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
-{"reverse", (PyCFunction)HarmTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"reverse", (PyCFunction)HarmTable_reverse, METH_NOARGS, "Reverse the table's data in time."},
+{"invert", (PyCFunction)HarmTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)HarmTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)HarmTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)HarmTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)HarmTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)HarmTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)HarmTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"copy", (PyCFunction)HarmTable_copy, METH_O, "Copy data from table given in argument."},
{"setData", (PyCFunction)HarmTable_setData, METH_O, "Sets the table from samples in a text file."},
{"setSize", (PyCFunction)HarmTable_setSize, METH_O, "Sets the size of the table in samples"},
@@ -505,10 +519,17 @@ static PyObject * ChebyTable_normalize(ChebyTable *self) { NORMALIZE };
static PyObject * ChebyTable_reset(ChebyTable *self) { TABLE_RESET };
static PyObject * ChebyTable_removeDC(ChebyTable *self) { REMOVE_DC };
static PyObject * ChebyTable_reverse(ChebyTable *self) { REVERSE };
+static PyObject * ChebyTable_invert(ChebyTable *self) { INVERT };
+static PyObject * ChebyTable_rectify(ChebyTable *self) { RECTIFY };
+static PyObject * ChebyTable_bipolarGain(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * ChebyTable_lowpass(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * ChebyTable_fadein(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * ChebyTable_fadeout(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * ChebyTable_pow(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * ChebyTable_copy(ChebyTable *self, PyObject *arg) { COPY };
static PyObject * ChebyTable_setTable(ChebyTable *self, PyObject *arg) { SET_TABLE };
static PyObject * ChebyTable_getTable(ChebyTable *self) { GET_TABLE };
-static PyObject * ChebyTable_getViewTable(ChebyTable *self) { GET_VIEW_TABLE };
+static PyObject * ChebyTable_getViewTable(ChebyTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * ChebyTable_put(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * ChebyTable_get(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -650,13 +671,20 @@ static PyMethodDef ChebyTable_methods[] = {
{"copy", (PyCFunction)ChebyTable_copy, METH_O, "Copy data from table given in argument."},
{"setTable", (PyCFunction)ChebyTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)ChebyTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)ChebyTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)ChebyTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)ChebyTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"setData", (PyCFunction)ChebyTable_setData, METH_O, "Sets the table from samples in a text file."},
{"normalize", (PyCFunction)ChebyTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
{"reset", (PyCFunction)ChebyTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)ChebyTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)ChebyTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)ChebyTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)ChebyTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)ChebyTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)ChebyTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)ChebyTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)ChebyTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)ChebyTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"setSize", (PyCFunction)ChebyTable_setSize, METH_O, "Sets the size of the table in samples"},
{"getSize", (PyCFunction)ChebyTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
{"put", (PyCFunction)ChebyTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -787,10 +815,17 @@ static PyObject * HannTable_normalize(HannTable *self) { NORMALIZE };
static PyObject * HannTable_reset(HannTable *self) { TABLE_RESET };
static PyObject * HannTable_removeDC(HannTable *self) { REMOVE_DC };
static PyObject * HannTable_reverse(HannTable *self) { REVERSE };
+static PyObject * HannTable_invert(HannTable *self) { INVERT };
+static PyObject * HannTable_rectify(HannTable *self) { RECTIFY };
+static PyObject * HannTable_bipolarGain(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * HannTable_lowpass(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * HannTable_fadein(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * HannTable_fadeout(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * HannTable_pow(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * HannTable_copy(HannTable *self, PyObject *arg) { COPY };
static PyObject * HannTable_setTable(HannTable *self, PyObject *arg) { SET_TABLE };
static PyObject * HannTable_getTable(HannTable *self) { GET_TABLE };
-static PyObject * HannTable_getViewTable(HannTable *self) { GET_VIEW_TABLE };
+static PyObject * HannTable_getViewTable(HannTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * HannTable_put(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * HannTable_get(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -835,13 +870,20 @@ static PyMethodDef HannTable_methods[] = {
{"copy", (PyCFunction)HannTable_copy, METH_O, "Copy data from table given in argument."},
{"setTable", (PyCFunction)HannTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)HannTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)HannTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)HannTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)HannTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"setData", (PyCFunction)HannTable_setData, METH_O, "Sets the table from samples in a text file."},
{"normalize", (PyCFunction)HannTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
{"reset", (PyCFunction)HannTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)HannTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)HannTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)HannTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)HannTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)HannTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)HannTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)HannTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)HannTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)HannTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"setSize", (PyCFunction)HannTable_setSize, METH_O, "Sets the size of the table in samples"},
{"getSize", (PyCFunction)HannTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
{"put", (PyCFunction)HannTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -991,10 +1033,17 @@ static PyObject * SincTable_normalize(SincTable *self) { NORMALIZE };
static PyObject * SincTable_reset(SincTable *self) { TABLE_RESET };
static PyObject * SincTable_removeDC(SincTable *self) { REMOVE_DC };
static PyObject * SincTable_reverse(SincTable *self) { REVERSE };
+static PyObject * SincTable_invert(SincTable *self) { INVERT };
+static PyObject * SincTable_rectify(SincTable *self) { RECTIFY };
+static PyObject * SincTable_bipolarGain(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * SincTable_lowpass(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * SincTable_fadein(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * SincTable_fadeout(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * SincTable_pow(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * SincTable_copy(SincTable *self, PyObject *arg) { COPY };
static PyObject * SincTable_setTable(SincTable *self, PyObject *arg) { SET_TABLE };
static PyObject * SincTable_getTable(SincTable *self) { GET_TABLE };
-static PyObject * SincTable_getViewTable(SincTable *self) { GET_VIEW_TABLE };
+static PyObject * SincTable_getViewTable(SincTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * SincTable_put(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * SincTable_get(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -1073,13 +1122,20 @@ static PyMethodDef SincTable_methods[] = {
{"copy", (PyCFunction)SincTable_copy, METH_O, "Copy data from table given in argument."},
{"setTable", (PyCFunction)SincTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)SincTable_getTable, METH_NOARGS, "Returns a list of table samples."},
- {"getViewTable", (PyCFunction)SincTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+ {"getViewTable", (PyCFunction)SincTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)SincTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"setData", (PyCFunction)SincTable_setData, METH_O, "Sets the table from samples in a text file."},
{"normalize", (PyCFunction)SincTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
{"reset", (PyCFunction)SincTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)SincTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)SincTable_reverse, METH_NOARGS, "Reverse the table's data."},
+ {"invert", (PyCFunction)SincTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+ {"rectify", (PyCFunction)SincTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+ {"bipolarGain", (PyCFunction)SincTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+ {"lowpass", (PyCFunction)SincTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+ {"fadein", (PyCFunction)SincTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+ {"fadeout", (PyCFunction)SincTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+ {"pow", (PyCFunction)SincTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"setSize", (PyCFunction)SincTable_setSize, METH_O, "Sets the size of the table in samples"},
{"getSize", (PyCFunction)SincTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
{"setFreq", (PyCFunction)SincTable_setFreq, METH_O, "Sets the frequency, in radians, of the sinc function."},
@@ -1203,10 +1259,17 @@ static PyObject * WinTable_normalize(WinTable *self) { NORMALIZE };
static PyObject * WinTable_reset(WinTable *self) { TABLE_RESET };
static PyObject * WinTable_removeDC(WinTable *self) { REMOVE_DC };
static PyObject * WinTable_reverse(WinTable *self) { REVERSE };
+static PyObject * WinTable_invert(WinTable *self) { INVERT };
+static PyObject * WinTable_rectify(WinTable *self) { RECTIFY };
+static PyObject * WinTable_bipolarGain(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * WinTable_lowpass(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * WinTable_fadein(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * WinTable_fadeout(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * WinTable_pow(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * WinTable_copy(WinTable *self, PyObject *arg) { COPY };
static PyObject * WinTable_setTable(WinTable *self, PyObject *arg) { SET_TABLE };
static PyObject * WinTable_getTable(WinTable *self) { GET_TABLE };
-static PyObject * WinTable_getViewTable(WinTable *self) { GET_VIEW_TABLE };
+static PyObject * WinTable_getViewTable(WinTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * WinTable_put(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * WinTable_get(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -1272,13 +1335,20 @@ static PyMethodDef WinTable_methods[] = {
{"copy", (PyCFunction)WinTable_copy, METH_O, "Copy data from table given in argument."},
{"setTable", (PyCFunction)WinTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)WinTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)WinTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)WinTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)WinTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"setData", (PyCFunction)WinTable_setData, METH_O, "Sets the table from samples in a text file."},
{"normalize", (PyCFunction)WinTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
{"reset", (PyCFunction)WinTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)WinTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)WinTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)WinTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)WinTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)WinTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)WinTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)WinTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)WinTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)WinTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"setSize", (PyCFunction)WinTable_setSize, METH_O, "Sets the size of the table in samples"},
{"getSize", (PyCFunction)WinTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
{"setType", (PyCFunction)WinTable_setType, METH_O, "Sets the type of the table."},
@@ -1415,10 +1485,17 @@ static PyObject * ParaTable_normalize(ParaTable *self) { NORMALIZE };
static PyObject * ParaTable_reset(ParaTable *self) { TABLE_RESET };
static PyObject * ParaTable_removeDC(ParaTable *self) { REMOVE_DC };
static PyObject * ParaTable_reverse(ParaTable *self) { REVERSE };
+static PyObject * ParaTable_invert(ParaTable *self) { INVERT };
+static PyObject * ParaTable_rectify(ParaTable *self) { RECTIFY };
+static PyObject * ParaTable_bipolarGain(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * ParaTable_lowpass(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * ParaTable_fadein(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * ParaTable_fadeout(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * ParaTable_pow(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * ParaTable_copy(ParaTable *self, PyObject *arg) { COPY };
static PyObject * ParaTable_setTable(ParaTable *self, PyObject *arg) { SET_TABLE };
static PyObject * ParaTable_getTable(ParaTable *self) { GET_TABLE };
-static PyObject * ParaTable_getViewTable(ParaTable *self) { GET_VIEW_TABLE };
+static PyObject * ParaTable_getViewTable(ParaTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * ParaTable_put(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * ParaTable_get(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -1463,13 +1540,20 @@ static PyMethodDef ParaTable_methods[] = {
{"copy", (PyCFunction)ParaTable_copy, METH_O, "Copy data from table given in argument."},
{"setTable", (PyCFunction)ParaTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)ParaTable_getTable, METH_NOARGS, "Returns a list of table samples."},
- {"getViewTable", (PyCFunction)ParaTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+ {"getViewTable", (PyCFunction)ParaTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)ParaTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"setData", (PyCFunction)ParaTable_setData, METH_O, "Sets the table from samples in a text file."},
{"normalize", (PyCFunction)ParaTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
{"reset", (PyCFunction)ParaTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)ParaTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)ParaTable_reverse, METH_NOARGS, "Reverse the table's data."},
+ {"invert", (PyCFunction)ParaTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+ {"rectify", (PyCFunction)ParaTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+ {"bipolarGain", (PyCFunction)ParaTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+ {"lowpass", (PyCFunction)ParaTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+ {"fadein", (PyCFunction)ParaTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+ {"fadeout", (PyCFunction)ParaTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+ {"pow", (PyCFunction)ParaTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"setSize", (PyCFunction)ParaTable_setSize, METH_O, "Sets the size of the table in samples"},
{"getSize", (PyCFunction)ParaTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
{"put", (PyCFunction)ParaTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -1639,10 +1723,17 @@ static PyObject * LinTable_normalize(LinTable *self) { NORMALIZE };
static PyObject * LinTable_reset(LinTable *self) { TABLE_RESET };
static PyObject * LinTable_removeDC(LinTable *self) { REMOVE_DC };
static PyObject * LinTable_reverse(LinTable *self) { REVERSE };
+static PyObject * LinTable_invert(LinTable *self) { INVERT };
+static PyObject * LinTable_rectify(LinTable *self) { RECTIFY };
+static PyObject * LinTable_bipolarGain(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * LinTable_lowpass(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * LinTable_fadein(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * LinTable_fadeout(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * LinTable_pow(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * LinTable_copy(LinTable *self, PyObject *arg) { COPY };
static PyObject * LinTable_setTable(LinTable *self, PyObject *arg) { SET_TABLE };
static PyObject * LinTable_getTable(LinTable *self) { GET_TABLE };
-static PyObject * LinTable_getViewTable(LinTable *self) { GET_VIEW_TABLE };
+static PyObject * LinTable_getViewTable(LinTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * LinTable_put(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * LinTable_get(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -1741,13 +1832,20 @@ static PyMethodDef LinTable_methods[] = {
{"copy", (PyCFunction)LinTable_copy, METH_O, "Copy data from table given in argument."},
{"setTable", (PyCFunction)LinTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)LinTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)LinTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)LinTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)LinTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"setData", (PyCFunction)LinTable_setData, METH_O, "Sets the table from samples in a text file."},
{"normalize", (PyCFunction)LinTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
{"reset", (PyCFunction)LinTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)LinTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)LinTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)LinTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)LinTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)LinTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)LinTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)LinTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)LinTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)LinTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"setSize", (PyCFunction)LinTable_setSize, METH_O, "Sets the size of the table in samples"},
{"getSize", (PyCFunction)LinTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
{"put", (PyCFunction)LinTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -1943,10 +2041,17 @@ static PyObject * LogTable_normalize(LogTable *self) { NORMALIZE };
static PyObject * LogTable_reset(LogTable *self) { TABLE_RESET };
static PyObject * LogTable_removeDC(LogTable *self) { REMOVE_DC };
static PyObject * LogTable_reverse(LogTable *self) { REVERSE };
+static PyObject * LogTable_invert(LogTable *self) { INVERT };
+static PyObject * LogTable_rectify(LogTable *self) { RECTIFY };
+static PyObject * LogTable_bipolarGain(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * LogTable_lowpass(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * LogTable_fadein(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * LogTable_fadeout(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * LogTable_pow(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * LogTable_copy(LogTable *self, PyObject *arg) { COPY };
static PyObject * LogTable_setTable(LogTable *self, PyObject *arg) { SET_TABLE };
static PyObject * LogTable_getTable(LogTable *self) { GET_TABLE };
-static PyObject * LogTable_getViewTable(LogTable *self) { GET_VIEW_TABLE };
+static PyObject * LogTable_getViewTable(LogTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * LogTable_put(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * LogTable_get(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -2045,13 +2150,20 @@ static PyMethodDef LogTable_methods[] = {
{"copy", (PyCFunction)LogTable_copy, METH_O, "Copy data from table given in argument."},
{"setTable", (PyCFunction)LogTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)LogTable_getTable, METH_NOARGS, "Returns a list of table samples."},
- {"getViewTable", (PyCFunction)LogTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+ {"getViewTable", (PyCFunction)LogTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)LogTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"setData", (PyCFunction)LogTable_setData, METH_O, "Sets the table from samples in a text file."},
{"normalize", (PyCFunction)LogTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
{"reset", (PyCFunction)LogTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)LogTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)LogTable_reverse, METH_NOARGS, "Reverse the table's data."},
+ {"invert", (PyCFunction)LogTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+ {"rectify", (PyCFunction)LogTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+ {"bipolarGain", (PyCFunction)LogTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+ {"lowpass", (PyCFunction)LogTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+ {"fadein", (PyCFunction)LogTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+ {"fadeout", (PyCFunction)LogTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+ {"pow", (PyCFunction)LogTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"setSize", (PyCFunction)LogTable_setSize, METH_O, "Sets the size of the table in samples"},
{"getSize", (PyCFunction)LogTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
{"put", (PyCFunction)LogTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -2225,10 +2337,17 @@ static PyObject * CosTable_normalize(CosTable *self) { NORMALIZE };
static PyObject * CosTable_reset(CosTable *self) { TABLE_RESET };
static PyObject * CosTable_removeDC(CosTable *self) { REMOVE_DC };
static PyObject * CosTable_reverse(CosTable *self) { REVERSE };
+static PyObject * CosTable_invert(CosTable *self) { INVERT };
+static PyObject * CosTable_rectify(CosTable *self) { RECTIFY };
+static PyObject * CosTable_bipolarGain(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * CosTable_lowpass(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * CosTable_fadein(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * CosTable_fadeout(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * CosTable_pow(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * CosTable_copy(CosTable *self, PyObject *arg) { COPY };
static PyObject * CosTable_setTable(CosTable *self, PyObject *arg) { SET_TABLE };
static PyObject * CosTable_getTable(CosTable *self) { GET_TABLE };
-static PyObject * CosTable_getViewTable(CosTable *self) { GET_VIEW_TABLE };
+static PyObject * CosTable_getViewTable(CosTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * CosTable_put(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * CosTable_get(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -2327,13 +2446,20 @@ static PyMethodDef CosTable_methods[] = {
{"copy", (PyCFunction)CosTable_copy, METH_O, "Copy data from table given in argument."},
{"setTable", (PyCFunction)CosTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)CosTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)CosTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)CosTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)CosTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"setData", (PyCFunction)CosTable_setData, METH_O, "Sets the table from samples in a text file."},
{"normalize", (PyCFunction)CosTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
{"reset", (PyCFunction)CosTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)CosTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)CosTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)CosTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)CosTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)CosTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)CosTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)CosTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)CosTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)CosTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"setSize", (PyCFunction)CosTable_setSize, METH_O, "Sets the size of the table in samples"},
{"getSize", (PyCFunction)CosTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
{"put", (PyCFunction)CosTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -2531,10 +2657,17 @@ static PyObject * CosLogTable_normalize(CosLogTable *self) { NORMALIZE };
static PyObject * CosLogTable_reset(CosLogTable *self) { TABLE_RESET };
static PyObject * CosLogTable_removeDC(CosLogTable *self) { REMOVE_DC };
static PyObject * CosLogTable_reverse(CosLogTable *self) { REVERSE };
+static PyObject * CosLogTable_invert(CosLogTable *self) { INVERT };
+static PyObject * CosLogTable_rectify(CosLogTable *self) { RECTIFY };
+static PyObject * CosLogTable_bipolarGain(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * CosLogTable_lowpass(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * CosLogTable_fadein(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * CosLogTable_fadeout(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * CosLogTable_pow(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * CosLogTable_copy(CosLogTable *self, PyObject *arg) { COPY };
static PyObject * CosLogTable_setTable(CosLogTable *self, PyObject *arg) { SET_TABLE };
static PyObject * CosLogTable_getTable(CosLogTable *self) { GET_TABLE };
-static PyObject * CosLogTable_getViewTable(CosLogTable *self) { GET_VIEW_TABLE };
+static PyObject * CosLogTable_getViewTable(CosLogTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * CosLogTable_put(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * CosLogTable_get(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -2633,13 +2766,20 @@ static PyMethodDef CosLogTable_methods[] = {
{"copy", (PyCFunction)CosLogTable_copy, METH_O, "Copy data from table given in argument."},
{"setTable", (PyCFunction)CosLogTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)CosLogTable_getTable, METH_NOARGS, "Returns a list of table samples."},
- {"getViewTable", (PyCFunction)CosLogTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+ {"getViewTable", (PyCFunction)CosLogTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)CosLogTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"setData", (PyCFunction)CosLogTable_setData, METH_O, "Sets the table from samples in a text file."},
{"normalize", (PyCFunction)CosLogTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
{"reset", (PyCFunction)CosLogTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)CosLogTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)CosLogTable_reverse, METH_NOARGS, "Reverse the table's data."},
+ {"invert", (PyCFunction)CosLogTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+ {"rectify", (PyCFunction)CosLogTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+ {"bipolarGain", (PyCFunction)CosLogTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+ {"lowpass", (PyCFunction)CosLogTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+ {"fadein", (PyCFunction)CosLogTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+ {"fadeout", (PyCFunction)CosLogTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+ {"pow", (PyCFunction)CosLogTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"setSize", (PyCFunction)CosLogTable_setSize, METH_O, "Sets the size of the table in samples"},
{"getSize", (PyCFunction)CosLogTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
{"put", (PyCFunction)CosLogTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -2840,10 +2980,17 @@ static PyObject * CurveTable_normalize(CurveTable * self) { NORMALIZE };
static PyObject * CurveTable_reset(CurveTable * self) { TABLE_RESET };
static PyObject * CurveTable_removeDC(CurveTable *self) { REMOVE_DC };
static PyObject * CurveTable_reverse(CurveTable *self) { REVERSE };
+static PyObject * CurveTable_invert(CurveTable *self) { INVERT };
+static PyObject * CurveTable_rectify(CurveTable *self) { RECTIFY };
+static PyObject * CurveTable_bipolarGain(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * CurveTable_lowpass(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * CurveTable_fadein(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * CurveTable_fadeout(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * CurveTable_pow(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * CurveTable_copy(CurveTable *self, PyObject *arg) { COPY };
static PyObject * CurveTable_setTable(CurveTable *self, PyObject *arg) { SET_TABLE };
static PyObject * CurveTable_getTable(CurveTable *self) { GET_TABLE };
-static PyObject * CurveTable_getViewTable(CurveTable *self) { GET_VIEW_TABLE };
+static PyObject * CurveTable_getViewTable(CurveTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * CurveTable_put(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * CurveTable_get(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -2984,7 +3131,7 @@ static PyMethodDef CurveTable_methods[] = {
{"copy", (PyCFunction)CurveTable_copy, METH_O, "Copy data from table given in argument."},
{"setTable", (PyCFunction)CurveTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)CurveTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)CurveTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)CurveTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)CurveTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"setData", (PyCFunction)CurveTable_setData, METH_O, "Sets the table from samples in a text file."},
{"setSize", (PyCFunction)CurveTable_setSize, METH_O, "Sets the size of the table in samples"},
@@ -2999,6 +3146,13 @@ static PyMethodDef CurveTable_methods[] = {
{"reset", (PyCFunction)CurveTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)CurveTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)CurveTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)CurveTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)CurveTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)CurveTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)CurveTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)CurveTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)CurveTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)CurveTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{NULL} /* Sentinel */
};
@@ -3190,10 +3344,17 @@ static PyObject * ExpTable_normalize(ExpTable * self) { NORMALIZE };
static PyObject * ExpTable_reset(ExpTable * self) { TABLE_RESET };
static PyObject * ExpTable_removeDC(ExpTable *self) { REMOVE_DC };
static PyObject * ExpTable_reverse(ExpTable *self) { REVERSE };
+static PyObject * ExpTable_invert(ExpTable *self) { INVERT };
+static PyObject * ExpTable_rectify(ExpTable *self) { RECTIFY };
+static PyObject * ExpTable_bipolarGain(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * ExpTable_lowpass(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * ExpTable_fadein(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * ExpTable_fadeout(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * ExpTable_pow(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * ExpTable_copy(ExpTable *self, PyObject *arg) { COPY };
static PyObject * ExpTable_setTable(ExpTable *self, PyObject *arg) { SET_TABLE };
static PyObject * ExpTable_getTable(ExpTable *self) { GET_TABLE };
-static PyObject * ExpTable_getViewTable(ExpTable *self) { GET_VIEW_TABLE };
+static PyObject * ExpTable_getViewTable(ExpTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * ExpTable_put(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * ExpTable_get(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -3333,7 +3494,7 @@ static PyMethodDef ExpTable_methods[] = {
{"copy", (PyCFunction)ExpTable_copy, METH_O, "Copy data from table given in argument."},
{"setTable", (PyCFunction)ExpTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)ExpTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)ExpTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)ExpTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)ExpTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"setData", (PyCFunction)ExpTable_setData, METH_O, "Sets the table from samples in a text file."},
{"setSize", (PyCFunction)ExpTable_setSize, METH_O, "Sets the size of the table in samples"},
@@ -3348,6 +3509,13 @@ static PyMethodDef ExpTable_methods[] = {
{"reset", (PyCFunction)ExpTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)ExpTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)ExpTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)ExpTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)ExpTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)ExpTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)ExpTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)ExpTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)ExpTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)ExpTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{NULL} /* Sentinel */
};
@@ -3856,6 +4024,13 @@ static PyObject * SndTable_normalize(SndTable *self) { NORMALIZE };
static PyObject * SndTable_reset(SndTable *self) { TABLE_RESET };
static PyObject * SndTable_removeDC(SndTable *self) { REMOVE_DC };
static PyObject * SndTable_reverse(SndTable *self) { REVERSE };
+static PyObject * SndTable_invert(SndTable *self) { INVERT };
+static PyObject * SndTable_rectify(SndTable *self) { RECTIFY };
+static PyObject * SndTable_bipolarGain(SndTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * SndTable_lowpass(SndTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * SndTable_fadein(SndTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * SndTable_fadeout(SndTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * SndTable_pow(SndTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * SndTable_copy(SndTable *self, PyObject *arg) { COPY };
static PyObject * SndTable_setTable(SndTable *self, PyObject *arg) { SET_TABLE };
static PyObject * SndTable_getTable(SndTable *self) { GET_TABLE };
@@ -3864,17 +4039,37 @@ static PyObject * SndTable_get(SndTable *self, PyObject *args, PyObject *kwds) {
static PyObject *
SndTable_getViewTable(SndTable *self, PyObject *args, PyObject *kwds) {
- int i, j, y, w, h, h2, step;
+ int i, j, y, w, h, h2, step, size;
int count = 0;
- MYFLT absin;
- PyObject *samples;
+ int yOffset = 0;
+ MYFLT absin, fstep;
+ MYFLT begin = 0.0;
+ MYFLT end = -1.0;
+ PyObject *samples, *tuple;
PyObject *sizetmp = NULL;
- static char *kwlist[] = {"size", NULL};
+ static char *kwlist[] = {"size", "begin", "end", "yOffset", NULL};
- if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &sizetmp))
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE__OFFI, kwlist, &sizetmp, &begin, &end, &yOffset))
return PyInt_FromLong(-1);
+ if (end <= 0.0)
+ end = self->size;
+ else {
+ end = end * self->sr;
+ if (end > self->size)
+ end = self->size;
+ }
+
+ if (begin < 0.0)
+ begin = 0;
+ else {
+ begin = begin * self->sr;
+ if (begin >= end)
+ begin = 0;
+ }
+ size = (int)(end - begin);
+
if (sizetmp) {
if (PyTuple_Check(sizetmp)) {
w = PyInt_AsLong(PyTuple_GET_ITEM(sizetmp, 0));
@@ -3894,20 +4089,52 @@ SndTable_getViewTable(SndTable *self, PyObject *args, PyObject *kwds) {
h = 200;
}
h2 = h/2;
- step = (int)(self->size / (MYFLT)(w));
-
- samples = PyList_New(w*4);
- for(i=0; i<w; i++) {
- absin = 0.0;
- for (j=0; j<step; j++) {
- if (MYFABS(self->data[count++]) > absin)
- absin = self->data[count];
+ step = (int)(size / (MYFLT)(w));
+ fstep = (MYFLT)(w) / (size-1);
+
+ if (step == 0) {
+ samples = PyList_New(size);
+ for (i=0; i<size; i++) {
+ tuple = PyTuple_New(2);
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong((int)(i*fstep)));
+ PyTuple_SetItem(tuple, 1, PyInt_FromLong(-self->data[i+(int)(begin)]*h2+h2+yOffset));
+ PyList_SetItem(samples, i, tuple);
+ }
+ }
+ else if (step < 32) {
+ samples = PyList_New(w);
+ for(i=0; i<w; i++) {
+ absin = 0.0;
+ for (j=0; j<step; j++) {
+ absin += -self->data[(int)(begin)+count];
+ count++;
+ }
+ y = (int)(absin / step * h2);
+ tuple = PyTuple_New(2);
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong(i));
+ PyTuple_SetItem(tuple, 1, PyInt_FromLong(h2+y+yOffset));
+ PyList_SetItem(samples, i, tuple);
+ }
+ }
+ else {
+ samples = PyList_New(w*2);
+ for(i=0; i<w; i++) {
+ absin = 0.0;
+ for (j=0; j<step; j++) {
+ if (MYFABS(self->data[(int)(begin)+count]) > absin)
+ absin = -self->data[(int)(begin)+count];
+ count++;
+ }
+ y = (int)(absin * h2);
+ tuple = PyTuple_New(2);
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong(i));
+ PyTuple_SetItem(tuple, 1, PyInt_FromLong(h2-y+yOffset));
+ PyList_SetItem(samples, i*2, tuple);
+ tuple = PyTuple_New(2);
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong(i));
+ PyTuple_SetItem(tuple, 1, PyInt_FromLong(h2+y+yOffset));
+ PyList_SetItem(samples, i*2+1, tuple);
}
- y = (int)(absin * h2);
- PyList_SetItem(samples, i*4, PyInt_FromLong(i));
- PyList_SetItem(samples, i*4+1, PyInt_FromLong(h2-y));
- PyList_SetItem(samples, i*4+2, PyInt_FromLong(i));
- PyList_SetItem(samples, i*4+3, PyInt_FromLong(h2+y));
}
return samples;
};
@@ -4080,6 +4307,13 @@ static PyMethodDef SndTable_methods[] = {
{"reset", (PyCFunction)SndTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)SndTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)SndTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)SndTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)SndTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)SndTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)SndTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)SndTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)SndTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)SndTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"put", (PyCFunction)SndTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
{"get", (PyCFunction)SndTable_get, METH_VARARGS|METH_KEYWORDS, "Gets the value at specified position in the table."},
{"setSound", (PyCFunction)SndTable_setSound, METH_VARARGS|METH_KEYWORDS, "Load a new sound in the table."},
@@ -4148,6 +4382,7 @@ typedef struct {
pyo_table_HEAD
MYFLT length;
MYFLT feedback;
+ MYFLT sr;
int pointer;
} NewTable;
@@ -4222,8 +4457,8 @@ NewTable_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_F_OF, kwlist, &self->length, &inittmp, &self->feedback))
Py_RETURN_NONE;
- double sr = PyFloat_AsDouble(PyObject_CallMethod(self->server, "getSamplingRate", NULL));
- self->size = (int)(self->length * sr + 0.5);
+ self->sr = (MYFLT)PyFloat_AsDouble(PyObject_CallMethod(self->server, "getSamplingRate", NULL));
+ self->size = (int)(self->length * self->sr + 0.5);
self->data = (MYFLT *)realloc(self->data, (self->size + 1) * sizeof(MYFLT));
for (i=0; i<(self->size+1); i++) {
@@ -4237,7 +4472,7 @@ NewTable_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
TableStream_setData(self->tablestream, self->data);
- TableStream_setSamplingRate(self->tablestream, sr);
+ TableStream_setSamplingRate(self->tablestream, self->sr);
return (PyObject *)self;
}
@@ -4249,6 +4484,13 @@ static PyObject * NewTable_normalize(NewTable *self) { NORMALIZE };
static PyObject * NewTable_reset(NewTable *self) { TABLE_RESET };
static PyObject * NewTable_removeDC(NewTable *self) { REMOVE_DC };
static PyObject * NewTable_reverse(NewTable *self) { REVERSE };
+static PyObject * NewTable_invert(NewTable *self) { INVERT };
+static PyObject * NewTable_rectify(NewTable *self) { RECTIFY };
+static PyObject * NewTable_bipolarGain(NewTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * NewTable_lowpass(NewTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * NewTable_fadein(NewTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * NewTable_fadeout(NewTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * NewTable_pow(NewTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * NewTable_copy(NewTable *self, PyObject *arg) { COPY };
static PyObject * NewTable_setTable(NewTable *self, PyObject *arg) { SET_TABLE };
static PyObject * NewTable_getTable(NewTable *self) { GET_TABLE };
@@ -4257,17 +4499,37 @@ static PyObject * NewTable_get(NewTable *self, PyObject *args, PyObject *kwds) {
static PyObject *
NewTable_getViewTable(NewTable *self, PyObject *args, PyObject *kwds) {
- int i, j, y, w, h, h2, step;
+ int i, j, y, w, h, h2, step, size;
int count = 0;
- MYFLT absin;
- PyObject *samples;
+ int yOffset = 0;
+ MYFLT absin, fstep;
+ MYFLT begin = 0.0;
+ MYFLT end = -1.0;
+ PyObject *samples, *tuple;
PyObject *sizetmp = NULL;
+
+ static char *kwlist[] = {"size", "begin", "end", "yOffset", NULL};
- static char *kwlist[] = {"size", NULL};
-
- if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &sizetmp))
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE__OFFI, kwlist, &sizetmp, &begin, &end, &yOffset))
return PyInt_FromLong(-1);
+ if (end <= 0.0)
+ end = self->size;
+ else {
+ end = end * self->sr;
+ if (end > self->size)
+ end = self->size;
+ }
+
+ if (begin < 0.0)
+ begin = 0;
+ else {
+ begin = begin * self->sr;
+ if (begin >= end)
+ begin = 0;
+ }
+ size = (int)(end - begin);
+
if (sizetmp) {
if (PyTuple_Check(sizetmp)) {
w = PyInt_AsLong(PyTuple_GET_ITEM(sizetmp, 0));
@@ -4287,20 +4549,52 @@ NewTable_getViewTable(NewTable *self, PyObject *args, PyObject *kwds) {
h = 200;
}
h2 = h/2;
- step = (int)(self->size / (MYFLT)(w));
-
- samples = PyList_New(w*4);
- for(i=0; i<w; i++) {
- absin = 0.0;
- for (j=0; j<step; j++) {
- if (MYFABS(self->data[count++]) > absin)
- absin = self->data[count];
+ step = (int)(size / (MYFLT)(w));
+ fstep = (MYFLT)(w) / (size-1);
+
+ if (step == 0) {
+ samples = PyList_New(size);
+ for (i=0; i<size; i++) {
+ tuple = PyTuple_New(2);
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong((int)(i*fstep)));
+ PyTuple_SetItem(tuple, 1, PyInt_FromLong(-self->data[i+(int)(begin)]*h2+h2+yOffset));
+ PyList_SetItem(samples, i, tuple);
+ }
+ }
+ else if (step < 32) {
+ samples = PyList_New(w);
+ for(i=0; i<w; i++) {
+ absin = 0.0;
+ for (j=0; j<step; j++) {
+ absin += -self->data[(int)(begin)+count];
+ count++;
+ }
+ y = (int)(absin / step * h2);
+ tuple = PyTuple_New(2);
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong(i));
+ PyTuple_SetItem(tuple, 1, PyInt_FromLong(h2+y+yOffset));
+ PyList_SetItem(samples, i, tuple);
+ }
+ }
+ else {
+ samples = PyList_New(w*2);
+ for(i=0; i<w; i++) {
+ absin = 0.0;
+ for (j=0; j<step; j++) {
+ if (MYFABS(self->data[(int)(begin)+count]) > absin)
+ absin = -self->data[(int)(begin)+count];
+ count++;
+ }
+ y = (int)(absin * h2);
+ tuple = PyTuple_New(2);
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong(i));
+ PyTuple_SetItem(tuple, 1, PyInt_FromLong(h2-y+yOffset));
+ PyList_SetItem(samples, i*2, tuple);
+ tuple = PyTuple_New(2);
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong(i));
+ PyTuple_SetItem(tuple, 1, PyInt_FromLong(h2+y+yOffset));
+ PyList_SetItem(samples, i*2+1, tuple);
}
- y = (int)(absin * h2);
- PyList_SetItem(samples, i*4, PyInt_FromLong(i));
- PyList_SetItem(samples, i*4+1, PyInt_FromLong(h2-y));
- PyList_SetItem(samples, i*4+2, PyInt_FromLong(i));
- PyList_SetItem(samples, i*4+3, PyInt_FromLong(h2+y));
}
return samples;
};
@@ -4360,6 +4654,13 @@ static PyMethodDef NewTable_methods[] = {
{"reset", (PyCFunction)NewTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)NewTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)NewTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)NewTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)NewTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)NewTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)NewTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)NewTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)NewTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)NewTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"put", (PyCFunction)NewTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
{"get", (PyCFunction)NewTable_get, METH_VARARGS|METH_KEYWORDS, "Gets the value at specified position in the table."},
{"getSize", (PyCFunction)NewTable_getSize, METH_NOARGS, "Return the size of the table in samples."},
@@ -4492,10 +4793,17 @@ static PyObject * DataTable_normalize(DataTable *self) { NORMALIZE };
static PyObject * DataTable_reset(DataTable *self) { TABLE_RESET };
static PyObject * DataTable_removeDC(DataTable *self) { REMOVE_DC };
static PyObject * DataTable_reverse(DataTable *self) { REVERSE };
+static PyObject * DataTable_invert(DataTable *self) { INVERT };
+static PyObject * DataTable_rectify(DataTable *self) { RECTIFY };
+static PyObject * DataTable_bipolarGain(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * DataTable_lowpass(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * DataTable_fadein(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * DataTable_fadeout(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * DataTable_pow(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
static PyObject * DataTable_copy(DataTable *self, PyObject *arg) { COPY };
static PyObject * DataTable_setTable(DataTable *self, PyObject *arg) { SET_TABLE };
static PyObject * DataTable_getTable(DataTable *self) { GET_TABLE };
-static PyObject * DataTable_getViewTable(DataTable *self) { GET_VIEW_TABLE };
+static PyObject * DataTable_getViewTable(DataTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
static PyObject * DataTable_put(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
static PyObject * DataTable_get(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
@@ -4523,13 +4831,20 @@ static PyMethodDef DataTable_methods[] = {
{"copy", (PyCFunction)DataTable_copy, METH_O, "Copy data from table given in argument."},
{"setTable", (PyCFunction)DataTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
{"getTable", (PyCFunction)DataTable_getTable, METH_NOARGS, "Returns a list of table samples."},
- {"getViewTable", (PyCFunction)DataTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+ {"getViewTable", (PyCFunction)DataTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
{"getTableStream", (PyCFunction)DataTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
{"setData", (PyCFunction)DataTable_setData, METH_O, "Sets the table from samples in a text file."},
{"normalize", (PyCFunction)DataTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
{"reset", (PyCFunction)DataTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
{"removeDC", (PyCFunction)DataTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
{"reverse", (PyCFunction)DataTable_reverse, METH_NOARGS, "Reverse the table's data."},
+ {"invert", (PyCFunction)DataTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+ {"rectify", (PyCFunction)DataTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+ {"bipolarGain", (PyCFunction)DataTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+ {"lowpass", (PyCFunction)DataTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+ {"fadein", (PyCFunction)DataTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+ {"fadeout", (PyCFunction)DataTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+ {"pow", (PyCFunction)DataTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
{"put", (PyCFunction)DataTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
{"get", (PyCFunction)DataTable_get, METH_VARARGS|METH_KEYWORDS, "Gets the value at specified position in the table."},
{"getSize", (PyCFunction)DataTable_getSize, METH_NOARGS, "Return the size of the table in samples."},
@@ -4720,13 +5035,11 @@ TableRec_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
INIT_INPUT_STREAM
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of TableRec must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableRec must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
+ Py_INCREF(tabletmp);
self->table = (NewTable *)tabletmp;
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
@@ -5210,16 +5523,15 @@ TableMorph_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
INIT_INPUT_STREAM
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of TableMorph must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableMorph must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
+ Py_INCREF(tabletmp);
self->table = (PyObject *)tabletmp;
Py_XDECREF(self->sources);
+ Py_INCREF(sourcestmp);
self->sources = (PyObject *)sourcestmp;
TableMorph_alloc_memories(self);
@@ -5521,6 +5833,7 @@ TrigTableRec_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
INIT_INPUT_STREAM
Py_XDECREF(self->trigger);
+ Py_INCREF(trigtmp);
self->trigger = trigtmp;
trig_streamtmp = PyObject_CallMethod((PyObject *)self->trigger, "_getStream", NULL);
Py_INCREF(trig_streamtmp);
@@ -5528,13 +5841,11 @@ TrigTableRec_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->trigger_stream = (Stream *)trig_streamtmp;
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of TrigTableRec must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of TrigTableRec must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
+ Py_INCREF(tabletmp);
self->table = (NewTable *)tabletmp;
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
@@ -5989,13 +6300,11 @@ TablePut_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
INIT_INPUT_STREAM
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of TablePut must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of TablePut must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
+ Py_INCREF(tabletmp);
self->table = (DataTable *)tabletmp;
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
diff --git a/src/objects/trigmodule.c b/src/objects/trigmodule.c
index cdbcf85..be86e0c 100644
--- a/src/objects/trigmodule.c
+++ b/src/objects/trigmodule.c
@@ -1394,7 +1394,7 @@ TrigFunc_setArg(TrigFunc *self, PyObject *arg)
PyObject *tmp;
tmp = arg;
- Py_DECREF(self->arg);
+ Py_XDECREF(self->arg);
Py_INCREF(tmp);
self->arg = tmp;
@@ -1692,11 +1692,8 @@ TrigEnv_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
INIT_INPUT_STREAM
if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
- PySys_WriteStderr("TypeError: \"table\" argument of TrigEnv must be a PyoTableObject.\n");
- if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
- PyObject_CallMethod(self->server, "shutdown", NULL);
- }
- Py_Exit(1);
+ PyErr_SetString(PyExc_TypeError, "\"table\" argument of TrigEnv must be a PyoTableObject.\n");
+ Py_RETURN_NONE;
}
Py_XDECREF(self->table);
self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
diff --git a/src/objects/utilsmodule.c b/src/objects/utilsmodule.c
index a82cec9..e4e5653 100644
--- a/src/objects/utilsmodule.c
+++ b/src/objects/utilsmodule.c
@@ -1203,11 +1203,11 @@ SampHold_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
INIT_INPUT_STREAM
- Py_XDECREF(self->controlsig); \
- self->controlsig = controlsigtmp; \
- controlsig_streamtmp = PyObject_CallMethod((PyObject *)self->controlsig, "_getStream", NULL); \
- Py_INCREF(controlsig_streamtmp); \
- Py_XDECREF(self->controlsig_stream); \
+ Py_XDECREF(self->controlsig);
+ self->controlsig = controlsigtmp;
+ controlsig_streamtmp = PyObject_CallMethod((PyObject *)self->controlsig, "_getStream", NULL);
+ Py_INCREF(controlsig_streamtmp);
+ Py_XDECREF(self->controlsig_stream);
self->controlsig_stream = (Stream *)controlsig_streamtmp;
if (valuetmp) {
@@ -1393,6 +1393,383 @@ SampHold_new, /* tp_new */
};
/************/
+/* TrackHold */
+/************/
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ PyObject *controlsig;
+ Stream *controlsig_stream;
+ PyObject *value;
+ Stream *value_stream;
+ MYFLT currentValue;
+ int flag;
+ int modebuffer[3]; // need at least 2 slots for mul & add
+} TrackHold;
+
+static void
+TrackHold_filters_i(TrackHold *self) {
+ MYFLT ctrl;
+ int i;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT *ctrlsig = Stream_getData((Stream *)self->controlsig_stream);
+ MYFLT val = PyFloat_AS_DOUBLE(self->value);
+
+ for (i=0; i<self->bufsize; i++) {
+ ctrl = ctrlsig[i];
+ if (ctrl > (val - 0.0001) && ctrl < (val + 0.0001)) {
+ if (self->flag == 1) {
+ self->currentValue = in[i];
+ self->flag = 0;
+ }
+ }
+ else {
+ self->currentValue = in[i];
+ self->flag = 1;
+ }
+ self->data[i] = self->currentValue;
+ }
+}
+
+static void
+TrackHold_filters_a(TrackHold *self) {
+ MYFLT ctrl, val;
+ int i;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT *ctrlsig = Stream_getData((Stream *)self->controlsig_stream);
+ MYFLT *valsig = Stream_getData((Stream *)self->value_stream);
+
+ for (i=0; i<self->bufsize; i++) {
+ ctrl = ctrlsig[i];
+ val = valsig[i];
+ if (ctrl > (val - 0.0001) && ctrl < (val + 0.0001)) {
+ if (self->flag == 1) {
+ self->currentValue = in[i];
+ self->flag = 0;
+ }
+ }
+ else {
+ self->currentValue = in[i];
+ self->flag = 1;
+ }
+ self->data[i] = self->currentValue;
+ }
+}
+
+static void TrackHold_postprocessing_ii(TrackHold *self) { POST_PROCESSING_II };
+static void TrackHold_postprocessing_ai(TrackHold *self) { POST_PROCESSING_AI };
+static void TrackHold_postprocessing_ia(TrackHold *self) { POST_PROCESSING_IA };
+static void TrackHold_postprocessing_aa(TrackHold *self) { POST_PROCESSING_AA };
+static void TrackHold_postprocessing_ireva(TrackHold *self) { POST_PROCESSING_IREVA };
+static void TrackHold_postprocessing_areva(TrackHold *self) { POST_PROCESSING_AREVA };
+static void TrackHold_postprocessing_revai(TrackHold *self) { POST_PROCESSING_REVAI };
+static void TrackHold_postprocessing_revaa(TrackHold *self) { POST_PROCESSING_REVAA };
+static void TrackHold_postprocessing_revareva(TrackHold *self) { POST_PROCESSING_REVAREVA };
+
+static void
+TrackHold_setProcMode(TrackHold *self)
+{
+ int procmode, muladdmode;
+ procmode = self->modebuffer[2];
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ switch (procmode) {
+ case 0:
+ self->proc_func_ptr = TrackHold_filters_i;
+ break;
+ case 1:
+ self->proc_func_ptr = TrackHold_filters_a;
+ break;
+ }
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = TrackHold_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = TrackHold_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = TrackHold_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = TrackHold_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = TrackHold_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = TrackHold_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = TrackHold_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = TrackHold_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = TrackHold_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+TrackHold_compute_next_data_frame(TrackHold *self)
+{
+ (*self->proc_func_ptr)(self);
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+TrackHold_traverse(TrackHold *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ Py_VISIT(self->controlsig);
+ Py_VISIT(self->controlsig_stream);
+ Py_VISIT(self->value);
+ Py_VISIT(self->value_stream);
+ return 0;
+}
+
+static int
+TrackHold_clear(TrackHold *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->input_stream);
+ Py_CLEAR(self->controlsig);
+ Py_CLEAR(self->controlsig_stream);
+ Py_CLEAR(self->value);
+ Py_CLEAR(self->value_stream);
+ return 0;
+}
+
+static void
+TrackHold_dealloc(TrackHold* self)
+{
+ pyo_DEALLOC
+ TrackHold_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrackHold_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *inputtmp, *input_streamtmp, *controlsigtmp, *controlsig_streamtmp, *valuetmp=NULL, *multmp=NULL, *addtmp=NULL;
+ TrackHold *self;
+ self = (TrackHold *)type->tp_alloc(type, 0);
+
+ self->value = PyFloat_FromDouble(0.0);
+ self->currentValue = 0.0;
+ self->flag = 1;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+ self->modebuffer[2] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, TrackHold_compute_next_data_frame);
+ self->mode_func_ptr = TrackHold_setProcMode;
+
+ static char *kwlist[] = {"input", "controlsig", "value", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OOO", kwlist, &inputtmp, &controlsigtmp, &valuetmp, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ INIT_INPUT_STREAM
+
+ Py_XDECREF(self->controlsig);
+ self->controlsig = controlsigtmp;
+ controlsig_streamtmp = PyObject_CallMethod((PyObject *)self->controlsig, "_getStream", NULL);
+ Py_INCREF(controlsig_streamtmp);
+ Py_XDECREF(self->controlsig_stream);
+ self->controlsig_stream = (Stream *)controlsig_streamtmp;
+
+ if (valuetmp) {
+ PyObject_CallMethod((PyObject *)self, "setValue", "O", valuetmp);
+ }
+
+ if (multmp) {
+ PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+ }
+
+ if (addtmp) {
+ PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * TrackHold_getServer(TrackHold* self) { GET_SERVER };
+static PyObject * TrackHold_getStream(TrackHold* self) { GET_STREAM };
+static PyObject * TrackHold_setMul(TrackHold *self, PyObject *arg) { SET_MUL };
+static PyObject * TrackHold_setAdd(TrackHold *self, PyObject *arg) { SET_ADD };
+static PyObject * TrackHold_setSub(TrackHold *self, PyObject *arg) { SET_SUB };
+static PyObject * TrackHold_setDiv(TrackHold *self, PyObject *arg) { SET_DIV };
+
+static PyObject * TrackHold_play(TrackHold *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrackHold_out(TrackHold *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * TrackHold_stop(TrackHold *self) { STOP };
+
+static PyObject * TrackHold_multiply(TrackHold *self, PyObject *arg) { MULTIPLY };
+static PyObject * TrackHold_inplace_multiply(TrackHold *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * TrackHold_add(TrackHold *self, PyObject *arg) { ADD };
+static PyObject * TrackHold_inplace_add(TrackHold *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * TrackHold_sub(TrackHold *self, PyObject *arg) { SUB };
+static PyObject * TrackHold_inplace_sub(TrackHold *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * TrackHold_div(TrackHold *self, PyObject *arg) { DIV };
+static PyObject * TrackHold_inplace_div(TrackHold *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+TrackHold_setValue(TrackHold *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->value);
+ if (isNumber == 1) {
+ self->value = PyNumber_Float(tmp);
+ self->modebuffer[2] = 0;
+ }
+ else {
+ self->value = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->value, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->value_stream);
+ self->value_stream = (Stream *)streamtmp;
+ self->modebuffer[2] = 1;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMemberDef TrackHold_members[] = {
+{"server", T_OBJECT_EX, offsetof(TrackHold, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(TrackHold, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(TrackHold, input), 0, "Input sound object."},
+{"controlsig", T_OBJECT_EX, offsetof(TrackHold, controlsig), 0, "Control input object."},
+{"value", T_OBJECT_EX, offsetof(TrackHold, value), 0, "Trigger value."},
+{"mul", T_OBJECT_EX, offsetof(TrackHold, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(TrackHold, add), 0, "Add factor."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef TrackHold_methods[] = {
+{"getServer", (PyCFunction)TrackHold_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)TrackHold_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)TrackHold_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"out", (PyCFunction)TrackHold_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"stop", (PyCFunction)TrackHold_stop, METH_NOARGS, "Stops computing."},
+{"setValue", (PyCFunction)TrackHold_setValue, METH_O, "Sets trigger value."},
+{"setMul", (PyCFunction)TrackHold_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)TrackHold_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)TrackHold_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)TrackHold_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL} /* Sentinel */
+};
+
+static PyNumberMethods TrackHold_as_number = {
+(binaryfunc)TrackHold_add, /*nb_add*/
+(binaryfunc)TrackHold_sub, /*nb_subtract*/
+(binaryfunc)TrackHold_multiply, /*nb_multiply*/
+(binaryfunc)TrackHold_div, /*nb_divide*/
+0, /*nb_remainder*/
+0, /*nb_divmod*/
+0, /*nb_power*/
+0, /*nb_neg*/
+0, /*nb_pos*/
+0, /*(unaryfunc)array_abs,*/
+0, /*nb_nonzero*/
+0, /*nb_invert*/
+0, /*nb_lshift*/
+0, /*nb_rshift*/
+0, /*nb_and*/
+0, /*nb_xor*/
+0, /*nb_or*/
+0, /*nb_coerce*/
+0, /*nb_int*/
+0, /*nb_long*/
+0, /*nb_float*/
+0, /*nb_oct*/
+0, /*nb_hex*/
+(binaryfunc)TrackHold_inplace_add, /*inplace_add*/
+(binaryfunc)TrackHold_inplace_sub, /*inplace_subtract*/
+(binaryfunc)TrackHold_inplace_multiply, /*inplace_multiply*/
+(binaryfunc)TrackHold_inplace_div, /*inplace_divide*/
+0, /*inplace_remainder*/
+0, /*inplace_power*/
+0, /*inplace_lshift*/
+0, /*inplace_rshift*/
+0, /*inplace_and*/
+0, /*inplace_xor*/
+0, /*inplace_or*/
+0, /*nb_floor_divide*/
+0, /*nb_true_divide*/
+0, /*nb_inplace_floor_divide*/
+0, /*nb_inplace_true_divide*/
+0, /* nb_index */
+};
+
+PyTypeObject TrackHoldType = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.TrackHold_base", /*tp_name*/
+sizeof(TrackHold), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)TrackHold_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+&TrackHold_as_number, /*tp_as_number*/
+0, /*tp_as_sequence*/
+0, /*tp_as_mapping*/
+0, /*tp_hash */
+0, /*tp_call*/
+0, /*tp_str*/
+0, /*tp_getattro*/
+0, /*tp_setattro*/
+0, /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"TrackHold objects. Let pass and freeze an audio stream.", /* tp_doc */
+(traverseproc)TrackHold_traverse, /* tp_traverse */
+(inquiry)TrackHold_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+TrackHold_methods, /* tp_methods */
+TrackHold_members, /* tp_members */
+0, /* tp_getset */
+0, /* tp_base */
+0, /* tp_dict */
+0, /* tp_descr_get */
+0, /* tp_descr_set */
+0, /* tp_dictoffset */
+0, /* tp_init */
+0, /* tp_alloc */
+TrackHold_new, /* tp_new */
+};
+
+/************/
/* Compare */
/************/
typedef struct {
@@ -4250,7 +4627,7 @@ MToF_process(MToF *self) {
for (i=0; i<self->bufsize; i++) {
midi = in[i];
if (midi != self->lastmidi) {
- self->data[i] = self->curfreq = 8.1757989156437 * MYPOW(1.0594630943593, midi);
+ self->data[i] = self->curfreq = 440.0 * MYPOW(2.0, (midi - 69) / 12.0);
self->lastmidi = midi;
}
else
@@ -4506,6 +4883,284 @@ PyTypeObject MToFType = {
};
/************/
+/* FToM */
+/************/
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ MYFLT lastfreq;
+ MYFLT curmidi;
+ int modebuffer[2]; // need at least 2 slots for mul & add
+} FToM;
+
+static void
+FToM_process(FToM *self) {
+ int i;
+ MYFLT freq;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+
+ for (i=0; i<self->bufsize; i++) {
+ freq = in[i];
+ if (freq != self->lastfreq) {
+ if (freq < 8.1758)
+ freq = 8.1578;
+ self->curmidi = 12.0 * MYLOG2(freq / 440.0) + 69;
+ self->lastfreq = freq;
+ }
+ else
+ self->data[i] = self->curmidi;
+ }
+}
+
+static void FToM_postprocessing_ii(FToM *self) { POST_PROCESSING_II };
+static void FToM_postprocessing_ai(FToM *self) { POST_PROCESSING_AI };
+static void FToM_postprocessing_ia(FToM *self) { POST_PROCESSING_IA };
+static void FToM_postprocessing_aa(FToM *self) { POST_PROCESSING_AA };
+static void FToM_postprocessing_ireva(FToM *self) { POST_PROCESSING_IREVA };
+static void FToM_postprocessing_areva(FToM *self) { POST_PROCESSING_AREVA };
+static void FToM_postprocessing_revai(FToM *self) { POST_PROCESSING_REVAI };
+static void FToM_postprocessing_revaa(FToM *self) { POST_PROCESSING_REVAA };
+static void FToM_postprocessing_revareva(FToM *self) { POST_PROCESSING_REVAREVA };
+
+static void
+FToM_setProcMode(FToM *self)
+{
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ self->proc_func_ptr = FToM_process;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = FToM_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = FToM_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = FToM_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = FToM_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = FToM_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = FToM_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = FToM_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = FToM_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = FToM_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+FToM_compute_next_data_frame(FToM *self)
+{
+ (*self->proc_func_ptr)(self);
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+FToM_traverse(FToM *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ return 0;
+}
+
+static int
+FToM_clear(FToM *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->input_stream);
+ return 0;
+}
+
+static void
+FToM_dealloc(FToM* self)
+{
+ pyo_DEALLOC
+ FToM_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+FToM_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *inputtmp, *input_streamtmp, *multmp=NULL, *addtmp=NULL;
+ FToM *self;
+ self = (FToM *)type->tp_alloc(type, 0);
+
+ self->lastfreq = 8.1758;
+ self->curmidi = 0.0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, FToM_compute_next_data_frame);
+ self->mode_func_ptr = FToM_setProcMode;
+
+ static char *kwlist[] = {"input", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist, &inputtmp, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ INIT_INPUT_STREAM
+
+ if (multmp) {
+ PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+ }
+
+ if (addtmp) {
+ PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * FToM_getServer(FToM* self) { GET_SERVER };
+static PyObject * FToM_getStream(FToM* self) { GET_STREAM };
+static PyObject * FToM_setMul(FToM *self, PyObject *arg) { SET_MUL };
+static PyObject * FToM_setAdd(FToM *self, PyObject *arg) { SET_ADD };
+static PyObject * FToM_setSub(FToM *self, PyObject *arg) { SET_SUB };
+static PyObject * FToM_setDiv(FToM *self, PyObject *arg) { SET_DIV };
+
+static PyObject * FToM_play(FToM *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * FToM_out(FToM *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * FToM_stop(FToM *self) { STOP };
+
+static PyObject * FToM_multiply(FToM *self, PyObject *arg) { MULTIPLY };
+static PyObject * FToM_inplace_multiply(FToM *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * FToM_add(FToM *self, PyObject *arg) { ADD };
+static PyObject * FToM_inplace_add(FToM *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * FToM_sub(FToM *self, PyObject *arg) { SUB };
+static PyObject * FToM_inplace_sub(FToM *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * FToM_div(FToM *self, PyObject *arg) { DIV };
+static PyObject * FToM_inplace_div(FToM *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef FToM_members[] = {
+ {"server", T_OBJECT_EX, offsetof(FToM, server), 0, "Pyo server."},
+ {"stream", T_OBJECT_EX, offsetof(FToM, stream), 0, "Stream object."},
+ {"input", T_OBJECT_EX, offsetof(FToM, input), 0, "Input sound object."},
+ {"mul", T_OBJECT_EX, offsetof(FToM, mul), 0, "Mul factor."},
+ {"add", T_OBJECT_EX, offsetof(FToM, add), 0, "Add factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef FToM_methods[] = {
+ {"getServer", (PyCFunction)FToM_getServer, METH_NOARGS, "Returns server object."},
+ {"_getStream", (PyCFunction)FToM_getStream, METH_NOARGS, "Returns stream object."},
+ {"play", (PyCFunction)FToM_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+ {"stop", (PyCFunction)FToM_stop, METH_NOARGS, "Stops computing."},
+ {"out", (PyCFunction)FToM_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+ {"setMul", (PyCFunction)FToM_setMul, METH_O, "Sets oscillator mul factor."},
+ {"setAdd", (PyCFunction)FToM_setAdd, METH_O, "Sets oscillator add factor."},
+ {"setSub", (PyCFunction)FToM_setSub, METH_O, "Sets inverse add factor."},
+ {"setDiv", (PyCFunction)FToM_setDiv, METH_O, "Sets inverse mul factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyNumberMethods FToM_as_number = {
+ (binaryfunc)FToM_add, /*nb_add*/
+ (binaryfunc)FToM_sub, /*nb_subtract*/
+ (binaryfunc)FToM_multiply, /*nb_multiply*/
+ (binaryfunc)FToM_div, /*nb_divide*/
+ 0, /*nb_remainder*/
+ 0, /*nb_divmod*/
+ 0, /*nb_power*/
+ 0, /*nb_neg*/
+ 0, /*nb_pos*/
+ 0, /*(unaryfunc)array_abs,*/
+ 0, /*nb_nonzero*/
+ 0, /*nb_invert*/
+ 0, /*nb_lshift*/
+ 0, /*nb_rshift*/
+ 0, /*nb_and*/
+ 0, /*nb_xor*/
+ 0, /*nb_or*/
+ 0, /*nb_coerce*/
+ 0, /*nb_int*/
+ 0, /*nb_long*/
+ 0, /*nb_float*/
+ 0, /*nb_oct*/
+ 0, /*nb_hex*/
+ (binaryfunc)FToM_inplace_add, /*inplace_add*/
+ (binaryfunc)FToM_inplace_sub, /*inplace_subtract*/
+ (binaryfunc)FToM_inplace_multiply, /*inplace_multiply*/
+ (binaryfunc)FToM_inplace_div, /*inplace_divide*/
+ 0, /*inplace_remainder*/
+ 0, /*inplace_power*/
+ 0, /*inplace_lshift*/
+ 0, /*inplace_rshift*/
+ 0, /*inplace_and*/
+ 0, /*inplace_xor*/
+ 0, /*inplace_or*/
+ 0, /*nb_floor_divide*/
+ 0, /*nb_true_divide*/
+ 0, /*nb_inplace_floor_divide*/
+ 0, /*nb_inplace_true_divide*/
+ 0, /* nb_index */
+};
+
+PyTypeObject FToMType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_pyo.FToM_base", /*tp_name*/
+ sizeof(FToM), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)FToM_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ &FToM_as_number, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "FToM objects. Converts frequency to midi note.", /* tp_doc */
+ (traverseproc)FToM_traverse, /* tp_traverse */
+ (inquiry)FToM_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ FToM_methods, /* tp_methods */
+ FToM_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ FToM_new, /* tp_new */
+};
+
+/************/
/* MToT */
/************/
typedef struct {
diff --git a/src/objects/wgverbmodule.c b/src/objects/wgverbmodule.c
index 79970ce..1fa6d06 100644
--- a/src/objects/wgverbmodule.c
+++ b/src/objects/wgverbmodule.c
@@ -26,18 +26,20 @@
#include "servermodule.h"
#include "dummymodule.h"
+#define NUM_REFS 13
static const MYFLT randomScaling = 0.5;
-static const MYFLT reverbParams[8][3] = {
-{ 2473.0, 0.0010, 3.100 },
-{ 2767.0, 0.0011, 3.500 },
-{ 3217.0, 0.0017, 1.110 },
-{ 3557.0, 0.0006, 3.973 },
-{ 3907.0, 0.0010, 2.341 },
-{ 4127.0, 0.0011, 1.897 },
-{ 2143.0, 0.0017, 0.891 },
-{ 1933.0, 0.0006, 3.221 }
-};
+static const MYFLT reverbParams[8][4] = {
+{ 2473.0, 0.0010, 3.100, 2503.0 },
+{ 2767.0, 0.0011, 3.500, 2749.0 },
+{ 3217.0, 0.0017, 1.110, 3187.0 },
+{ 3557.0, 0.0006, 3.973, 3583.0 },
+{ 3907.0, 0.0010, 2.341, 3929.0 },
+{ 4127.0, 0.0011, 1.897, 4093.0 },
+{ 2143.0, 0.0017, 0.891, 2131.0 },
+{ 1933.0, 0.0006, 3.221, 1951.0 }};
+
+static const MYFLT first_ref_delays[NUM_REFS] = {283, 467, 587, 677, 757, 911, 1117, 1223, 1307, 1429, 1553, 1613, 1783};
typedef struct {
pyo_audio_HEAD
@@ -486,12 +488,6 @@ WGVerb_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->mix = PyFloat_FromDouble(0.5);
self->lastFreq = self->damp = 0.0;
- for (i=0; i<8; i++) {
- self->in_count[i] = 0;
- self->lastSamples[i] = 0.0;
- self->rnd_value[i] = self->rnd_oldValue[i] = self->rnd_diff[i] = 0.0;
- self->rnd_time[i] = 1.0;
- }
self->total_signal = 0.0;
self->modebuffer[0] = 0;
self->modebuffer[1] = 0;
@@ -770,7 +766,7 @@ sizeof(WGVerb), /*tp_basicsize*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
-"WGVerb objects. WGVerb signal by x samples.", /* tp_doc */
+"WGVerb objects. Waveguide-based reverberation network.", /* tp_doc */
(traverseproc)WGVerb_traverse, /* tp_traverse */
(inquiry)WGVerb_clear, /* tp_clear */
0, /* tp_richcompare */
@@ -789,3 +785,1327 @@ WGVerb_members, /* tp_members */
0, /* tp_alloc */
WGVerb_new, /* tp_new */
};
+
+/***************/
+/**** STRev ****/
+/***************/
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ PyObject *inpos;
+ Stream *inpos_stream;
+ PyObject *revtime;
+ Stream *revtime_stream;
+ PyObject *cutoff;
+ Stream *cutoff_stream;
+ PyObject *mix;
+ Stream *mix_stream;
+ void (*mix_func_ptr)();
+ int modebuffer[4];
+ MYFLT firstRefGain;
+ MYFLT total_signal[2];
+ MYFLT delays[2][8];
+ long size[2][8];
+ int in_count[2][8];
+ MYFLT *buffer[2][8];
+ MYFLT *ref_buffer[NUM_REFS];
+ int ref_size[NUM_REFS];
+ int ref_in_count[NUM_REFS];
+ MYFLT avg_time;
+ MYFLT srfac;
+ // lowpass
+ MYFLT damp[2];
+ MYFLT lastFreq;
+ MYFLT nyquist;
+ MYFLT lastInpos;
+ // sample memories
+ MYFLT lastSamples[2][8];
+ // jitters
+ MYFLT rnd[2][8];
+ MYFLT rnd_value[2][8];
+ MYFLT rnd_oldValue[2][8];
+ MYFLT rnd_diff[2][8];
+ MYFLT rnd_time[2][8];
+ MYFLT rnd_timeInc[2][8];
+ MYFLT rnd_range[2][8];
+ MYFLT rnd_halfRange[2][8];
+ MYFLT *buffer_streams;
+ MYFLT *input_buffer[2];
+} STReverb;
+
+static void
+STReverb_process_ii(STReverb *self) {
+ int i, j, k, k2, ind, half;
+ MYFLT val, x, x1, xind, frac, junction, inval, filt, amp1, amp2, b, f, sum_ref, feed, step, invp;
+ MYFLT ref_amp_l[NUM_REFS];
+ MYFLT ref_amp_r[NUM_REFS];
+ MYFLT ref_buf[2];
+
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT inpos = PyFloat_AS_DOUBLE(self->inpos);
+ if (self->modebuffer[1] == 0)
+ feed = PyFloat_AS_DOUBLE(self->revtime);
+ else
+ feed = Stream_getData((Stream *)self->revtime_stream)[0];
+ MYFLT freq = PyFloat_AS_DOUBLE(self->cutoff);
+
+ if (inpos < 0.0)
+ inpos = 0.0;
+ else if (inpos > 1.0)
+ inpos = 1.0;
+
+ if (feed < 0.01)
+ feed = 0.01;
+ feed = MYPOW(100.0, -self->avg_time/feed);
+
+ if (freq < 20.0)
+ freq = 20.0;
+ else if (freq > self->nyquist)
+ freq = self->nyquist;
+
+ if (freq != self->lastFreq || inpos != self->lastInpos) {
+ self->lastFreq = freq;
+ self->lastInpos = inpos;
+ f = ((1.0 - inpos) * 0.3 + 0.7) * freq;
+ b = 2.0 - MYCOS(TWOPI * f / self->sr);
+ self->damp[0] = (b - MYSQRT(b * b - 1.0));
+ f = (inpos * 0.3 + 0.7) * freq;
+ b = 2.0 - MYCOS(TWOPI * f / self->sr);
+ self->damp[1] = (b - MYSQRT(b * b - 1.0));
+ }
+
+ /* position of the source and first reflexions */
+ amp1 = 1.0 - inpos;
+ amp2 = inpos;
+ half = (NUM_REFS - 1) / 2;
+ if (inpos <= 0.5) {
+ step = (0.5 - inpos) / half;
+ ref_amp_l[half] = ref_amp_r[half] = 0.5;
+ for (k=0; k<half; k++) {
+ k2 = NUM_REFS - 1 - k;
+ ref_amp_r[k] = ref_amp_l[k2] = inpos + step * k;
+ ref_amp_l[k] = ref_amp_r[k2] = 1.0 - ref_amp_r[k];
+ ref_amp_r[k2] *= inpos + 0.5;
+ }
+ }
+ else {
+ invp = 1.0 - inpos;
+ step = (0.5 - invp) / half;
+ ref_amp_l[half] = ref_amp_r[half] = 0.5;
+ for (k=0; k<half; k++) {
+ k2 = NUM_REFS - 1 - k;
+ ref_amp_l[k] = ref_amp_r[k2] = invp + step * k;
+ ref_amp_r[k] = ref_amp_l[k2] = 1.0 - ref_amp_l[k];
+ ref_amp_l[k2] *= invp + 0.5;
+ }
+ }
+
+ for (i=0; i<self->bufsize; i++) {
+ self->input_buffer[0][i] = in[i] * amp1;
+ self->input_buffer[1][i] = in[i] * amp2;
+ ref_buf[0] = ref_buf[1] = 0.0;
+ for (k=0; k<NUM_REFS; k++) {
+ sum_ref = self->ref_buffer[k][self->ref_in_count[k]];
+ self->ref_buffer[k][self->ref_in_count[k]] = in[i];
+ self->ref_in_count[k]++;
+ if (self->ref_in_count[k] == self->ref_size[k])
+ self->ref_in_count[k] = 0;
+ ref_buf[0] += sum_ref * ref_amp_l[k];
+ ref_buf[1] += sum_ref * ref_amp_r[k];
+ }
+ for (k=0; k<2; k++) {
+ inval = self->input_buffer[k][i] * 0.8 + self->input_buffer[1-k][i] * 0.2 + ref_buf[k] * 0.1;
+ junction = self->total_signal[k] * .25;
+ self->total_signal[k] = ref_buf[k] * self->firstRefGain;
+ for (j=0; j<8; j++) {
+ self->rnd_time[k][j] += self->rnd_timeInc[k][j];
+ if (self->rnd_time[k][j] < 0.0)
+ self->rnd_time[k][j] += 1.0;
+ else if (self->rnd_time[k][j] >= 1.0) {
+ self->rnd_time[k][j] -= 1.0;
+ self->rnd_oldValue[k][j] = self->rnd_value[k][j];
+ self->rnd_value[k][j] = self->rnd_range[k][j] * (rand()/((MYFLT)(RAND_MAX)+1)) - self->rnd_halfRange[k][j];
+ self->rnd_diff[k][j] = self->rnd_value[k][j] - self->rnd_oldValue[k][j];
+ }
+ self->rnd[k][j] = self->rnd_oldValue[k][j] + self->rnd_diff[k][j] * self->rnd_time[k][j];
+
+ xind = self->in_count[k][j] - (self->delays[k][j] + self->rnd[k][j]);
+ if (xind < 0)
+ xind += self->size[k][j];
+ ind = (int)xind;
+ frac = xind - ind;
+ x = self->buffer[k][j][ind];
+ x1 = self->buffer[k][j][ind+1];
+ val = x + (x1 - x) * frac;
+ val *= feed;
+ filt = val + (self->lastSamples[k][j] - val) * self->damp[k];
+ self->total_signal[k] += filt;
+
+ self->buffer[k][j][self->in_count[k][j]] = inval + junction - self->lastSamples[k][j];
+ self->lastSamples[k][j] = filt;
+ if(self->in_count[k][j] == 0)
+ self->buffer[k][j][self->size[k][j]] = self->buffer[k][j][0];
+ self->in_count[k][j]++;
+ if (self->in_count[k][j] >= self->size[k][j])
+ self->in_count[k][j] = 0;
+ }
+ self->buffer_streams[i+k*self->bufsize] = self->total_signal[k] * 0.25;
+ }
+ }
+}
+
+static void
+STReverb_process_ai(STReverb *self) {
+ MYFLT val, x, x1, xind, frac, junction, inval, filt, amp1, amp2, b, f, sum_ref, inpos, feed, step, invp;
+ MYFLT ref_amp_l[NUM_REFS];
+ MYFLT ref_amp_r[NUM_REFS];
+ MYFLT ref_buf[2];
+ int i, j, k, k2, ind, half;
+
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT *pos = Stream_getData((Stream *)self->inpos_stream);
+ if (self->modebuffer[1] == 0)
+ feed = PyFloat_AS_DOUBLE(self->revtime);
+ else
+ feed = Stream_getData((Stream *)self->revtime_stream)[0];
+ MYFLT freq = PyFloat_AS_DOUBLE(self->cutoff);
+
+ if (feed < 0.01)
+ feed = 0.01;
+ feed = MYPOW(100.0, -self->avg_time/feed);
+
+ if (freq < 20.0)
+ freq = 20.0;
+ else if (freq > self->nyquist)
+ freq = self->nyquist;
+
+ for (i=0; i<self->bufsize; i++) {
+ inpos = pos[i];
+ if (inpos < 0.0)
+ inpos = 0.0;
+ else if (inpos > 1.0)
+ inpos = 1.0;
+ if (freq != self->lastFreq || inpos != self->lastInpos) {
+ self->lastFreq = freq;
+ self->lastInpos = inpos;
+ f = ((1.0 - inpos) * 0.3 + 0.7) * freq;
+ b = 2.0 - MYCOS(TWOPI * f / self->sr);
+ self->damp[0] = (b - MYSQRT(b * b - 1.0));
+ f = (inpos * 0.3 + 0.7) * freq;
+ b = 2.0 - MYCOS(TWOPI * f / self->sr);
+ self->damp[1] = (b - MYSQRT(b * b - 1.0));
+ }
+
+ /* position of the source and first reflexions */
+ amp1 = 1.0 - inpos;
+ amp2 = inpos;
+ half = (NUM_REFS - 1) / 2;
+ if (inpos <= 0.5) {
+ step = (0.5 - inpos) / half;
+ ref_amp_l[half] = ref_amp_r[half] = 0.5;
+ for (k=0; k<half; k++) {
+ k2 = NUM_REFS - 1 - k;
+ ref_amp_r[k] = ref_amp_l[k2] = inpos + step * k;
+ ref_amp_l[k] = ref_amp_r[k2] = 1.0 - ref_amp_r[k];
+ ref_amp_r[k2] *= inpos + 0.5;
+ }
+ }
+ else {
+ invp = 1.0 - inpos;
+ step = (0.5 - invp) / half;
+ ref_amp_l[half] = ref_amp_r[half] = 0.5;
+ for (k=0; k<half; k++) {
+ k2 = NUM_REFS - 1 - k;
+ ref_amp_l[k] = ref_amp_r[k2] = invp + step * k;
+ ref_amp_r[k] = ref_amp_l[k2] = 1.0 - ref_amp_l[k];
+ ref_amp_l[k2] *= invp + 0.5;
+ }
+ }
+
+ self->input_buffer[0][i] = in[i] * amp1;
+ self->input_buffer[1][i] = in[i] * amp2;
+ ref_buf[0] = ref_buf[1] = 0.0;
+ for (k=0; k<NUM_REFS; k++) {
+ sum_ref = self->ref_buffer[k][self->ref_in_count[k]];
+ self->ref_buffer[k][self->ref_in_count[k]] = in[i];
+ self->ref_in_count[k]++;
+ if (self->ref_in_count[k] == self->ref_size[k])
+ self->ref_in_count[k] = 0;
+ ref_buf[0] += sum_ref * ref_amp_l[k];
+ ref_buf[1] += sum_ref * ref_amp_r[k];
+ }
+ for (k=0; k<2; k++) {
+ inval = self->input_buffer[k][i] * 0.8 + self->input_buffer[1-k][i] * 0.2 + ref_buf[k] * 0.1;
+ junction = self->total_signal[k] * .25;
+ self->total_signal[k] = ref_buf[k] * self->firstRefGain;
+ for (j=0; j<8; j++) {
+ self->rnd_time[k][j] += self->rnd_timeInc[k][j];
+ if (self->rnd_time[k][j] < 0.0)
+ self->rnd_time[k][j] += 1.0;
+ else if (self->rnd_time[k][j] >= 1.0) {
+ self->rnd_time[k][j] -= 1.0;
+ self->rnd_oldValue[k][j] = self->rnd_value[k][j];
+ self->rnd_value[k][j] = self->rnd_range[k][j] * (rand()/((MYFLT)(RAND_MAX)+1)) - self->rnd_halfRange[k][j];
+ self->rnd_diff[k][j] = self->rnd_value[k][j] - self->rnd_oldValue[k][j];
+ }
+ self->rnd[k][j] = self->rnd_oldValue[k][j] + self->rnd_diff[k][j] * self->rnd_time[k][j];
+
+ xind = self->in_count[k][j] - (self->delays[k][j] + self->rnd[k][j]);
+ if (xind < 0)
+ xind += self->size[k][j];
+ ind = (int)xind;
+ frac = xind - ind;
+ x = self->buffer[k][j][ind];
+ x1 = self->buffer[k][j][ind+1];
+ val = x + (x1 - x) * frac;
+ val *= feed;
+ filt = val + (self->lastSamples[k][j] - val) * self->damp[k];
+ self->total_signal[k] += filt;
+
+ self->buffer[k][j][self->in_count[k][j]] = inval + junction - self->lastSamples[k][j];
+ self->lastSamples[k][j] = filt;
+ if(self->in_count[k][j] == 0)
+ self->buffer[k][j][self->size[k][j]] = self->buffer[k][j][0];
+ self->in_count[k][j]++;
+ if (self->in_count[k][j] >= self->size[k][j])
+ self->in_count[k][j] = 0;
+ }
+ self->buffer_streams[i+k*self->bufsize] = self->total_signal[k] * 0.25;
+ }
+ }
+}
+
+static void
+STReverb_process_ia(STReverb *self) {
+ MYFLT val, x, x1, xind, frac, junction, inval, filt, amp1, amp2, b, f, sum_ref, feed, freq, step, invp;
+ MYFLT ref_amp_l[NUM_REFS];
+ MYFLT ref_amp_r[NUM_REFS];
+ MYFLT ref_buf[2];
+ int i, j, k, k2, ind, half;
+
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT inpos = PyFloat_AS_DOUBLE(self->inpos);
+ if (self->modebuffer[1] == 0)
+ feed = PyFloat_AS_DOUBLE(self->revtime);
+ else
+ feed = Stream_getData((Stream *)self->revtime_stream)[0];
+ MYFLT *fr = Stream_getData((Stream *)self->cutoff_stream);
+
+ if (inpos < 0.0)
+ inpos = 0.0;
+ else if (inpos > 1.0)
+ inpos = 1.0;
+
+ if (feed < 0.01)
+ feed = 0.01;
+ feed = MYPOW(100.0, -self->avg_time/feed);
+
+ /* position of the source and first reflexions */
+ amp1 = 1.0 - inpos;
+ amp2 = inpos;
+ half = (NUM_REFS - 1) / 2;
+ if (inpos <= 0.5) {
+ step = (0.5 - inpos) / half;
+ ref_amp_l[half] = ref_amp_r[half] = 0.5;
+ for (k=0; k<half; k++) {
+ k2 = NUM_REFS - 1 - k;
+ ref_amp_r[k] = ref_amp_l[k2] = inpos + step * k;
+ ref_amp_l[k] = ref_amp_r[k2] = 1.0 - ref_amp_r[k];
+ ref_amp_r[k2] *= inpos + 0.5;
+ }
+ }
+ else {
+ invp = 1.0 - inpos;
+ step = (0.5 - invp) / half;
+ ref_amp_l[half] = ref_amp_r[half] = 0.5;
+ for (k=0; k<half; k++) {
+ k2 = NUM_REFS - 1 - k;
+ ref_amp_l[k] = ref_amp_r[k2] = invp + step * k;
+ ref_amp_r[k] = ref_amp_l[k2] = 1.0 - ref_amp_l[k];
+ ref_amp_l[k2] *= invp + 0.5;
+ }
+ }
+
+ for (i=0; i<self->bufsize; i++) {
+ freq = fr[i];
+ if (freq < 20.0)
+ freq = 20.0;
+ else if (freq > self->nyquist)
+ freq = self->nyquist;
+
+ if (freq != self->lastFreq || inpos != self->lastInpos) {
+ self->lastFreq = freq;
+ self->lastInpos = inpos;
+ f = ((1.0 - inpos) * 0.3 + 0.7) * freq;
+ b = 2.0 - MYCOS(TWOPI * f / self->sr);
+ self->damp[0] = (b - MYSQRT(b * b - 1.0));
+ f = (inpos * 0.3 + 0.7) * freq;
+ b = 2.0 - MYCOS(TWOPI * f / self->sr);
+ self->damp[1] = (b - MYSQRT(b * b - 1.0));
+ }
+
+ self->input_buffer[0][i] = in[i] * amp1;
+ self->input_buffer[1][i] = in[i] * amp2;
+ ref_buf[0] = ref_buf[1] = 0.0;
+ for (k=0; k<NUM_REFS; k++) {
+ sum_ref = self->ref_buffer[k][self->ref_in_count[k]];
+ self->ref_buffer[k][self->ref_in_count[k]] = in[i];
+ self->ref_in_count[k]++;
+ if (self->ref_in_count[k] == self->ref_size[k])
+ self->ref_in_count[k] = 0;
+ ref_buf[0] += sum_ref * ref_amp_l[k];
+ ref_buf[1] += sum_ref * ref_amp_r[k];
+ }
+ for (k=0; k<2; k++) {
+ inval = self->input_buffer[k][i] * 0.8 + self->input_buffer[1-k][i] * 0.2 + ref_buf[k] * 0.1;
+ junction = self->total_signal[k] * .25;
+ self->total_signal[k] = ref_buf[k] * self->firstRefGain;
+ for (j=0; j<8; j++) {
+ self->rnd_time[k][j] += self->rnd_timeInc[k][j];
+ if (self->rnd_time[k][j] < 0.0)
+ self->rnd_time[k][j] += 1.0;
+ else if (self->rnd_time[k][j] >= 1.0) {
+ self->rnd_time[k][j] -= 1.0;
+ self->rnd_oldValue[k][j] = self->rnd_value[k][j];
+ self->rnd_value[k][j] = self->rnd_range[k][j] * (rand()/((MYFLT)(RAND_MAX)+1)) - self->rnd_halfRange[k][j];
+ self->rnd_diff[k][j] = self->rnd_value[k][j] - self->rnd_oldValue[k][j];
+ }
+ self->rnd[k][j] = self->rnd_oldValue[k][j] + self->rnd_diff[k][j] * self->rnd_time[k][j];
+
+ xind = self->in_count[k][j] - (self->delays[k][j] + self->rnd[k][j]);
+ if (xind < 0)
+ xind += self->size[k][j];
+ ind = (int)xind;
+ frac = xind - ind;
+ x = self->buffer[k][j][ind];
+ x1 = self->buffer[k][j][ind+1];
+ val = x + (x1 - x) * frac;
+ val *= feed;
+ filt = val + (self->lastSamples[k][j] - val) * self->damp[k];
+ self->total_signal[k] += filt;
+
+ self->buffer[k][j][self->in_count[k][j]] = inval + junction - self->lastSamples[k][j];
+ self->lastSamples[k][j] = filt;
+ if(self->in_count[k][j] == 0)
+ self->buffer[k][j][self->size[k][j]] = self->buffer[k][j][0];
+ self->in_count[k][j]++;
+ if (self->in_count[k][j] >= self->size[k][j])
+ self->in_count[k][j] = 0;
+ }
+ self->buffer_streams[i+k*self->bufsize] = self->total_signal[k] * 0.25;
+ }
+ }
+}
+
+static void
+STReverb_process_aa(STReverb *self) {
+ MYFLT val, x, x1, xind, frac, junction, inval, filt, amp1, amp2, b, f, sum_ref, inpos, feed, freq, step, invp;
+ MYFLT ref_amp_l[NUM_REFS];
+ MYFLT ref_amp_r[NUM_REFS];
+ MYFLT ref_buf[2];
+ int i, j, k, k2, ind, half;
+
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+ MYFLT *pos = Stream_getData((Stream *)self->inpos_stream);
+ if (self->modebuffer[1] == 0)
+ feed = PyFloat_AS_DOUBLE(self->revtime);
+ else
+ feed = Stream_getData((Stream *)self->revtime_stream)[0];
+ MYFLT *fr = Stream_getData((Stream *)self->cutoff_stream);
+
+ if (feed < 0.01)
+ feed = 0.01;
+ feed = MYPOW(100.0, -self->avg_time/feed);
+
+ for (i=0; i<self->bufsize; i++) {
+ inpos = pos[i];
+ freq = fr[i];
+ if (inpos < 0.0)
+ inpos = 0.0;
+ else if (inpos > 1.0)
+ inpos = 1.0;
+ if (freq < 20.0)
+ freq = 20.0;
+ else if (freq > self->nyquist)
+ freq = self->nyquist;
+
+ if (freq != self->lastFreq || inpos != self->lastInpos) {
+ self->lastFreq = freq;
+ self->lastInpos = inpos;
+ f = ((1.0 - inpos) * 0.3 + 0.7) * freq;
+ b = 2.0 - MYCOS(TWOPI * f / self->sr);
+ self->damp[0] = (b - MYSQRT(b * b - 1.0));
+ f = (inpos * 0.3 + 0.7) * freq;
+ b = 2.0 - MYCOS(TWOPI * f / self->sr);
+ self->damp[1] = (b - MYSQRT(b * b - 1.0));
+ }
+
+ /* position of the source and first reflexions */
+ amp1 = 1.0 - inpos;
+ amp2 = inpos;
+ half = (NUM_REFS - 1) / 2;
+ if (inpos <= 0.5) {
+ step = (0.5 - inpos) / half;
+ ref_amp_l[half] = ref_amp_r[half] = 0.5;
+ for (k=0; k<half; k++) {
+ k2 = NUM_REFS - 1 - k;
+ ref_amp_r[k] = ref_amp_l[k2] = inpos + step * k;
+ ref_amp_l[k] = ref_amp_r[k2] = 1.0 - ref_amp_r[k];
+ ref_amp_r[k2] *= inpos + 0.5;
+ }
+ }
+ else {
+ invp = 1.0 - inpos;
+ step = (0.5 - invp) / half;
+ ref_amp_l[half] = ref_amp_r[half] = 0.5;
+ for (k=0; k<half; k++) {
+ k2 = NUM_REFS - 1 - k;
+ ref_amp_l[k] = ref_amp_r[k2] = invp + step * k;
+ ref_amp_r[k] = ref_amp_l[k2] = 1.0 - ref_amp_l[k];
+ ref_amp_l[k2] *= invp + 0.5;
+ }
+ }
+
+ self->input_buffer[0][i] = in[i] * amp1;
+ self->input_buffer[1][i] = in[i] * amp2;
+ ref_buf[0] = ref_buf[1] = 0.0;
+ for (k=0; k<NUM_REFS; k++) {
+ sum_ref = self->ref_buffer[k][self->ref_in_count[k]];
+ self->ref_buffer[k][self->ref_in_count[k]] = in[i];
+ self->ref_in_count[k]++;
+ if (self->ref_in_count[k] == self->ref_size[k])
+ self->ref_in_count[k] = 0;
+ ref_buf[0] += sum_ref * ref_amp_l[k];
+ ref_buf[1] += sum_ref * ref_amp_r[k];
+ }
+ for (k=0; k<2; k++) {
+ inval = self->input_buffer[k][i] * 0.8 + self->input_buffer[1-k][i] * 0.2 + ref_buf[k] * 0.1;
+ junction = self->total_signal[k] * .25;
+ self->total_signal[k] = ref_buf[k] * self->firstRefGain;
+ for (j=0; j<8; j++) {
+ self->rnd_time[k][j] += self->rnd_timeInc[k][j];
+ if (self->rnd_time[k][j] < 0.0)
+ self->rnd_time[k][j] += 1.0;
+ else if (self->rnd_time[k][j] >= 1.0) {
+ self->rnd_time[k][j] -= 1.0;
+ self->rnd_oldValue[k][j] = self->rnd_value[k][j];
+ self->rnd_value[k][j] = self->rnd_range[k][j] * (rand()/((MYFLT)(RAND_MAX)+1)) - self->rnd_halfRange[k][j];
+ self->rnd_diff[k][j] = self->rnd_value[k][j] - self->rnd_oldValue[k][j];
+ }
+ self->rnd[k][j] = self->rnd_oldValue[k][j] + self->rnd_diff[k][j] * self->rnd_time[k][j];
+
+ xind = self->in_count[k][j] - (self->delays[k][j] + self->rnd[k][j]);
+ if (xind < 0)
+ xind += self->size[k][j];
+ ind = (int)xind;
+ frac = xind - ind;
+ x = self->buffer[k][j][ind];
+ x1 = self->buffer[k][j][ind+1];
+ val = x + (x1 - x) * frac;
+ val *= feed;
+ filt = val + (self->lastSamples[k][j] - val) * self->damp[k];
+ self->total_signal[k] += filt;
+
+ self->buffer[k][j][self->in_count[k][j]] = inval + junction - self->lastSamples[k][j];
+ self->lastSamples[k][j] = filt;
+ if(self->in_count[k][j] == 0)
+ self->buffer[k][j][self->size[k][j]] = self->buffer[k][j][0];
+ self->in_count[k][j]++;
+ if (self->in_count[k][j] >= self->size[k][j])
+ self->in_count[k][j] = 0;
+ }
+ self->buffer_streams[i+k*self->bufsize] = self->total_signal[k] * 0.25;
+ }
+ }
+}
+
+static void
+STReverb_mix_i(STReverb *self) {
+ int i, k;
+ MYFLT val;
+
+ MYFLT mix = PyFloat_AS_DOUBLE(self->mix);
+
+ if (mix < 0.0)
+ mix = 0.0;
+ else if (mix > 1.0)
+ mix = 1.0;
+
+ for (i=0; i<self->bufsize; i++) {
+ for (k=0; k<2; k++) {
+ val = self->input_buffer[k][i] + (self->buffer_streams[i+k*self->bufsize] - self->input_buffer[k][i]) * mix;
+ self->buffer_streams[i+k*self->bufsize] = val;
+ }
+ }
+}
+
+static void
+STReverb_mix_a(STReverb *self) {
+ int i, k;
+ MYFLT mix, val;
+
+ MYFLT *mi = Stream_getData((Stream *)self->mix_stream);
+
+ for (i=0; i<self->bufsize; i++) {
+ mix = mi[i];
+ if (mix < 0.0)
+ mix = 0.0;
+ else if (mix > 1.0)
+ mix = 1.0;
+
+ for (k=0; k<2; k++) {
+ val = self->input_buffer[k][i] + (self->buffer_streams[i+k*self->bufsize] - self->input_buffer[k][i]) * mix;
+ self->buffer_streams[i+k*self->bufsize] = val;
+ }
+ }
+}
+
+static void
+STReverb_setProcMode(STReverb *self)
+{
+ int procmode, mixmode;
+ procmode = self->modebuffer[0] + self->modebuffer[2] * 10;
+ mixmode = self->modebuffer[3];
+
+ switch (procmode) {
+ case 0:
+ self->proc_func_ptr = STReverb_process_ii;
+ break;
+ case 1:
+ self->proc_func_ptr = STReverb_process_ai;
+ break;
+ case 10:
+ self->proc_func_ptr = STReverb_process_ia;
+ break;
+ case 11:
+ self->proc_func_ptr = STReverb_process_aa;
+ break;
+ }
+ switch (mixmode) {
+ case 0:
+ self->mix_func_ptr = STReverb_mix_i;
+ break;
+ case 1:
+ self->mix_func_ptr = STReverb_mix_a;
+ break;
+ }
+}
+
+MYFLT *
+STReverb_getSamplesBuffer(STReverb *self)
+{
+ return (MYFLT *)self->buffer_streams;
+}
+
+static void
+STReverb_compute_next_data_frame(STReverb *self)
+{
+ (*self->proc_func_ptr)(self);
+ (*self->mix_func_ptr)(self);
+}
+
+static int
+STReverb_traverse(STReverb *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ Py_VISIT(self->inpos);
+ Py_VISIT(self->inpos_stream);
+ Py_VISIT(self->revtime);
+ Py_VISIT(self->revtime_stream);
+ Py_VISIT(self->cutoff);
+ Py_VISIT(self->cutoff_stream);
+ Py_VISIT(self->mix);
+ Py_VISIT(self->mix_stream);
+ return 0;
+}
+
+static int
+STReverb_clear(STReverb *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->input_stream);
+ Py_CLEAR(self->inpos);
+ Py_CLEAR(self->inpos_stream);
+ Py_CLEAR(self->revtime);
+ Py_CLEAR(self->revtime_stream);
+ Py_CLEAR(self->cutoff);
+ Py_CLEAR(self->cutoff_stream);
+ Py_CLEAR(self->mix);
+ Py_CLEAR(self->mix_stream);
+ return 0;
+}
+
+static void
+STReverb_dealloc(STReverb* self)
+{
+ int i, k;
+ pyo_DEALLOC
+ for (k=0; k<2; k++) {
+ free(self->input_buffer[k]);
+ for (i=0; i<8; i++) {
+ free(self->buffer[k][i]);
+ }
+ }
+ for (i=0; i<NUM_REFS; i++) {
+ free(self->ref_buffer[i]);
+ }
+ free(self->buffer_streams);
+ STReverb_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+STReverb_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i, j, k, din;
+ long maxsize;
+ MYFLT roomSize = 1.0;
+ MYFLT firstRefTmp = -3.0;
+ PyObject *inputtmp, *input_streamtmp, *inpostmp=NULL, *revtimetmp=NULL, *cutofftmp=NULL, *mixtmp=NULL;
+ STReverb *self;
+ self = (STReverb *)type->tp_alloc(type, 0);
+
+ self->inpos = PyFloat_FromDouble(0.5);
+ self->revtime = PyFloat_FromDouble(0.5);
+ self->cutoff = PyFloat_FromDouble(5000.0);
+ self->mix = PyFloat_FromDouble(0.5);
+ self->total_signal[0] = self->total_signal[1] = self->lastFreq = self->damp[0] = self->damp[1] = 0.0;
+ self->lastInpos = -1.0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+ self->modebuffer[2] = 0;
+
+ INIT_OBJECT_COMMON
+
+ self->nyquist = self->sr * 0.49;
+ self->srfac = self->sr / 44100.0;
+
+ Stream_setFunctionPtr(self->stream, STReverb_compute_next_data_frame);
+ self->mode_func_ptr = STReverb_setProcMode;
+
+ static char *kwlist[] = {"input", "inpos", "revtime", "cutoff", "mix", "roomSize", "firstRefGain", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_O_OOOOFF, kwlist, &inputtmp, &inpostmp, &revtimetmp, &cutofftmp, &mixtmp, &roomSize, &firstRefTmp))
+ Py_RETURN_NONE;
+
+ INIT_INPUT_STREAM
+
+ if (inpostmp) {
+ PyObject_CallMethod((PyObject *)self, "setInpos", "O", inpostmp);
+ }
+
+ if (revtimetmp) {
+ PyObject_CallMethod((PyObject *)self, "setRevtime", "O", revtimetmp);
+ }
+
+ if (cutofftmp) {
+ PyObject_CallMethod((PyObject *)self, "setCutoff", "O", cutofftmp);
+ }
+
+ if (mixtmp) {
+ PyObject_CallMethod((PyObject *)self, "setMix", "O", mixtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ self->firstRefGain = MYPOW(10.0, firstRefTmp * 0.05);
+ if (roomSize < 0.25)
+ roomSize = 0.25;
+ else if (roomSize > 4.0)
+ roomSize = 4.0;
+
+ self->avg_time = 0.0;
+ for (k=0; k<2; k++) {
+ din = k * 3;
+ for (i=0; i<8; i++) {
+ self->in_count[k][i] = 0;
+ self->lastSamples[k][i] = 0.0;
+ self->rnd[k][i] = self->rnd_value[k][i] = self->rnd_oldValue[k][i] = self->rnd_diff[k][i] = 0.0;
+ self->rnd_time[k][i] = 1.0;
+ self->rnd_timeInc[k][i] = reverbParams[i][2] * randomScaling / self->sr;
+ self->rnd_range[k][i] = reverbParams[i][1] * randomScaling * self->sr;
+ self->rnd_halfRange[k][i] = self->rnd_range[k][i] * 0.5;
+ self->delays[k][i] = reverbParams[i][din] * self->srfac * roomSize;
+ self->avg_time += self->delays[k][i] / self->sr;
+ self->size[k][i] = reverbParams[i][din] * self->srfac * roomSize + (int)(reverbParams[i][1] * self->sr + 0.5);
+ maxsize = reverbParams[i][din] * self->srfac * 4.0 + (int)(reverbParams[i][1] * self->sr + 0.5);
+ self->buffer[k][i] = (MYFLT *)realloc(self->buffer[k][i], (maxsize+1) * sizeof(MYFLT));
+ for (j=0; j<(maxsize+1); j++) {
+ self->buffer[k][i][j] = 0.;
+ }
+ }
+ }
+ self->avg_time /= 16.0;
+
+ for (k=0; k<NUM_REFS; k++) {
+ self->ref_in_count[k] = 0;
+ self->ref_size[k] = (int)(first_ref_delays[k] * self->srfac * roomSize + 0.5);
+ maxsize = (int)(first_ref_delays[k] * self->srfac * 4.0 + 0.5);
+ self->ref_buffer[k] = (MYFLT *)realloc(self->ref_buffer[k], (maxsize+1) * sizeof(MYFLT));
+ for (i=0; i<(maxsize+1); i++) {
+ self->ref_buffer[k][i] = 0.0;
+ }
+ }
+
+ for (k=0; k<2; k++) {
+ self->input_buffer[k] = (MYFLT *)realloc(self->input_buffer[k], self->bufsize * sizeof(MYFLT));
+ for (i=0; i<self->bufsize; i++) {
+ self->input_buffer[k][i] = 0.0;
+ }
+ }
+
+ self->buffer_streams = (MYFLT *)realloc(self->buffer_streams, 2 * self->bufsize * sizeof(MYFLT));
+ for (i=0; i<(2 * self->bufsize); i++) {
+ self->buffer_streams[i] = 0.0;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * STReverb_getServer(STReverb* self) { GET_SERVER };
+static PyObject * STReverb_getStream(STReverb* self) { GET_STREAM };
+
+static PyObject * STReverb_play(STReverb *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * STReverb_stop(STReverb *self) { STOP };
+
+static PyObject *
+STReverb_setInpos(STReverb *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->inpos);
+ if (isNumber == 1) {
+ self->inpos = PyNumber_Float(tmp);
+ self->modebuffer[0] = 0;
+ }
+ else {
+ self->inpos = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->inpos, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->inpos_stream);
+ self->inpos_stream = (Stream *)streamtmp;
+ self->modebuffer[0] = 1;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+STReverb_setRevtime(STReverb *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->revtime);
+ if (isNumber == 1) {
+ self->revtime = PyNumber_Float(tmp);
+ self->modebuffer[1] = 0;
+ }
+ else {
+ self->revtime = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->revtime, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->revtime_stream);
+ self->revtime_stream = (Stream *)streamtmp;
+ self->modebuffer[1] = 1;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+STReverb_setCutoff(STReverb *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->cutoff);
+ if (isNumber == 1) {
+ self->cutoff = PyNumber_Float(tmp);
+ self->modebuffer[2] = 0;
+ }
+ else {
+ self->cutoff = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->cutoff, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->cutoff_stream);
+ self->cutoff_stream = (Stream *)streamtmp;
+ self->modebuffer[2] = 1;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+STReverb_setMix(STReverb *self, PyObject *arg)
+{
+ PyObject *tmp, *streamtmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ tmp = arg;
+ Py_INCREF(tmp);
+ Py_DECREF(self->mix);
+ if (isNumber == 1) {
+ self->mix = PyNumber_Float(tmp);
+ self->modebuffer[3] = 0;
+ }
+ else {
+ self->mix = tmp;
+ streamtmp = PyObject_CallMethod((PyObject *)self->mix, "_getStream", NULL);
+ Py_INCREF(streamtmp);
+ Py_XDECREF(self->mix_stream);
+ self->mix_stream = (Stream *)streamtmp;
+ self->modebuffer[3] = 1;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+STReverb_setRoomSize(STReverb *self, PyObject *arg)
+{
+ int i, j, k, din;
+ long maxsize;
+ MYFLT roomSize;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ if (isNumber == 1) {
+ roomSize = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ if (roomSize < 0.25)
+ roomSize = 0.25;
+ else if (roomSize > 4.0)
+ roomSize = 4.0;
+
+ self->avg_time = 0.0;
+ for (k=0; k<2; k++) {
+ din = k * 3;
+ for (i=0; i<8; i++) {
+ self->in_count[k][i] = 0;
+ self->lastSamples[k][i] = 0.0;
+ self->rnd[k][i] = self->rnd_value[k][i] = self->rnd_oldValue[k][i] = self->rnd_diff[k][i] = 0.0;
+ self->rnd_time[k][i] = 1.0;
+ self->delays[k][i] = reverbParams[i][din] * self->srfac * roomSize;
+ self->avg_time += self->delays[k][i] / self->sr;
+ self->size[k][i] = reverbParams[i][din] * self->srfac * roomSize + (int)(reverbParams[i][1] * self->sr + 0.5);
+ maxsize = reverbParams[i][din] * self->srfac * 2 + (int)(reverbParams[i][1] * self->sr + 0.5);
+ for (j=0; j<(maxsize+1); j++) {
+ self->buffer[k][i][j] = 0.;
+ }
+ }
+ }
+ self->avg_time /= 16.0;
+
+ for (k=0; k<NUM_REFS; k++) {
+ self->ref_in_count[k] = 0;
+ self->ref_size[k] = (int)(first_ref_delays[k] * self->srfac * roomSize + 0.5);
+ maxsize = (int)(first_ref_delays[k] * self->srfac * 2 + 0.5);
+ for (i=0; i<(maxsize+1); i++) {
+ self->ref_buffer[k][i] = 0.0;
+ }
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+STReverb_setFirstRefGain(STReverb *self, PyObject *arg)
+{
+ MYFLT tmp;
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ if (isNumber == 1) {
+ tmp = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->firstRefGain = MYPOW(10.0, tmp * 0.05);
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMemberDef STReverb_members[] = {
+{"server", T_OBJECT_EX, offsetof(STReverb, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(STReverb, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(STReverb, input), 0, "Input sound object."},
+{"inpos", T_OBJECT_EX, offsetof(STReverb, inpos), 0, "Position left-right of the source."},
+{"revtime", T_OBJECT_EX, offsetof(STReverb, revtime), 0, "Reverb duration value."},
+{"cutoff", T_OBJECT_EX, offsetof(STReverb, cutoff), 0, "STReverb lowpass filter cutoff."},
+{"mix", T_OBJECT_EX, offsetof(STReverb, mix), 0, "Balance between dry and wet signals."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef STReverb_methods[] = {
+{"getServer", (PyCFunction)STReverb_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)STReverb_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)STReverb_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)STReverb_stop, METH_NOARGS, "Stops computing."},
+{"setInpos", (PyCFunction)STReverb_setInpos, METH_O, "Sets position of the source between 0 -> 1."},
+{"setRevtime", (PyCFunction)STReverb_setRevtime, METH_O, "Sets reverb duration in seconds."},
+{"setCutoff", (PyCFunction)STReverb_setCutoff, METH_O, "Sets lowpass filter cutoff."},
+{"setMix", (PyCFunction)STReverb_setMix, METH_O, "Sets balance between dry and wet signals."},
+{"setFirstRefGain", (PyCFunction)STReverb_setFirstRefGain, METH_O, "Sets gain of the first reflexions."},
+{"setRoomSize", (PyCFunction)STReverb_setRoomSize, METH_O, "Sets room size scaler."},
+{NULL} /* Sentinel */
+};
+
+PyTypeObject STReverbType = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.STReverb_base", /*tp_name*/
+sizeof(STReverb), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)STReverb_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+0, /*tp_as_number*/
+0, /*tp_as_sequence*/
+0, /*tp_as_mapping*/
+0, /*tp_hash */
+0, /*tp_call*/
+0, /*tp_str*/
+0, /*tp_getattro*/
+0, /*tp_setattro*/
+0, /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"STReverb objects. Waveguide-based reverberation network.", /* tp_doc */
+(traverseproc)STReverb_traverse, /* tp_traverse */
+(inquiry)STReverb_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+STReverb_methods, /* tp_methods */
+STReverb_members, /* tp_members */
+0, /* tp_getset */
+0, /* tp_base */
+0, /* tp_dict */
+0, /* tp_descr_get */
+0, /* tp_descr_set */
+0, /* tp_dictoffset */
+0, /* tp_init */
+0, /* tp_alloc */
+STReverb_new, /* tp_new */
+};
+
+/************************************************************************************************/
+/* STReverb streamer object */
+/************************************************************************************************/
+typedef struct {
+ pyo_audio_HEAD
+ STReverb *mainSplitter;
+ int modebuffer[2];
+ int chnl; // STRev order
+} STRev;
+
+static void STRev_postprocessing_ii(STRev *self) { POST_PROCESSING_II };
+static void STRev_postprocessing_ai(STRev *self) { POST_PROCESSING_AI };
+static void STRev_postprocessing_ia(STRev *self) { POST_PROCESSING_IA };
+static void STRev_postprocessing_aa(STRev *self) { POST_PROCESSING_AA };
+static void STRev_postprocessing_ireva(STRev *self) { POST_PROCESSING_IREVA };
+static void STRev_postprocessing_areva(STRev *self) { POST_PROCESSING_AREVA };
+static void STRev_postprocessing_revai(STRev *self) { POST_PROCESSING_REVAI };
+static void STRev_postprocessing_revaa(STRev *self) { POST_PROCESSING_REVAA };
+static void STRev_postprocessing_revareva(STRev *self) { POST_PROCESSING_REVAREVA };
+
+static void
+STRev_setProcMode(STRev *self)
+{
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = STRev_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = STRev_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = STRev_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = STRev_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = STRev_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = STRev_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = STRev_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = STRev_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = STRev_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+STRev_compute_next_data_frame(STRev *self)
+{
+ int i;
+ MYFLT *tmp;
+ int offset = self->chnl * self->bufsize;
+ tmp = STReverb_getSamplesBuffer((STReverb *)self->mainSplitter);
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = tmp[i + offset];
+ }
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+STRev_traverse(STRev *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->mainSplitter);
+ return 0;
+}
+
+static int
+STRev_clear(STRev *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->mainSplitter);
+ return 0;
+}
+
+static void
+STRev_dealloc(STRev* self)
+{
+ pyo_DEALLOC
+ STRev_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+STRev_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *maintmp=NULL, *multmp=NULL, *addtmp=NULL;
+ STRev *self;
+ self = (STRev *)type->tp_alloc(type, 0);
+
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, STRev_compute_next_data_frame);
+ self->mode_func_ptr = STRev_setProcMode;
+
+ static char *kwlist[] = {"mainSplitter", "chnl", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi|OO", kwlist, &maintmp, &self->chnl, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ Py_XDECREF(self->mainSplitter);
+ Py_INCREF(maintmp);
+ self->mainSplitter = (STReverb *)maintmp;
+
+ if (multmp) {
+ PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+ }
+
+ if (addtmp) {
+ PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+ }
+
+ PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * STRev_getServer(STRev* self) { GET_SERVER };
+static PyObject * STRev_getStream(STRev* self) { GET_STREAM };
+static PyObject * STRev_setMul(STRev *self, PyObject *arg) { SET_MUL };
+static PyObject * STRev_setAdd(STRev *self, PyObject *arg) { SET_ADD };
+static PyObject * STRev_setSub(STRev *self, PyObject *arg) { SET_SUB };
+static PyObject * STRev_setDiv(STRev *self, PyObject *arg) { SET_DIV };
+
+static PyObject * STRev_play(STRev *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * STRev_out(STRev *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * STRev_stop(STRev *self) { STOP };
+
+static PyObject * STRev_multiply(STRev *self, PyObject *arg) { MULTIPLY };
+static PyObject * STRev_inplace_multiply(STRev *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * STRev_add(STRev *self, PyObject *arg) { ADD };
+static PyObject * STRev_inplace_add(STRev *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * STRev_sub(STRev *self, PyObject *arg) { SUB };
+static PyObject * STRev_inplace_sub(STRev *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * STRev_div(STRev *self, PyObject *arg) { DIV };
+static PyObject * STRev_inplace_div(STRev *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef STRev_members[] = {
+{"server", T_OBJECT_EX, offsetof(STRev, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(STRev, stream), 0, "Stream object."},
+{"mul", T_OBJECT_EX, offsetof(STRev, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(STRev, add), 0, "Add factor."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef STRev_methods[] = {
+{"getServer", (PyCFunction)STRev_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)STRev_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)STRev_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"out", (PyCFunction)STRev_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"stop", (PyCFunction)STRev_stop, METH_NOARGS, "Stops computing."},
+{"setMul", (PyCFunction)STRev_setMul, METH_O, "Sets STRev mul factor."},
+{"setAdd", (PyCFunction)STRev_setAdd, METH_O, "Sets STRev add factor."},
+{"setSub", (PyCFunction)STRev_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)STRev_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL} /* Sentinel */
+};
+
+static PyNumberMethods STRev_as_number = {
+(binaryfunc)STRev_add, /*nb_add*/
+(binaryfunc)STRev_sub, /*nb_subtract*/
+(binaryfunc)STRev_multiply, /*nb_multiply*/
+(binaryfunc)STRev_div, /*nb_divide*/
+0, /*nb_remainder*/
+0, /*nb_divmod*/
+0, /*nb_power*/
+0, /*nb_neg*/
+0, /*nb_pos*/
+0, /*(unaryfunc)array_abs,*/
+0, /*nb_nonzero*/
+0, /*nb_invert*/
+0, /*nb_lshift*/
+0, /*nb_rshift*/
+0, /*nb_and*/
+0, /*nb_xor*/
+0, /*nb_or*/
+0, /*nb_coerce*/
+0, /*nb_int*/
+0, /*nb_long*/
+0, /*nb_float*/
+0, /*nb_oct*/
+0, /*nb_hex*/
+(binaryfunc)STRev_inplace_add, /*inplace_add*/
+(binaryfunc)STRev_inplace_sub, /*inplace_subtract*/
+(binaryfunc)STRev_inplace_multiply, /*inplace_multiply*/
+(binaryfunc)STRev_inplace_div, /*inplace_divide*/
+0, /*inplace_remainder*/
+0, /*inplace_power*/
+0, /*inplace_lshift*/
+0, /*inplace_rshift*/
+0, /*inplace_and*/
+0, /*inplace_xor*/
+0, /*inplace_or*/
+0, /*nb_floor_divide*/
+0, /*nb_true_divide*/
+0, /*nb_inplace_floor_divide*/
+0, /*nb_inplace_true_divide*/
+0, /* nb_index */
+};
+
+PyTypeObject STRevType = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.STRev_base", /*tp_name*/
+sizeof(STRev), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)STRev_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+&STRev_as_number, /*tp_as_number*/
+0, /*tp_as_sequence*/
+0, /*tp_as_mapping*/
+0, /*tp_hash */
+0, /*tp_call*/
+0, /*tp_str*/
+0, /*tp_getattro*/
+0, /*tp_setattro*/
+0, /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"STRev objects. Reads one channel from a STReverb object.", /* tp_doc */
+(traverseproc)STRev_traverse, /* tp_traverse */
+(inquiry)STRev_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+STRev_methods, /* tp_methods */
+STRev_members, /* tp_members */
+0, /* tp_getset */
+0, /* tp_base */
+0, /* tp_dict */
+0, /* tp_descr_get */
+0, /* tp_descr_set */
+0, /* tp_dictoffset */
+0, /* tp_init */
+0, /* tp_alloc */
+STRev_new, /* tp_new */
+};
diff --git a/utils/E-Pyo.py b/utils/E-Pyo.py
index e0b42f5..dfb2ae7 100755
--- a/utils/E-Pyo.py
+++ b/utils/E-Pyo.py
@@ -3,13 +3,28 @@
"""
E-Pyo is a simple text editor especially configured to edit pyo audio programs.
-You can do absolutely everything you want to with this piece of software.
+You can do absolutely everything you want with this piece of software.
Olivier Belanger - 2012
+TODO:
+ - Fix printing to pdf
+ - Output panel close button on OSX (display only)
"""
from __future__ import with_statement
-import sys, os, string, inspect, keyword, wx, codecs, subprocess, unicodedata, contextlib, StringIO, shutil, copy, pprint, random, time, threading
+import sys
+import __builtin__
+__builtin__.EPYO_APP_OPENED = True
+
+if sys.platform == "linux2":
+ import wxversion
+ if wxversion.checkInstalled("3.0"):
+ wxversion.select("3.0")
+ elif wxversion.checkInstalled("2.8"):
+ wxversion.select("2.8")
+
+import os, string, inspect, keyword, wx, codecs, subprocess, unicodedata
+import contextlib, StringIO, shutil, copy, pprint, random, time, threading
from types import UnicodeType, MethodType, ListType
from wx.lib.wordwrap import wordwrap
from wx.lib.embeddedimage import PyEmbeddedImage
@@ -17,8 +32,8 @@ import wx.lib.colourselect as csel
import wx.lib.scrolledpanel as scrolled
import wx.lib.dialogs
import wx.combo
-import wx.stc as stc
-import FlatNotebook as FNB
+import wx.stc as stc
+import wx.lib.agw.flatnotebook as FNB
from pyo import *
from PyoDoc import ManualFrame
@@ -40,6 +55,70 @@ APP_VERSION = PYO_VERSION
OSX_APP_BUNDLED = False
WIN_APP_BUNDLED = False
+################## Utility Functions ##################
+ at contextlib.contextmanager
+def stdoutIO(stdout=None):
+ old = sys.stdout
+ if stdout is None:
+ stdout = StringIO.StringIO()
+ sys.stdout = stdout
+ yield stdout
+ sys.stdout = old
+
+def convert_line_endings(temp, mode):
+ #modes: 0 - Unix, 1 - Mac, 2 - DOS
+ if mode == 0:
+ temp = string.replace(temp, '\r\n', '\n')
+ temp = string.replace(temp, '\r', '\n')
+ elif mode == 1:
+ temp = string.replace(temp, '\r\n', '\r')
+ temp = string.replace(temp, '\n', '\r')
+ elif mode == 2:
+ import re
+ temp = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", temp)
+ return temp
+
+def ensureNFD(unistr):
+ if PLATFORM in ['linux2', 'win32']:
+ encodings = [DEFAULT_ENCODING, ENCODING,
+ 'cp1252', 'iso-8859-1', 'utf-16']
+ format = 'NFC'
+ else:
+ encodings = [DEFAULT_ENCODING, ENCODING,
+ 'macroman', 'iso-8859-1', 'utf-16']
+ format = 'NFC'
+ decstr = unistr
+ if type(decstr) != UnicodeType:
+ for encoding in encodings:
+ try:
+ decstr = decstr.decode(encoding)
+ break
+ except UnicodeDecodeError:
+ continue
+ except:
+ decstr = "UnableToDecodeString"
+ print "Unicode encoding not in a recognized format..."
+ break
+ if decstr == "UnableToDecodeString":
+ return unistr
+ else:
+ return unicodedata.normalize(format, decstr)
+
+def toSysEncoding(unistr):
+ try:
+ if PLATFORM == "win32":
+ unistr = unistr.encode(ENCODING)
+ else:
+ unistr = unicode(unistr)
+ except:
+ pass
+ return unistr
+
+def hex_to_rgb(value):
+ value = value.lstrip('#')
+ lv = len(value)
+ return tuple(int(value[i:i+lv/3], 16) for i in range(0, lv, lv/3))
+
TEMP_PATH = os.path.join(os.path.expanduser('~'), '.epyo')
if not os.path.isdir(TEMP_PATH):
os.mkdir(TEMP_PATH)
@@ -49,6 +128,7 @@ if not os.path.isfile(PREFERENCES_PATH):
with open(PREFERENCES_PATH, "w") as f:
f.write("epyo_prefs = {}")
+epyo_prefs = {}
with open(PREFERENCES_PATH, "r") as f:
text = f.read()
exec text in locals()
@@ -201,7 +281,7 @@ DEFAULT_STYLE = os.path.join(STYLES_PATH, "Default")
if not os.path.isfile(os.path.join(STYLES_PATH, "Default")):
shutil.copy(os.path.join(os.getcwd(), "styles", "Default"), DEFAULT_STYLE)
if PREFERENCES.has_key("pref_style"):
- PREF_STYLE = os.path.join(STYLES_PATH, PREFERENCES["pref_style"])
+ PREF_STYLE = os.path.join(ensureNFD(STYLES_PATH), PREFERENCES["pref_style"])
else:
PREF_STYLE = DEFAULT_STYLE
@@ -216,70 +296,6 @@ if not os.path.isfile(MARKERS_FILE):
BACKGROUND_SERVER_DEFAULT_ARGS = 'sr=44100, nchnls=2, buffersize=256, duplex=1, audio="portaudio", jackname="pyo"'
BACKGROUND_SERVER_ARGS = PREFERENCES.get("background_server_args", BACKGROUND_SERVER_DEFAULT_ARGS)
-################## Utility Functions ##################
- at contextlib.contextmanager
-def stdoutIO(stdout=None):
- old = sys.stdout
- if stdout is None:
- stdout = StringIO.StringIO()
- sys.stdout = stdout
- yield stdout
- sys.stdout = old
-
-def convert_line_endings(temp, mode):
- #modes: 0 - Unix, 1 - Mac, 2 - DOS
- if mode == 0:
- temp = string.replace(temp, '\r\n', '\n')
- temp = string.replace(temp, '\r', '\n')
- elif mode == 1:
- temp = string.replace(temp, '\r\n', '\r')
- temp = string.replace(temp, '\n', '\r')
- elif mode == 2:
- import re
- temp = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", temp)
- return temp
-
-def ensureNFD(unistr):
- if PLATFORM in ['linux2', 'win32']:
- encodings = [DEFAULT_ENCODING, ENCODING,
- 'cp1252', 'latin_1', 'utf-16']
- format = 'NFC'
- else:
- encodings = [DEFAULT_ENCODING, ENCODING,
- 'macroman', 'latin_1', 'utf-16']
- format = 'NFC'
- decstr = unistr
- if type(decstr) != UnicodeType:
- for encoding in encodings:
- try:
- decstr = decstr.decode(encoding)
- break
- except UnicodeDecodeError:
- continue
- except:
- decstr = "UnableToDecodeString"
- print "Unicode encoding not in a recognized format..."
- break
- if decstr == "UnableToDecodeString":
- return unistr
- else:
- return unicodedata.normalize(format, decstr)
-
-def toSysEncoding(unistr):
- try:
- if PLATFORM == "win32":
- unistr = unistr.encode(ENCODING)
- else:
- unistr = unicode(unistr)
- except:
- pass
- return unistr
-
-def hex_to_rgb(value):
- value = value.lstrip('#')
- lv = len(value)
- return tuple(int(value[i:i+lv/3], 16) for i in range(0, lv, lv/3))
-
################## TEMPLATES ##################
HEADER_TEMPLATE = """#!/usr/bin/env python
# encoding: utf-8
@@ -378,7 +394,7 @@ class MyFrame(wx.Frame):
self.frTxt.SetLabel("Freq: %.2f" % x)
self.freqPort.value = x
-app = wx.PySimpleApp()
+app = wx.App(False)
mainFrame = MyFrame(None, title='Simple App', pos=(100,100), size=(500,300))
mainFrame.Show()
app.MainLoop()
@@ -396,14 +412,90 @@ class MyFrame(wx.Frame):
if __name__ == "__main__":
- app = wx.PySimpleApp()
+ app = wx.App(False)
mainFrame = MyFrame(None, title='Simple App', pos=(100,100), size=(500,300))
mainFrame.Show()
app.MainLoop()
'''
-TEMPLATE_NAMES = {93: "Header", 94: "Pyo", 95: "WxPython", 96: "Cecilia5", 97: "Zyne", 98: "Audio Interface"}
-TEMPLATE_DICT = {93: HEADER_TEMPLATE, 94: PYO_TEMPLATE, 95: WXPYTHON_TEMPLATE, 96: CECILIA5_TEMPLATE,
- 97: ZYNE_TEMPLATE, 98: AUDIO_INTERFACE_TEMPLATE}
+
+RADIOPYO_TEMPLATE = '''#!/usr/bin/env python
+# encoding: utf-8
+"""
+Template for a RadioPyo song (version 1.0).
+
+A RadioPyo song is a musical python script using the python-pyo
+module to create the audio processing chain. You can connect to
+the radio here : http://radiopyo.acaia.ca/
+
+There is only a few rules:
+ 1 - It must be a one-page script.
+ 2 - No soundfile, only synthesis.
+ 3 - The script must be finite in time, with fade-in and fade-out
+ to avoid clicks between pieces. Use the DURATION variable.
+
+belangeo - 2014
+
+"""
+from pyo import *
+
+################### USER-DEFINED VARIABLES ###################
+### READY is used to manage the server behaviour depending ###
+### of the context. Set this variable to True when the ###
+### music is ready for the radio. TITLE and ARTIST are the ###
+### infos shown by the radio player. DURATION set the ###
+### duration of the audio file generated for the streaming.###
+##############################################################
+READY = False # Set to True when ready for the radio
+TITLE = "Song Title" # The title of the music
+ARTIST = "Artist Name" # Your artist name
+DURATION = 300 # The duration of the music in seconds
+##################### These are optional #####################
+GENRE = "Electronic" # Kind of your music, if there is any
+DATE = 2014 # Year of creation
+
+####################### SERVER CREATION ######################
+if READY:
+ s = Server(duplex=0, audio="offline").boot()
+ s.recordOptions(dur=DURATION, filename="radiopyo.ogg", fileformat=7)
+else:
+ s = Server(duplex=0).boot()
+
+
+##################### PROCESSING SECTION #####################
+# global volume (should be used to control the overall sound)
+fade = Fader(fadein=0.001, fadeout=10, dur=DURATION).play()
+
+
+###
+### Insert your algorithms here...
+###
+
+
+#################### START THE PROCESSING ###################
+s.start()
+if not READY:
+ s.gui(locals())
+'''
+
+TEMPLATE_NAMES = {98: "Header", 97: "Pyo", 96: "WxPython", 95: "Cecilia5", 94: "Zyne", 93: "Audio Interface", 92: "RadioPyo"}
+TEMPLATE_DICT = {98: HEADER_TEMPLATE, 97: PYO_TEMPLATE, 96: WXPYTHON_TEMPLATE, 95: CECILIA5_TEMPLATE,
+ 94: ZYNE_TEMPLATE, 93: AUDIO_INTERFACE_TEMPLATE, 92: RADIOPYO_TEMPLATE}
+
+TEMPLATE_PATH = os.path.join(RESOURCES_PATH, "templates")
+if not os.path.isdir(TEMPLATE_PATH):
+ os.mkdir(TEMPLATE_PATH)
+
+templateid = 91
+template_files = sorted([f for f in os.listdir(TEMPLATE_PATH) if f.endswith(".py")])
+for f in template_files:
+ try:
+ with open(os.path.join(TEMPLATE_PATH, f)) as ftemp:
+ ftext = ftemp.read()
+ TEMPLATE_NAMES[templateid] = f.replace(".py", "")
+ TEMPLATE_DICT[templateid] = ftext
+ templateid -= 1
+ except:
+ pass
################## BUILTIN KEYWORDS COMPLETION ##################
FROM_COMP = ''' `module` import `*`
@@ -639,17 +731,21 @@ KEY_COMMANDS = {
"23. Alt + Shift + BACK": "Delete the word to the right of the caret",
"24. Ctrl/Cmd + BACK": "Delete back from the current position to the start of the line",
"25. Ctrl/Cmd + Shift + BACK": "Delete forwards from the current position to the end of the line",
-"26. TAB": "If selection is empty or all on one line replace the selection with a tab character. If more than one line selected, indent the lines. In the middle of a word, trig the AutoCompletion of pyo keywords. Just after a complete pyo keyword, insert its default arguments. Just after a complete python builtin keyword, insert a default structure snippet. Just after a variable name, representing a pyo object, followed by a dot, trig the AutoCompletion of the object's attributes.",
+"26. TAB": "If selection is empty or all on one line replace the selection with a tab character. If more than one line selected, indent the lines. In the middle of a word, trig the AutoCompletion of pyo keywords. Just after an open brace following a pyo keyword, insert its default arguments. Just after a complete python builtin keyword, insert a default structure snippet. Just after a variable name, representing a pyo object, followed by a dot, trig the AutoCompletion of the object's attributes.",
"27. Shift + TAB": "Dedent the selected lines",
"28. Alt + 'C'": "Line Copy",
"29. Alt + 'D'": "Line Duplicate",
"30. Alt + 'X'": "Line Cut",
"31. Alt + 'V'": "Line Paste",
-"32. Alt + CLICK + DRAG": "Rectangular selection"
+"32. Alt + CLICK + DRAG": "Rectangular selection",
+"33. Shit + Return": "Show the init line of a pyo object in a tooltip",
+"34. Ctrl/Cmd + Return": "Show the __doc__ string of a python object, module or function",
+"35. CLICK in the most left margin": "Add a marker to the corresponding line",
+"36. Shift + CLICK on a marker": "Delete the marker"
}
############## Allowed Extensions ##############
-ALLOWED_EXT = PREFERENCES.get("allowed_ext", ["py", "c5", "txt", "", "c", "h", "cpp", "hpp", "sh", "rst", "iss"])
+ALLOWED_EXT = PREFERENCES.get("allowed_ext", ["py", "c5", "txt", "", "c", "h", "cpp", "hpp", "sh", "rst", "iss", "sg"])
############## Pyo keywords ##############
tree = OBJECTS_TREE
@@ -685,7 +781,7 @@ elif wx.Platform == '__WXMAC__':
else:
FONT_SIZE = 8
FONT_SIZE2 = 7
- DEFAULT_FONT_FACE = 'Courier New'
+ DEFAULT_FONT_FACE = 'Monospace'
STYLES_GENERALS = ['default', 'background', 'selback', 'caret']
@@ -702,7 +798,31 @@ STYLES_LABELS = {'default': 'Foreground', 'background': 'Background', 'selback':
with open(PREF_STYLE) as f:
text = f.read()
exec text in locals()
-STYLES = copy.deepcopy(style)
+try:
+ STYLES = copy.deepcopy(style)
+except:
+ STYLES = {'background': {'colour': '#FFFFFF'},
+ 'bracebad': {'colour': '#DD0000'},
+ 'bracelight': {'colour': '#AABBDD'},
+ 'caret': {'colour': '#000000'},
+ 'class': {'bold': 1, 'colour': '#000097', 'italic': 0, 'underline': 0},
+ 'comment': {'bold': 0, 'colour': '#0066FF', 'italic': 1, 'underline': 0},
+ 'commentblock': {'bold': 0, 'colour': u'#468EFF', 'italic': 1, 'underline': 0},
+ 'default': {'bold': 0, 'colour': '#000000', 'italic': 0, 'underline': 0},
+ 'foldmarginback': {'colour': '#D0D0D0'},
+ 'function': {'bold': 1, 'colour': '#0000A2', 'italic': 0, 'underline': 0},
+ 'keyword': {'bold': 1, 'colour': '#0000FF', 'italic': 0, 'underline': 0},
+ 'lineedge': {'colour': '#DDDDDD'},
+ 'linenumber': {'bold': 0, 'colour': '#000000', 'italic': 0, 'underline': 0},
+ 'marginback': {'colour': '#B0B0B0'},
+ 'markerbg': {'colour': '#000000'},
+ 'markerfg': {'colour': '#CCCCCC'},
+ 'number': {'bold': 1, 'colour': '#0000CD', 'italic': 0, 'underline': 0},
+ 'operator': {'bold': 1, 'colour': '#000000', 'italic': 0, 'underline': 0},
+ 'pyokeyword': {'bold': 1, 'colour': '#5555FF', 'italic': 0, 'underline': 0},
+ 'selback': {'colour': '#C0DFFF'},
+ 'string': {'bold': 0, 'colour': '#036A07', 'italic': 0, 'underline': 0},
+ 'triple': {'bold': 0, 'colour': '#03BA07', 'italic': 0, 'underline': 0}}
if not STYLES.has_key('face'):
STYLES['face'] = DEFAULT_FONT_FACE
if not STYLES.has_key('size'):
@@ -739,7 +859,6 @@ class DataEvent(wx.PyEvent):
def Clone (self):
self.__class__ (self.GetId())
-
class RunningThread(threading.Thread):
def __init__(self, path, cwd, event_receiver):
threading.Thread.__init__(self)
@@ -772,30 +891,38 @@ class RunningThread(threading.Thread):
vars_to_remove = "PYTHONHOME PYTHONPATH EXECUTABLEPATH RESOURCEPATH ARGVZERO PYTHONOPTIMIZE"
prelude = "export -n %s;export PATH=/usr/local/bin:/usr/local/lib:$PATH;" % vars_to_remove
if CALLER_NEED_TO_INVOKE_32_BIT:
- self.proc = subprocess.Popen(['%s%s%s "%s"' % (prelude, SET_32_BIT_ARCH, WHICH_PYTHON, self.path)],
+ self.proc = subprocess.Popen(['%s%s%s -u "%s"' % (prelude, SET_32_BIT_ARCH, WHICH_PYTHON, self.path)],
shell=True, cwd=self.cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
else:
- self.proc = subprocess.Popen(['%s%s "%s"' % (prelude, WHICH_PYTHON, self.path)], cwd=self.cwd,
+ self.proc = subprocess.Popen(['%s%s -u "%s"' % (prelude, WHICH_PYTHON, self.path)], cwd=self.cwd,
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
elif PLATFORM == "darwin":
if CALLER_NEED_TO_INVOKE_32_BIT:
- self.proc = subprocess.Popen(['%s%s "%s"' % (SET_32_BIT_ARCH, WHICH_PYTHON, self.path)],
+ self.proc = subprocess.Popen(['%s%s -u "%s"' % (SET_32_BIT_ARCH, WHICH_PYTHON, self.path)],
shell=True, cwd=self.cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
else:
- self.proc = subprocess.Popen(['%s "%s"' % (WHICH_PYTHON, self.path)], cwd=self.cwd,
+ self.proc = subprocess.Popen(['%s -u "%s"' % (WHICH_PYTHON, self.path)], cwd=self.cwd,
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
elif PLATFORM == "win32":
- self.proc = subprocess.Popen([WHICH_PYTHON, self.path], cwd=self.cwd, shell=False,
+ self.proc = subprocess.Popen([WHICH_PYTHON, "-u", self.path], cwd=self.cwd, shell=False,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
else:
- self.proc = subprocess.Popen([WHICH_PYTHON, self.path], cwd=self.cwd,
+ self.proc = subprocess.Popen([WHICH_PYTHON, "-u", self.path], cwd=self.cwd,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ header = '=== Output log of process "%s", launched: %s ===\n' % (self.filename, time.strftime('"%d %b %Y %H:%M:%S"', time.localtime()))
+ data_event = DataEvent({"log": header, "pid": self.pid, "filename": self.filename, "active": True})
+ wx.PostEvent(self.event_receiver, data_event)
while self.proc.poll() == None and not self.terminated:
- time.sleep(.25)
+ log = ""
+ for line in self.proc.stdout.readline():
+ log = log + line
+ data_event = DataEvent({"log": log, "pid": self.pid, "filename": self.filename, "active": True})
+ wx.PostEvent(self.event_receiver, data_event)
+ sys.stdout.flush()
+ time.sleep(.025)
stdout, stderr = self.proc.communicate()
- header = '=== Output log of process "%s", launched: %s ===\n' % (self.filename, time.strftime('"%d %b %Y %H:%M:%S"', time.localtime()))
- output = header + stdout + stderr
+ output = stdout + stderr
if "StartNotification name = default" in output:
output = output.replace("StartNotification name = default", "")
if "epyo_tempfile.py" in output:
@@ -817,12 +944,12 @@ class RunningThread(threading.Thread):
pos += 1
elinepos = pos
linenum = int(output[slinepos:elinepos].strip())
- output = output[:slinepos] + str(linenum-2) + output[elinepos:]
+ output = output[:slinepos] + str(linenum-3) + output[elinepos:]
except:
pass
if self.terminated:
output = output + "\n=== Process killed. ==="
- data_event = DataEvent({"log": output, "pid": self.pid, "filename": self.filename})
+ data_event = DataEvent({"log": output, "pid": self.pid, "filename": self.filename, "active": False})
wx.PostEvent(self.event_receiver, data_event)
class KeyCommandsFrame(wx.Frame):
@@ -961,6 +1088,9 @@ class EditorPreview(stc.StyledTextCtrl):
self.SetFoldMarginHiColour(True, STYLES['foldmarginback']['colour'])
self.SetEdgeColumn(60)
+ # WxPython 3 needs the lexer to be set before folding property
+ self.SetProperty("fold", "1")
+
class ComponentPanel(scrolled.ScrolledPanel):
def __init__(self, parent, size):
scrolled.ScrolledPanel.__init__(self, parent, wx.ID_ANY, pos=(0,0), size=size, style=wx.SUNKEN_BORDER)
@@ -974,17 +1104,17 @@ class ComponentPanel(scrolled.ScrolledPanel):
box = wx.BoxSizer(wx.HORIZONTAL)
label = wx.StaticText(self, wx.ID_ANY, label=STYLES_LABELS[component])
box.Add(label, 1, wx.EXPAND|wx.TOP|wx.LEFT, 3)
- btog = wx.ToggleButton(self, wx.ID_ANY, label="B", size=(20,20))
+ btog = wx.ToggleButton(self, wx.ID_ANY, label="B", size=(24,20))
btog.SetValue(STYLES[component]['bold'])
box.Add(btog, 0, wx.TOP|wx.ALIGN_RIGHT, 1)
btog.Bind(wx.EVT_TOGGLEBUTTON, self.OnBToggleButton)
self.bTogRefs[btog] = component
- itog = wx.ToggleButton(self, wx.ID_ANY, label="I", size=(20,20))
+ itog = wx.ToggleButton(self, wx.ID_ANY, label="I", size=(24,20))
itog.SetValue(STYLES[component]['italic'])
box.Add(itog, 0, wx.TOP|wx.ALIGN_RIGHT, 1)
itog.Bind(wx.EVT_TOGGLEBUTTON, self.OnIToggleButton)
self.iTogRefs[itog] = component
- utog = wx.ToggleButton(self, wx.ID_ANY, label="U", size=(20,20))
+ utog = wx.ToggleButton(self, wx.ID_ANY, label="U", size=(24,20))
utog.SetValue(STYLES[component]['underline'])
box.Add(utog, 0, wx.TOP|wx.ALIGN_RIGHT, 1)
utog.Bind(wx.EVT_TOGGLEBUTTON, self.OnUToggleButton)
@@ -1068,7 +1198,12 @@ class ColourEditor(wx.Frame):
self.cur_style = ""
- toolbar = self.CreateToolBar()
+ self.panel = wx.Panel(self)
+ self.panel.SetAutoLayout(True)
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ self.panel.SetSizer(mainSizer)
+
+ toolbar = wx.ToolBar(self.panel, -1)
saveButton = wx.Button(toolbar, wx.ID_ANY, label="Save Style")
saveButton.Bind(wx.EVT_BUTTON, self.OnSave)
toolbar.AddControl(saveButton)
@@ -1085,25 +1220,22 @@ class ColourEditor(wx.Frame):
toolbar.AddControl(deleteButton)
toolbar.Realize()
- self.panel = wx.Panel(self)
- self.panel.SetAutoLayout(True)
- mainSizer = wx.BoxSizer(wx.VERTICAL)
- self.panel.SetSizer(mainSizer)
+ mainSizer.Add(toolbar, 0, wx.EXPAND)
enum = wx.FontEnumerator()
enum.EnumerateFacenames(fixedWidthOnly=True)
facelist = enum.GetFacenames()
facelist.sort()
- buttonData = [ (STYLES_GENERALS[0], STYLES['default']['colour'], (50, 20), STYLES_LABELS['default']),
- (STYLES_GENERALS[1], STYLES['background']['colour'], (50, 20), STYLES_LABELS['background']),
- (STYLES_GENERALS[2], STYLES['selback']['colour'], (50, 20), STYLES_LABELS['selback']),
- (STYLES_GENERALS[3], STYLES['caret']['colour'], (50, 20), STYLES_LABELS['caret']) ]
+ buttonData = [ (STYLES_GENERALS[0], STYLES['default']['colour'], (50, 24), STYLES_LABELS['default']),
+ (STYLES_GENERALS[1], STYLES['background']['colour'], (50, 24), STYLES_LABELS['background']),
+ (STYLES_GENERALS[2], STYLES['selback']['colour'], (50, 24), STYLES_LABELS['selback']),
+ (STYLES_GENERALS[3], STYLES['caret']['colour'], (50, 24), STYLES_LABELS['caret']) ]
self.buttonRefs = {}
section1Sizer = wx.BoxSizer(wx.HORIZONTAL)
- buttonSizer1 = wx.FlexGridSizer(1, 2, 25, 5)
+ buttonSizer1 = wx.FlexGridSizer(0, 2, 25, 5)
for name, color, size, label in buttonData[:2]:
b = csel.ColourSelect(self.panel, -1, "", hex_to_rgb(color), size=size)
b.Bind(csel.EVT_COLOURSELECT, self.OnSelectColour)
@@ -1112,7 +1244,7 @@ class ColourEditor(wx.Frame):
(b, 0, wx.LEFT|wx.RIGHT, 5)])
section1Sizer.Add(buttonSizer1, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP|wx.ALIGN_LEFT, 10)
section1Sizer.AddSpacer(110)
- buttonSizer2 = wx.FlexGridSizer(1, 2, 25, 5)
+ buttonSizer2 = wx.FlexGridSizer(0, 2, 25, 5)
for name, color, size, label in buttonData[2:4]:
b = csel.ColourSelect(self.panel, -1, "", hex_to_rgb(color), size=size)
b.Bind(csel.EVT_COLOURSELECT, self.OnSelectColour)
@@ -1189,7 +1321,7 @@ class ColourEditor(wx.Frame):
global STYLES
stl = event.GetString()
self.cur_style = stl
- with open(os.path.join(STYLES_PATH, stl)) as f:
+ with open(os.path.join(ensureNFD(STYLES_PATH), stl)) as f:
text = f.read()
exec text in locals()
STYLES = copy.deepcopy(style)
@@ -1294,7 +1426,7 @@ class SnippetTree(wx.Panel):
self.sizer = wx.BoxSizer(wx.VERTICAL)
toolbarbox = wx.BoxSizer(wx.HORIZONTAL)
- self.toolbar = wx.ToolBar(self, -1, size=(-1,36))
+ self.toolbar = wx.ToolBar(self, -1)
self.toolbar.SetToolBitmapSize(tsize)
self.toolbar.AddLabelTool(SNIPPET_ADD_FOLDER_ID, "Add Category", folder_add_bmp, shortHelp="Add a New Category")
self.toolbar.AddLabelTool(SNIPPET_DEL_FILE_ID, "Delete", file_add_bmp, shortHelp="Delete Snippet or Category")
@@ -1412,7 +1544,7 @@ class SnippetTree(wx.Panel):
name = self.tree.GetItemText(item)
ritem = self.tree.GetItemParent(item)
category = self.tree.GetItemText(ritem)
- self.GetParent().GetParent().onLoad(name, category)
+ self.GetParent().GetParent().onLoad(name, category)
def select(self, item):
self.tree.SelectItem(item)
@@ -1507,13 +1639,12 @@ class SnippetFrame(wx.Frame):
saveButton = wx.Button(self.toolbar, wx.ID_ANY, label="Save Snippet")
self.toolbar.AddControl(saveButton)
self.Bind(wx.EVT_BUTTON, self.onSave, id=saveButton.GetId())
-
+ self.toolbar.Realize()
+
toolbarBox.Add(self.toolbar, 1, wx.ALIGN_LEFT|wx.EXPAND|wx.LEFT, 5)
toolbar2 = wx.ToolBar(self.panel, -1)
self.tagButton = wx.Button(toolbar2, wx.ID_ANY, label="Tag Selection")
- X = self.tagButton.GetSize()[0]
- toolbar2.SetSize((X+8, 40))
toolbar2.AddControl(self.tagButton)
self.Bind(wx.EVT_BUTTON, self.onTagSelection, id=self.tagButton.GetId())
toolbar2.Realize()
@@ -1550,10 +1681,10 @@ class SnippetFrame(wx.Frame):
self.entry.InsertText(select[0], "`")
def onLoad(self, name, category):
- if os.path.isfile(os.path.join(SNIPPETS_PATH, category, name)):
+ if os.path.isfile(os.path.join(ensureNFD(SNIPPETS_PATH), category, name)):
self.snippet_name = name
self.category_name = category
- with codecs.open(os.path.join(SNIPPETS_PATH, self.category_name, self.snippet_name), "r", encoding="utf-8") as f:
+ with codecs.open(os.path.join(ensureNFD(SNIPPETS_PATH), self.category_name, self.snippet_name), "r", encoding="utf-8") as f:
text = f.read()
exec text in locals()
try:
@@ -1570,6 +1701,7 @@ class SnippetFrame(wx.Frame):
def onSave(self, evt):
dlg = wx.SingleChoiceDialog(self, 'Choose the Snippet Category',
'Snippet Category', SNIPPETS_CATEGORIES, wx.OK)
+ dlg.SetSize((250,300))
dlg.CenterOnParent()
if dlg.ShowModal() == wx.ID_OK:
category = dlg.GetStringSelection()
@@ -1765,6 +1897,14 @@ class MainFrame(wx.Frame):
EVT_DATA_EVENT(self, self.format_outputLog)
+ if sys.platform == "darwin":
+ accel_ctrl = wx.ACCEL_CMD
+ else:
+ accel_ctrl = wx.ACCEL_CTRL
+ # To set up an accelerator key
+ #aEntry = wx.AcceleratorEntry(accel_ctrl|wx.ACCEL_SHIFT, wx.WXK_UP, 602)
+ # "\t%s" % aEntry.ToString()
+
self.snippet_frame = SnippetFrame(self, title='Snippet Editor', pos=(25,25), size=(700,450))
self.style_frame = ColourEditor(self, title='Style Editor', pos=(100,100), size=(500,550))
self.style_frame.setCurrentStyle(PREF_STYLE)
@@ -1789,7 +1929,7 @@ class MainFrame(wx.Frame):
menu1.Append(wx.ID_NEW, "New\tCtrl+N")
self.Bind(wx.EVT_MENU, self.new, id=wx.ID_NEW)
self.submenu1 = wx.Menu()
- for key, name in sorted(TEMPLATE_NAMES.items()):
+ for key, name in sorted(TEMPLATE_NAMES.items(), reverse=True):
self.submenu1.Append(key, "%s Template" % name)
menu1.AppendMenu(99, "New From Template", self.submenu1)
self.Bind(wx.EVT_MENU, self.newFromTemplate, id=min(TEMPLATE_NAMES.keys()), id2=max(TEMPLATE_NAMES.keys()))
@@ -1825,11 +1965,14 @@ class MainFrame(wx.Frame):
self.Bind(wx.EVT_MENU, self.save, id=wx.ID_SAVE)
menu1.Append(wx.ID_SAVEAS, "Save As...\tShift+Ctrl+S")
self.Bind(wx.EVT_MENU, self.saveas, id=wx.ID_SAVEAS)
- menu1.AppendSeparator()
- menu1.Append(wx.ID_PREVIEW, "Print Preview")
- self.Bind(wx.EVT_MENU, self.OnPrintPreview, id=wx.ID_PREVIEW)
- menu1.Append(wx.ID_PRINT, "Print\tCtrl+P")
- self.Bind(wx.EVT_MENU, self.OnPrint, id=wx.ID_PRINT)
+ menu1.Append(100, "Save As Template...")
+ self.Bind(wx.EVT_MENU, self.saveasTemplate, id=100)
+ # TODO : printing not working well enough
+ #menu1.AppendSeparator()
+ #menu1.Append(wx.ID_PREVIEW, "Print Preview")
+ #self.Bind(wx.EVT_MENU, self.OnPrintPreview, id=wx.ID_PREVIEW)
+ #menu1.Append(wx.ID_PRINT, "Print\tCtrl+P")
+ #self.Bind(wx.EVT_MENU, self.OnPrint, id=wx.ID_PRINT)
if sys.platform != "darwin":
menu1.AppendSeparator()
prefItem = menu1.Append(wx.ID_PREFERENCES, "Preferences...\tCtrl+;")
@@ -1868,20 +2011,28 @@ class MainFrame(wx.Frame):
menu2.Append(107, "Remove Trailing White Space")
self.Bind(wx.EVT_MENU, self.removeTrailingWhiteSpace, id=107)
menu2.AppendSeparator()
- menu2.Append(103, "Collapse/Expand\tCtrl+I")
+ menu2.Append(103, "Fold All\tCtrl+I")
self.Bind(wx.EVT_MENU, self.fold, id=103)
+ menu2.Append(104, "Expand All\tShift+Ctrl+I")
+ self.Bind(wx.EVT_MENU, self.fold, id=104)
+ menu2.Append(105, "Fold/Expand Current Scope\tCtrl+8")
+ self.Bind(wx.EVT_MENU, self.foldExpandScope, id=105)
menu2.Append(108, "Un/Comment Selection\tCtrl+J")
self.Bind(wx.EVT_MENU, self.OnComment, id=108)
- menu2.Append(114, "Show AutoCompletion\tCtrl+K")
- self.Bind(wx.EVT_MENU, self.autoComp, id=114)
menu2.Append(121, "Insert File Path...\tShift+Ctrl+P")
self.Bind(wx.EVT_MENU, self.insertPath, id=121)
menu2.AppendSeparator()
- menu2.Append(170, "Convert Selection to Uppercase\tCtrl+U")
- menu2.Append(171, "Convert Selection to Lowercase\tShift+Ctrl+U")
+ menu2.Append(114, "Auto Complete container syntax", kind=wx.ITEM_CHECK)
+ self.Bind(wx.EVT_MENU, self.autoCompContainer, id=114)
+ menu2.Check(114, PREFERENCES.get("auto_comp_container", 0))
+ menu2.AppendSeparator()
+ submenu2 = wx.Menu()
+ submenu2.Append(170, "Convert Selection to Uppercase\tCtrl+U")
+ submenu2.Append(171, "Convert Selection to Lowercase\tShift+Ctrl+U")
self.Bind(wx.EVT_MENU, self.upperLower, id=170, id2=171)
- menu2.Append(172, "Convert Tabs to Spaces")
+ submenu2.Append(172, "Convert Tabs to Spaces")
self.Bind(wx.EVT_MENU, self.tabsToSpaces, id=172)
+ menu2.AppendMenu(-1, "Text Converters", submenu2)
menu2.AppendSeparator()
menu2.Append(140, "Goto line...\tCtrl+L")
self.Bind(wx.EVT_MENU, self.gotoLine, id=140)
@@ -1941,6 +2092,10 @@ class MainFrame(wx.Frame):
self.Bind(wx.EVT_MENU, self.showDocFrame, id=190)
menu4.Append(180, "Open Documentation for Pyo Object Under Caret\tCtrl+D")
self.Bind(wx.EVT_MENU, self.showDoc, id=180)
+ menu4.Append(181, "Show args for Pyo Object Under Caret\tShift+Return")
+ self.Bind(wx.EVT_MENU, self.showArgs, id=181)
+ menu4.Append(182, "Show __doc__ String for Word Under Caret\tCtrl+Return")
+ self.Bind(wx.EVT_MENU, self.showDocString, id=182)
menu4.AppendSeparator()
menu4.Append(185, "Rebuild Documentation")
self.Bind(wx.EVT_MENU, self.rebuildDoc, id=185)
@@ -1963,11 +2118,6 @@ class MainFrame(wx.Frame):
self.makeSnippetMenu()
self.menuBar.Append(self.menu7, "Snippets")
- if sys.platform == "darwin":
- accel_ctrl = wx.ACCEL_CMD
- else:
- accel_ctrl = wx.ACCEL_CTRL
-
menu8 = wx.Menu()
menu8.Append(600, "Add Marker to Current Line\tShift+Ctrl+M")
self.Bind(wx.EVT_MENU, self.addMarker, id=600)
@@ -1976,10 +2126,8 @@ class MainFrame(wx.Frame):
menu8.Append(604, "Delete All Markers")
self.Bind(wx.EVT_MENU, self.deleteAllMarkers, id=604)
menu8.AppendSeparator()
- aEntry = wx.AcceleratorEntry(accel_ctrl|wx.ACCEL_SHIFT, wx.WXK_UP, 602)
- menu8.Append(602, 'Navigate Markers Upward\t%s' % aEntry.ToString())
- aEntry = wx.AcceleratorEntry(accel_ctrl|wx.ACCEL_SHIFT, wx.WXK_DOWN, 603)
- menu8.Append(603, 'Navigate Markers Downward\t%s' % aEntry.ToString())
+ menu8.Append(602, 'Navigate Markers Upward\tCtrl+9')
+ menu8.Append(603, 'Navigate Markers Downward\tCtrl+0')
self.Bind(wx.EVT_MENU, self.navigateMarkers, id=602, id2=603)
self.menuBar.Append(menu8, "Markers")
@@ -2028,22 +2176,23 @@ class MainFrame(wx.Frame):
self.SetMenuBar(self.menuBar)
+ self.status = self.CreateStatusBar()
+ self.status.Bind(wx.EVT_SIZE, self.StatusOnSize)
+ self.status.SetFieldsCount(3)
+
if PLATFORM == "darwin":
ststyle = wx.TE_PROCESS_ENTER|wx.NO_BORDER
- sth = 17
+ sth = self.status.GetSize()[1] #16
cch = -1
elif PLATFORM == "linux2":
ststyle = wx.TE_PROCESS_ENTER|wx.SIMPLE_BORDER
- sth = 20
- cch = 21
+ sth = self.status.GetSize()[1]+1 #20
+ cch = self.status.GetSize()[1] #21
elif PLATFORM == "win32":
ststyle = wx.TE_PROCESS_ENTER|wx.SIMPLE_BORDER
sth = 20
cch = 20
- self.status = self.CreateStatusBar()
- self.status.Bind(wx.EVT_SIZE, self.StatusOnSize)
- self.status.SetFieldsCount(3)
self.field1X, field1Y = self.status.GetTextExtent("Quick Search:")
self.status.SetStatusWidths([self.field1X+9,-1,-2])
self.status.SetStatusText("Quick Search:", 0)
@@ -2080,11 +2229,11 @@ class MainFrame(wx.Frame):
yoff1 = -1
yoff2 = -5
elif PLATFORM == "linux2":
- yoff1 = 1
- yoff2 = 0
- elif PLATFORM == "win32":
yoff1 = -2
- yoff2 = -2
+ yoff2 = -1
+ elif PLATFORM == "win32":
+ yoff1 = 0
+ yoff2 = -1
self.status.SetStatusText("Quick Search:", 0)
rect = self.status.GetFieldRect(1)
@@ -2118,6 +2267,7 @@ class MainFrame(wx.Frame):
def makeSnippetMenu(self):
itemId = 30000
+ accel_entries = []
for cat in SNIPPETS_CATEGORIES:
submenu = wx.Menu(title=cat)
files = [f for f in os.listdir(os.path.join(SNIPPETS_PATH, cat))]
@@ -2147,6 +2297,7 @@ class MainFrame(wx.Frame):
short = short.replace("-", "")
if short != "":
accel_tuple = wx.AcceleratorEntry(accel, ord(short), itemId)
+ accel_entries.append(accel_tuple)
short = accel_tuple.ToString()
submenu.Append(itemId, "%s\t%s" % (file, short))
else:
@@ -2155,6 +2306,10 @@ class MainFrame(wx.Frame):
itemId += 1
self.menu7.AppendMenu(itemId, cat, submenu)
itemId += 1
+ if accel_entries != []:
+ accel_table = wx.AcceleratorTable(accel_entries)
+ self.SetAcceleratorTable(accel_table)
+
self.menu7.AppendSeparator()
self.menu7.Append(51, "Open Snippet Editor")
self.Bind(wx.EVT_MENU, self.showSnippetEditor, id=51)
@@ -2294,7 +2449,6 @@ class MainFrame(wx.Frame):
def addMarker(self, evt):
line = self.panel.editor.GetCurrentLine()
self.panel.editor.addMarker(line)
- self.panel.editor.addMarkerComment(line)
def deleteMarker(self, evt):
line = self.panel.editor.GetCurrentLine()
@@ -2317,25 +2471,37 @@ class MainFrame(wx.Frame):
val = int(dlg.GetValue())
except:
val = -1
- dlg.Destroy()
+ dlg.Destroy()
if val != -1:
- pos = self.panel.editor.FindColumn(val-1, 0)
- self.panel.editor.SetCurrentPos(pos)
- self.panel.editor.EnsureVisible(val)
- self.panel.editor.EnsureCaretVisible()
+ val -= 1
+ pos = self.panel.editor.FindColumn(val, 0)
+ self.panel.editor.GotoLine(val)
+ first = self.panel.editor.GetFirstVisibleLine()
+ if val == first:
+ self.panel.editor.LineScroll(0, -self.panel.editor.LinesOnScreen()/2)
+ else:
+ self.panel.editor.LineScroll(0, self.panel.editor.LinesOnScreen()/2)
+ #self.panel.editor.SetCurrentPos(pos)
+ #self.panel.editor.EnsureVisible(val)
+ #self.panel.editor.EnsureCaretVisible()
wx.CallAfter(self.panel.editor.SetAnchor, pos)
def OnComment(self, evt):
self.panel.editor.OnComment()
def fold(self, event):
- self.panel.editor.FoldAll()
+ if event.GetId() == 103:
+ self.panel.editor.FoldAll()
+ else:
+ self.panel.editor.ExpandAll()
- def autoComp(self, evt):
- try:
- self.panel.editor.showAutoComp()
- except AttributeError:
- pass
+ def foldExpandScope(self, evt):
+ self.panel.editor.foldExpandCurrentScope()
+
+ def autoCompContainer(self, evt):
+ state = evt.GetInt()
+ PREFERENCES["auto_comp_container"] = state
+ self.panel.editor.showAutoCompContainer(state)
def showFind(self, evt):
self.panel.editor.OnShowFindReplace()
@@ -2444,20 +2610,24 @@ class MainFrame(wx.Frame):
paths = dlg.GetPaths()
if len(paths) == 1:
text = ensureNFD(paths[0])
+ if PLATFORM == "win32":
+ text = text.replace("\\", "/")
self.panel.editor.ReplaceSelection("'" + text + "'")
else:
text = ", ".join(["'"+ensureNFD(path)+"'" for path in paths])
+ if PLATFORM == "win32":
+ text = text.replace("\\", "/")
self.panel.editor.ReplaceSelection("[" + text + "]")
PREFERENCES["insert_path"] = os.path.split(paths[0])[0]
dlg.Destroy()
def insertSnippet(self, evt):
id = evt.GetId()
- menu = self.menu7 #event.GetEventObject()
+ menu = self.menu7
item = menu.FindItemById(id)
name = item.GetLabel()
category = item.GetMenu().GetTitle()
- with codecs.open(os.path.join(SNIPPETS_PATH, category, name), "r", encoding="utf-8") as f:
+ with codecs.open(os.path.join(ensureNFD(SNIPPETS_PATH), category, name), "r", encoding="utf-8") as f:
text = f.read()
exec text in locals()
self.panel.editor.insertSnippet(snippet["value"])
@@ -2474,7 +2644,7 @@ class MainFrame(wx.Frame):
def setStyle(self, st, fromMenu=False):
global STYLES
- with open(os.path.join(STYLES_PATH, st)) as f:
+ with open(os.path.join(ensureNFD(STYLES_PATH), st)) as f:
text = f.read()
exec text in locals()
STYLES = copy.deepcopy(style)
@@ -2654,7 +2824,7 @@ class MainFrame(wx.Frame):
item = menu.FindItemById(id)
filename = item.GetLabel()
folder = item.GetMenu().GetTitle()
- path = os.path.join(EXAMPLE_PATH, folder, filename)
+ path = os.path.join(ensureNFD(EXAMPLE_PATH), folder, filename)
self.panel.addPage(ensureNFD(path))
def openTutorial(self, event):
@@ -2707,12 +2877,28 @@ class MainFrame(wx.Frame):
PREFERENCES["save_file_path"] = os.path.split(path)[0]
dlg.Destroy()
+ def saveasTemplate(self, event):
+ dlg = wx.TextEntryDialog(self, 'Give a name to your template:', 'Save file as template...')
+ if dlg.ShowModal() == wx.ID_OK:
+ fname = dlg.GetValue()
+ if not fname.endswith(".py"):
+ fname = fname + ".py"
+ try:
+ text = self.panel.editor.GetTextUTF8()
+ except:
+ text = self.panel.editor.GetText()
+ with open(os.path.join(TEMPLATE_PATH, fname), "w") as f:
+ f.write(text)
+ dlg.Destroy()
+
def close(self, event):
action = self.panel.editor.close()
if action == 'delete':
+ self.panel.close_from_menu = True
self.panel.deletePage()
else:
pass
+ self.panel.close_from_menu = False
def closeAll(self, event):
count = self.panel.notebook.GetPageCount()
@@ -2745,8 +2931,9 @@ class MainFrame(wx.Frame):
def format_outputLog(self, evt):
data = evt.data
- self.panel.outputlog.setLog(data["log"])
- self.panel.outputlog.removeProcess(data["pid"], data["filename"])
+ self.panel.outputlog.appendToLog(data["log"])
+ if not data["active"]:
+ self.panel.outputlog.removeProcess(data["pid"], data["filename"])
def run(self, path):
cwd = self.getCurrentWorkingDirectory()
@@ -2810,6 +2997,7 @@ class MainFrame(wx.Frame):
self.panel.editor.addText(s.getvalue())
def startStopBackgroundServer(self, evt):
+ # TODO: need to add midi output driver
if not self.back_server_started:
outDriverIndex = -1
preferedDriver = PREFERENCES.get("background_server_out_device", "")
@@ -2866,15 +3054,25 @@ class MainFrame(wx.Frame):
self.sendToServerItem.Enable(False)
def sendSelectionToBackgroundServer(self, evt):
+ end = None
text = self.panel.editor.GetSelectedTextUTF8()
if text == "":
pos = self.panel.editor.GetCurrentPos()
line = self.panel.editor.LineFromPosition(pos)
text = self.panel.editor.GetLineUTF8(line)
+ else:
+ end = self.panel.editor.GetSelectionEnd()
if self.server_pipe != None:
for line in text.splitlines():
self.server_pipe.write(line + "\n")
self.server_pipe.write("\n")
+ if end != None:
+ self.panel.editor.SetCurrentPos(end)
+ self.panel.editor.LineDown()
+ line = self.panel.editor.GetCurrentLine()
+ pos = self.panel.editor.PositionFromLine(line)
+ self.panel.editor.SetCurrentPos(pos)
+ self.panel.editor.SetSelectionEnd(pos)
def buildDoc(self):
self.doc_frame = ManualFrame(osx_app_bundled=OSX_APP_BUNDLED, which_python=WHICH_PYTHON,
@@ -2899,6 +3097,12 @@ class MainFrame(wx.Frame):
except:
pass
self.buildDoc()
+
+ def showArgs(self, evt):
+ self.panel.editor.onShowTip()
+
+ def showDocString(self, evt):
+ self.panel.editor.onShowDocString()
def onShowEditorKeyCommands(self, evt):
if not self.keyCommandsFrame.IsShown():
@@ -2980,6 +3184,7 @@ class MainPanel(wx.Panel):
wx.Panel.__init__(self, parent, size=size, style=wx.SUNKEN_BORDER)
self.new_inc = 0
+ self.close_from_menu = False
self.mainFrame = parent
mainBox = wx.BoxSizer(wx.HORIZONTAL)
@@ -2988,13 +3193,12 @@ class MainPanel(wx.Panel):
self.left_splitter = wx.SplitterWindow(self.splitter, -1, style=wx.SP_LIVE_UPDATE|wx.SP_3DSASH)
self.right_splitter = wx.SplitterWindow(self.splitter, -1, style=wx.SP_LIVE_UPDATE|wx.SP_3DSASH)
- #self.right_splitter.SetMinimumPaneSize(150)
self.project = ProjectTree(self.left_splitter, self, (-1, -1))
self.markers = MarkersPanel(self.left_splitter, self, (-1, -1))
- self.notebook = FNB.FlatNotebook(self.right_splitter, size=(-1,-1),
- style=FNB.FNB_FF2|FNB.FNB_X_ON_TAB|FNB.FNB_NO_X_BUTTON|FNB.FNB_DROPDOWN_TABS_LIST|FNB.FNB_HIDE_ON_SINGLE_TAB)
+ self.notebook = FNB.FlatNotebook(self.right_splitter, size=(-1,-1))
+ self.notebook.SetAGWWindowStyleFlag(FNB.FNB_FF2|FNB.FNB_X_ON_TAB|FNB.FNB_NO_X_BUTTON|FNB.FNB_DROPDOWN_TABS_LIST|FNB.FNB_HIDE_ON_SINGLE_TAB)
self.addNewPage()
self.outputlog = OutputLogPanel(self.right_splitter, self, size=(-1,150))
@@ -3006,8 +3210,8 @@ class MainPanel(wx.Panel):
mainBox.Add(self.splitter, 1, wx.EXPAND)
self.SetSizer(mainBox)
- self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.onPageChange)
- self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CLOSING, self.onClosingPage)
+ self.notebook.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.onPageChange)
+ self.notebook.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CLOSING, self.onClosingPage)
def addNewPage(self):
title = "Untitled-%i.py" % self.new_inc
@@ -3035,6 +3239,11 @@ class MainPanel(wx.Panel):
except:
continue
editor.setText(ensureNFD(text))
+
+ # Scan the entire document (needed for FoldAll to fold everything)
+ editor.GotoLine(editor.GetLineCount())
+ wx.CallAfter(editor.GotoLine, 0)
+
editor.path = file
editor.saveMark = True
editor.EmptyUndoBuffer()
@@ -3057,7 +3266,10 @@ class MainPanel(wx.Panel):
self.editor.setMarkers(copy.deepcopy(markers))
def onClosingPage(self, evt):
- action = self.editor.closeNoCancel()
+ if not self.close_from_menu:
+ action = self.editor.close()
+ if action == "keep":
+ evt.Veto()
def deletePage(self):
select = self.notebook.GetSelection()
@@ -3097,6 +3309,22 @@ class MainPanel(wx.Panel):
ed = self.notebook.GetPage(i)
ed.Close()
+#######################################################
+### The idea of EditorPanel is to allow multiple views
+### at the same time in a single notebook page.
+### Also: A tree view of classes and functions of the file
+### Not yet implemented... ( TODO )
+#######################################################
+class EditorPanel(wx.Panel):
+ def __init__(self, parent):
+ wx.Panel.__init__(self, parent, -1)
+ self.editor = Editor(parent, -1, size=(0, -1))
+ self.editor2 = Editor(parent, -1, size=(0, -1))
+ box = wx.BoxSizer(wx.HORIZONTAL)
+ box.Add(self.editor, 1, wx.ALL|wx.EXPAND, 5)
+ box.Add(self.editor2, 1, wx.ALL|wx.EXPAND, 5)
+ self.SetSizerAndFit(box)
+
class Editor(stc.StyledTextCtrl):
def __init__(self, parent, ID, pos=wx.DefaultPosition, size=wx.DefaultSize, style= wx.NO_BORDER | wx.WANTS_CHARS,
setTitle=None, getTitle=None):
@@ -3122,6 +3350,8 @@ class Editor(stc.StyledTextCtrl):
self.markers_dict = {}
self.current_marker = -1
self.objs_attr_dict = {}
+ self.auto_comp_container = PREFERENCES.get("auto_comp_container", 0)
+
self.alphaStr = string.lowercase + string.uppercase + '0123456789'
@@ -3168,22 +3398,16 @@ class Editor(stc.StyledTextCtrl):
self.SetMarginSensitive(2, True)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
+ self.Bind(wx.EVT_CHAR, self.OnChar)
self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
self.Bind(wx.EVT_CLOSE, self.OnClose)
- self.Bind(wx.EVT_FIND, self.OnFind)
- self.Bind(wx.EVT_FIND_NEXT, self.OnFind)
- self.Bind(wx.EVT_FIND_REPLACE, self.OnFind)
- self.Bind(wx.EVT_FIND_REPLACE_ALL, self.OnFind)
- self.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
self.EmptyUndoBuffer()
self.SetFocus()
self.setStyle()
# Remove unwanted KeyCommands
- self.CmdKeyClear(stc.STC_KEY_UP, stc.STC_SCMOD_CTRL)
- self.CmdKeyClear(stc.STC_KEY_DOWN, stc.STC_SCMOD_CTRL)
self.CmdKeyClear(stc.STC_KEY_RIGHT, stc.STC_SCMOD_ALT)
self.CmdKeyClear(stc.STC_KEY_LEFT, stc.STC_SCMOD_ALT)
self.CmdKeyClear(stc.STC_KEY_RIGHT, stc.STC_SCMOD_SHIFT | stc.STC_SCMOD_ALT)
@@ -3192,20 +3416,10 @@ class Editor(stc.StyledTextCtrl):
self.CmdKeyClear(stc.STC_KEY_LEFT, stc.STC_SCMOD_CTRL)
self.CmdKeyClear(stc.STC_KEY_RIGHT, stc.STC_SCMOD_SHIFT | stc.STC_SCMOD_CTRL)
self.CmdKeyClear(stc.STC_KEY_LEFT, stc.STC_SCMOD_SHIFT | stc.STC_SCMOD_CTRL)
- self.CmdKeyClear(stc.STC_KEY_HOME, 0)
- self.CmdKeyClear(stc.STC_KEY_HOME, stc.STC_SCMOD_ALT)
- self.CmdKeyClear(stc.STC_KEY_HOME, stc.STC_SCMOD_CTRL)
- self.CmdKeyClear(stc.STC_KEY_HOME, stc.STC_SCMOD_SHIFT)
- self.CmdKeyClear(stc.STC_KEY_HOME, stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT)
- self.CmdKeyClear(stc.STC_KEY_HOME, stc.STC_SCMOD_CTRL | stc.STC_SCMOD_SHIFT)
- self.CmdKeyClear(stc.STC_KEY_END, 0)
- self.CmdKeyClear(stc.STC_KEY_END, stc.STC_SCMOD_ALT)
- self.CmdKeyClear(stc.STC_KEY_END, stc.STC_SCMOD_CTRL)
- self.CmdKeyClear(stc.STC_KEY_END, stc.STC_SCMOD_SHIFT)
- self.CmdKeyClear(stc.STC_KEY_END, stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT)
- self.CmdKeyClear(stc.STC_KEY_END, stc.STC_SCMOD_CTRL | stc.STC_SCMOD_SHIFT)
self.CmdKeyClear(stc.STC_KEY_DELETE, 0)
self.CmdKeyClear(stc.STC_KEY_DELETE, stc.STC_SCMOD_SHIFT)
+ self.CmdKeyClear(stc.STC_KEY_DELETE, stc.STC_SCMOD_CTRL)
+ self.CmdKeyClear(stc.STC_KEY_DELETE, stc.STC_SCMOD_SHIFT | stc.STC_SCMOD_CTRL)
self.CmdKeyClear(stc.STC_KEY_BACK, stc.STC_SCMOD_ALT)
self.CmdKeyClear(stc.STC_KEY_BACK, stc.STC_SCMOD_SHIFT)
self.CmdKeyClear(stc.STC_KEY_BACK, stc.STC_SCMOD_CTRL)
@@ -3213,22 +3427,19 @@ class Editor(stc.StyledTextCtrl):
self.CmdKeyClear(stc.STC_KEY_INSERT, 0)
self.CmdKeyClear(stc.STC_KEY_INSERT, stc.STC_SCMOD_SHIFT)
self.CmdKeyClear(stc.STC_KEY_INSERT, stc.STC_SCMOD_CTRL)
- self.CmdKeyClear(ord('Z'), stc.STC_SCMOD_CTRL)
self.CmdKeyClear(ord('Y'), stc.STC_SCMOD_CTRL)
- self.CmdKeyClear(ord('X'), stc.STC_SCMOD_CTRL)
- self.CmdKeyClear(ord('C'), stc.STC_SCMOD_CTRL)
- self.CmdKeyClear(ord('V'), stc.STC_SCMOD_CTRL)
- self.CmdKeyClear(ord('A'), stc.STC_SCMOD_CTRL)
+ self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
- self.CmdKeyClear(ord('U'), stc.STC_SCMOD_CTRL)
self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL | stc.STC_SCMOD_SHIFT)
- self.CmdKeyClear(ord('U'), stc.STC_SCMOD_CTRL | stc.STC_SCMOD_SHIFT)
self.CmdKeyClear(stc.STC_KEY_RETURN, stc.STC_SCMOD_SHIFT)
self.CmdKeyClear(stc.STC_KEY_ADD, stc.STC_SCMOD_CTRL)
self.CmdKeyClear(stc.STC_KEY_SUBTRACT, stc.STC_SCMOD_CTRL)
self.CmdKeyClear(stc.STC_KEY_DIVIDE, stc.STC_SCMOD_CTRL)
+ self.CmdKeyAssign(ord('U'), stc.STC_SCMOD_CTRL, stc.STC_CMD_UPPERCASE)
+ self.CmdKeyAssign(ord('U'), stc.STC_SCMOD_CTRL | stc.STC_SCMOD_SHIFT, stc.STC_CMD_LOWERCASE)
+
wx.CallAfter(self.SetAnchor, 0)
self.Refresh()
@@ -3248,6 +3459,7 @@ class Editor(stc.StyledTextCtrl):
if STYLES[forekey]['underline']:
st += ",underline"
return st
+
self.StyleSetSpec(stc.STC_STYLE_DEFAULT, buildStyle('default', 'background'))
self.StyleClearAll() # Reset all to be like the default
@@ -3266,8 +3478,23 @@ class Editor(stc.StyledTextCtrl):
self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, buildStyle('default', 'bracebad') + ",bold")
ext = os.path.splitext(self.path)[1].strip(".")
+ if ext == "":
+ try:
+ with open(self.path, "r") as f:
+ fline = f.readline()
+ if fline.startswith("#!"):
+ fline = fline.replace("/", " ")
+ last = fline.split()[-1]
+ ext = {"python": "py", "bash": "sh", "sh": "sh"}.get(last, "")
+ else:
+ text = f.read()
+ if "desc:" in text:
+ ext = "jsfx"
+ except:
+ pass
if ext in ["py", "pyw", "c5"]:
self.SetLexer(stc.STC_LEX_PYTHON)
+ self.SetStyleBits(self.GetStyleBitsNeeded())
self.SetKeyWords(0, " ".join(keyword.kwlist) + " None True False ")
self.SetKeyWords(1, " ".join(PYO_WORDLIST))
self.StyleSetSpec(stc.STC_P_DEFAULT, buildStyle('default'))
@@ -3286,6 +3513,11 @@ class Editor(stc.StyledTextCtrl):
self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, buildStyle('commentblock'))
elif ext in ["c", "cc", "cpp", "cxx", "cs", "h", "hh", "hpp", "hxx"]:
self.SetLexer(stc.STC_LEX_CPP)
+ self.SetStyleBits(self.GetStyleBitsNeeded())
+ self.SetProperty('fold.comment', '1')
+ self.SetProperty('fold.preprocessor', '1')
+ self.SetProperty('fold.compact', '1')
+ self.SetProperty('styling.within.preprocessor', '0')
self.SetKeyWords(0, "auto break case char const continue default do double else enum extern float for goto if int long \
register return short signed sizeof static struct switch typedef union unsigned void volatile while ")
self.StyleSetSpec(stc.STC_C_DEFAULT, buildStyle('default'))
@@ -3302,6 +3534,7 @@ class Editor(stc.StyledTextCtrl):
self.StyleSetSpec(stc.STC_C_PREPROCESSOR, buildStyle('commentblock'))
elif ext == "sh":
self.SetLexer(stc.STC_LEX_BASH)
+ self.SetStyleBits(self.GetStyleBitsNeeded())
self.SetKeyWords(0, "! [[ ]] case do done elif else esac fi for function if in select then time until while { } \
alias bg bind break builtin caller cd command compgen complete compopt continue declare dirs disown echo enable \
eval exec exit export fc fg getopts hash help history jobs kill let local logout mapfile popd printf pushd pwd \
@@ -3316,12 +3549,53 @@ class Editor(stc.StyledTextCtrl):
self.StyleSetSpec(stc.STC_SH_IDENTIFIER, buildStyle('default'))
self.StyleSetSpec(stc.STC_SH_PARAM, buildStyle('default'))
self.StyleSetSpec(stc.STC_SH_SCALAR, buildStyle('function'))
+ elif ext in ["jsfx", "jsfx-inc"]:
+ self.SetLexer(stc.STC_LEX_CPP)
+ self.SetStyleBits(self.GetStyleBitsNeeded())
+ self.SetProperty('fold.comment', '1')
+ self.SetProperty('fold.preprocessor', '1')
+ self.SetProperty('fold.compact', '1')
+ self.SetProperty('styling.within.preprocessor', '0')
+ self.SetKeyWords(1, "abs acos asin atan atan2 atexit ceil convolve_c cos defer eval exp fclose feof fflush \
+ fft fft_ipermute fft_permute fgetc floor fopen fprintf fread freembuf fseek ftell fwrite \
+ gfx_aaaaa gfx_arc gfx_blit gfx_blit gfx_blitext gfx_blurto gfx_circle gfx_deltablit \
+ gfx_drawchar gfx_drawnumber gfx_drawstr gfx_getchar gfx_getfont gfx_getimgdim gfx_getpixel \
+ gfx_gradrect gfx_init gfx_line gfx_lineto gfx_loadimg gfx_measurestr gfx_muladdrect gfx_printf \
+ gfx_quit gfx_rect gfx_rectto gfx_roundrect gfx_setfont gfx_setimgdim gfx_setpixel gfx_transformblit \
+ gfx_update ifft invsqrt log log10 match matchi max memcpy memset min pow printf rand sign sin sleep \
+ sprintf sqr sqrt stack_exch stack_peek stack_pop stack_push str_delsub str_getchar str_insert \
+ str_setchar str_setlen strcat strcmp strcpy strcpy_from strcpy_substr stricmp strlen strncat strncmp \
+ strncpy strnicmp tan tcp_close tcp_connect tcp_listen tcp_listen_end tcp_recv tcp_send tcp_set_block \
+ time time_precise")
+ self.SetKeyWords(0, "loop while function local static instance this global globals _global gfx_r gfx_g gfx_b gfx_a gfx_w \
+ gfx_h gfx_x gfx_y gfx_mode gfx_clear gfx_dest gfx_texth mouse_x mouse_y mouse_cap mouse_wheel mouse_hwheel \
+ @init @slider @sample @block @serialize @gfx import desc slider1 slider2 slider3 slider4 slider5 \
+ slider6 slider7 slider8 slider9 slider10 slider11 slider12 slider13 slider14 slider15 slider16 in_pin \
+ out_pin filename ")
+ self.StyleSetSpec(stc.STC_C_DEFAULT, buildStyle('default'))
+ self.StyleSetSpec(stc.STC_C_COMMENT, buildStyle('comment'))
+ self.StyleSetSpec(stc.STC_C_COMMENTDOC, buildStyle('comment'))
+ self.StyleSetSpec(stc.STC_C_COMMENTLINE, buildStyle('comment'))
+ self.StyleSetSpec(stc.STC_C_COMMENTLINEDOC, buildStyle('comment'))
+ self.StyleSetSpec(stc.STC_C_NUMBER, buildStyle('number'))
+ self.StyleSetSpec(stc.STC_C_STRING, buildStyle('string'))
+ self.StyleSetSpec(stc.STC_C_CHARACTER, buildStyle('string'))
+ self.StyleSetSpec(stc.STC_C_WORD, buildStyle('keyword'))
+ self.StyleSetSpec(stc.STC_C_WORD2, buildStyle('pyokeyword'))
+ self.StyleSetSpec(stc.STC_C_OPERATOR, buildStyle('operator'))
+ self.StyleSetSpec(stc.STC_C_IDENTIFIER, buildStyle('default'))
+ self.StyleSetSpec(stc.STC_C_PREPROCESSOR, buildStyle('commentblock'))
self.SetEdgeColour(STYLES["lineedge"]['colour'])
self.SetCaretForeground(STYLES['caret']['colour'])
self.SetSelBackground(1, STYLES['selback']['colour'])
self.SetFoldMarginColour(True, STYLES['foldmarginback']['colour'])
self.SetFoldMarginHiColour(True, STYLES['foldmarginback']['colour'])
+ self.CallTipSetForeground(STYLES['default']['colour'])
+ self.CallTipSetBackground(STYLES['background']['colour'])
+
+ # WxPython 3 needs the lexer to be set before folding property
+ self.SetProperty("fold", "1")
def OnQuickSearch(self, str, next=True):
if self.GetSelection() != (0,0):
@@ -3348,10 +3622,14 @@ class Editor(stc.StyledTextCtrl):
self.ScrollToLine(line - halfNumLinesOnScreen)
def OnShowFindReplace(self):
- data = wx.FindReplaceData()
- self.findReplace = wx.FindReplaceDialog(self, data, "Find & Replace", wx.FR_REPLACEDIALOG | wx.FR_NOUPDOWN)
- self.findReplace.data = data # save a reference to it...
- self.findReplace.Show(True)
+ self.data = wx.FindReplaceData()
+ dlg = wx.FindReplaceDialog(self, self.data, "Find & Replace", wx.FR_REPLACEDIALOG | wx.FR_NOUPDOWN)
+ dlg.Bind(wx.EVT_FIND, self.OnFind)
+ dlg.Bind(wx.EVT_FIND_NEXT, self.OnFind)
+ dlg.Bind(wx.EVT_FIND_REPLACE, self.OnFind)
+ dlg.Bind(wx.EVT_FIND_REPLACE_ALL, self.OnFind)
+ dlg.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
+ dlg.Show(True)
def OnFind(self, evt):
map = { wx.wxEVT_COMMAND_FIND : "FIND",
@@ -3359,41 +3637,50 @@ class Editor(stc.StyledTextCtrl):
wx.wxEVT_COMMAND_FIND_REPLACE : "REPLACE",
wx.wxEVT_COMMAND_FIND_REPLACE_ALL : "REPLACE_ALL" }
- et = evt.GetEventType()
+ evtType = evt.GetEventType()
findTxt = evt.GetFindString()
+ newTxt = evt.GetReplaceString()
+ findStrLen = len(findTxt)
+ newStrLen = len(newTxt)
+ diffLen = newStrLen - findStrLen
selection = self.GetSelection()
if selection[0] == selection[1]:
selection = (0, self.GetLength())
- if map[et] == 'FIND':
+ if map[evtType] == 'FIND':
startpos = self.FindText(selection[0], selection[1], findTxt, evt.GetFlags())
endpos = startpos+len(findTxt)
self.anchor1 = endpos
self.anchor2 = selection[1]
self.SetSelection(startpos, endpos)
- elif map[et] == 'FIND_NEXT':
+ elif map[evtType] == 'FIND_NEXT':
startpos = self.FindText(self.anchor1, self.anchor2, findTxt, evt.GetFlags())
endpos = startpos+len(findTxt)
self.anchor1 = endpos
self.SetSelection(startpos, endpos)
- elif map[et] == 'REPLACE':
- startpos = self.FindText(selection[0], selection[1], findTxt)
- endpos = startpos+len(findTxt)
+ elif map[evtType] == 'REPLACE':
+ startpos = self.FindText(selection[0], selection[1], findTxt, evt.GetFlags())
if startpos != -1:
+ endpos = startpos+len(findTxt)
self.SetSelection(startpos, endpos)
- self.ReplaceSelection(evt.GetReplaceString())
- elif map[et] == 'REPLACE_ALL':
- self.anchor1 = selection[0]
+ self.ReplaceSelection(newTxt)
+ self.anchor1 = startpos + newStrLen + 1
+ self.anchor2 += diffLen
+ elif map[evtType] == 'REPLACE_ALL':
+ self.anchor1 = startpos = selection[0]
self.anchor2 = selection[1]
- startpos = selection[0]
while startpos != -1:
- startpos = self.FindText(self.anchor1, self.anchor2, findTxt)
- endpos = startpos+len(findTxt)
- self.anchor1 = endpos
+ startpos = self.FindText(self.anchor1, self.anchor2, findTxt, evt.GetFlags())
if startpos != -1:
+ endpos = startpos+len(findTxt)
self.SetSelection(startpos, endpos)
- self.ReplaceSelection(evt.GetReplaceString())
+ self.ReplaceSelection(newTxt)
+ self.anchor1 = startpos + newStrLen + 1
+ self.anchor2 += diffLen
+ line = self.GetCurrentLine()
+ halfNumLinesOnScreen = self.LinesOnScreen() / 2
+ self.ScrollToLine(line - halfNumLinesOnScreen)
def OnFindClose(self, evt):
evt.GetDialog().Destroy()
@@ -3452,30 +3739,6 @@ class Editor(stc.StyledTextCtrl):
for line in lines:
f.write("%s=%s\n" % (line[0], line[1]))
- def closeNoCancel(self):
- if self.GetModify():
- if not self.path: f = "Untitled"
- else: f = self.path
- dlg = wx.MessageDialog(None, 'file ' + f + ' has been modified. Do you want to save?',
- 'Warning!', wx.YES | wx.NO)
- but = dlg.ShowModal()
- if but == wx.ID_YES:
- dlg.Destroy()
- if not self.path or "Untitled-" in self.path:
- dlg2 = wx.FileDialog(None, message="Save file as ... (the file will be closed even if you pressed Cancel!)", defaultDir=os.getcwd(),
- defaultFile="", style=wx.SAVE|wx.FD_OVERWRITE_PROMPT)
- dlg2.SetFilterIndex(0)
- if dlg2.ShowModal() == wx.ID_OK:
- path = dlg2.GetPath()
- self.SaveFile(path)
- dlg2.Destroy()
- else:
- dlg2.Destroy()
- else:
- self.SaveFile(self.path)
- elif but == wx.ID_NO:
- dlg.Destroy()
-
def close(self):
if self.GetModify():
if not self.path: f = "Untitled"
@@ -3595,6 +3858,9 @@ class Editor(stc.StyledTextCtrl):
currentword = self.GetTextRangeUTF8(startpos, endpos)
return currentword
+ def showAutoCompContainer(self, state):
+ self.auto_comp_container = state
+
def showAutoComp(self):
propagate = True
charBefore = " "
@@ -3612,15 +3878,27 @@ class Editor(stc.StyledTextCtrl):
propagate = False
return propagate
- def insertDefArgs(self, currentword):
+ def insertDefArgs(self, currentword, charat):
propagate = True
+ braceend = True
+ currentword = ""
+ if charat == ord("("):
+ pos = self.GetCurrentPos()
+ if chr(self.GetCharAt(pos)) == ')':
+ braceend = False
+ startpos = self.WordStartPosition(pos-2, True)
+ endpos = self.WordEndPosition(pos-2, True)
+ currentword = self.GetTextRangeUTF8(startpos, endpos)
for word in PYO_WORDLIST:
if word == currentword:
text = class_args(eval(word)).replace(word, "")
self.args_buffer = text.replace("(", "").replace(")", "").split(",")
self.args_buffer = [arg.strip() for arg in self.args_buffer]
self.args_line_number = [self.GetCurrentLine(), self.GetCurrentLine()+1]
- self.insertText(self.GetCurrentPos(), text, False)
+ if braceend:
+ self.insertText(self.GetCurrentPos(), text[1:], False)
+ else:
+ self.insertText(self.GetCurrentPos(), text[1:-1], False)
self.selection = self.GetSelectedText()
wx.CallAfter(self.navigateArgs)
propagate = False
@@ -3760,7 +4038,7 @@ class Editor(stc.StyledTextCtrl):
def processTab(self, currentword, autoCompActive, charat, pos):
propagate = self.showAutoComp()
if propagate:
- propagate = self.insertDefArgs(currentword)
+ propagate = self.insertDefArgs(currentword, charat)
if propagate:
propagate = self.checkForBuiltinComp()
if propagate:
@@ -3775,30 +4053,64 @@ class Editor(stc.StyledTextCtrl):
except:
pass
- def navigateMarkers(self, down=True):
- if self.markers_dict != {}:
- llen = len(self.markers_dict)
- keys = sorted(self.markers_dict.keys())
- if down:
- self.current_marker += 1
- else:
- self.current_marker -= 1
- if self.current_marker < 0:
- self.current_marker = llen - 1
- elif self.current_marker >= llen:
- self.current_marker = 0
- line = keys[self.current_marker]
- self.GotoLine(line)
- halfNumLinesOnScreen = self.LinesOnScreen() / 2
- self.ScrollToLine(line - halfNumLinesOnScreen)
- self.GetParent().GetParent().GetParent().GetParent().markers.setSelected(self.current_marker)
+ def onShowDocString(self):
+ if self.GetSelectedText() != "":
+ currentword = self.GetSelectedText()
+ else:
+ currentword = self.getWordUnderCaret()
+ firstCaretPos = self.GetCurrentPos()
+ caretPos = self.GetCurrentPos()
+ startpos = self.WordStartPosition(caretPos, True)
+ while chr(self.GetCharAt(startpos-1)) == ".":
+ self.GotoPos(startpos-2)
+ parent = self.getWordUnderCaret()
+ currentword = parent + "." + currentword
+ caretPos = self.GetCurrentPos()
+ startpos = self.WordStartPosition(caretPos, True)
+ self.GotoPos(firstCaretPos)
+ lineCount = self.GetLineCount()
+ text = ""
+ for i in range(lineCount):
+ line = self.GetLine(i)
+ if "import " in line:
+ text = text + line
+ try:
+ exec text in locals()
+ docstr = eval(currentword).__doc__
+ dlg = wx.lib.dialogs.ScrolledMessageDialog(self, docstr, "__doc__ string for %s" % currentword, size=(700,500))
+ dlg.CenterOnParent()
+ dlg.ShowModal()
+ except:
+ pass
+ def OnChar(self, evt):
+ propagate = True
+
+ if chr(evt.GetKeyCode()) in ['[', '{', '(', '"', '`'] and self.auto_comp_container:
+ if chr(evt.GetKeyCode()) == '[':
+ self.AddText('[]')
+ elif chr(evt.GetKeyCode()) == '{':
+ self.AddText('{}')
+ elif chr(evt.GetKeyCode()) == '(':
+ self.AddText('()')
+ elif chr(evt.GetKeyCode()) == '"':
+ self.AddText('""')
+ elif chr(evt.GetKeyCode()) == '`':
+ self.AddText('``')
+ self.CharLeft()
+ propagate = False
+
+ if propagate:
+ evt.Skip()
+ else:
+ evt.StopPropagation()
+
def OnKeyDown(self, evt):
if PLATFORM == "darwin":
ControlDown = evt.CmdDown
else:
ControlDown = evt.ControlDown
-
+
propagate = True
# Stop propagation on markers navigation --- Shift+Ctrl+Arrows up/down
if evt.GetKeyCode() in [wx.WXK_DOWN,wx.WXK_UP] and evt.ShiftDown() and ControlDown():
@@ -3807,6 +4119,10 @@ class Editor(stc.StyledTextCtrl):
elif evt.GetKeyCode() == wx.WXK_RETURN and evt.ShiftDown():
self.onShowTip()
propagate = False
+ # Stop propagation on Tip Show of __doc__ string --- Ctrl+Return
+ elif evt.GetKeyCode() == wx.WXK_RETURN and ControlDown():
+ self.onShowDocString()
+ propagate = False
# Move and/or Select one word left or right --- (Shift+)Alt+Arrows left/right
elif evt.GetKeyCode() == wx.WXK_LEFT and evt.AltDown() and evt.ShiftDown():
@@ -3832,6 +4148,11 @@ class Editor(stc.StyledTextCtrl):
self.CmdKeyExecute(stc.STC_CMD_LINEEND)
propagate = False
+ # Delete forward DELETE
+ elif evt.GetKeyCode() == wx.WXK_DELETE:
+ self.CmdKeyExecute(stc.STC_CMD_CHARRIGHT)
+ self.CmdKeyExecute(stc.STC_CMD_DELETEBACK)
+ propagate = False
# Delete the word to the right of the caret --- Shift+Alt+BACK
elif evt.GetKeyCode() == wx.WXK_BACK and evt.AltDown() and evt.ShiftDown():
self.DelWordRight()
@@ -3863,6 +4184,19 @@ class Editor(stc.StyledTextCtrl):
self.Paste()
propagate = False
+ # Show documentation for pyo object under the caret
+ elif evt.GetKeyCode() == ord('D') and ControlDown():
+ self.GetParent().GetParent().GetParent().GetParent().GetParent().showDoc(None)
+ propagate = False
+ # Goto line
+ elif evt.GetKeyCode() == ord('L') and ControlDown():
+ self.GetParent().GetParent().GetParent().GetParent().GetParent().gotoLine(None)
+ propagate = False
+ # Send line/selection to pyo background server
+ elif evt.GetKeyCode() == ord('T') and ControlDown():
+ self.GetParent().GetParent().GetParent().GetParent().GetParent().sendSelectionToBackgroundServer(None)
+ propagate = False
+
# Process Return key --- automatic indentation
elif evt.GetKeyCode() == wx.WXK_RETURN:
wx.CallAfter(self.processReturn)
@@ -3943,6 +4277,7 @@ class Editor(stc.StyledTextCtrl):
# pos = self.GetLineEndPosition(i)
# if self.GetCharAt(pos-1) != 172:
# self.InsertTextUTF8(pos, "¬")
+ self.moveMarkers()
self.checkScrollbar()
self.OnModified()
evt.Skip()
@@ -3970,96 +4305,129 @@ class Editor(stc.StyledTextCtrl):
self.GotoPos(pos+1)
self.DelWordLeft()
+ def navigateMarkers(self, down=True):
+ if self.markers_dict != {}:
+ llen = len(self.markers_dict)
+ swap = [(x[1], x[0]) for x in self.markers_dict.items()]
+ handles = [x[1] for x in sorted(swap)]
+ if down:
+ self.current_marker += 1
+ else:
+ self.current_marker -= 1
+ if self.current_marker < 0:
+ self.current_marker = llen - 1
+ elif self.current_marker >= llen:
+ self.current_marker = 0
+ handle = handles[self.current_marker]
+ line = self.markers_dict[handle][0]
+ self.GotoLine(line)
+ halfNumLinesOnScreen = self.LinesOnScreen() / 2
+ self.ScrollToLine(line - halfNumLinesOnScreen)
+ self.GetParent().GetParent().GetParent().GetParent().markers.setSelected(handle)
+
def setMarkers(self, dic):
+ try:
+ key = dic.keys()[0]
+ except:
+ return
+ if type(dic[key]) != ListType:
+ return
self.markers_dict = dic
- for line in self.markers_dict.keys():
+ for handle in self.markers_dict.keys():
+ line = self.markers_dict[handle][0]
self.MarkerAdd(line, 0)
self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
- def addMarker(self, line):
- if line not in self.markers_dict.keys():
- self.MarkerAdd(line, 0)
- self.markers_dict[line] = ""
+ def moveMarkers(self):
+ dict = {}
+ for handle in self.markers_dict.keys():
+ line = self.MarkerLineFromHandle(handle)
+ comment = self.markers_dict[handle][1]
+ dict[handle] = [line, comment]
+ if dict != self.markers_dict:
+ self.markers_dict = dict
self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
- return True
+
+ def addMarker(self, line):
+ if not self.MarkerGet(line):
+ handle = self.MarkerAdd(line, 0)
+ self.markers_dict[handle] = [line, ""]
+ comment = ""
+ dlg = wx.TextEntryDialog(self, 'Enter a comment for that marker:', 'Marker Comment')
+ if dlg.ShowModal() == wx.ID_OK:
+ comment = dlg.GetValue()
+ dlg.Destroy()
else:
- return False
+ dlg.Destroy()
+ return
+ self.markers_dict[handle][1] = comment
+ self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
def deleteMarker(self, line):
- if line in self.markers_dict.keys():
- del self.markers_dict[line]
- self.MarkerDelete(line, 0)
- self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
+ for handle in self.markers_dict.keys():
+ if line == self.markers_dict[handle][0]:
+ del self.markers_dict[handle]
+ self.MarkerDeleteHandle(handle)
+ self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
def deleteAllMarkers(self):
self.markers_dict = {}
self.MarkerDeleteAll(0)
self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
- def addMarkerComment(self, line):
- if line in self.markers_dict.keys():
- comment = ""
- dlg = wx.TextEntryDialog(self, 'Enter a comment for that marker:', 'Marker Comment')
- if dlg.ShowModal() == wx.ID_OK:
- comment = dlg.GetValue()
- dlg.Destroy()
- else:
- dlg.Destroy()
- return
- self.markers_dict[line] = comment
- self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
-
def OnMarginClick(self, evt):
if evt.GetMargin() == 0:
- if PLATFORM == "darwin":
- modif = evt.GetAlt
- else:
- modif = evt.GetControl
lineClicked = self.LineFromPosition(evt.GetPosition())
- if modif():
+ if evt.GetShift():
self.deleteMarker(lineClicked)
- elif evt.GetShift():
- self.addMarkerComment(lineClicked)
else:
- ok = self.addMarker(lineClicked)
- if ok:
- self.addMarkerComment(lineClicked)
+ self.addMarker(lineClicked)
elif evt.GetMargin() == 2:
if evt.GetShift() and evt.GetControl():
- self.FoldAll()
+ self.ToggleFoldAll()
else:
lineClicked = self.LineFromPosition(evt.GetPosition())
-
if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
- if evt.GetShift():
- self.SetFoldExpanded(lineClicked, True)
- self.Expand(lineClicked, True, True, 1)
- elif evt.GetControl():
- if self.GetFoldExpanded(lineClicked):
- self.SetFoldExpanded(lineClicked, False)
- self.Expand(lineClicked, False, True, 0)
- else:
- self.SetFoldExpanded(lineClicked, True)
- self.Expand(lineClicked, True, True, 100)
- else:
- self.ToggleFold(lineClicked)
+ self.ToggleFold(lineClicked)
def FoldAll(self):
lineCount = self.GetLineCount()
- expanding = True
+ lineNum = 0
+ while lineNum < lineCount:
+ level = self.GetFoldLevel(lineNum)
+ if level & stc.STC_FOLDLEVELHEADERFLAG and \
+ (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
+ lastChild = self.GetLastChild(lineNum, -1)
+ self.SetFoldExpanded(lineNum, False)
+ if lastChild > lineNum:
+ self.HideLines(lineNum+1, lastChild)
+ lineNum = lineNum + 1
+
+ def ExpandAll(self):
+ lineCount = self.GetLineCount()
+ lineNum = 0
+ while lineNum < lineCount:
+ level = self.GetFoldLevel(lineNum)
+ if level & stc.STC_FOLDLEVELHEADERFLAG and \
+ (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
+ self.SetFoldExpanded(lineNum, True)
+ lineNum = self.Expand(lineNum, True)
+ lineNum = lineNum - 1
+ lineNum = lineNum + 1
+ def ToggleFoldAll(self):
+ lineCount = self.GetLineCount()
+ expanding = True
# find out if we are folding or unfolding
for lineNum in range(lineCount):
if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
expanding = not self.GetFoldExpanded(lineNum)
break
-
lineNum = 0
while lineNum < lineCount:
level = self.GetFoldLevel(lineNum)
if level & stc.STC_FOLDLEVELHEADERFLAG and \
(level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
-
if expanding:
self.SetFoldExpanded(lineNum, True)
lineNum = self.Expand(lineNum, True)
@@ -4071,6 +4439,16 @@ class Editor(stc.StyledTextCtrl):
self.HideLines(lineNum+1, lastChild)
lineNum = lineNum + 1
+ def foldExpandCurrentScope(self):
+ line = self.GetCurrentLine()
+ while (line >= 0):
+ level = self.GetFoldLevel(line)
+ if level & stc.STC_FOLDLEVELHEADERFLAG and (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
+ self.ToggleFold(line)
+ self.GotoLine(line)
+ break
+ line -= 1
+
def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
lastChild = self.GetLastChild(line, level)
line = line + 1
@@ -4167,6 +4545,12 @@ class OutputLogEditor(SimpleEditor):
def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style= wx.NO_BORDER):
SimpleEditor.__init__(self, parent=parent, ID=ID, pos=pos, size=size, style=style)
+ def appendToLog(self, text):
+ self.SetReadOnly(False)
+ self.AppendText(text)
+ self.GotoLine(self.GetLineCount())
+ self.SetReadOnly(True)
+
def setLog(self, text):
self.SetReadOnly(False)
self.SetText(text)
@@ -4184,7 +4568,7 @@ class OutputLogPanel(wx.Panel):
self.sizer = wx.BoxSizer(wx.VERTICAL)
toolbarbox = wx.BoxSizer(wx.HORIZONTAL)
- self.toolbar = wx.ToolBar(self, -1, size=(-1,36))
+ self.toolbar = wx.ToolBar(self, -1)
self.toolbar.SetMargins((5, 0))
font, psize = self.toolbar.GetFont(), self.toolbar.GetFont().GetPointSize()
if PLATFORM == "darwin":
@@ -4193,7 +4577,7 @@ class OutputLogPanel(wx.Panel):
if PLATFORM == "win32":
self.toolbar.AddSeparator()
- title = wx.StaticText(self.toolbar, -1, "Output panel")
+ title = wx.StaticText(self.toolbar, -1, " Output panel")
title.SetFont(font)
self.toolbar.AddControl(title)
self.toolbar.AddSeparator()
@@ -4204,17 +4588,17 @@ class OutputLogPanel(wx.Panel):
self.toolbar.AddControl(self.processPopup)
if PLATFORM == "win32":
self.toolbar.AddSeparator()
- self.processKill = wx.Button(self.toolbar, -1, label="Kill", size=(40,-1))
+ self.processKill = wx.Button(self.toolbar, -1, label="Kill", size=(40,self.processPopup.GetSize()[1]))
self.processKill.SetFont(font)
self.toolbar.AddControl(self.processKill)
self.processKill.Bind(wx.EVT_BUTTON, self.killProcess)
if PLATFORM == "win32":
self.toolbar.AddSeparator()
- self.runningLabel = wx.StaticText(self.toolbar, -1, "Running: 0")
+ self.runningLabel = wx.StaticText(self.toolbar, -1, " Running: 0")
self.runningLabel.SetFont(font)
self.toolbar.AddControl(self.runningLabel)
self.toolbar.AddSeparator()
- self.copyLog = wx.Button(self.toolbar, -1, label="Copy log", size=(70,-1))
+ self.copyLog = wx.Button(self.toolbar, -1, label="Copy log", size=(70,self.processPopup.GetSize()[1]))
self.copyLog.SetFont(font)
self.toolbar.AddControl(self.copyLog)
self.copyLog.Bind(wx.EVT_BUTTON, self.onCopy)
@@ -4231,8 +4615,10 @@ class OutputLogPanel(wx.Panel):
self.toolbar.Realize()
toolbarbox.Add(self.toolbar, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 0)
- tb2 = wx.ToolBar(self, -1, size=(-1,36))
- tb2.SetToolBitmapSize(tsize)
+ tb2 = wx.ToolBar(self, -1, size=(-1,32))
+ if PLATFORM == "darwin":
+ tb2.SetToolBitmapSize(tsize)
+ tb2.AddSeparator()
tb2.AddLabelTool(17, "Close Panel", close_panel_bmp, shortHelp="Close Panel")
tb2.Realize()
toolbarbox.Add(tb2, 0, wx.ALIGN_RIGHT, 0)
@@ -4259,6 +4645,7 @@ class OutputLogPanel(wx.Panel):
self.processPopup.SetStringSelection("%d :: %s" % (procID, filename))
self.running += 1
self.runningLabel.SetLabel("Running: %d" % self.running)
+ self.editor.setLog("")
def removeProcess(self, procID, filename):
str = "%d :: %s" % (procID, filename)
@@ -4274,6 +4661,9 @@ class OutputLogPanel(wx.Panel):
thread = self.mainPanel.mainFrame.processes[procID][0]
thread.kill()
+ def appendToLog(self, text):
+ self.editor.appendToLog(text)
+
def setLog(self, text):
self.editor.setLog(text)
@@ -4577,11 +4967,11 @@ class ProjectTree(wx.Panel):
filename = os.path.join(parent, filename)
dirPath = os.path.split(self.projectDict[parent])[0]
path = os.path.join(dirPath, filename)
-# for root, dirs, files in os.walk(dirPath):
-# if files:
-# for file in files:
-# if file == self.tree.GetItemText(item):
-# path = os.path.join(root, file)
+ #for root, dirs, files in os.walk(dirPath):
+ # if files:
+ # for file in files:
+ # if file == self.tree.GetItemText(item):
+ # path = os.path.join(root, file)
self.mainPanel.addPage(path)
def select(self, item):
@@ -4623,16 +5013,18 @@ class MarkersListScroll(scrolled.ScrolledPanel):
def setDict(self, dic):
self.row_dict = dic
self.box.Clear(True)
- for i, key in enumerate(sorted(self.row_dict.keys())):
+ swap = [(x[1], x[0]) for x in self.row_dict.items()]
+ handles = [x[1] for x in sorted(swap)]
+ for i in handles:
label = wx.StaticBitmap(self, wx.ID_ANY)
label.SetBitmap(self.arrow_bit)
- self.box.Add(label, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 2, userData=(i,key))
- line = wx.StaticText(self, wx.ID_ANY, label=str(key+1))
+ self.box.Add(label, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 2, userData=(i,self.row_dict[i][0]))
+ line = wx.StaticText(self, wx.ID_ANY, label=str(self.row_dict[i][0]+1))
line.SetFont(self.font)
- self.box.Add(line, 0, wx.ALIGN_LEFT|wx.TOP, 3, userData=(i,key))
- comment = wx.StaticText(self, wx.ID_ANY, label=self.row_dict[key])
+ self.box.Add(line, 0, wx.ALIGN_LEFT|wx.TOP, 3, userData=(i,self.row_dict[i][0]))
+ comment = wx.StaticText(self, wx.ID_ANY, label=self.row_dict[i][1])
comment.SetFont(self.font)
- self.box.Add(comment, 1, wx.EXPAND|wx.ALIGN_LEFT|wx.TOP, 3, userData=(i,key))
+ self.box.Add(comment, 1, wx.EXPAND|wx.ALIGN_LEFT|wx.TOP, 3, userData=(i,self.row_dict[i][0]))
self.box.Layout()
label.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
line.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
@@ -4655,13 +5047,14 @@ class MarkersListScroll(scrolled.ScrolledPanel):
halfNumLinesOnScreen = editor.LinesOnScreen() / 2
editor.ScrollToLine(line - halfNumLinesOnScreen)
else:
- line = sorted(self.row_dict.keys())[self.selected]
+ line = self.row_dict[self.selected][0]
self.selected2 = item.GetUserData()[0]
line2 = item.GetUserData()[1]
- editor.GotoLine(line)
+ l1, l2 = min(line, line2), max(line, line2)
+ editor.GotoLine(l1)
halfNumLinesOnScreen = editor.LinesOnScreen() / 2
- editor.ScrollToLine(line - halfNumLinesOnScreen)
- editor.SetSelection(editor.PositionFromLine(line), editor.PositionFromLine(line2+1))
+ editor.ScrollToLine(l1 - halfNumLinesOnScreen)
+ editor.SetSelection(editor.PositionFromLine(l1), editor.PositionFromLine(l2+1))
break
self.setColour()
@@ -4741,7 +5134,7 @@ class PreferencesDialog(wx.Dialog):
font.SetWeight(wx.BOLD)
if PLATFORM == "linux2":
- entryfont.SetPointSize(pointsize-1)
+ entryfont.SetPointSize(pointsize)
elif PLATFORM == "win32":
entryfont.SetPointSize(pointsize)
else:
@@ -4901,7 +5294,7 @@ class PreferencesDialog(wx.Dialog):
res_folder = self.entry_res.GetValue()
if os.path.isdir(res_folder):
- if res_folder != RESOURCES_PATH:
+ if res_folder != ensureNFD(RESOURCES_PATH):
RESOURCES_PATH = PREFERENCES["resources_path"] = res_folder
# snippets
old_snippets_path = SNIPPETS_PATH
@@ -4959,9 +5352,10 @@ class STCPrintout(wx.Printout):
a wrapped line, so it may be a difficult task to ever implement printing
with line wrapping using the wx.StyledTextCtrl.FormatRange method.
"""
- debuglevel = 0
+ debuglevel = 1
- def __init__(self, stc, page_setup_data=None, print_mode=None, title=None, border=False, lines_per_page=None, output_point_size=None):
+ def __init__(self, stc, page_setup_data=None, print_mode=None, title=None,
+ border=False, lines_per_page=None, output_point_size=None):
"""Constructor.
@param stc: wx.StyledTextCtrl to print
@@ -5022,6 +5416,7 @@ class STCPrintout(wx.Printout):
except (TypeError, ValueError):
self.user_lines_per_page = None
+ self.page_count = 2
self.border_around_text = border
self.setHeaderFont()
@@ -5368,6 +5763,36 @@ class MyFileDropTarget(wx.FileDropTarget):
else:
pass
+class EPyoApp(wx.App):
+ def __init__(self, *args, **kwargs):
+ wx.App.__init__(self, *args, **kwargs)
+
+ def OnInit(self):
+ X,Y = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X), wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
+ if X < 850: X -= 50
+ else: X = 850
+ if Y < 750: Y -= 50
+ else: Y = 750
+ self.frame = MainFrame(None, -1, title='E-Pyo Editor', pos=(10,25), size=(X, Y))
+ self.frame.Show()
+ return True
+
+ def MacOpenFiles(self, filenames):
+ if type(filenames) != ListType:
+ filenames = [filenames]
+ for filename in filenames:
+ if os.path.isdir(filename):
+ self.frame.panel.project.loadFolder(filename)
+ sys.path.append(filename)
+ elif os.path.isfile(filename):
+ self.frame.panel.addPage(filename)
+
+ def MacReopenApp(self):
+ try:
+ self.frame.Raise()
+ except:
+ pass
+
if __name__ == '__main__':
filesToOpen = []
foldersToOpen = []
@@ -5381,12 +5806,5 @@ if __name__ == '__main__':
else:
pass
- app = wx.PySimpleApp()
- X,Y = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X), wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
- if X < 850: X -= 50
- else: X = 850
- if Y < 750: Y -= 50
- else: Y = 750
- frame = MainFrame(None, -1, title='E-Pyo Editor', pos=(10,25), size=(X, Y))
- frame.Show()
+ app = EPyoApp(redirect=False)
app.MainLoop()
diff --git a/utils/E-PyoIcon.png b/utils/E-PyoIcon.png
new file mode 100644
index 0000000..f971f13
Binary files /dev/null and b/utils/E-PyoIcon.png differ
diff --git a/utils/FlatNotebook.py b/utils/FlatNotebook.py
deleted file mode 100755
index f4c7d34..0000000
--- a/utils/FlatNotebook.py
+++ /dev/null
@@ -1,4940 +0,0 @@
-# --------------------------------------------------------------------------- #
-# FLATNOTEBOOK Widget wxPython IMPLEMENTATION
-#
-# Original C++ Code From Eran. You Can Find It At:
-#
-# http://wxforum.shadonet.com/viewtopic.php?t=5761&start=0
-#
-# License: wxWidgets license
-#
-#
-# Python Code By:
-#
-# Andrea Gavana, @ 02 Oct 2006
-# Latest Revision: 30 May 2008, 23.00 GMT
-#
-#
-# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
-# Write To Me At:
-#
-# andrea.gavana at gmail.com
-# gavana at kpo.kz
-#
-# Or, Obviously, To The wxPython Mailing List!!!
-#
-#
-# End Of Comments
-# --------------------------------------------------------------------------- #
-
-"""
-The FlatNotebook is a full implementation of the wx.Notebook, and designed to be
-a drop-in replacement for wx.Notebook. The API functions are similar so one can
-expect the function to behave in the same way.
-
-Some features:
-
- - The buttons are highlighted a la Firefox style
- - The scrolling is done for bulks of tabs (so, the scrolling is faster and better)
- - The buttons area is never overdrawn by tabs (unlike many other implementations I saw)
- - It is a generic control
- - Currently there are 5 differnt styles - VC8, VC 71, Standard, Fancy and Firefox 2;
- - Mouse middle click can be used to close tabs
- - A function to add right click menu for tabs (simple as SetRightClickMenu)
- - All styles has bottom style as well (they can be drawn in the bottom of screen)
- - An option to hide 'X' button or navigation buttons (separately)
- - Gradient coloring of the selected tabs and border
- - Support for drag 'n' drop of tabs, both in the same notebook or to another notebook
- - Possibility to have closing button on the active tab directly
- - Support for disabled tabs
- - Colours for active/inactive tabs, and captions
- - Background of tab area can be painted in gradient (VC8 style only)
- - Colourful tabs - a random gentle colour is generated for each new tab (very cool, VC8 style only)
-
-
-And much more.
-
-
-License And Version:
-
-FlatNotebook Is Freeware And Distributed Under The wxPython License.
-
-Latest Revision: Andrea Gavana @ 30 May 2008, 23.00 GMT
-
-Version 2.5.
-
- at undocumented: FNB_HEIGHT_SPACER, VERTICAL_BORDER_PADDING, VC8_SHAPE_LEN,
- wxEVT*, left_arrow_*, right_arrow*, x_button*, down_arrow*,
- FNBDragInfo, FNBDropTarget, GetMondrian*
-"""
-
-__docformat__ = "epytext"
-
-
-#----------------------------------------------------------------------
-# Beginning Of FLATNOTEBOOK wxPython Code
-#----------------------------------------------------------------------
-
-import wx
-import random
-import math
-import weakref
-import cPickle
-
-if wx.Platform == '__WXMAC__':
- import Carbon.Appearance
-
-# Check for the new method in 2.7 (not present in 2.6.3.3)
-if wx.VERSION_STRING < "2.7":
- wx.Rect.Contains = lambda self, point: wx.Rect.Inside(self, point)
-
-FNB_HEIGHT_SPACER = 10
-
-# Use Visual Studio 2003 (VC7.1) style for tabs
-FNB_VC71 = 1
-"""Use Visual Studio 2003 (VC7.1) style for tabs"""
-
-# Use fancy style - square tabs filled with gradient coloring
-FNB_FANCY_TABS = 2
-"""Use fancy style - square tabs filled with gradient coloring"""
-
-# Draw thin border around the page
-FNB_TABS_BORDER_SIMPLE = 4
-"""Draw thin border around the page"""
-
-# Do not display the 'X' button
-FNB_NO_X_BUTTON = 8
-"""Do not display the 'X' button"""
-
-# Do not display the Right / Left arrows
-FNB_NO_NAV_BUTTONS = 16
-"""Do not display the right/left arrows"""
-
-# Use the mouse middle button for cloing tabs
-FNB_MOUSE_MIDDLE_CLOSES_TABS = 32
-"""Use the mouse middle button for cloing tabs"""
-
-# Place tabs at bottom - the default is to place them
-# at top
-FNB_BOTTOM = 64
-"""Place tabs at bottom - the default is to place them at top"""
-
-# Disable dragging of tabs
-FNB_NODRAG = 128
-"""Disable dragging of tabs"""
-
-# Use Visual Studio 2005 (VC8) style for tabs
-FNB_VC8 = 256
-"""Use Visual Studio 2005 (VC8) style for tabs"""
-
-# Firefox 2 tabs style
-FNB_FF2 = 131072
-"""Use Firefox 2 style for tabs"""
-
-# Place 'X' on a tab
-FNB_X_ON_TAB = 512
-"""Place 'X' close button on the active tab"""
-
-FNB_BACKGROUND_GRADIENT = 1024
-"""Use gradients to paint the tabs background"""
-
-FNB_COLORFUL_TABS = 2048
-"""Use colourful tabs (VC8 style only)"""
-
-# Style to close tab using double click - styles 1024, 2048 are reserved
-FNB_DCLICK_CLOSES_TABS = 4096
-"""Style to close tab using double click"""
-
-FNB_SMART_TABS = 8192
-"""Use Smart Tabbing, like Alt+Tab on Windows"""
-
-FNB_DROPDOWN_TABS_LIST = 16384
-"""Use a dropdown menu on the left in place of the arrows"""
-
-FNB_ALLOW_FOREIGN_DND = 32768
-"""Allows drag 'n' drop operations between different L{FlatNotebook}s"""
-
-FNB_HIDE_ON_SINGLE_TAB = 65536
-"""Hides the Page Container when there is one or fewer tabs"""
-
-VERTICAL_BORDER_PADDING = 4
-
-# Button size is a 16x16 xpm bitmap
-BUTTON_SPACE = 16
-"""Button size is a 16x16 xpm bitmap"""
-
-VC8_SHAPE_LEN = 16
-
-MASK_COLOR = wx.Colour(0, 128, 128)
-"""Mask colour for the arrow bitmaps"""
-
-# Button status
-FNB_BTN_PRESSED = 2
-"""Navigation button is pressed"""
-FNB_BTN_HOVER = 1
-"""Navigation button is hovered"""
-FNB_BTN_NONE = 0
-"""No navigation"""
-
-# Hit Test results
-FNB_TAB = 1 # On a tab
-"""Indicates mouse coordinates inside a tab"""
-FNB_X = 2 # On the X button
-"""Indicates mouse coordinates inside the I{X} region"""
-FNB_TAB_X = 3 # On the 'X' button (tab's X button)
-"""Indicates mouse coordinates inside the I{X} region in a tab"""
-FNB_LEFT_ARROW = 4 # On the rotate left arrow button
-"""Indicates mouse coordinates inside the left arrow region"""
-FNB_RIGHT_ARROW = 5 # On the rotate right arrow button
-"""Indicates mouse coordinates inside the right arrow region"""
-FNB_DROP_DOWN_ARROW = 6 # On the drop down arrow button
-"""Indicates mouse coordinates inside the drop down arrow region"""
-FNB_NOWHERE = 0 # Anywhere else
-"""Indicates mouse coordinates not on any tab of the notebook"""
-
-FNB_DEFAULT_STYLE = FNB_MOUSE_MIDDLE_CLOSES_TABS | FNB_HIDE_ON_SINGLE_TAB
-"""L{FlatNotebook} default style"""
-
-# FlatNotebook Events:
-# wxEVT_FLATNOTEBOOK_PAGE_CHANGED: Event Fired When You Switch Page;
-# wxEVT_FLATNOTEBOOK_PAGE_CHANGING: Event Fired When You Are About To Switch
-# Pages, But You Can Still "Veto" The Page Changing By Avoiding To Call
-# event.Skip() In Your Event Handler;
-# wxEVT_FLATNOTEBOOK_PAGE_CLOSING: Event Fired When A Page Is Closing, But
-# You Can Still "Veto" The Page Changing By Avoiding To Call event.Skip()
-# In Your Event Handler;
-# wxEVT_FLATNOTEBOOK_PAGE_CLOSED: Event Fired When A Page Is Closed.
-# wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU: Event Fired When A Menu Pops-up In A Tab.
-
-wxEVT_FLATNOTEBOOK_PAGE_CHANGED = wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
-wxEVT_FLATNOTEBOOK_PAGE_CHANGING = wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
-wxEVT_FLATNOTEBOOK_PAGE_CLOSING = wx.NewEventType()
-wxEVT_FLATNOTEBOOK_PAGE_CLOSED = wx.NewEventType()
-wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU = wx.NewEventType()
-
-#-----------------------------------#
-# FlatNotebookEvent
-#-----------------------------------#
-
-EVT_FLATNOTEBOOK_PAGE_CHANGED = wx.EVT_NOTEBOOK_PAGE_CHANGED
-"""Notify client objects when the active page in L{FlatNotebook}
-has changed."""
-EVT_FLATNOTEBOOK_PAGE_CHANGING = wx.EVT_NOTEBOOK_PAGE_CHANGING
-"""Notify client objects when the active page in L{FlatNotebook}
-is about to change."""
-EVT_FLATNOTEBOOK_PAGE_CLOSING = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, 1)
-"""Notify client objects when a page in L{FlatNotebook} is closing."""
-EVT_FLATNOTEBOOK_PAGE_CLOSED = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSED, 1)
-"""Notify client objects when a page in L{FlatNotebook} has been closed."""
-EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU, 1)
-"""Notify client objects when a pop-up menu should appear next to a tab."""
-
-
-# Some icons in XPM format
-
-left_arrow_disabled_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #555555",
- "# c #000000",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````.```````",
- "```````..```````",
- "``````.`.```````",
- "`````.``.```````",
- "````.```.```````",
- "`````.``.```````",
- "``````.`.```````",
- "```````..```````",
- "````````.```````",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````````````"
- ]
-
-x_button_pressed_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #4766e0",
- "# c #9e9ede",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "`..............`",
- "`.############.`",
- "`.############.`",
- "`.############.`",
- "`.###aa####aa#.`",
- "`.####aa##aa##.`",
- "`.#####aaaa###.`",
- "`.######aa####.`",
- "`.#####aaaa###.`",
- "`.####aa##aa##.`",
- "`.###aa####aa#.`",
- "`.############.`",
- "`..............`",
- "````````````````",
- "````````````````"
- ]
-
-
-left_arrow_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #555555",
- "# c #000000",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````.```````",
- "```````..```````",
- "``````...```````",
- "`````....```````",
- "````.....```````",
- "`````....```````",
- "``````...```````",
- "```````..```````",
- "````````.```````",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````````````"
- ]
-
-x_button_hilite_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #4766e0",
- "# c #c9dafb",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "`..............`",
- "`.############.`",
- "`.############.`",
- "`.##aa####aa##.`",
- "`.###aa##aa###.`",
- "`.####aaaa####.`",
- "`.#####aa#####.`",
- "`.####aaaa####.`",
- "`.###aa##aa###.`",
- "`.##aa####aa##.`",
- "`.############.`",
- "`.############.`",
- "`..............`",
- "````````````````",
- "````````````````"
- ]
-
-x_button_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #555555",
- "# c #000000",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````````````",
- "````..````..````",
- "`````..``..`````",
- "``````....``````",
- "```````..```````",
- "``````....``````",
- "`````..``..`````",
- "````..````..````",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````````````"
- ]
-
-left_arrow_pressed_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #4766e0",
- "# c #9e9ede",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "`..............`",
- "`.############.`",
- "`.############.`",
- "`.#######a####.`",
- "`.######aa####.`",
- "`.#####aaa####.`",
- "`.####aaaa####.`",
- "`.###aaaaa####.`",
- "`.####aaaa####.`",
- "`.#####aaa####.`",
- "`.######aa####.`",
- "`.#######a####.`",
- "`..............`",
- "````````````````",
- "````````````````"
- ]
-
-left_arrow_hilite_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #4766e0",
- "# c #c9dafb",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "`..............`",
- "`.############.`",
- "`.######a#####.`",
- "`.#####aa#####.`",
- "`.####aaa#####.`",
- "`.###aaaa#####.`",
- "`.##aaaaa#####.`",
- "`.###aaaa#####.`",
- "`.####aaa#####.`",
- "`.#####aa#####.`",
- "`.######a#####.`",
- "`.############.`",
- "`..............`",
- "````````````````",
- "````````````````"
- ]
-
-right_arrow_disabled_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #555555",
- "# c #000000",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "````````````````",
- "````````````````",
- "```````.````````",
- "```````..```````",
- "```````.`.``````",
- "```````.``.`````",
- "```````.```.````",
- "```````.``.`````",
- "```````.`.``````",
- "```````..```````",
- "```````.````````",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````````````"
- ]
-
-right_arrow_hilite_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #4766e0",
- "# c #c9dafb",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "`..............`",
- "`.############.`",
- "`.####a#######.`",
- "`.####aa######.`",
- "`.####aaa#####.`",
- "`.####aaaa####.`",
- "`.####aaaaa###.`",
- "`.####aaaa####.`",
- "`.####aaa#####.`",
- "`.####aa######.`",
- "`.####a#######.`",
- "`.############.`",
- "`..............`",
- "````````````````",
- "````````````````"
- ]
-
-right_arrow_pressed_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #4766e0",
- "# c #9e9ede",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "`..............`",
- "`.############.`",
- "`.############.`",
- "`.#####a######.`",
- "`.#####aa#####.`",
- "`.#####aaa####.`",
- "`.#####aaaa###.`",
- "`.#####aaaaa##.`",
- "`.#####aaaa###.`",
- "`.#####aaa####.`",
- "`.#####aa#####.`",
- "`.#####a######.`",
- "`..............`",
- "````````````````",
- "````````````````"
- ]
-
-
-right_arrow_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #555555",
- "# c #000000",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "````````````````",
- "````````````````",
- "```````.````````",
- "```````..```````",
- "```````...``````",
- "```````....`````",
- "```````.....````",
- "```````....`````",
- "```````...``````",
- "```````..```````",
- "```````.````````",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````````````"
- ]
-
-down_arrow_hilite_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #4766e0",
- "# c #c9dafb",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "``.............`",
- "``.###########.`",
- "``.###########.`",
- "``.###########.`",
- "``.#aaaaaaaaa#.`",
- "``.##aaaaaaa##.`",
- "``.###aaaaa###.`",
- "``.####aaa####.`",
- "``.#####a#####.`",
- "``.###########.`",
- "``.###########.`",
- "``.###########.`",
- "``.............`",
- "````````````````",
- "````````````````"
- ]
-
-down_arrow_pressed_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #4766e0",
- "# c #9e9ede",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "``.............`",
- "``.###########.`",
- "``.###########.`",
- "``.###########.`",
- "``.###########.`",
- "``.###########.`",
- "``.#aaaaaaaaa#.`",
- "``.##aaaaaaa##.`",
- "``.###aaaaa###.`",
- "``.####aaa####.`",
- "``.#####a#####.`",
- "``.###########.`",
- "``.............`",
- "````````````````",
- "````````````````"
- ]
-
-
-down_arrow_xpm = [
- " 16 16 8 1",
- "` c #008080",
- ". c #000000",
- "# c #000000",
- "a c #000000",
- "b c #000000",
- "c c #000000",
- "d c #000000",
- "e c #000000",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````````````",
- "````.........```",
- "`````.......````",
- "``````.....`````",
- "```````...``````",
- "````````.```````",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````````````",
- "````````````````"
- ]
-
-
-#----------------------------------------------------------------------
-def GetMondrianData():
- return \
-'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
-\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00qID\
-ATX\x85\xed\xd6;\n\x800\x10E\xd1{\xc5\x8d\xb9r\x97\x16\x0b\xad$\x8a\x82:\x16\
-o\xda\x84pB2\x1f\x81Fa\x8c\x9c\x08\x04Z{\xcf\xa72\xbcv\xfa\xc5\x08 \x80r\x80\
-\xfc\xa2\x0e\x1c\xe4\xba\xfaX\x1d\xd0\xde]S\x07\x02\xd8>\xe1wa-`\x9fQ\xe9\
-\x86\x01\x04\x10\x00\\(Dk\x1b-\x04\xdc\x1d\x07\x14\x98;\x0bS\x7f\x7f\xf9\x13\
-\x04\x10@\xf9X\xbe\x00\xc9 \x14K\xc1<={\x00\x00\x00\x00IEND\xaeB`\x82'
-
-
-def GetMondrianBitmap():
- return wx.BitmapFromImage(GetMondrianImage().Scale(16, 16))
-
-
-def GetMondrianImage():
- import cStringIO
- stream = cStringIO.StringIO(GetMondrianData())
- return wx.ImageFromStream(stream)
-
-
-def GetMondrianIcon():
- icon = wx.EmptyIcon()
- icon.CopyFromBitmap(GetMondrianBitmap())
- return icon
-#----------------------------------------------------------------------
-
-
-def LightColour(color, percent):
- """ Brighten input colour by percent. """
-
- end_color = wx.WHITE
-
- rd = end_color.Red() - color.Red()
- gd = end_color.Green() - color.Green()
- bd = end_color.Blue() - color.Blue()
-
- high = 100
-
- # We take the percent way of the color from color -. white
- i = percent
- r = color.Red() + ((i*rd*100)/high)/100
- g = color.Green() + ((i*gd*100)/high)/100
- b = color.Blue() + ((i*bd*100)/high)/100
- return wx.Colour(r, g, b)
-
-
-def RandomColour():
- """ Creates a random colour. """
-
- r = random.randint(0, 255) # Random value betweem 0-255
- g = random.randint(0, 255) # Random value betweem 0-255
- b = random.randint(0, 255) # Random value betweem 0-255
-
- return wx.Colour(r, g, b)
-
-
-def PaintStraightGradientBox(dc, rect, startColor, endColor, vertical=True):
- """ Draws a gradient colored box from startColor to endColor. """
-
- rd = endColor.Red() - startColor.Red()
- gd = endColor.Green() - startColor.Green()
- bd = endColor.Blue() - startColor.Blue()
-
- # Save the current pen and brush
- savedPen = dc.GetPen()
- savedBrush = dc.GetBrush()
-
- if vertical:
- high = rect.GetHeight()-1
- else:
- high = rect.GetWidth()-1
-
- if high < 1:
- return
-
- for i in xrange(high+1):
-
- r = startColor.Red() + ((i*rd*100)/high)/100
- g = startColor.Green() + ((i*gd*100)/high)/100
- b = startColor.Blue() + ((i*bd*100)/high)/100
-
- p = wx.Pen(wx.Colour(r, g, b))
- dc.SetPen(p)
-
- if vertical:
- dc.DrawLine(rect.x, rect.y+i, rect.x+rect.width, rect.y+i)
- else:
- dc.DrawLine(rect.x+i, rect.y, rect.x+i, rect.y+rect.height)
-
- # Restore the pen and brush
- dc.SetPen(savedPen)
- dc.SetBrush(savedBrush)
-
-
-
-# -----------------------------------------------------------------------------
-# Util functions
-# -----------------------------------------------------------------------------
-
-def DrawButton(dc, rect, focus, upperTabs):
-
- # Define the rounded rectangle base on the given rect
- # we need an array of 9 points for it
- regPts = [wx.Point() for indx in xrange(9)]
-
- if focus:
- if upperTabs:
- leftPt = wx.Point(rect.x, rect.y + (rect.height / 10)*8)
- rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 10)*8)
- else:
- leftPt = wx.Point(rect.x, rect.y + (rect.height / 10)*5)
- rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 10)*5)
- else:
- leftPt = wx.Point(rect.x, rect.y + (rect.height / 2))
- rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 2))
-
- # Define the top region
- top = wx.RectPP(rect.GetTopLeft(), rightPt)
- bottom = wx.RectPP(leftPt, rect.GetBottomRight())
-
- topStartColor = wx.WHITE
-
- if not focus:
- topStartColor = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 50)
-
- topEndColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)
- bottomStartColor = topEndColor
- bottomEndColor = topEndColor
-
- # Incase we use bottom tabs, switch the colors
- if upperTabs:
- if focus:
- PaintStraightGradientBox(dc, top, topStartColor, topEndColor)
- PaintStraightGradientBox(dc, bottom, bottomStartColor, bottomEndColor)
- else:
- PaintStraightGradientBox(dc, top, topEndColor , topStartColor)
- PaintStraightGradientBox(dc, bottom, bottomStartColor, bottomEndColor)
-
- else:
- if focus:
- PaintStraightGradientBox(dc, bottom, topEndColor, bottomEndColor)
- PaintStraightGradientBox(dc, top,topStartColor, topStartColor)
- else:
- PaintStraightGradientBox(dc, bottom, bottomStartColor, bottomEndColor)
- PaintStraightGradientBox(dc, top, topEndColor, topStartColor)
-
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
-
-# ---------------------------------------------------------------------------- #
-# Class FNBDropSource
-# Gives Some Custom UI Feedback during the DnD Operations
-# ---------------------------------------------------------------------------- #
-
-class FNBDropSource(wx.DropSource):
- """
- Give some custom UI feedback during the drag and drop operation in this
- function. It is called on each mouse move, so your implementation must
- not be too slow.
- """
-
- def __init__(self, win):
- """ Default class constructor. Used internally. """
-
- wx.DropSource.__init__(self, win)
- self._win = win
-
-
- def GiveFeedback(self, effect):
- """ Provides user with a nice feedback when tab is being dragged. """
-
- self._win.DrawDragHint()
- return False
-
-
-# ---------------------------------------------------------------------------- #
-# Class FNBDragInfo
-# Stores All The Information To Allow Drag And Drop Between Different
-# FlatNotebooks.
-# ---------------------------------------------------------------------------- #
-
-class FNBDragInfo:
-
- _map = weakref.WeakValueDictionary()
-
- def __init__(self, container, pageindex):
- """ Default class constructor. """
-
- self._id = id(container)
- FNBDragInfo._map[self._id] = container
- self._pageindex = pageindex
-
-
- def GetContainer(self):
- """ Returns the L{FlatNotebook} page (usually a panel). """
-
- return FNBDragInfo._map.get(self._id, None)
-
-
- def GetPageIndex(self):
- """ Returns the page index associated with a page. """
-
- return self._pageindex
-
-
-# ---------------------------------------------------------------------------- #
-# Class FNBDropTarget
-# Simply Used To Handle The OnDrop() Method When Dragging And Dropping Between
-# Different FlatNotebooks.
-# ---------------------------------------------------------------------------- #
-
-class FNBDropTarget(wx.DropTarget):
-
- def __init__(self, parent):
- """ Default class constructor. """
-
- wx.DropTarget.__init__(self)
-
- self._parent = parent
- self._dataobject = wx.CustomDataObject(wx.CustomDataFormat("FlatNotebook"))
- self.SetDataObject(self._dataobject)
-
-
- def OnData(self, x, y, dragres):
- """ Handles the OnData() method to call the real DnD routine. """
-
- if not self.GetData():
- return wx.DragNone
-
- draginfo = self._dataobject.GetData()
- drginfo = cPickle.loads(draginfo)
-
- return self._parent.OnDropTarget(x, y, drginfo.GetPageIndex(), drginfo.GetContainer())
-
-
-# ---------------------------------------------------------------------------- #
-# Class PageInfo
-# Contains parameters for every FlatNotebook page
-# ---------------------------------------------------------------------------- #
-
-class PageInfo:
- """
- This class holds all the information (caption, image, etc...) belonging to a
- single tab in L{FlatNotebook}.
- """
-
- def __init__(self, caption="", imageindex=-1, tabangle=0, enabled=True):
- """
- Default Class Constructor.
-
- Parameters:
- @param caption: the tab caption;
- @param imageindex: the tab image index based on the assigned (set) wx.ImageList (if any);
- @param tabangle: the tab angle (only on standard tabs, from 0 to 15 degrees);
- @param enabled: sets enabled or disabled the tab.
- """
-
- self._strCaption = caption
- self._TabAngle = tabangle
- self._ImageIndex = imageindex
- self._bEnabled = enabled
- self._pos = wx.Point(-1, -1)
- self._size = wx.Size(-1, -1)
- self._region = wx.Region()
- self._xRect = wx.Rect()
- self._color = None
- self._hasFocus = False
-
-
- def SetCaption(self, value):
- """ Sets the tab caption. """
-
- self._strCaption = value
-
-
- def GetCaption(self):
- """ Returns the tab caption. """
-
- return self._strCaption
-
-
- def SetPosition(self, value):
- """ Sets the tab position. """
-
- self._pos = value
-
-
- def GetPosition(self):
- """ Returns the tab position. """
-
- return self._pos
-
-
- def SetSize(self, value):
- """ Sets the tab size. """
-
- self._size = value
-
-
- def GetSize(self):
- """ Returns the tab size. """
-
- return self._size
-
-
- def SetTabAngle(self, value):
- """ Sets the tab header angle (0 <= tab <= 15 degrees). """
-
- self._TabAngle = min(45, value)
-
-
- def GetTabAngle(self):
- """ Returns the tab angle. """
-
- return self._TabAngle
-
-
- def SetImageIndex(self, value):
- """ Sets the tab image index. """
-
- self._ImageIndex = value
-
-
- def GetImageIndex(self):
- """ Returns the tab umage index. """
-
- return self._ImageIndex
-
-
- def GetEnabled(self):
- """ Returns whether the tab is enabled or not. """
-
- return self._bEnabled
-
-
- def EnableTab(self, enabled):
- """ Sets the tab enabled or disabled. """
-
- self._bEnabled = enabled
-
-
- def SetRegion(self, points=[]):
- """ Sets the tab region. """
-
- self._region = wx.RegionFromPoints(points)
-
-
- def GetRegion(self):
- """ Returns the tab region. """
-
- return self._region
-
-
- def SetXRect(self, xrect):
- """ Sets the button 'X' area rect. """
-
- self._xRect = xrect
-
-
- def GetXRect(self):
- """ Returns the button 'X' area rect. """
-
- return self._xRect
-
-
- def GetColour(self):
- """ Returns the tab colour. """
-
- return self._color
-
-
- def SetColour(self, color):
- """ Sets the tab colour. """
-
- self._color = color
-
-
-# ---------------------------------------------------------------------------- #
-# Class FlatNotebookEvent
-# ---------------------------------------------------------------------------- #
-
-class FlatNotebookEvent(wx.PyCommandEvent):
- """
- This events will be sent when a EVT_FLATNOTEBOOK_PAGE_CHANGED,
- EVT_FLATNOTEBOOK_PAGE_CHANGING, EVT_FLATNOTEBOOK_PAGE_CLOSING,
- EVT_FLATNOTEBOOK_PAGE_CLOSED and EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU is
- mapped in the parent.
- """
-
- def __init__(self, eventType, id=1, nSel=-1, nOldSel=-1):
- """ Default class constructor. """
-
- wx.PyCommandEvent.__init__(self, eventType, id)
- self._eventType = eventType
-
- self.notify = wx.NotifyEvent(eventType, id)
-
-
- def GetNotifyEvent(self):
- """Returns the actual wx.NotifyEvent."""
-
- return self.notify
-
-
- def IsAllowed(self):
- """Returns whether the event is allowed or not."""
-
- return self.notify.IsAllowed()
-
-
- def Veto(self):
- """Vetos the event."""
-
- self.notify.Veto()
-
-
- def Allow(self):
- """The event is allowed."""
-
- self.notify.Allow()
-
-
- def SetSelection(self, nSel):
- """ Sets event selection. """
-
- self._selection = nSel
-
-
- def SetOldSelection(self, nOldSel):
- """ Sets old event selection. """
-
- self._oldselection = nOldSel
-
-
- def GetSelection(self):
- """ Returns event selection. """
-
- return self._selection
-
-
- def GetOldSelection(self):
- """ Returns old event selection """
-
- return self._oldselection
-
-
-# ---------------------------------------------------------------------------- #
-# Class TabNavigatorWindow
-# ---------------------------------------------------------------------------- #
-
-class TabNavigatorWindow(wx.Dialog):
- """
- This class is used to create a modal dialog that enables "Smart Tabbing",
- similar to what you would get by hitting Alt+Tab on Windows.
- """
-
- def __init__(self, parent=None, icon=None):
- """ Default class constructor. Used internally."""
-
- wx.Dialog.__init__(self, parent, wx.ID_ANY, "", style=0)
-
- self._selectedItem = -1
- self._indexMap = []
-
- if icon is None:
- self._bmp = GetMondrianBitmap()
- else:
- self._bmp = icon
-
- sz = wx.BoxSizer(wx.VERTICAL)
-
- self._listBox = wx.ListBox(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(200, 150), [], wx.LB_SINGLE | wx.NO_BORDER)
-
- mem_dc = wx.MemoryDC()
- mem_dc.SelectObject(wx.EmptyBitmap(1,1))
- font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
- font.SetWeight(wx.BOLD)
- mem_dc.SetFont(font)
-
- panelHeight = mem_dc.GetCharHeight()
- panelHeight += 4 # Place a spacer of 2 pixels
-
- # Out signpost bitmap is 24 pixels
- if panelHeight < 24:
- panelHeight = 24
-
- self._panel = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(200, panelHeight))
-
- sz.Add(self._panel)
- sz.Add(self._listBox, 1, wx.EXPAND)
-
- self.SetSizer(sz)
-
- # Connect events to the list box
- self._listBox.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
- self._listBox.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKey)
- self._listBox.Bind(wx.EVT_LISTBOX_DCLICK, self.OnItemSelected)
-
- # Connect paint event to the panel
- self._panel.Bind(wx.EVT_PAINT, self.OnPanelPaint)
- self._panel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnPanelEraseBg)
-
- self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
- self._listBox.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
- self.PopulateListControl(parent)
-
- self.GetSizer().Fit(self)
- self.GetSizer().SetSizeHints(self)
- self.GetSizer().Layout()
- self.Centre()
-
- # Set focus on the list box to avoid having to click on it to change
- # the tab selection under GTK.
- self._listBox.SetFocus()
-
-
- def OnKeyUp(self, event):
- """Handles the wx.EVT_KEY_UP for the L{TabNavigatorWindow}."""
-
- if event.GetKeyCode() == wx.WXK_CONTROL:
- self.CloseDialog()
-
-
- def OnNavigationKey(self, event):
- """Handles the wx.EVT_NAVIGATION_KEY for the L{TabNavigatorWindow}. """
-
- selected = self._listBox.GetSelection()
- bk = self.GetParent()
- maxItems = bk.GetPageCount()
-
- if event.GetDirection():
-
- # Select next page
- if selected == maxItems - 1:
- itemToSelect = 0
- else:
- itemToSelect = selected + 1
-
- else:
-
- # Previous page
- if selected == 0:
- itemToSelect = maxItems - 1
- else:
- itemToSelect = selected - 1
-
- self._listBox.SetSelection(itemToSelect)
-
-
- def PopulateListControl(self, book):
- """Populates the L{TabNavigatorWindow} listbox with a list of tabs."""
-
- selection = book.GetSelection()
- count = book.GetPageCount()
-
- self._listBox.Append(book.GetPageText(selection))
- self._indexMap.append(selection)
-
- prevSel = book.GetPreviousSelection()
-
- if prevSel != wx.NOT_FOUND:
-
- # Insert the previous selection as second entry
- self._listBox.Append(book.GetPageText(prevSel))
- self._indexMap.append(prevSel)
-
- for c in xrange(count):
-
- # Skip selected page
- if c == selection:
- continue
-
- # Skip previous selected page as well
- if c == prevSel:
- continue
-
- self._listBox.Append(book.GetPageText(c))
- self._indexMap.append(c)
-
- # Select the next entry after the current selection
- self._listBox.SetSelection(0)
- dummy = wx.NavigationKeyEvent()
- dummy.SetDirection(True)
- self.OnNavigationKey(dummy)
-
-
- def OnItemSelected(self, event):
- """Handles the wx.EVT_LISTBOX_DCLICK event for the wx.ListBox inside L{TabNavigatorWindow}. """
-
- self.CloseDialog()
-
-
- def CloseDialog(self):
- """Closes the L{TabNavigatorWindow} dialog, setting selection in L{FlatNotebook}."""
-
- bk = self.GetParent()
- self._selectedItem = self._listBox.GetSelection()
- iter = self._indexMap[self._selectedItem]
- self.EndModal(wx.ID_OK)
- wx.CallAfter(bk._pages.FireEvent, iter)
- self.Destroy()
-
-
- def OnPanelPaint(self, event):
- """Handles the wx.EVT_PAINT event for L{TabNavigatorWindow} top panel. """
-
- dc = wx.PaintDC(self._panel)
- rect = self._panel.GetClientRect()
-
- bmp = wx.EmptyBitmap(rect.width, rect.height)
-
- mem_dc = wx.MemoryDC()
- mem_dc.SelectObject(bmp)
-
- endColour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
- startColour = LightColour(endColour, 50)
- PaintStraightGradientBox(mem_dc, rect, startColour, endColour)
-
- # Draw the caption title and place the bitmap
- # get the bitmap optimal position, and draw it
- bmpPt, txtPt = wx.Point(), wx.Point()
- bmpPt.y = (rect.height - self._bmp.GetHeight())/2
- bmpPt.x = 3
- mem_dc.DrawBitmap(self._bmp, bmpPt.x, bmpPt.y, True)
-
- # get the text position, and draw it
- font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
- font.SetWeight(wx.BOLD)
- mem_dc.SetFont(font)
- fontHeight = mem_dc.GetCharHeight()
-
- txtPt.x = bmpPt.x + self._bmp.GetWidth() + 4
- txtPt.y = (rect.height - fontHeight)/2
- mem_dc.SetTextForeground(wx.WHITE)
- mem_dc.DrawText("Opened tabs:", txtPt.x, txtPt.y)
- mem_dc.SelectObject(wx.NullBitmap)
-
- dc.DrawBitmap(bmp, 0, 0)
-
-
- def OnPanelEraseBg(self, event):
- """Handles the wx.EVT_ERASE_BACKGROUND event for L{TabNavigatorWindow} top panel. """
-
- pass
-
-
-# ---------------------------------------------------------------------------- #
-# Class FNBRenderer
-# ---------------------------------------------------------------------------- #
-
-class FNBRenderer:
- """
- Parent class for the 4 renderers defined: I{Standard}, I{VC71}, I{Fancy}
- and I{VC8}. This class implements the common methods of all 4 renderers.
- """
-
- def __init__(self):
- """Default class constructor. """
-
- self._tabHeight = None
-
- if wx.Platform == "__WXMAC__":
- # Hack to get proper highlight color for focus rectangle from
- # current theme by creating a theme brush and getting its color.
- # kThemeBrushFocusHighlight is available on Mac OS 8.5 and higher
- brush = wx.BLACK_BRUSH
- brush.MacSetTheme(Carbon.Appearance.kThemeBrushFocusHighlight)
- self._focusPen = wx.Pen(brush.GetColour(), 2, wx.SOLID)
- else:
- self._focusPen = wx.Pen(wx.BLACK, 1, wx.USER_DASH)
- self._focusPen.SetDashes([1, 1])
- self._focusPen.SetCap(wx.CAP_BUTT)
-
-
- def GetLeftButtonPos(self, pageContainer):
- """ Returns the left button position in the navigation area. """
-
- pc = pageContainer
- style = pc.GetParent().GetWindowStyleFlag()
- rect = pc.GetClientRect()
- clientWidth = rect.width
-
- if style & FNB_NO_X_BUTTON and (style & FNB_DROPDOWN_TABS_LIST != FNB_DROPDOWN_TABS_LIST):
- return clientWidth - 38
- else:
- return clientWidth - 54
-
-
- def GetRightButtonPos(self, pageContainer):
- """ Returns the right button position in the navigation area. """
-
- pc = pageContainer
- style = pc.GetParent().GetWindowStyleFlag()
- rect = pc.GetClientRect()
- clientWidth = rect.width
-
- if style & FNB_NO_X_BUTTON and (style & FNB_DROPDOWN_TABS_LIST != FNB_DROPDOWN_TABS_LIST):
- return clientWidth - 22
- else:
- return clientWidth - 38
-
-
- def GetDropArrowButtonPos(self, pageContainer):
- """ Returns the drop down button position in the navigation area. """
-
- pc = pageContainer
- style = pc.GetParent().GetWindowStyleFlag()
- rect = pc.GetClientRect()
- clientWidth = rect.width
-
- if style & FNB_DROPDOWN_TABS_LIST != FNB_DROPDOWN_TABS_LIST:
- return clientWidth
- else:
- return clientWidth - 22
-
-
- def GetXPos(self, pageContainer):
- """ Returns the 'X' button position in the navigation area. """
-
- pc = pageContainer
- style = pc.GetParent().GetWindowStyleFlag()
- rect = pc.GetClientRect()
- clientWidth = rect.width
-
- if style & FNB_NO_X_BUTTON:
- return clientWidth
- else:
- return clientWidth - 22
-
-
- def GetButtonsAreaLength(self, pageContainer):
- """ Returns the navigation area width. """
-
- pc = pageContainer
- style = pc.GetParent().GetWindowStyleFlag()
-
- # ''
- if style & FNB_NO_NAV_BUTTONS and style & FNB_NO_X_BUTTON and not style & FNB_DROPDOWN_TABS_LIST:
- return 0
-
- # 'x'
- elif style & FNB_NO_NAV_BUTTONS and not style & FNB_NO_X_BUTTON and not style & FNB_DROPDOWN_TABS_LIST:
- return 22
-
- # '<>'
- if not style & FNB_NO_NAV_BUTTONS and style & FNB_NO_X_BUTTON and not style & FNB_DROPDOWN_TABS_LIST:
- return 53 - 16
-
- # 'vx'
- if style & FNB_DROPDOWN_TABS_LIST and not style & FNB_NO_X_BUTTON:
- return 22 + 16
-
- # 'v'
- if style & FNB_DROPDOWN_TABS_LIST and style & FNB_NO_X_BUTTON and style & FNB_NO_NAV_BUTTONS:
- return 22
-
- # '<>v'
- if style & FNB_DROPDOWN_TABS_LIST and style & FNB_NO_X_BUTTON and not style & FNB_NO_NAV_BUTTONS:
- return 53
-
- # '<>x'
- return 53
-
-
- def DrawArrowAccordingToState(self, dc, pc, rect):
-
- lightFactor = (pc.HasFlag(FNB_BACKGROUND_GRADIENT) and [70] or [0])[0]
- PaintStraightGradientBox(dc, rect, pc._tabAreaColor, LightColour(pc._tabAreaColor, lightFactor))
-
-
- def DrawLeftArrow(self, pageContainer, dc):
- """ Draw the left navigation arrow. """
-
- pc = pageContainer
-
- style = pc.GetParent().GetWindowStyleFlag()
- if style & FNB_NO_NAV_BUTTONS:
- return
-
- # Make sure that there are pages in the container
- if not pc._pagesInfoVec:
- return
-
- # Set the bitmap according to the button status
- if pc._nLeftButtonStatus == FNB_BTN_HOVER:
- arrowBmp = wx.BitmapFromXPMData(left_arrow_hilite_xpm)
- elif pc._nLeftButtonStatus == FNB_BTN_PRESSED:
- arrowBmp = wx.BitmapFromXPMData(left_arrow_pressed_xpm)
- else:
- arrowBmp = wx.BitmapFromXPMData(left_arrow_xpm)
-
- if pc._nFrom == 0:
- # Handle disabled arrow
- arrowBmp = wx.BitmapFromXPMData(left_arrow_disabled_xpm)
-
- arrowBmp.SetMask(wx.Mask(arrowBmp, MASK_COLOR))
-
- # Erase old bitmap
- posx = self.GetLeftButtonPos(pc)
- self.DrawArrowAccordingToState(dc, pc, wx.Rect(posx, 6, 16, 14))
-
- # Draw the new bitmap
- dc.DrawBitmap(arrowBmp, posx, 6, True)
-
-
- def DrawRightArrow(self, pageContainer, dc):
- """ Draw the right navigation arrow. """
-
- pc = pageContainer
-
- style = pc.GetParent().GetWindowStyleFlag()
- if style & FNB_NO_NAV_BUTTONS:
- return
-
- # Make sure that there are pages in the container
- if not pc._pagesInfoVec:
- return
-
- # Set the bitmap according to the button status
- if pc._nRightButtonStatus == FNB_BTN_HOVER:
- arrowBmp = wx.BitmapFromXPMData(right_arrow_hilite_xpm)
- elif pc._nRightButtonStatus == FNB_BTN_PRESSED:
- arrowBmp = wx.BitmapFromXPMData(right_arrow_pressed_xpm)
- else:
- arrowBmp = wx.BitmapFromXPMData(right_arrow_xpm)
-
- # Check if the right most tab is visible, if it is
- # don't rotate right anymore
- if pc._pagesInfoVec[-1].GetPosition() != wx.Point(-1, -1):
- arrowBmp = wx.BitmapFromXPMData(right_arrow_disabled_xpm)
-
- arrowBmp.SetMask(wx.Mask(arrowBmp, MASK_COLOR))
-
- # erase old bitmap
- posx = self.GetRightButtonPos(pc)
- self.DrawArrowAccordingToState(dc, pc, wx.Rect(posx, 6, 16, 14))
-
- # Draw the new bitmap
- dc.DrawBitmap(arrowBmp, posx, 6, True)
-
-
- def DrawDropDownArrow(self, pageContainer, dc):
- """ Draws the drop-down arrow in the navigation area. """
-
- pc = pageContainer
-
- # Check if this style is enabled
- style = pc.GetParent().GetWindowStyleFlag()
- if not style & FNB_DROPDOWN_TABS_LIST:
- return
-
- # Make sure that there are pages in the container
- if not pc._pagesInfoVec:
- return
-
- if pc._nArrowDownButtonStatus == FNB_BTN_HOVER:
- downBmp = wx.BitmapFromXPMData(down_arrow_hilite_xpm)
- elif pc._nArrowDownButtonStatus == FNB_BTN_PRESSED:
- downBmp = wx.BitmapFromXPMData(down_arrow_pressed_xpm)
- else:
- downBmp = wx.BitmapFromXPMData(down_arrow_xpm)
-
- downBmp.SetMask(wx.Mask(downBmp, MASK_COLOR))
-
- # erase old bitmap
- posx = self.GetDropArrowButtonPos(pc)
- self.DrawArrowAccordingToState(dc, pc, wx.Rect(posx, 6, 16, 14))
-
- # Draw the new bitmap
- dc.DrawBitmap(downBmp, posx, 6, True)
-
-
- def DrawX(self, pageContainer, dc):
- """ Draw the 'X' navigation button in the navigation area. """
-
- pc = pageContainer
-
- # Check if this style is enabled
- style = pc.GetParent().GetWindowStyleFlag()
- if style & FNB_NO_X_BUTTON:
- return
-
- # Make sure that there are pages in the container
- if not pc._pagesInfoVec:
- return
-
- # Set the bitmap according to the button status
- if pc._nXButtonStatus == FNB_BTN_HOVER:
- xbmp = wx.BitmapFromXPMData(x_button_hilite_xpm)
- elif pc._nXButtonStatus == FNB_BTN_PRESSED:
- xbmp = wx.BitmapFromXPMData(x_button_pressed_xpm)
- else:
- xbmp = wx.BitmapFromXPMData(x_button_xpm)
-
- xbmp.SetMask(wx.Mask(xbmp, MASK_COLOR))
-
- # erase old bitmap
- posx = self.GetXPos(pc)
- self.DrawArrowAccordingToState(dc, pc, wx.Rect(posx, 6, 16, 14))
-
- # Draw the new bitmap
- dc.DrawBitmap(xbmp, posx, 6, True)
-
-
- def DrawTabX(self, pageContainer, dc, rect, tabIdx, btnStatus):
- """ Draws the 'X' in the selected tab. """
-
- pc = pageContainer
- if not pc.HasFlag(FNB_X_ON_TAB):
- return
-
- # We draw the 'x' on the active tab only
- if tabIdx != pc.GetSelection() or tabIdx < 0:
- return
-
- # Set the bitmap according to the button status
-
- if btnStatus == FNB_BTN_HOVER:
- xBmp = wx.BitmapFromXPMData(x_button_hilite_xpm)
- elif btnStatus == FNB_BTN_PRESSED:
- xBmp = wx.BitmapFromXPMData(x_button_pressed_xpm)
- else:
- xBmp = wx.BitmapFromXPMData(x_button_xpm)
-
- # Set the masking
- xBmp.SetMask(wx.Mask(xBmp, MASK_COLOR))
-
- # Draw the new bitmap
- dc.DrawBitmap(xBmp, rect.x, rect.y, True)
-
- # Update the vector
- rr = wx.Rect(rect.x, rect.y, 14, 13)
- pc._pagesInfoVec[tabIdx].SetXRect(rr)
-
-
- def DrawTabsLine(self, pageContainer, dc, selTabX1=-1, selTabX2=-1):
- """ Draws a line over the tabs. """
-
- pc = pageContainer
-
- clntRect = pc.GetClientRect()
- clientRect3 = wx.Rect(0, 0, clntRect.width, clntRect.height)
-
- if pc.HasFlag(FNB_FF2):
- if not pc.HasFlag(FNB_BOTTOM):
- fillColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)
- else:
- fillColor = wx.WHITE
-
- dc.SetPen(wx.Pen(fillColor))
-
- if pc.HasFlag(FNB_BOTTOM):
-
- dc.DrawLine(1, 0, clntRect.width-1, 0)
- dc.DrawLine(1, 1, clntRect.width-1, 1)
-
- dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)))
- dc.DrawLine(1, 2, clntRect.width-1, 2)
-
- dc.SetPen(wx.Pen(fillColor))
- dc.DrawLine(selTabX1 + 2, 2, selTabX2 - 1, 2)
-
- else:
-
- dc.DrawLine(1, clntRect.height, clntRect.width-1, clntRect.height)
- dc.DrawLine(1, clntRect.height-1, clntRect.width-1, clntRect.height-1)
-
- dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)))
- dc.DrawLine(1, clntRect.height-2, clntRect.width-1, clntRect.height-2)
-
- dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)))
- dc.DrawLine(selTabX1 + 2, clntRect.height-2, selTabX2-1, clntRect.height-2)
-
- else:
-
- if pc.HasFlag(FNB_BOTTOM):
-
- clientRect = wx.Rect(0, 2, clntRect.width, clntRect.height - 2)
- clientRect2 = wx.Rect(0, 1, clntRect.width, clntRect.height - 1)
-
- else:
-
- clientRect = wx.Rect(0, 0, clntRect.width, clntRect.height - 2)
- clientRect2 = wx.Rect(0, 0, clntRect.width, clntRect.height - 1)
-
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- dc.SetPen(wx.Pen(pc.GetSingleLineBorderColour()))
- dc.DrawRectangleRect(clientRect2)
- dc.DrawRectangleRect(clientRect3)
-
- dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)))
- dc.DrawRectangleRect(clientRect)
-
- if not pc.HasFlag(FNB_TABS_BORDER_SIMPLE):
-
- dc.SetPen(wx.Pen((pc.HasFlag(FNB_VC71) and [wx.Colour(247, 243, 233)] or [pc._tabAreaColor])[0]))
- dc.DrawLine(0, 0, 0, clientRect.height+1)
-
- if pc.HasFlag(FNB_BOTTOM):
-
- dc.DrawLine(0, clientRect.height+1, clientRect.width, clientRect.height+1)
-
- else:
-
- dc.DrawLine(0, 0, clientRect.width, 0)
-
- dc.DrawLine(clientRect.width - 1, 0, clientRect.width - 1, clientRect.height+1)
-
-
- def CalcTabWidth(self, pageContainer, tabIdx, tabHeight):
- """ Calculates the width of the input tab. """
-
- pc = pageContainer
- dc = wx.MemoryDC()
- dc.SelectObject(wx.EmptyBitmap(1,1))
-
- boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
- boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-
- if pc.IsDefaultTabs():
- shapePoints = int(tabHeight*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
-
- # Calculate the text length using the bold font, so when selecting a tab
- # its width will not change
- dc.SetFont(boldFont)
- width, pom = dc.GetTextExtent(pc.GetPageText(tabIdx))
-
- # Set a minimum size to a tab
- if width < 20:
- width = 20
-
- tabWidth = 2*pc._pParent.GetPadding() + width
-
- # Style to add a small 'x' button on the top right
- # of the tab
- if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
- # The xpm image that contains the 'x' button is 9 pixels
- spacer = 9
- if pc.HasFlag(FNB_VC8):
- spacer = 4
-
- tabWidth += pc._pParent.GetPadding() + spacer
-
- if pc.IsDefaultTabs():
- # Default style
- tabWidth += 2*shapePoints
-
- hasImage = pc._ImageList != None and pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
-
- # For VC71 style, we only add the icon size (16 pixels)
- if hasImage:
-
- if not pc.IsDefaultTabs():
- tabWidth += 16 + pc._pParent.GetPadding()
- else:
- # Default style
- tabWidth += 16 + pc._pParent.GetPadding() + shapePoints/2
-
- return tabWidth
-
-
- def CalcTabHeight(self, pageContainer):
- """ Calculates the height of the input tab. """
-
- if self._tabHeight:
- return self._tabHeight
-
- pc = pageContainer
- dc = wx.MemoryDC()
- dc.SelectObject(wx.EmptyBitmap(1,1))
-
- # For GTK it seems that we must do this steps in order
- # for the tabs will get the proper height on initialization
- # on MSW, preforming these steps yields wierd results
- normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
- boldFont = normalFont
-
- if "__WXGTK__" in wx.PlatformInfo:
- boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
- dc.SetFont(boldFont)
-
- height = dc.GetCharHeight()
-
- tabHeight = height + FNB_HEIGHT_SPACER # We use 8 pixels as padding
- if "__WXGTK__" in wx.PlatformInfo:
- # On GTK the tabs are should be larger
- tabHeight += 6
-
- self._tabHeight = tabHeight
-
- return tabHeight
-
-
- def DrawTabs(self, pageContainer, dc):
- """ Actually draws the tabs in L{FlatNotebook}."""
-
- pc = pageContainer
- if "__WXMAC__" in wx.PlatformInfo:
- # Works well on MSW & GTK, however this lines should be skipped on MAC
- if not pc._pagesInfoVec or pc._nFrom >= len(pc._pagesInfoVec):
- pc.Hide()
- return
-
- # Get the text hight
- tabHeight = self.CalcTabHeight(pageContainer)
- style = pc.GetParent().GetWindowStyleFlag()
-
- # Calculate the number of rows required for drawing the tabs
- rect = pc.GetClientRect()
- clientWidth = rect.width
-
- # Set the maximum client size
- pc.SetSizeHints(self.GetButtonsAreaLength(pc), tabHeight)
- borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
-
- if style & FNB_VC71:
- backBrush = wx.Brush(wx.Colour(247, 243, 233))
- else:
- backBrush = wx.Brush(pc._tabAreaColor)
-
- noselBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE))
- selBrush = wx.Brush(pc._activeTabColor)
-
- size = pc.GetSize()
-
- # Background
- dc.SetTextBackground((style & FNB_VC71 and [wx.Colour(247, 243, 233)] or [pc.GetBackgroundColour()])[0])
- dc.SetTextForeground(pc._activeTextColor)
- dc.SetBrush(backBrush)
-
- # If border style is set, set the pen to be border pen
- if pc.HasFlag(FNB_TABS_BORDER_SIMPLE):
- dc.SetPen(borderPen)
- else:
- colr = (pc.HasFlag(FNB_VC71) and [wx.Colour(247, 243, 233)] or [pc.GetBackgroundColour()])[0]
- dc.SetPen(wx.Pen(colr))
-
- if pc.HasFlag(FNB_FF2):
- lightFactor = (pc.HasFlag(FNB_BACKGROUND_GRADIENT) and [70] or [0])[0]
- PaintStraightGradientBox(dc, pc.GetClientRect(), pc._tabAreaColor, LightColour(pc._tabAreaColor, lightFactor))
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
- dc.DrawRectangle(0, 0, size.x, size.y)
-
- # We always draw the bottom/upper line of the tabs
- # regradless the style
- dc.SetPen(borderPen)
-
- if not pc.HasFlag(FNB_FF2):
- self.DrawTabsLine(pc, dc)
-
- # Restore the pen
- dc.SetPen(borderPen)
-
- if pc.HasFlag(FNB_VC71):
-
- greyLineYVal = (pc.HasFlag(FNB_BOTTOM) and [0] or [size.y - 2])[0]
- whiteLineYVal = (pc.HasFlag(FNB_BOTTOM) and [3] or [size.y - 3])[0]
-
- pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
- dc.SetPen(pen)
-
- # Draw thik grey line between the windows area and
- # the tab area
- for num in xrange(3):
- dc.DrawLine(0, greyLineYVal + num, size.x, greyLineYVal + num)
-
- wbPen = (pc.HasFlag(FNB_BOTTOM) and [wx.BLACK_PEN] or [wx.WHITE_PEN])[0]
- dc.SetPen(wbPen)
- dc.DrawLine(1, whiteLineYVal, size.x - 1, whiteLineYVal)
-
- # Restore the pen
- dc.SetPen(borderPen)
-
- # Draw labels
- normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
- boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
- boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
- dc.SetFont(boldFont)
-
- posx = pc._pParent.GetPadding()
-
- # Update all the tabs from 0 to 'pc._nFrom' to be non visible
- for i in xrange(pc._nFrom):
-
- pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1))
- pc._pagesInfoVec[i].GetRegion().Clear()
-
- count = pc._nFrom
-
- #----------------------------------------------------------
- # Go over and draw the visible tabs
- #----------------------------------------------------------
- x1 = x2 = -1
- for i in xrange(pc._nFrom, len(pc._pagesInfoVec)):
-
- dc.SetPen(borderPen)
-
- if not pc.HasFlag(FNB_FF2):
- dc.SetBrush((i==pc.GetSelection() and [selBrush] or [noselBrush])[0])
-
- # Now set the font to the correct font
- dc.SetFont((i==pc.GetSelection() and [boldFont] or [normalFont])[0])
-
- # Add the padding to the tab width
- # Tab width:
- # +-----------------------------------------------------------+
- # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
- # +-----------------------------------------------------------+
- tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
-
- # Check if we can draw more
- if posx + tabWidth + self.GetButtonsAreaLength(pc) >= clientWidth:
- break
-
- count = count + 1
-
- # By default we clean the tab region
- pc._pagesInfoVec[i].GetRegion().Clear()
-
- # Clean the 'x' buttn on the tab.
- # A 'Clean' rectangle, is a rectangle with width or height
- # with values lower than or equal to 0
- pc._pagesInfoVec[i].GetXRect().SetSize(wx.Size(-1, -1))
-
- # Draw the tab (border, text, image & 'x' on tab)
- self.DrawTab(pc, dc, posx, i, tabWidth, tabHeight, pc._nTabXButtonStatus)
-
- if pc.GetSelection() == i:
- x1 = posx
- x2 = posx + tabWidth + 2
-
- # Restore the text forground
- dc.SetTextForeground(pc._activeTextColor)
-
- # Update the tab position & size
- posy = (pc.HasFlag(FNB_BOTTOM) and [0] or [VERTICAL_BORDER_PADDING])[0]
-
- pc._pagesInfoVec[i].SetPosition(wx.Point(posx, posy))
- pc._pagesInfoVec[i].SetSize(wx.Size(tabWidth, tabHeight))
- self.DrawFocusRectangle(dc, pc, pc._pagesInfoVec[i])
-
- posx += tabWidth
-
- # Update all tabs that can not fit into the screen as non-visible
- for i in xrange(count, len(pc._pagesInfoVec)):
- pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1))
- pc._pagesInfoVec[i].GetRegion().Clear()
-
- # Draw the left/right/close buttons
- # Left arrow
- self.DrawLeftArrow(pc, dc)
- self.DrawRightArrow(pc, dc)
- self.DrawX(pc, dc)
- self.DrawDropDownArrow(pc, dc)
-
- if pc.HasFlag(FNB_FF2):
- self.DrawTabsLine(pc, dc, x1, x2)
-
-
- def DrawFocusRectangle(self, dc, pageContainer, page):
- """ Draws a focus rectangle like the native Notebooks. """
-
- if not page._hasFocus:
- return
-
- tabPos = wx.Point(*page.GetPosition())
- if pageContainer.GetParent().GetWindowStyleFlag() & FNB_VC8:
- vc8ShapeLen = self.CalcTabHeight(pageContainer) - VERTICAL_BORDER_PADDING - 2
- tabPos.x += vc8ShapeLen
-
- rect = wx.RectPS(tabPos, page.GetSize())
- rect = wx.Rect(rect.x+2, rect.y+2, rect.width-4, rect.height-8)
-
- if wx.Platform == '__WXMAC__':
- rect.SetWidth(rect.GetWidth() + 1)
-
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- dc.SetPen(self._focusPen)
- dc.DrawRoundedRectangleRect(rect, 2)
-
-
- def DrawDragHint(self, pc, tabIdx):
- """
- Draws tab drag hint, the default implementation is to do nothing.
- You can override this function to provide a nice feedback to user.
- """
-
- pass
-
-
- def NumberTabsCanFit(self, pageContainer, fr=-1):
-
- pc = pageContainer
-
- rect = pc.GetClientRect()
- clientWidth = rect.width
-
- vTabInfo = []
-
- tabHeight = self.CalcTabHeight(pageContainer)
-
- # The drawing starts from posx
- posx = pc._pParent.GetPadding()
-
- if fr < 0:
- fr = pc._nFrom
-
- for i in xrange(fr, len(pc._pagesInfoVec)):
-
- tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
- if posx + tabWidth + self.GetButtonsAreaLength(pc) >= clientWidth:
- break;
-
- # Add a result to the returned vector
- tabRect = wx.Rect(posx, VERTICAL_BORDER_PADDING, tabWidth , tabHeight)
- vTabInfo.append(tabRect)
-
- # Advance posx
- posx += tabWidth + FNB_HEIGHT_SPACER
-
- return vTabInfo
-
-
-# ---------------------------------------------------------------------------- #
-# Class FNBRendererMgr
-# A manager that handles all the renderers defined below and calls the
-# appropriate one when drawing is needed
-# ---------------------------------------------------------------------------- #
-
-class FNBRendererMgr:
- """
- This class represents a manager that handles all the 4 renderers defined
- and calls the appropriate one when drawing is needed.
- """
-
- def __init__(self):
- """ Default class constructor. """
-
- # register renderers
-
- self._renderers = {}
- self._renderers.update({-1: FNBRendererDefault()})
- self._renderers.update({FNB_VC71: FNBRendererVC71()})
- self._renderers.update({FNB_FANCY_TABS: FNBRendererFancy()})
- self._renderers.update({FNB_VC8: FNBRendererVC8()})
- self._renderers.update({FNB_FF2: FNBRendererFirefox2()})
-
-
- def GetRenderer(self, style):
- """ Returns the current renderer based on the style selected. """
-
- if style & FNB_VC71:
- return self._renderers[FNB_VC71]
-
- if style & FNB_FANCY_TABS:
- return self._renderers[FNB_FANCY_TABS]
-
- if style & FNB_VC8:
- return self._renderers[FNB_VC8]
-
- if style & FNB_FF2:
- return self._renderers[FNB_FF2]
-
- # the default is to return the default renderer
- return self._renderers[-1]
-
-
-#------------------------------------------
-# Default renderer
-#------------------------------------------
-
-class FNBRendererDefault(FNBRenderer):
- """
- This class handles the drawing of tabs using the I{Standard} renderer.
- """
-
- def __init__(self):
- """ Default class constructor. """
-
- FNBRenderer.__init__(self)
-
-
- def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
- """ Draws a tab using the I{Standard} style. """
-
- # Default style
- borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
- pc = pageContainer
-
- tabPoints = [wx.Point() for ii in xrange(7)]
- tabPoints[0].x = posx
- tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0]
-
- tabPoints[1].x = int(posx+(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
- tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
-
- tabPoints[2].x = tabPoints[1].x+2
- tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
-
- tabPoints[3].x = int(posx+tabWidth-(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))-2
- tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
-
- tabPoints[4].x = tabPoints[3].x+2
- tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
-
- tabPoints[5].x = int(tabPoints[4].x+(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
- tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0]
-
- tabPoints[6].x = tabPoints[0].x
- tabPoints[6].y = tabPoints[0].y
-
- if tabIdx == pc.GetSelection():
-
- # Draw the tab as rounded rectangle
- dc.DrawPolygon(tabPoints)
-
- else:
-
- if tabIdx != pc.GetSelection() - 1:
-
- # Draw a vertical line to the right of the text
- pt1x = tabPoints[5].x
- pt1y = (pc.HasFlag(FNB_BOTTOM) and [4] or [tabHeight - 6])[0]
- pt2x = tabPoints[5].x
- pt2y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - 4] or [4])[0]
- dc.DrawLine(pt1x, pt1y, pt2x, pt2y)
-
- if tabIdx == pc.GetSelection():
-
- savePen = dc.GetPen()
- whitePen = wx.Pen(wx.WHITE)
- whitePen.SetWidth(1)
- dc.SetPen(whitePen)
-
- secPt = wx.Point(tabPoints[5].x + 1, tabPoints[5].y)
- dc.DrawLine(tabPoints[0].x, tabPoints[0].y, secPt.x, secPt.y)
-
- # Restore the pen
- dc.SetPen(savePen)
-
- # -----------------------------------
- # Text and image drawing
- # -----------------------------------
-
- # Text drawing offset from the left border of the
- # rectangle
-
- # The width of the images are 16 pixels
- padding = pc.GetParent().GetPadding()
- shapePoints = int(tabHeight*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
- hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
- imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
-
- if hasImage:
- textOffset = 2*pc._pParent._nPadding + 16 + shapePoints/2
- else:
- textOffset = pc._pParent._nPadding + shapePoints/2
-
- textOffset += 2
-
- if tabIdx != pc.GetSelection():
-
- # Set the text background to be like the vertical lines
- dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
-
- if hasImage:
-
- imageXOffset = textOffset - 16 - padding
- pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
- posx + imageXOffset, imageYCoord,
- wx.IMAGELIST_DRAW_TRANSPARENT, True)
-
- dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
-
- # draw 'x' on tab (if enabled)
- if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
-
- textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
- tabCloseButtonXCoord = posx + textOffset + textWidth + 1
-
- # take a bitmap from the position of the 'x' button (the x on tab button)
- # this bitmap will be used later to delete old buttons
- tabCloseButtonYCoord = imageYCoord
- x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
-
- # Draw the tab
- self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)
-
-
-#------------------------------------------
-# Firefox2 renderer
-#------------------------------------------
-class FNBRendererFirefox2(FNBRenderer):
- """
- This class handles the drawing of tabs using the I{Firefox 2} renderer.
- """
-
- def __init__(self):
- """ Default class constructor. """
-
- FNBRenderer.__init__(self)
-
-
- def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
- """ Draws a tab using the I{Firefox 2} style. """
-
- borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
- pc = pageContainer
-
- tabPoints = [wx.Point() for indx in xrange(7)]
- tabPoints[0].x = posx + 2
- tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0]
-
- tabPoints[1].x = tabPoints[0].x
- tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
-
- tabPoints[2].x = tabPoints[1].x+2
- tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
-
- tabPoints[3].x = posx + tabWidth - 2
- tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
-
- tabPoints[4].x = tabPoints[3].x + 2
- tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
-
- tabPoints[5].x = tabPoints[4].x
- tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0]
-
- tabPoints[6].x = tabPoints[0].x
- tabPoints[6].y = tabPoints[0].y
-
- #------------------------------------
- # Paint the tab with gradient
- #------------------------------------
- rr = wx.RectPP(tabPoints[2], tabPoints[5])
- DrawButton(dc, rr, pc.GetSelection() == tabIdx , not pc.HasFlag(FNB_BOTTOM))
-
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- dc.SetPen(borderPen)
-
- # Draw the tab as rounded rectangle
- dc.DrawPolygon(tabPoints)
-
- # -----------------------------------
- # Text and image drawing
- # -----------------------------------
-
- # The width of the images are 16 pixels
- padding = pc.GetParent().GetPadding()
- shapePoints = int(tabHeight*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
- hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
- imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
-
- if hasImage:
- textOffset = 2*padding + 16 + shapePoints/2
- else:
- textOffset = padding + shapePoints/2
-
- textOffset += 2
-
- if tabIdx != pc.GetSelection():
-
- # Set the text background to be like the vertical lines
- dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
-
- if hasImage:
- imageXOffset = textOffset - 16 - padding
- pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
- posx + imageXOffset, imageYCoord,
- wx.IMAGELIST_DRAW_TRANSPARENT, True)
-
- dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
-
- # draw 'x' on tab (if enabled)
- if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
-
- textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
- tabCloseButtonXCoord = posx + textOffset + textWidth + 1
-
- # take a bitmap from the position of the 'x' button (the x on tab button)
- # this bitmap will be used later to delete old buttons
- tabCloseButtonYCoord = imageYCoord
- x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
-
- # Draw the tab
- self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)
-
-
-#------------------------------------------------------------------
-# Visual studio 7.1
-#------------------------------------------------------------------
-
-class FNBRendererVC71(FNBRenderer):
- """
- This class handles the drawing of tabs using the I{VC71} renderer.
- """
-
- def __init__(self):
- """ Default class constructor. """
-
- FNBRenderer.__init__(self)
-
-
- def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
- """ Draws a tab using the I{VC71} style. """
-
- # Visual studio 7.1 style
- borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
- pc = pageContainer
-
- dc.SetPen((tabIdx == pc.GetSelection() and [wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))] or [borderPen])[0])
- dc.SetBrush((tabIdx == pc.GetSelection() and [wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))] or [wx.Brush(wx.Colour(247, 243, 233))])[0])
-
- if tabIdx == pc.GetSelection():
-
- posy = (pc.HasFlag(FNB_BOTTOM) and [0] or [VERTICAL_BORDER_PADDING])[0]
- tabH = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - 5] or [tabHeight - 3])[0]
- dc.DrawRectangle(posx, posy, tabWidth, tabH)
-
- # Draw a black line on the left side of the
- # rectangle
- dc.SetPen(wx.BLACK_PEN)
-
- blackLineY1 = VERTICAL_BORDER_PADDING
- blackLineY2 = tabH
- dc.DrawLine(posx + tabWidth, blackLineY1, posx + tabWidth, blackLineY2)
-
- # To give the tab more 3D look we do the following
- # Incase the tab is on top,
- # Draw a thik white line on topof the rectangle
- # Otherwise, draw a thin (1 pixel) black line at the bottom
-
- pen = wx.Pen((pc.HasFlag(FNB_BOTTOM) and [wx.BLACK] or [wx.WHITE])[0])
- dc.SetPen(pen)
- whiteLinePosY = (pc.HasFlag(FNB_BOTTOM) and [blackLineY2] or [VERTICAL_BORDER_PADDING ])[0]
- dc.DrawLine(posx , whiteLinePosY, posx + tabWidth + 1, whiteLinePosY)
-
- # Draw a white vertical line to the left of the tab
- dc.SetPen(wx.WHITE_PEN)
- if not pc.HasFlag(FNB_BOTTOM):
- blackLineY2 += 1
-
- dc.DrawLine(posx, blackLineY1, posx, blackLineY2)
-
- else:
-
- # We dont draw a rectangle for non selected tabs, but only
- # vertical line on the left
-
- blackLineY1 = (pc.HasFlag(FNB_BOTTOM) and [VERTICAL_BORDER_PADDING + 2] or [VERTICAL_BORDER_PADDING + 1])[0]
- blackLineY2 = pc.GetSize().y - 5
- dc.DrawLine(posx + tabWidth, blackLineY1, posx + tabWidth, blackLineY2)
-
- # -----------------------------------
- # Text and image drawing
- # -----------------------------------
-
- # Text drawing offset from the left border of the
- # rectangle
-
- # The width of the images are 16 pixels
- padding = pc.GetParent().GetPadding()
- hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
- imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [5] or [8])[0]
-
- if hasImage:
- textOffset = 2*pc._pParent._nPadding + 16
- else:
- textOffset = pc._pParent._nPadding
-
- if tabIdx != pc.GetSelection():
-
- # Set the text background to be like the vertical lines
- dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
-
- if hasImage:
-
- imageXOffset = textOffset - 16 - padding
- pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
- posx + imageXOffset, imageYCoord,
- wx.IMAGELIST_DRAW_TRANSPARENT, True)
-
- dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
-
- # draw 'x' on tab (if enabled)
- if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
-
- textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
- tabCloseButtonXCoord = posx + textOffset + textWidth + 1
-
- # take a bitmap from the position of the 'x' button (the x on tab button)
- # this bitmap will be used later to delete old buttons
- tabCloseButtonYCoord = imageYCoord
- x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
-
- # Draw the tab
- self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)
-
-
-#------------------------------------------------------------------
-# Fancy style
-#------------------------------------------------------------------
-
-class FNBRendererFancy(FNBRenderer):
- """
- This class handles the drawing of tabs using the I{Fancy} renderer.
- """
-
- def __init__(self):
- """ Default class constructor. """
-
- FNBRenderer.__init__(self)
-
-
- def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
- """ Draws a tab using the I{Fancy} style, similar to VC71 but with gradients. """
-
- # Fancy tabs - like with VC71 but with the following differences:
- # - The Selected tab is colored with gradient color
- borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
- pc = pageContainer
-
- pen = (tabIdx == pc.GetSelection() and [wx.Pen(pc._pParent.GetBorderColour())] or [wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))])[0]
-
- if tabIdx == pc.GetSelection():
-
- posy = (pc.HasFlag(FNB_BOTTOM) and [2] or [VERTICAL_BORDER_PADDING])[0]
- th = tabHeight - 5
-
- rect = wx.Rect(posx, posy, tabWidth, th)
-
- col2 = (pc.HasFlag(FNB_BOTTOM) and [pc._pParent.GetGradientColourTo()] or [pc._pParent.GetGradientColourFrom()])[0]
- col1 = (pc.HasFlag(FNB_BOTTOM) and [pc._pParent.GetGradientColourFrom()] or [pc._pParent.GetGradientColourTo()])[0]
-
- PaintStraightGradientBox(dc, rect, col1, col2)
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- dc.SetPen(pen)
- dc.DrawRectangleRect(rect)
-
- # erase the bottom/top line of the rectangle
- dc.SetPen(wx.Pen(pc._pParent.GetGradientColourFrom()))
- if pc.HasFlag(FNB_BOTTOM):
- dc.DrawLine(rect.x, 2, rect.x + rect.width, 2)
- else:
- dc.DrawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1)
-
- else:
-
- # We dont draw a rectangle for non selected tabs, but only
- # vertical line on the left
- dc.SetPen(borderPen)
- dc.DrawLine(posx + tabWidth, VERTICAL_BORDER_PADDING + 3, posx + tabWidth, tabHeight - 4)
-
-
- # -----------------------------------
- # Text and image drawing
- # -----------------------------------
-
- # Text drawing offset from the left border of the
- # rectangle
-
- # The width of the images are 16 pixels
- padding = pc.GetParent().GetPadding()
- hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
- imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
-
- if hasImage:
- textOffset = 2*pc._pParent._nPadding + 16
- else:
- textOffset = pc._pParent._nPadding
-
- textOffset += 2
-
- if tabIdx != pc.GetSelection():
-
- # Set the text background to be like the vertical lines
- dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
-
- if hasImage:
-
- imageXOffset = textOffset - 16 - padding
- pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
- posx + imageXOffset, imageYCoord,
- wx.IMAGELIST_DRAW_TRANSPARENT, True)
-
- dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
-
- # draw 'x' on tab (if enabled)
- if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
-
- textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
- tabCloseButtonXCoord = posx + textOffset + textWidth + 1
-
- # take a bitmap from the position of the 'x' button (the x on tab button)
- # this bitmap will be used later to delete old buttons
- tabCloseButtonYCoord = imageYCoord
- x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
-
- # Draw the tab
- self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)
-
-
-#------------------------------------------------------------------
-# Visual studio 2005 (VS8)
-#------------------------------------------------------------------
-class FNBRendererVC8(FNBRenderer):
- """
- This class handles the drawing of tabs using the I{VC8} renderer.
- """
-
- def __init__(self):
- """ Default class constructor. """
-
- FNBRenderer.__init__(self)
- self._first = True
- self._factor = 1
-
-
- def DrawTabs(self, pageContainer, dc):
- """ Draws all the tabs using VC8 style. Overloads The DrawTabs method in parent class. """
-
- pc = pageContainer
-
- if "__WXMAC__" in wx.PlatformInfo:
- # Works well on MSW & GTK, however this lines should be skipped on MAC
- if not pc._pagesInfoVec or pc._nFrom >= len(pc._pagesInfoVec):
- pc.Hide()
- return
-
- # Get the text hight
- tabHeight = self.CalcTabHeight(pageContainer)
-
- # Set the font for measuring the tab height
- normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
- boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
- boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-
- # Calculate the number of rows required for drawing the tabs
- rect = pc.GetClientRect()
-
- # Set the maximum client size
- pc.SetSizeHints(self.GetButtonsAreaLength(pc), tabHeight)
- borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
-
- # Create brushes
- backBrush = wx.Brush(pc._tabAreaColor)
- noselBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE))
- selBrush = wx.Brush(pc._activeTabColor)
- size = pc.GetSize()
-
- # Background
- dc.SetTextBackground(pc.GetBackgroundColour())
- dc.SetTextForeground(pc._activeTextColor)
-
- # If border style is set, set the pen to be border pen
- if pc.HasFlag(FNB_TABS_BORDER_SIMPLE):
- dc.SetPen(borderPen)
- else:
- dc.SetPen(wx.TRANSPARENT_PEN)
-
- lightFactor = (pc.HasFlag(FNB_BACKGROUND_GRADIENT) and [70] or [0])[0]
-
- # For VC8 style, we color the tab area in gradient coloring
- lightcolour = LightColour(pc._tabAreaColor, lightFactor)
- PaintStraightGradientBox(dc, pc.GetClientRect(), pc._tabAreaColor, lightcolour)
-
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- dc.DrawRectangle(0, 0, size.x, size.y)
-
- # We always draw the bottom/upper line of the tabs
- # regradless the style
- dc.SetPen(borderPen)
- self.DrawTabsLine(pc, dc)
-
- # Restore the pen
- dc.SetPen(borderPen)
-
- # Draw labels
- dc.SetFont(boldFont)
-
- # Update all the tabs from 0 to 'pc.self._nFrom' to be non visible
- for i in xrange(pc._nFrom):
-
- pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1))
- pc._pagesInfoVec[i].GetRegion().Clear()
-
- # Draw the visible tabs, in VC8 style, we draw them from right to left
- vTabsInfo = self.NumberTabsCanFit(pc)
-
- activeTabPosx = 0
- activeTabWidth = 0
- activeTabHeight = 0
-
- for cur in xrange(len(vTabsInfo)-1, -1, -1):
-
- # 'i' points to the index of the currently drawn tab
- # in pc.GetPageInfoVector() vector
- i = pc._nFrom + cur
- dc.SetPen(borderPen)
- dc.SetBrush((i==pc.GetSelection() and [selBrush] or [noselBrush])[0])
-
- # Now set the font to the correct font
- dc.SetFont((i==pc.GetSelection() and [boldFont] or [normalFont])[0])
-
- # Add the padding to the tab width
- # Tab width:
- # +-----------------------------------------------------------+
- # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
- # +-----------------------------------------------------------+
-
- tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
- posx = vTabsInfo[cur].x
-
- # By default we clean the tab region
- # incase we use the VC8 style which requires
- # the region, it will be filled by the function
- # drawVc8Tab
- pc._pagesInfoVec[i].GetRegion().Clear()
-
- # Clean the 'x' buttn on the tab
- # 'Clean' rectanlge is a rectangle with width or height
- # with values lower than or equal to 0
- pc._pagesInfoVec[i].GetXRect().SetSize(wx.Size(-1, -1))
-
- # Draw the tab
- # Incase we are drawing the active tab
- # we need to redraw so it will appear on top
- # of all other tabs
-
- # when using the vc8 style, we keep the position of the active tab so we will draw it again later
- if i == pc.GetSelection() and pc.HasFlag(FNB_VC8):
-
- activeTabPosx = posx
- activeTabWidth = tabWidth
- activeTabHeight = tabHeight
-
- else:
-
- self.DrawTab(pc, dc, posx, i, tabWidth, tabHeight, pc._nTabXButtonStatus)
-
- # Restore the text forground
- dc.SetTextForeground(pc._activeTextColor)
-
- # Update the tab position & size
- pc._pagesInfoVec[i].SetPosition(wx.Point(posx, VERTICAL_BORDER_PADDING))
- pc._pagesInfoVec[i].SetSize(wx.Size(tabWidth, tabHeight))
-
- # Incase we are in VC8 style, redraw the active tab (incase it is visible)
- if pc.GetSelection() >= pc._nFrom and pc.GetSelection() < pc._nFrom + len(vTabsInfo):
-
- self.DrawTab(pc, dc, activeTabPosx, pc.GetSelection(), activeTabWidth, activeTabHeight, pc._nTabXButtonStatus)
-
- # Update all tabs that can not fit into the screen as non-visible
- for xx in xrange(pc._nFrom + len(vTabsInfo), len(pc._pagesInfoVec)):
-
- pc._pagesInfoVec[xx].SetPosition(wx.Point(-1, -1))
- pc._pagesInfoVec[xx].GetRegion().Clear()
-
- # Draw the left/right/close buttons
- # Left arrow
- self.DrawLeftArrow(pc, dc)
- self.DrawRightArrow(pc, dc)
- self.DrawX(pc, dc)
- self.DrawDropDownArrow(pc, dc)
-
-
- def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
- """ Draws a tab using VC8 style. """
-
- pc = pageContainer
- borderPen = wx.Pen(pc._pParent.GetBorderColour())
- tabPoints = [wx.Point() for ii in xrange(8)]
-
- # If we draw the first tab or the active tab,
- # we draw a full tab, else we draw a truncated tab
- #
- # X(2) X(3)
- # X(1) X(4)
- #
- # X(5)
- #
- # X(0),(7) X(6)
- #
- #
-
- tabPoints[0].x = (pc.HasFlag(FNB_BOTTOM) and [posx] or [posx+self._factor])[0]
- tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 3])[0]
-
- tabPoints[1].x = tabPoints[0].x + tabHeight - VERTICAL_BORDER_PADDING - 3 - self._factor
- tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
-
- tabPoints[2].x = tabPoints[1].x + 4
- tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
-
- tabPoints[3].x = tabPoints[2].x + tabWidth - 2
- tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
-
- tabPoints[4].x = tabPoints[3].x + 1
- tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabPoints[3].y - 1] or [tabPoints[3].y + 1])[0]
-
- tabPoints[5].x = tabPoints[4].x + 1
- tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [(tabPoints[4].y - 1)] or [tabPoints[4].y + 1])[0]
-
- tabPoints[6].x = tabPoints[2].x + tabWidth
- tabPoints[6].y = tabPoints[0].y
-
- tabPoints[7].x = tabPoints[0].x
- tabPoints[7].y = tabPoints[0].y
-
- pc._pagesInfoVec[tabIdx].SetRegion(tabPoints)
-
- # Draw the polygon
- br = dc.GetBrush()
- dc.SetBrush(wx.Brush((tabIdx == pc.GetSelection() and [pc._activeTabColor] or [pc._colorTo])[0]))
- dc.SetPen(wx.Pen((tabIdx == pc.GetSelection() and [wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)] or [pc._colorBorder])[0]))
- dc.DrawPolygon(tabPoints)
-
- # Restore the brush
- dc.SetBrush(br)
- rect = pc.GetClientRect()
-
- if tabIdx != pc.GetSelection() and not pc.HasFlag(FNB_BOTTOM):
-
- # Top default tabs
- dc.SetPen(wx.Pen(pc._pParent.GetBorderColour()))
- lineY = rect.height
- curPen = dc.GetPen()
- curPen.SetWidth(1)
- dc.SetPen(curPen)
- dc.DrawLine(posx, lineY, posx+rect.width, lineY)
-
- # Incase we are drawing the selected tab, we draw the border of it as well
- # but without the bottom (upper line incase of wxBOTTOM)
- if tabIdx == pc.GetSelection():
-
- borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
- dc.SetPen(borderPen)
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- dc.DrawPolygon(tabPoints)
-
- # Delete the bottom line (or the upper one, incase we use wxBOTTOM)
- dc.SetPen(wx.WHITE_PEN)
- dc.DrawLine(tabPoints[0].x, tabPoints[0].y, tabPoints[6].x, tabPoints[6].y)
-
- self.FillVC8GradientColour(pc, dc, tabPoints, tabIdx == pc.GetSelection(), tabIdx)
-
- # Draw a thin line to the right of the non-selected tab
- if tabIdx != pc.GetSelection():
-
- dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)))
- dc.DrawLine(tabPoints[4].x-1, tabPoints[4].y, tabPoints[5].x-1, tabPoints[5].y)
- dc.DrawLine(tabPoints[5].x-1, tabPoints[5].y, tabPoints[6].x-1, tabPoints[6].y)
-
- # Text drawing offset from the left border of the
- # rectangle
-
- # The width of the images are 16 pixels
- vc8ShapeLen = tabHeight - VERTICAL_BORDER_PADDING - 2
- if pc.TabHasImage(tabIdx):
- textOffset = 2*pc._pParent.GetPadding() + 16 + vc8ShapeLen
- else:
- textOffset = pc._pParent.GetPadding() + vc8ShapeLen
-
- # Draw the image for the tab if any
- imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
-
- if pc.TabHasImage(tabIdx):
-
- imageXOffset = textOffset - 16 - pc._pParent.GetPadding()
- pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
- posx + imageXOffset, imageYCoord,
- wx.IMAGELIST_DRAW_TRANSPARENT, True)
-
- boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-
- # if selected tab, draw text in bold
- if tabIdx == pc.GetSelection():
- boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-
- dc.SetFont(boldFont)
- dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
-
- # draw 'x' on tab (if enabled)
- if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
-
- textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
- tabCloseButtonXCoord = posx + textOffset + textWidth + 1
-
- # take a bitmap from the position of the 'x' button (the x on tab button)
- # this bitmap will be used later to delete old buttons
- tabCloseButtonYCoord = imageYCoord
- x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
- # Draw the tab
- self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)
-
- self.DrawFocusRectangle(dc, pc, pc._pagesInfoVec[tabIdx])
-
-
- def FillVC8GradientColour(self, pageContainer, dc, tabPoints, bSelectedTab, tabIdx):
- """ Fills a tab with a gradient shading. """
-
- # calculate gradient coefficients
- pc = pageContainer
-
- if self._first:
- self._first = False
- pc._colorTo = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 0)
- pc._colorFrom = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 60)
-
- col2 = pc._pParent.GetGradientColourTo()
- col1 = pc._pParent.GetGradientColourFrom()
-
- # If colorful tabs style is set, override the tab color
- if pc.HasFlag(FNB_COLORFUL_TABS):
-
- if not pc._pagesInfoVec[tabIdx].GetColour():
-
- # First time, generate color, and keep it in the vector
- tabColor = RandomColour()
- pc._pagesInfoVec[tabIdx].SetColour(tabColor)
-
- if pc.HasFlag(FNB_BOTTOM):
-
- col2 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 50)
- col1 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 80)
-
- else:
-
- col1 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 50)
- col2 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 80)
-
- size = abs(tabPoints[2].y - tabPoints[0].y) - 1
-
- rf, gf, bf = 0, 0, 0
- rstep = float(col2.Red() - col1.Red())/float(size)
- gstep = float(col2.Green() - col1.Green())/float(size)
- bstep = float(col2.Blue() - col1.Blue())/float(size)
-
- y = tabPoints[0].y
-
- # If we are drawing the selected tab, we need also to draw a line
- # from 0.tabPoints[0].x and tabPoints[6].x . end, we achieve this
- # by drawing the rectangle with transparent brush
- # the line under the selected tab will be deleted by the drwaing loop
- if bSelectedTab:
- self.DrawTabsLine(pc, dc)
-
- while 1:
-
- if pc.HasFlag(FNB_BOTTOM):
-
- if y > tabPoints[0].y + size:
- break
-
- else:
-
- if y < tabPoints[0].y - size:
- break
-
- currCol = wx.Colour(col1.Red() + rf, col1.Green() + gf, col1.Blue() + bf)
-
- dc.SetPen((bSelectedTab and [wx.Pen(pc._activeTabColor)] or [wx.Pen(currCol)])[0])
- startX = self.GetStartX(tabPoints, y, pc.GetParent().GetWindowStyleFlag())
- endX = self.GetEndX(tabPoints, y, pc.GetParent().GetWindowStyleFlag())
- dc.DrawLine(startX, y, endX, y)
-
- # Draw the border using the 'edge' point
- dc.SetPen(wx.Pen((bSelectedTab and [wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)] or [pc._colorBorder])[0]))
-
- dc.DrawPoint(startX, y)
- dc.DrawPoint(endX, y)
-
- # Progress the color
- rf += rstep
- gf += gstep
- bf += bstep
-
- if pc.HasFlag(FNB_BOTTOM):
- y = y + 1
- else:
- y = y - 1
-
-
- def GetStartX(self, tabPoints, y, style):
- """ Returns the x start position of a tab. """
-
- x1, x2, y1, y2 = 0.0, 0.0, 0.0, 0.0
-
- # We check the 3 points to the left
-
- bBottomStyle = (style & FNB_BOTTOM and [True] or [False])[0]
- match = False
-
- if bBottomStyle:
-
- for i in xrange(3):
-
- if y >= tabPoints[i].y and y < tabPoints[i+1].y:
-
- x1 = tabPoints[i].x
- x2 = tabPoints[i+1].x
- y1 = tabPoints[i].y
- y2 = tabPoints[i+1].y
- match = True
- break
-
- else:
-
- for i in xrange(3):
-
- if y <= tabPoints[i].y and y > tabPoints[i+1].y:
-
- x1 = tabPoints[i].x
- x2 = tabPoints[i+1].x
- y1 = tabPoints[i].y
- y2 = tabPoints[i+1].y
- match = True
- break
-
- if not match:
- return tabPoints[2].x
-
- # According to the equation y = ax + b => x = (y-b)/a
- # We know the first 2 points
-
- if x2 == x1:
- return x2
- else:
- a = (y2 - y1)/(x2 - x1)
-
- b = y1 - ((y2 - y1)/(x2 - x1))*x1
-
- if a == 0:
- return int(x1)
-
- x = (y - b)/a
-
- return int(x)
-
-
- def GetEndX(self, tabPoints, y, style):
- """ Returns the x end position of a tab. """
-
- x1, x2, y1, y2 = 0.0, 0.0, 0.0, 0.0
-
- # We check the 3 points to the left
- bBottomStyle = (style & FNB_BOTTOM and [True] or [False])[0]
- match = False
-
- if bBottomStyle:
-
- for i in xrange(7, 3, -1):
-
- if y >= tabPoints[i].y and y < tabPoints[i-1].y:
-
- x1 = tabPoints[i].x
- x2 = tabPoints[i-1].x
- y1 = tabPoints[i].y
- y2 = tabPoints[i-1].y
- match = True
- break
-
- else:
-
- for i in xrange(7, 3, -1):
-
- if y <= tabPoints[i].y and y > tabPoints[i-1].y:
-
- x1 = tabPoints[i].x
- x2 = tabPoints[i-1].x
- y1 = tabPoints[i].y
- y2 = tabPoints[i-1].y
- match = True
- break
-
- if not match:
- return tabPoints[3].x
-
- # According to the equation y = ax + b => x = (y-b)/a
- # We know the first 2 points
-
- # Vertical line
- if x1 == x2:
- return int(x1)
-
- a = (y2 - y1)/(x2 - x1)
- b = y1 - ((y2 - y1)/(x2 - x1))*x1
-
- if a == 0:
- return int(x1)
-
- x = (y - b)/a
-
- return int(x)
-
-
- def NumberTabsCanFit(self, pageContainer, fr=-1):
- """ Returns the number of tabs that can fit in the visible area. """
-
- pc = pageContainer
-
- rect = pc.GetClientRect()
- clientWidth = rect.width
-
- # Empty results
- vTabInfo = []
- tabHeight = self.CalcTabHeight(pageContainer)
-
- # The drawing starts from posx
- posx = pc._pParent.GetPadding()
-
- if fr < 0:
- fr = pc._nFrom
-
- for i in xrange(fr, len(pc._pagesInfoVec)):
-
- vc8glitch = tabHeight + FNB_HEIGHT_SPACER
- tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
-
- if posx + tabWidth + vc8glitch + self.GetButtonsAreaLength(pc) >= clientWidth:
- break
-
- # Add a result to the returned vector
- tabRect = wx.Rect(posx, VERTICAL_BORDER_PADDING, tabWidth, tabHeight)
- vTabInfo.append(tabRect)
-
- # Advance posx
- posx += tabWidth + FNB_HEIGHT_SPACER
-
- return vTabInfo
-
-
-# ---------------------------------------------------------------------------- #
-# Class FlatNotebook
-# ---------------------------------------------------------------------------- #
-
-class FlatNotebook(wx.PyPanel):
- """
- Display one or more windows in a notebook.
-
- B{Events}:
- - B{EVT_FLATNOTEBOOK_PAGE_CHANGING}: sent when the active
- page in the notebook is changing
- - B{EVT_FLATNOTEBOOK_PAGE_CHANGED}: sent when the active
- page in the notebook has changed
- - B{EVT_FLATNOTEBOOK_PAGE_CLOSING}: sent when a page in the
- notebook is closing
- - B{EVT_FLATNOTEBOOK_PAGE_CLOSED}: sent when a page in the
- notebook has been closed
- - B{EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU}: sent when the user
- clicks a tab in the notebook with the right mouse
- button
- """
-
- def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
- style=0, name="FlatNotebook"):
- """
- Default class constructor.
-
- All the parameters are as in wxPython class construction, except the
- 'style': this can be assigned to whatever combination of FNB_* styles.
-
- """
-
- self._bForceSelection = False
- self._nPadding = 6
- self._nFrom = 0
- style |= wx.TAB_TRAVERSAL
- self._pages = None
- self._windows = []
- self._popupWin = None
- self._naviIcon = None
-
- wx.PyPanel.__init__(self, parent, id, pos, size, style)
-
- self._pages = PageContainer(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, style)
-
- self.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKey)
-
- self.Init()
-
-
- def Init(self):
- """ Initializes all the class attributes. """
-
- self._pages._colorBorder = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
-
- self._mainSizer = wx.BoxSizer(wx.VERTICAL)
- self.SetSizer(self._mainSizer)
-
- # The child panels will inherit this bg color, so leave it at the default value
- #self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_APPWORKSPACE))
-
- # Set default page height
- dc = wx.ClientDC(self)
-
- if "__WXGTK__" in wx.PlatformInfo:
- # For GTK it seems that we must do this steps in order
- # for the tabs will get the proper height on initialization
- # on MSW, preforming these steps yields wierd results
- boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
- boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
- dc.SetFont(boldFont)
-
- height = dc.GetCharHeight()
-
- tabHeight = height + FNB_HEIGHT_SPACER # We use 8 pixels as padding
-
- if "__WXGTK__" in wx.PlatformInfo:
- tabHeight += 6
-
- self._pages.SetSizeHints(-1, tabHeight)
- # Add the tab container to the sizer
- self._mainSizer.Insert(0, self._pages, 0, wx.EXPAND)
- self._mainSizer.Layout()
-
- self._pages._nFrom = self._nFrom
- self._pDropTarget = FNBDropTarget(self)
- self.SetDropTarget(self._pDropTarget)
-
-
- def DoGetBestSize(self):
- """ Overrides DoGetBestSize to handle sizers nicely. """
-
- if not self._windows:
- # Something is better than nothing... no pages!
- return wx.Size(20, 20)
-
- maxWidth = maxHeight = 0
- tabHeight = self.GetPageBestSize().height
-
- for win in self._windows:
- # Loop over all the windows to get their best size
- width, height = win.GetBestSize()
- maxWidth, maxHeight = max(maxWidth, width), max(maxHeight, height)
-
- return wx.Size(maxWidth, maxHeight+tabHeight)
-
-
- def SetActiveTabTextColour(self, textColour):
- """ Sets the text colour for the active tab. """
-
- self._pages._activeTextColor = textColour
-
-
- def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer):
- """ Handles the drop action from a DND operation. """
-
- return self._pages.OnDropTarget(x, y, nTabPage, wnd_oldContainer)
-
-
- def GetPreviousSelection(self):
- """ Returns the previous selection. """
-
- return self._pages._iPreviousActivePage
-
-
- def AddPage(self, page, text, select=True, imageId=-1):
- """
- Add a page to the L{FlatNotebook}.
-
- @param page: Specifies the new page.
- @param text: Specifies the text for the new page.
- @param select: Specifies whether the page should be selected.
- @param imageId: Specifies the optional image index for the new page.
-
- Return value:
- True if successful, False otherwise.
- """
-
- # sanity check
- if not page:
- return False
-
- # reparent the window to us
- page.Reparent(self)
-
- # Add tab
- bSelected = select or len(self._windows) == 0
-
- if bSelected:
-
- bSelected = False
-
- # Check for selection and send events
- oldSelection = self._pages._iActivePage
- tabIdx = len(self._windows)
-
- event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetId())
- event.SetSelection(tabIdx)
- event.SetOldSelection(oldSelection)
- event.SetEventObject(self)
-
- if not self.GetEventHandler().ProcessEvent(event) or event.IsAllowed() or len(self._windows) == 0:
- bSelected = True
-
- curSel = self._pages.GetSelection()
-
- if not self._pages.IsShown():
- self._pages.Show()
-
- self._pages.AddPage(text, bSelected, imageId)
- self._windows.append(page)
-
- self.Freeze()
-
- # Check if a new selection was made
- if bSelected:
-
- if curSel >= 0:
-
- # Remove the window from the main sizer
- self._mainSizer.Detach(self._windows[curSel])
- self._windows[curSel].Hide()
-
- if self.GetWindowStyleFlag() & FNB_BOTTOM:
-
- self._mainSizer.Insert(0, page, 1, wx.EXPAND)
-
- else:
-
- # We leave a space of 1 pixel around the window
- self._mainSizer.Add(page, 1, wx.EXPAND)
-
- # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
- event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
- event.SetOldSelection(oldSelection)
- self.GetEventHandler().ProcessEvent(event)
-
- else:
-
- # Hide the page
- page.Hide()
-
- self.Thaw()
- self._mainSizer.Layout()
- self.Refresh()
-
- return True
-
-
- def SetImageList(self, imageList):
- """ Sets the image list for the page control. """
-
- self._pages.SetImageList(imageList)
-
-
- def AssignImageList(self, imageList):
- """ Assigns the image list for the page control. """
-
- self._pages.AssignImageList(imageList)
-
-
- def GetImageList(self):
- """ Returns the associated image list. """
-
- return self._pages.GetImageList()
-
-
- def InsertPage(self, indx, page, text, select=True, imageId=-1):
- """
- Inserts a new page at the specified position.
-
- @param indx: Specifies the position of the new page.
- @param page: Specifies the new page.
- @param text: Specifies the text for the new page.
- @param select: Specifies whether the page should be selected.
- @param imageId: Specifies the optional image index for the new page.
-
- Return value:
- True if successful, False otherwise.
- """
-
- # sanity check
- if not page:
- return False
-
- # reparent the window to us
- page.Reparent(self)
-
- if not self._windows:
-
- self.AddPage(page, text, select, imageId)
- return True
-
- # Insert tab
- bSelected = select or not self._windows
- curSel = self._pages.GetSelection()
-
- indx = max(0, min(indx, len(self._windows)))
-
- if indx <= len(self._windows):
-
- self._windows.insert(indx, page)
-
- else:
-
- self._windows.append(page)
-
- if bSelected:
-
- bSelected = False
-
- # Check for selection and send events
- oldSelection = self._pages._iActivePage
-
- event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetId())
- event.SetSelection(indx)
- event.SetOldSelection(oldSelection)
- event.SetEventObject(self)
-
- if not self.GetEventHandler().ProcessEvent(event) or event.IsAllowed() or len(self._windows) == 0:
- bSelected = True
-
- self._pages.InsertPage(indx, text, bSelected, imageId)
-
- if indx <= curSel:
- curSel = curSel + 1
-
- self.Freeze()
-
- # Check if a new selection was made
- if bSelected:
-
- if curSel >= 0:
-
- # Remove the window from the main sizer
- self._mainSizer.Detach(self._windows[curSel])
- self._windows[curSel].Hide()
-
- self._pages.SetSelection(indx)
-
- # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
- event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
- event.SetOldSelection(oldSelection)
- self.GetEventHandler().ProcessEvent(event)
-
- else:
-
- # Hide the page
- page.Hide()
-
- self.Thaw()
- self._mainSizer.Layout()
- self.Refresh()
-
- return True
-
-
- def SetSelection(self, page):
- """
- Sets the selection for the given page.
- The call to this function generates the page changing events
- """
-
- if page >= len(self._windows) or not self._windows:
- return
-
- # Support for disabed tabs
- if not self._pages.GetEnabled(page) and len(self._windows) > 1 and not self._bForceSelection:
- return
-
- curSel = self._pages.GetSelection()
-
- # program allows the page change
- self.Freeze()
- if curSel >= 0:
-
- # Remove the window from the main sizer
- self._mainSizer.Detach(self._windows[curSel])
- self._windows[curSel].Hide()
-
- if self.GetWindowStyleFlag() & FNB_BOTTOM:
-
- self._mainSizer.Insert(0, self._windows[page], 1, wx.EXPAND)
-
- else:
-
- # We leave a space of 1 pixel around the window
- self._mainSizer.Add(self._windows[page], 1, wx.EXPAND)
-
- self._windows[page].Show()
- self.Thaw()
-
- self._mainSizer.Layout()
-
- if page != self._pages._iActivePage:
- # there is a real page changing
- self._pages._iPreviousActivePage = self._pages._iActivePage
-
- self._pages._iActivePage = page
- self._pages.DoSetSelection(page)
-
- def DeletePage(self, page):
- """
- Deletes the specified page, and the associated window.
- The call to this function generates the page changing events.
- """
-
- if page >= len(self._windows) or page < 0:
- return
-
- # Fire a closing event
- event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId())
- event.SetSelection(page)
- event.SetEventObject(self)
- self.GetEventHandler().ProcessEvent(event)
-
- # The event handler allows it?
- if not event.IsAllowed():
- return
-
- self.Freeze()
-
- # Delete the requested page
- pageRemoved = self._windows[page]
-
- # If the page is the current window, remove it from the sizer
- # as well
- if page == self._pages.GetSelection():
- self._mainSizer.Detach(pageRemoved)
-
- # Remove it from the array as well
- self._windows.pop(page)
-
- # Now we can destroy it in wxWidgets use Destroy instead of delete
- pageRemoved.Destroy()
-
- self.Thaw()
-
- self._pages.DoDeletePage(page)
- self.Refresh()
- self.Update()
-
- # Fire a closed event
- closedEvent = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED, self.GetId())
- closedEvent.SetSelection(page)
- closedEvent.SetEventObject(self)
- self.GetEventHandler().ProcessEvent(closedEvent)
-
-
- def DeleteAllPages(self):
- """ Deletes all the pages. """
-
- if not self._windows:
- return False
-
- self.Freeze()
-
- for page in self._windows:
- page.Destroy()
-
- self._windows = []
- self.Thaw()
-
- # Clear the container of the tabs as well
- self._pages.DeleteAllPages()
- return True
-
-
- def GetCurrentPage(self):
- """ Returns the currently selected notebook page or None. """
-
- sel = self._pages.GetSelection()
- if sel < 0:
- return None
-
- return self._windows[sel]
-
-
- def GetPage(self, page):
- """ Returns the window at the given page position, or None. """
-
- if page >= len(self._windows):
- return None
-
- return self._windows[page]
-
-
- def GetPageIndex(self, win):
- """ Returns the index at which the window is found. """
-
- try:
- return self._windows.index(win)
- except:
- return -1
-
-
- def GetSelection(self):
- """ Returns the currently selected page, or -1 if none was selected. """
-
- return self._pages.GetSelection()
-
-
- def AdvanceSelection(self, forward=True):
- """
- Cycles through the tabs.
- The call to this function generates the page changing events.
- """
-
- self._pages.AdvanceSelection(forward)
-
-
- def GetPageCount(self):
- """ Returns the number of pages in the L{FlatNotebook} control. """
-
- return self._pages.GetPageCount()
-
- def SetNavigatorIcon(self, bmp):
- """ Set the icon used by the L{TabNavigatorWindow} """
- if isinstance(bmp, wx.Bitmap) and bmp.IsOk():
- # Make sure image is proper size
- if bmp.GetSize() != (16, 16):
- img = bmp.ConvertToImage()
- img.Rescale(16, 16, wx.IMAGE_QUALITY_HIGH)
- bmp = wx.BitmapFromImage(img)
- self._naviIcon = bmp
- else:
- raise TypeError, "SetNavigatorIcon requires a valid bitmap"
-
- def Navigation(self, direction=True):
- if len(self._windows) >= 1:
- if not self._popupWin:
- self._popupWin = TabNavigatorWindow(self, self._naviIcon)
- self._popupWin.SetReturnCode(wx.ID_OK)
- self._popupWin.ShowModal()
- self._popupWin.Destroy()
- self._popupWin = None
- else:
- # a dialog is already opened
- self._popupWin.Navigation(direction)
-
- def OnNavigationKey(self, event):
- """ Handles the wx.EVT_NAVIGATION_KEY event for L{FlatNotebook}. """
-
- if event.IsWindowChange():
- if len(self._windows) == 0:
- return
- # change pages
- if self.HasFlag(FNB_SMART_TABS):
- if not self._popupWin:
- self._popupWin = TabNavigatorWindow(self, self._naviIcon)
- self._popupWin.SetReturnCode(wx.ID_OK)
- self._popupWin.ShowModal()
- self._popupWin.Destroy()
- self._popupWin = None
- else:
- # a dialog is already opened
- self._popupWin.OnNavigationKey(event)
- return
- else:
- # change pages
- self.AdvanceSelection(event.GetDirection())
-
- else:
- event.Skip()
-
-
- def GetPageShapeAngle(self, page_index):
- """ Returns the angle associated to a tab. """
-
- if page_index < 0 or page_index >= len(self._pages._pagesInfoVec):
- return None, False
-
- result = self._pages._pagesInfoVec[page_index].GetTabAngle()
- return result, True
-
-
- def SetPageShapeAngle(self, page_index, angle):
- """ Sets the angle associated to a tab. """
-
- if page_index < 0 or page_index >= len(self._pages._pagesInfoVec):
- return
-
- if angle > 15:
- return
-
- self._pages._pagesInfoVec[page_index].SetTabAngle(angle)
-
-
- def SetAllPagesShapeAngle(self, angle):
- """ Sets the angle associated to all the tab. """
-
- if angle > 15:
- return
-
- for ii in xrange(len(self._pages._pagesInfoVec)):
- self._pages._pagesInfoVec[ii].SetTabAngle(angle)
-
- self.Refresh()
-
-
- def GetPageBestSize(self):
- """ Return the page best size. """
-
- return self._pages.GetClientSize()
-
-
- def SetPageText(self, page, text):
- """ Sets the text for the given page. """
-
- bVal = self._pages.SetPageText(page, text)
- self._pages.EnsureVisible(page, False)
- self._pages.Refresh()
-
- return bVal
-
-
- def SetPadding(self, padding):
- """
- Sets the amount of space around each page's icon and label, in pixels.
- NB: only the horizontal padding is considered.
- """
-
- self._nPadding = padding.GetWidth()
-
-
- def GetTabArea(self):
- """ Returns the associated page. """
-
- return self._pages
-
-
- def GetPadding(self):
- """ Returns the amount of space around each page's icon and label, in pixels. """
-
- return self._nPadding
-
-
- def SetWindowStyleFlag(self, style):
- """ Sets the L{FlatNotebook} window style flags. """
-
- wx.PyPanel.SetWindowStyleFlag(self, style)
- renderer = self._pages._mgr.GetRenderer(self.GetWindowStyleFlag())
- renderer._tabHeight = None
-
- if self._pages:
-
- # For changing the tab position (i.e. placing them top/bottom)
- # refreshing the tab container is not enough
- self.SetSelection(self._pages._iActivePage)
-
- if not self._pages.HasFlag(FNB_HIDE_ON_SINGLE_TAB):
- #For Redrawing the Tabs once you remove the Hide tyle
- self._pages._ReShow()
-
-
- def RemovePage(self, page):
- """ Deletes the specified page, without deleting the associated window. """
-
- if page >= len(self._windows):
- return False
-
- # Fire a closing event
- event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId())
- event.SetSelection(page)
- event.SetEventObject(self)
- self.GetEventHandler().ProcessEvent(event)
-
- # The event handler allows it?
- if not event.IsAllowed():
- return False
-
- self.Freeze()
-
- # Remove the requested page
- pageRemoved = self._windows[page]
-
- # If the page is the current window, remove it from the sizer
- # as well
- if page == self._pages.GetSelection():
- self._mainSizer.Detach(pageRemoved)
-
- # Remove it from the array as well
- self._windows.pop(page)
- self.Thaw()
-
- self._pages.DoDeletePage(page)
-
- return True
-
-
- def SetRightClickMenu(self, menu):
- """ Sets the popup menu associated to a right click on a tab. """
-
- self._pages._pRightClickMenu = menu
-
-
- def GetPageText(self, nPage):
- """ Returns the tab caption. """
-
- return self._pages.GetPageText(nPage)
-
-
- def SetGradientColours(self, fr, to, border):
- """ Sets the gradient colours for the tab. """
-
- self._pages._colorFrom = fr
- self._pages._colorTo = to
- self._pages._colorBorder = border
-
-
- def SetGradientColourFrom(self, fr):
- """ Sets the starting colour for the gradient. """
-
- self._pages._colorFrom = fr
-
-
- def SetGradientColourTo(self, to):
- """ Sets the ending colour for the gradient. """
-
- self._pages._colorTo = to
-
-
- def SetGradientColourBorder(self, border):
- """ Sets the tab border colour. """
-
- self._pages._colorBorder = border
-
-
- def GetGradientColourFrom(self):
- """ Gets first gradient colour. """
-
- return self._pages._colorFrom
-
-
- def GetGradientColourTo(self):
- """ Gets second gradient colour. """
-
- return self._pages._colorTo
-
-
- def GetGradientColourBorder(self):
- """ Gets the tab border colour. """
-
- return self._pages._colorBorder
-
-
- def GetBorderColour(self):
- """ Returns the border colour. """
-
- return self._pages._colorBorder
-
-
- def GetActiveTabTextColour(self):
- """ Get the active tab text colour. """
-
- return self._pages._activeTextColor
-
-
- def SetPageImage(self, page, image):
- """
- Sets the image index for the given page. Image is an index into the
- image list which was set with SetImageList.
- """
-
- self._pages.SetPageImage(page, image)
-
-
- def GetPageImage(self, nPage):
- """
- Returns the image index for the given page. Image is an index into the
- image list which was set with SetImageList.
- """
-
- return self._pages.GetPageImage(nPage)
-
-
- def GetEnabled(self, page):
- """ Returns whether a tab is enabled or not. """
-
- return self._pages.GetEnabled(page)
-
-
- def EnableTab(self, page, enabled=True):
- """ Enables or disables a tab. """
-
- if page >= len(self._windows):
- return
-
- self._windows[page].Enable(enabled)
- self._pages.EnableTab(page, enabled)
-
-
- def GetNonActiveTabTextColour(self):
- """ Returns the non active tabs text colour. """
-
- return self._pages._nonActiveTextColor
-
-
- def SetNonActiveTabTextColour(self, color):
- """ Sets the non active tabs text colour. """
-
- self._pages._nonActiveTextColor = color
-
-
- def SetTabAreaColour(self, color):
- """ Sets the area behind the tabs colour. """
-
- self._pages._tabAreaColor = color
-
-
- def GetTabAreaColour(self):
- """ Returns the area behind the tabs colour. """
-
- return self._pages._tabAreaColor
-
-
- def SetActiveTabColour(self, color):
- """ Sets the active tab colour. """
-
- self._pages._activeTabColor = color
-
-
- def GetActiveTabColour(self):
- """ Returns the active tab colour. """
-
- return self._pages._activeTabColor
-
-
- def EnsureVisible(self, page):
- """ Ensures that a tab is visible. """
-
- self._pages.DoSetSelection(page)
-
-
-# ---------------------------------------------------------------------------- #
-# Class PageContainer
-# Acts as a container for the pages you add to FlatNotebook
-# ---------------------------------------------------------------------------- #
-
-class PageContainer(wx.Panel):
- """
- This class acts as a container for the pages you add to L{FlatNotebook}.
- """
-
- def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
- size=wx.DefaultSize, style=0):
- """ Default class constructor. """
-
- self._ImageList = None
- self._iActivePage = -1
- self._pDropTarget = None
- self._nLeftClickZone = FNB_NOWHERE
- self._iPreviousActivePage = -1
-
- self._pRightClickMenu = None
- self._nXButtonStatus = FNB_BTN_NONE
- self._nArrowDownButtonStatus = FNB_BTN_NONE
- self._pParent = parent
- self._nRightButtonStatus = FNB_BTN_NONE
- self._nLeftButtonStatus = FNB_BTN_NONE
- self._nTabXButtonStatus = FNB_BTN_NONE
-
- self._pagesInfoVec = []
-
- self._colorTo = wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION)
- self._colorFrom = wx.WHITE
- self._activeTabColor = wx.WHITE
- self._activeTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNTEXT)
- self._nonActiveTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNTEXT)
- self._tabAreaColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE)
-
- self._nFrom = 0
- self._isdragging = False
-
- # Set default page height, this is done according to the system font
- memDc = wx.MemoryDC()
- memDc.SelectObject(wx.EmptyBitmap(1,1))
-
- if "__WXGTK__" in wx.PlatformInfo:
- boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
- boldFont.SetWeight(wx.BOLD)
- memDc.SetFont(boldFont)
-
- height = memDc.GetCharHeight()
- tabHeight = height + FNB_HEIGHT_SPACER # We use 10 pixels as padding
-
- wx.Panel.__init__(self, parent, id, pos, wx.Size(size.x, tabHeight),
- style|wx.NO_BORDER|wx.NO_FULL_REPAINT_ON_RESIZE|wx.WANTS_CHARS)
-
- self._pDropTarget = FNBDropTarget(self)
- self.SetDropTarget(self._pDropTarget)
- self._mgr = FNBRendererMgr()
-
- self.Bind(wx.EVT_PAINT, self.OnPaint)
- self.Bind(wx.EVT_SIZE, self.OnSize)
- self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
- self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
- self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
- self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
- self.Bind(wx.EVT_MOTION, self.OnMouseMove)
- self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
- self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
- self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnterWindow)
- self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
- self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
- self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
- self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
-
-
- def OnEraseBackground(self, event):
- """ Handles the wx.EVT_ERASE_BACKGROUND event for L{PageContainer} (does nothing)."""
-
- pass
-
-
- def _ReShow(self):
- """ Handles the Redraw of the tabs when the FNB_HIDE_ON_SINGLE_TAB has been removed """
- self.Show()
- self.GetParent()._mainSizer.Layout()
- self.Refresh()
-
-
- def OnPaint(self, event):
- """ Handles the wx.EVT_PAINT event for L{PageContainer}."""
-
- dc = wx.BufferedPaintDC(self)
- renderer = self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag())
- renderer.DrawTabs(self, dc)
-
- if self.HasFlag(FNB_HIDE_ON_SINGLE_TAB) and len(self._pagesInfoVec) <= 1:
- self.Hide()
- self.GetParent()._mainSizer.Layout()
- self.Refresh()
-
-
- def AddPage(self, caption, selected=True, imgindex=-1):
- """
- Add a page to the L{FlatNotebook}.
-
- @param window: Specifies the new page.
- @param caption: Specifies the text for the new page.
- @param selected: Specifies whether the page should be selected.
- @param imgindex: Specifies the optional image index for the new page.
-
- Return value:
- True if successful, False otherwise.
- """
-
- if selected:
-
- self._iPreviousActivePage = self._iActivePage
- self._iActivePage = len(self._pagesInfoVec)
-
- # Create page info and add it to the vector
- pageInfo = PageInfo(caption, imgindex)
- self._pagesInfoVec.append(pageInfo)
- self.Refresh()
-
-
- def InsertPage(self, indx, text, selected=True, imgindex=-1):
- """
- Inserts a new page at the specified position.
-
- @param indx: Specifies the position of the new page.
- @param page: Specifies the new page.
- @param text: Specifies the text for the new page.
- @param select: Specifies whether the page should be selected.
- @param imgindex: Specifies the optional image index for the new page.
-
- Return value:
- True if successful, False otherwise.
- """
-
- if selected:
-
- self._iPreviousActivePage = self._iActivePage
- self._iActivePage = len(self._pagesInfoVec)
-
- self._pagesInfoVec.insert(indx, PageInfo(text, imgindex))
-
- self.Refresh()
- return True
-
-
- def OnSize(self, event):
- """ Handles the wx.EVT_SIZE events for L{PageContainer}. """
-
- # When resizing the control, try to fit to screen as many tabs as we can
- style = self.GetParent().GetWindowStyleFlag()
- renderer = self._mgr.GetRenderer(style)
-
- fr = 0
- page = self.GetSelection()
-
- for fr in xrange(self._nFrom):
- vTabInfo = renderer.NumberTabsCanFit(self, fr)
- if page - fr >= len(vTabInfo):
- continue
- break
-
- self._nFrom = fr
-
- self.EnsureVisible(page, False)
- self.Refresh() # Call on paint
- event.Skip()
-
-
- def OnMiddleDown(self, event):
- """ Handles the wx.EVT_MIDDLE_DOWN events for L{PageContainer}. """
-
- # Test if this style is enabled
- style = self.GetParent().GetWindowStyleFlag()
-
- if not style & FNB_MOUSE_MIDDLE_CLOSES_TABS:
- return
-
- where, tabIdx = self.HitTest(event.GetPosition())
-
- if where == FNB_TAB:
- self.DeletePage(tabIdx)
-
- event.Skip()
-
-
- def OnRightDown(self, event):
- """ Handles the wx.EVT_RIGHT_DOWN events for L{PageContainer}. """
-
- where, tabIdx = self.HitTest(event.GetPosition())
-
- if where in [FNB_TAB, FNB_TAB_X]:
-
- if self._pagesInfoVec[tabIdx].GetEnabled():
- # Fire events and eventually (if allowed) change selection
- self.FireEvent(tabIdx)
-
- # send a message to popup a custom menu
- event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU, self.GetParent().GetId())
- event.SetSelection(tabIdx)
- event.SetOldSelection(self._iActivePage)
- event.SetEventObject(self.GetParent())
- self.GetParent().GetEventHandler().ProcessEvent(event)
-
- if self._pRightClickMenu:
- self.PopupMenu(self._pRightClickMenu)
-
- event.Skip()
-
-
- def OnLeftDown(self, event):
- """ Handles the wx.EVT_LEFT_DOWN events for L{PageContainer}. """
-
- # Reset buttons status
- self._nXButtonStatus = FNB_BTN_NONE
- self._nLeftButtonStatus = FNB_BTN_NONE
- self._nRightButtonStatus = FNB_BTN_NONE
- self._nTabXButtonStatus = FNB_BTN_NONE
- self._nArrowDownButtonStatus = FNB_BTN_NONE
-
- self._nLeftClickZone, tabIdx = self.HitTest(event.GetPosition())
-
- if self._nLeftClickZone == FNB_DROP_DOWN_ARROW:
- self._nArrowDownButtonStatus = FNB_BTN_PRESSED
- self.Refresh()
- elif self._nLeftClickZone == FNB_LEFT_ARROW:
- self._nLeftButtonStatus = FNB_BTN_PRESSED
- self.Refresh()
- elif self._nLeftClickZone == FNB_RIGHT_ARROW:
- self._nRightButtonStatus = FNB_BTN_PRESSED
- self.Refresh()
- elif self._nLeftClickZone == FNB_X:
- self._nXButtonStatus = FNB_BTN_PRESSED
- self.Refresh()
- elif self._nLeftClickZone == FNB_TAB_X:
- self._nTabXButtonStatus = FNB_BTN_PRESSED
- self.Refresh()
-
- elif self._nLeftClickZone == FNB_TAB:
-
- if self._iActivePage != tabIdx:
-
- # In case the tab is disabled, we dont allow to choose it
- if self._pagesInfoVec[tabIdx].GetEnabled():
- self.FireEvent(tabIdx)
-
-
- def RotateLeft(self):
-
- if self._nFrom == 0:
- return
-
- # Make sure that the button was pressed before
- if self._nLeftButtonStatus != FNB_BTN_PRESSED:
- return
-
- self._nLeftButtonStatus = FNB_BTN_HOVER
-
- # We scroll left with bulks of 5
- scrollLeft = self.GetNumTabsCanScrollLeft()
-
- self._nFrom -= scrollLeft
- if self._nFrom < 0:
- self._nFrom = 0
-
- self.Refresh()
-
-
- def RotateRight(self):
-
- if self._nFrom >= len(self._pagesInfoVec) - 1:
- return
-
- # Make sure that the button was pressed before
- if self._nRightButtonStatus != FNB_BTN_PRESSED:
- return
-
- self._nRightButtonStatus = FNB_BTN_HOVER
-
- # Check if the right most tab is visible, if it is
- # don't rotate right anymore
- if self._pagesInfoVec[len(self._pagesInfoVec)-1].GetPosition() != wx.Point(-1, -1):
- return
-
- self._nFrom += 1
- self.Refresh()
-
-
- def OnLeftUp(self, event):
- """ Handles the wx.EVT_LEFT_UP events for L{PageContainer}. """
-
- # forget the zone that was initially clicked
- self._nLeftClickZone = FNB_NOWHERE
-
- where, tabIdx = self.HitTest(event.GetPosition())
-
- # Make sure selected tab has focus
-# self.SetFocus()
-
- if where == FNB_LEFT_ARROW:
- self.RotateLeft()
-
- elif where == FNB_RIGHT_ARROW:
- self.RotateRight()
-
- elif where == FNB_X:
-
- # Make sure that the button was pressed before
- if self._nXButtonStatus != FNB_BTN_PRESSED:
- return
-
- self._nXButtonStatus = FNB_BTN_HOVER
-
- self.DeletePage(self._iActivePage)
-
- elif where == FNB_TAB_X:
-
- # Make sure that the button was pressed before
- if self._nTabXButtonStatus != FNB_BTN_PRESSED:
- return
-
- self._nTabXButtonStatus = FNB_BTN_HOVER
-
- self.DeletePage(self._iActivePage)
-
- elif where == FNB_DROP_DOWN_ARROW:
-
- # Make sure that the button was pressed before
- if self._nArrowDownButtonStatus != FNB_BTN_PRESSED:
- return
-
- self._nArrowDownButtonStatus = FNB_BTN_NONE
-
- # Refresh the button status
- renderer = self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag())
- dc = wx.ClientDC(self)
- renderer.DrawDropDownArrow(self, dc)
-
- self.PopupTabsMenu()
-
- event.Skip()
-
-
- def HitTest(self, pt):
- """
- HitTest method for L{PageContainer}.
- Returns the flag (if any) and the hit page (if any).
- """
-
- style = self.GetParent().GetWindowStyleFlag()
- render = self._mgr.GetRenderer(style)
-
- fullrect = self.GetClientRect()
- btnLeftPos = render.GetLeftButtonPos(self)
- btnRightPos = render.GetRightButtonPos(self)
- btnDropdownPos = render.GetDropArrowButtonPos(self)
- btnXPos = render.GetXPos(self)
-
- tabIdx = -1
-
- if len(self._pagesInfoVec) == 0:
- return FNB_NOWHERE, tabIdx
-
- rect = wx.Rect(btnXPos, 8, 16, 16)
- if rect.Contains(pt):
- return (style & FNB_NO_X_BUTTON and [FNB_NOWHERE] or [FNB_X])[0], tabIdx
-
- rect = wx.Rect(btnDropdownPos, 8, 16, 16)
- if style & FNB_DROPDOWN_TABS_LIST:
- rect = wx.Rect(render.GetDropArrowButtonPos(self), 8, 16, 16)
- if rect.Contains(pt):
- return FNB_DROP_DOWN_ARROW, tabIdx
-
- rect = wx.Rect(btnRightPos, 8, 16, 16)
- if rect.Contains(pt):
- return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_RIGHT_ARROW])[0], tabIdx
-
- rect = wx.Rect(btnLeftPos, 8, 16, 16)
- if rect.Contains(pt):
- return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_LEFT_ARROW])[0], tabIdx
-
- # Test whether a left click was made on a tab
- bFoundMatch = False
-
- for cur in xrange(self._nFrom, len(self._pagesInfoVec)):
-
- pgInfo = self._pagesInfoVec[cur]
-
- if pgInfo.GetPosition() == wx.Point(-1, -1):
- continue
-
- if style & FNB_X_ON_TAB and cur == self.GetSelection():
- # 'x' button exists on a tab
- if self._pagesInfoVec[cur].GetXRect().Contains(pt):
- return FNB_TAB_X, cur
-
- if style & FNB_VC8:
-
- if self._pagesInfoVec[cur].GetRegion().Contains(pt.x, pt.y):
- if bFoundMatch or cur == self.GetSelection():
- return FNB_TAB, cur
-
- tabIdx = cur
- bFoundMatch = True
-
- else:
-
- tabRect = wx.Rect(pgInfo.GetPosition().x, pgInfo.GetPosition().y,
- pgInfo.GetSize().x, pgInfo.GetSize().y)
-
- if tabRect.Contains(pt):
- # We have a match
- return FNB_TAB, cur
-
- if bFoundMatch:
- return FNB_TAB, tabIdx
-
- if self._isdragging:
- # We are doing DND, so check also the region outside the tabs
- # try before the first tab
- pgInfo = self._pagesInfoVec[0]
- tabRect = wx.Rect(0, pgInfo.GetPosition().y, pgInfo.GetPosition().x, self.GetParent().GetSize().y)
- if tabRect.Contains(pt):
- return FNB_TAB, 0
-
- # try after the last tab
- pgInfo = self._pagesInfoVec[-1]
- startpos = pgInfo.GetPosition().x+pgInfo.GetSize().x
- tabRect = wx.Rect(startpos, pgInfo.GetPosition().y, fullrect.width-startpos, self.GetParent().GetSize().y)
-
- if tabRect.Contains(pt):
- return FNB_TAB, len(self._pagesInfoVec)
-
- # Default
- return FNB_NOWHERE, -1
-
-
- def SetSelection(self, page):
- """ Sets the selected page. """
-
- book = self.GetParent()
- book.SetSelection(page)
- self.DoSetSelection(page)
-
-
- def DoSetSelection(self, page):
- """ Does the actual selection of a page. """
-
- if page < len(self._pagesInfoVec):
- #! fix for tabfocus
- da_page = self._pParent.GetPage(page)
-
-# if da_page != None:
-# da_page.SetFocus()
-#
- self.EnsureVisible(page)
-
- def EnsureVisible(self, page, refresh=True):
- if not self.IsTabVisible(page):
- # Try to remove one tab from start and try again
-
- if not self.CanFitToScreen(page):
-
- if self._nFrom > page:
- self._nFrom = page
- else:
- while self._nFrom < page:
- self._nFrom += 1
- if self.CanFitToScreen(page):
- break
- if refresh:
- self.Refresh()
-
-
- def DeletePage(self, page):
- """ Delete the specified page from L{FlatNotebook}. """
-
- book = self.GetParent()
- book.DeletePage(page)
- book.Refresh()
-
-
- def IsTabVisible(self, page):
- """ Returns whether a tab is visible or not. """
-
- iLastVisiblePage = self.GetLastVisibleTab()
- return page <= iLastVisiblePage and page >= self._nFrom
-
-
- def DoDeletePage(self, page):
- """ Does the actual page deletion. """
-
- # Remove the page from the vector
- book = self.GetParent()
- self._pagesInfoVec.pop(page)
-
- # Thanks to Yiaanis AKA Mandrav
- if self._iActivePage >= page:
- self._iActivePage = self._iActivePage - 1
- self._iPreviousActivePage = -1
-
- # The delete page was the last first on the array,
- # but the book still has more pages, so we set the
- # active page to be the first one (0)
- if self._iActivePage < 0 and len(self._pagesInfoVec) > 0:
- self._iActivePage = 0
- self._iPreviousActivePage = -1
-
- # Refresh the tabs
- if self._iActivePage >= 0:
-
- book._bForceSelection = True
-
- # Check for selection and send event
- event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId())
- event.SetSelection(self._iActivePage)
- event.SetOldSelection(self._iPreviousActivePage)
- event.SetEventObject(self.GetParent())
- self.GetParent().GetEventHandler().ProcessEvent(event)
-
- book.SetSelection(self._iActivePage)
- book._bForceSelection = False
-
- # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
- event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
- event.SetOldSelection(self._iPreviousActivePage)
- self.GetParent().GetEventHandler().ProcessEvent(event)
-
- if not self._pagesInfoVec:
- # Erase the page container drawings
- dc = wx.ClientDC(self)
- dc.Clear()
-
-
- def DeleteAllPages(self):
- """ Deletes all the pages. """
-
- self._iActivePage = -1
- self._iPreviousActivePage = -1
- self._nFrom = 0
- self._pagesInfoVec = []
-
- # Erase the page container drawings
- dc = wx.ClientDC(self)
- dc.Clear()
-
-
- def OnMouseMove(self, event):
- """ Handles the wx.EVT_MOTION for L{PageContainer}. """
-
- if self._pagesInfoVec and self.IsShown():
-
- xButtonStatus = self._nXButtonStatus
- xTabButtonStatus = self._nTabXButtonStatus
- rightButtonStatus = self._nRightButtonStatus
- leftButtonStatus = self._nLeftButtonStatus
- dropDownButtonStatus = self._nArrowDownButtonStatus
-
- style = self.GetParent().GetWindowStyleFlag()
-
- self._nXButtonStatus = FNB_BTN_NONE
- self._nRightButtonStatus = FNB_BTN_NONE
- self._nLeftButtonStatus = FNB_BTN_NONE
- self._nTabXButtonStatus = FNB_BTN_NONE
- self._nArrowDownButtonStatus = FNB_BTN_NONE
-
- where, tabIdx = self.HitTest(event.GetPosition())
-
- if where == FNB_X:
- if event.LeftIsDown():
-
- self._nXButtonStatus = (self._nLeftClickZone==FNB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-
- else:
-
- self._nXButtonStatus = FNB_BTN_HOVER
-
- elif where == FNB_DROP_DOWN_ARROW:
- if event.LeftIsDown():
-
- self._nArrowDownButtonStatus = (self._nLeftClickZone==FNB_DROP_DOWN_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-
- else:
-
- self._nArrowDownButtonStatus = FNB_BTN_HOVER
-
- elif where == FNB_TAB_X:
- if event.LeftIsDown():
-
- self._nTabXButtonStatus = (self._nLeftClickZone==FNB_TAB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-
- else:
-
- self._nTabXButtonStatus = FNB_BTN_HOVER
-
- elif where == FNB_RIGHT_ARROW:
- if event.LeftIsDown():
-
- self._nRightButtonStatus = (self._nLeftClickZone==FNB_RIGHT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-
- else:
-
- self._nRightButtonStatus = FNB_BTN_HOVER
-
- elif where == FNB_LEFT_ARROW:
- if event.LeftIsDown():
-
- self._nLeftButtonStatus = (self._nLeftClickZone==FNB_LEFT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-
- else:
-
- self._nLeftButtonStatus = FNB_BTN_HOVER
-
- elif where == FNB_TAB:
- # Call virtual method for showing tooltip
- self.ShowTabTooltip(tabIdx)
-
- if not self.GetEnabled(tabIdx):
- # Set the cursor to be 'No-entry'
- wx.SetCursor(wx.StockCursor(wx.CURSOR_NO_ENTRY))
-
- # Support for drag and drop
- if event.Dragging() and not (style & FNB_NODRAG):
-
- self._isdragging = True
- draginfo = FNBDragInfo(self, tabIdx)
- drginfo = cPickle.dumps(draginfo)
- dataobject = wx.CustomDataObject(wx.CustomDataFormat("FlatNotebook"))
- dataobject.SetData(drginfo)
- dragSource = FNBDropSource(self)
- dragSource.SetData(dataobject)
- dragSource.DoDragDrop(wx.Drag_DefaultMove)
-
- bRedrawX = self._nXButtonStatus != xButtonStatus
- bRedrawRight = self._nRightButtonStatus != rightButtonStatus
- bRedrawLeft = self._nLeftButtonStatus != leftButtonStatus
- bRedrawTabX = self._nTabXButtonStatus != xTabButtonStatus
- bRedrawDropArrow = self._nArrowDownButtonStatus != dropDownButtonStatus
-
- render = self._mgr.GetRenderer(style)
-
- if (bRedrawX or bRedrawRight or bRedrawLeft or bRedrawTabX or bRedrawDropArrow):
-
- dc = wx.ClientDC(self)
-
- if bRedrawX:
-
- render.DrawX(self, dc)
-
- if bRedrawLeft:
-
- render.DrawLeftArrow(self, dc)
-
- if bRedrawRight:
-
- render.DrawRightArrow(self, dc)
-
- if bRedrawTabX:
-
- self.Refresh()
-
- if bRedrawDropArrow:
-
- render.DrawDropDownArrow(self, dc)
-
- event.Skip()
-
-
- def GetLastVisibleTab(self):
- """ Returns the last visible tab. """
-
- if self._nFrom < 0:
- return -1
-
- ii = 0
-
- for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
-
- if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
- break
-
- return ii-1
-
-
- def GetNumTabsCanScrollLeft(self):
- """ Returns the number of tabs than can be scrolled left. """
-
- if self._nFrom - 1 >= 0:
- return 1
-
- return 0
-
-
- def IsDefaultTabs(self):
- """ Returns whether a tab has a default style. """
-
- style = self.GetParent().GetWindowStyleFlag()
- res = (style & FNB_VC71) or (style & FNB_FANCY_TABS) or (style & FNB_VC8)
- return not res
-
-
- def AdvanceSelection(self, bForward=True):
- """
- Cycles through the tabs.
- The call to this function generates the page changing events.
- """
-
- nSel = self.GetSelection()
-
- if nSel < 0:
- return
-
- nMax = self.GetPageCount() - 1
-
- if bForward:
- newSelection = (nSel == nMax and [0] or [nSel + 1])[0]
- else:
- newSelection = (nSel == 0 and [nMax] or [nSel - 1])[0]
-
- if not self._pagesInfoVec[newSelection].GetEnabled():
- return
-
- self.FireEvent(newSelection)
-
-
- def OnMouseLeave(self, event):
- """ Handles the wx.EVT_LEAVE_WINDOW event for L{PageContainer}. """
-
- self._nLeftButtonStatus = FNB_BTN_NONE
- self._nXButtonStatus = FNB_BTN_NONE
- self._nRightButtonStatus = FNB_BTN_NONE
- self._nTabXButtonStatus = FNB_BTN_NONE
- self._nArrowDownButtonStatus = FNB_BTN_NONE
-
- style = self.GetParent().GetWindowStyleFlag()
- render = self._mgr.GetRenderer(style)
-
- dc = wx.ClientDC(self)
-
- render.DrawX(self, dc)
- render.DrawLeftArrow(self, dc)
- render.DrawRightArrow(self, dc)
-
- selection = self.GetSelection()
-
- if selection == -1:
- event.Skip()
- return
-
- if not self.IsTabVisible(selection):
- if selection == len(self._pagesInfoVec) - 1:
- if not self.CanFitToScreen(selection):
- event.Skip()
- return
- else:
- event.Skip()
- return
-
- render.DrawTabX(self, dc, self._pagesInfoVec[selection].GetXRect(), selection, self._nTabXButtonStatus)
- render.DrawFocusRectangle(dc, self, self._pagesInfoVec[selection])
-
- event.Skip()
-
-
- def OnMouseEnterWindow(self, event):
- """ Handles the wx.EVT_ENTER_WINDOW event for L{PageContainer}. """
-
- self._nLeftButtonStatus = FNB_BTN_NONE
- self._nXButtonStatus = FNB_BTN_NONE
- self._nRightButtonStatus = FNB_BTN_NONE
- self._nLeftClickZone = FNB_BTN_NONE
- self._nArrowDownButtonStatus = FNB_BTN_NONE
-
- event.Skip()
-
-
- def ShowTabTooltip(self, tabIdx):
- """ Shows a tab tooltip. """
-
- pWindow = self._pParent.GetPage(tabIdx)
-
- if pWindow:
- pToolTip = pWindow.GetToolTip()
- if pToolTip and pToolTip.GetWindow() == pWindow:
- self.SetToolTipString(pToolTip.GetTip())
-
-
- def SetPageImage(self, page, imgindex):
- """ Sets the image index associated to a page. """
-
- if page < len(self._pagesInfoVec):
-
- self._pagesInfoVec[page].SetImageIndex(imgindex)
- self.Refresh()
-
-
- def GetPageImage(self, page):
- """ Returns the image index associated to a page. """
-
- if page < len(self._pagesInfoVec):
-
- return self._pagesInfoVec[page].GetImageIndex()
-
- return -1
-
-
- def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer):
- """ Handles the drop action from a DND operation. """
-
- # Disable drag'n'drop for disabled tab
- if not wnd_oldContainer._pagesInfoVec[nTabPage].GetEnabled():
- return wx.DragCancel
-
- self._isdragging = True
- oldContainer = wnd_oldContainer
- nIndex = -1
-
- where, nIndex = self.HitTest(wx.Point(x, y))
-
- oldNotebook = oldContainer.GetParent()
- newNotebook = self.GetParent()
-
- if oldNotebook == newNotebook:
-
- if nTabPage >= 0:
-
- if where == FNB_TAB:
- self.MoveTabPage(nTabPage, nIndex)
-
- elif self.GetParent().GetWindowStyleFlag() & FNB_ALLOW_FOREIGN_DND:
-
- if wx.Platform in ["__WXMSW__", "__WXGTK__", "__WXMAC__"]:
- if nTabPage >= 0:
-
- window = oldNotebook.GetPage(nTabPage)
-
- if window:
- where, nIndex = newNotebook._pages.HitTest(wx.Point(x, y))
- caption = oldContainer.GetPageText(nTabPage)
- imageindex = oldContainer.GetPageImage(nTabPage)
- oldNotebook.RemovePage(nTabPage)
- window.Reparent(newNotebook)
-
- if imageindex >= 0:
-
- bmp = oldNotebook.GetImageList().GetBitmap(imageindex)
- newImageList = newNotebook.GetImageList()
-
- if not newImageList:
- xbmp, ybmp = bmp.GetWidth(), bmp.GetHeight()
- newImageList = wx.ImageList(xbmp, ybmp)
- imageindex = 0
- else:
- imageindex = newImageList.GetImageCount()
-
- newImageList.Add(bmp)
- newNotebook.SetImageList(newImageList)
-
- newNotebook.InsertPage(nIndex, window, caption, True, imageindex)
-
- self._isdragging = False
-
- return wx.DragMove
-
-
- def MoveTabPage(self, nMove, nMoveTo):
- """ Moves a tab inside the same L{FlatNotebook}. """
-
- if nMove == nMoveTo:
- return
-
- elif nMoveTo < len(self._pParent._windows):
- nMoveTo = nMoveTo + 1
-
- self._pParent.Freeze()
-
- # Remove the window from the main sizer
- nCurSel = self._pParent._pages.GetSelection()
- self._pParent._mainSizer.Detach(self._pParent._windows[nCurSel])
- self._pParent._windows[nCurSel].Hide()
-
- pWindow = self._pParent._windows[nMove]
- self._pParent._windows.pop(nMove)
- self._pParent._windows.insert(nMoveTo-1, pWindow)
-
- pgInfo = self._pagesInfoVec[nMove]
-
- self._pagesInfoVec.pop(nMove)
- self._pagesInfoVec.insert(nMoveTo - 1, pgInfo)
-
- # Add the page according to the style
- pSizer = self._pParent._mainSizer
- style = self.GetParent().GetWindowStyleFlag()
-
- if style & FNB_BOTTOM:
-
- pSizer.Insert(0, pWindow, 1, wx.EXPAND)
-
- else:
-
- # We leave a space of 1 pixel around the window
- pSizer.Add(pWindow, 1, wx.EXPAND)
-
- pWindow.Show()
-
- pSizer.Layout()
- self._iActivePage = nMoveTo - 1
- self._iPreviousActivePage = -1
- self.DoSetSelection(self._iActivePage)
- self.Refresh()
- self._pParent.Thaw()
-
-
- def CanFitToScreen(self, page):
- """ Returns wheter a tab can fit in the left space in the screen or not. """
-
- # Incase the from is greater than page,
- # we need to reset the self._nFrom, so in order
- # to force the caller to do so, we return false
- if self._nFrom > page:
- return False
-
- style = self.GetParent().GetWindowStyleFlag()
- render = self._mgr.GetRenderer(style)
-
- vTabInfo = render.NumberTabsCanFit(self)
-
- if page - self._nFrom >= len(vTabInfo):
- return False
-
- return True
-
-
- def GetNumOfVisibleTabs(self):
- """ Returns the number of visible tabs. """
-
- count = 0
- for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
- if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
- break
- count = count + 1
-
- return count
-
-
- def GetEnabled(self, page):
- """ Returns whether a tab is enabled or not. """
-
- if page >= len(self._pagesInfoVec):
- return True # Seems strange, but this is the default
-
- return self._pagesInfoVec[page].GetEnabled()
-
-
- def EnableTab(self, page, enabled=True):
- """ Enables or disables a tab. """
-
- if page >= len(self._pagesInfoVec):
- return
-
- self._pagesInfoVec[page].EnableTab(enabled)
-
-
- def GetSingleLineBorderColour(self):
- """ Returns the colour for the single line border. """
-
- if self.HasFlag(FNB_FANCY_TABS):
- return self._colorFrom
-
- return wx.WHITE
-
-
- def HasFlag(self, flag):
- """ Returns whether a flag is present in the L{FlatNotebook} style. """
-
- style = self.GetParent().GetWindowStyleFlag()
- res = (style & flag and [True] or [False])[0]
- return res
-
-
- def ClearFlag(self, flag):
- """ Deletes a flag from the L{FlatNotebook} style. """
-
- style = self.GetParent().GetWindowStyleFlag()
- style &= ~flag
- self.SetWindowStyleFlag(style)
-
-
- def TabHasImage(self, tabIdx):
- """ Returns whether a tab has an associated image index or not. """
-
- if self._ImageList:
- return self._pagesInfoVec[tabIdx].GetImageIndex() != -1
-
- return False
-
-
- def OnLeftDClick(self, event):
- """ Handles the wx.EVT_LEFT_DCLICK event for L{PageContainer}. """
-
- where, tabIdx = self.HitTest(event.GetPosition())
-
- if where == FNB_RIGHT_ARROW:
- self.RotateRight()
-
- elif where == FNB_LEFT_ARROW:
- self.RotateLeft()
-
- elif self.HasFlag(FNB_DCLICK_CLOSES_TABS):
-
- if where == FNB_TAB:
- self.DeletePage(tabIdx)
-
- else:
-
- event.Skip()
-
-
- def OnSetFocus(self, event):
- """ Handles the wx.EVT_SET_FOCUS event for L{PageContainer}. """
-
- if self._iActivePage < 0:
- event.Skip()
- return
-
- self.SetFocusedPage(self._iActivePage)
-
-
- def OnKillFocus(self, event):
- """ Handles the wx.EVT_KILL_FOCUS event for L{PageContainer}. """
-
- self.SetFocusedPage()
-
-
- def OnKeyDown(self, event):
- """
- When the PageContainer has the focus tabs can be changed with
- the left/right arrow keys.
- """
- key = event.GetKeyCode()
- if key == wx.WXK_LEFT:
- self.GetParent().AdvanceSelection(False)
- elif key == wx.WXK_RIGHT:
- self.GetParent().AdvanceSelection(True)
- elif key == wx.WXK_TAB and not event.ControlDown():
- flags = 0
- if not event.ShiftDown(): flags |= wx.NavigationKeyEvent.IsForward
- if event.CmdDown(): flags |= wx.NavigationKeyEvent.WinChange
- self.Navigate(flags)
- else:
- event.Skip()
-
-
- def SetFocusedPage(self, pageIndex=-1):
- """
- Sets/Unsets the focus on the appropriate page.
- If pageIndex is defaulted, we have lost focus and no focus indicator is drawn.
- """
-
- for indx, page in enumerate(self._pagesInfoVec):
- if indx == pageIndex:
- page._hasFocus = True
- else:
- page._hasFocus = False
-
- self.Refresh()
-
-
- def PopupTabsMenu(self):
- """ Pops up the menu activated with the drop down arrow in the navigation area. """
-
- popupMenu = wx.Menu()
-
- for i in xrange(len(self._pagesInfoVec)):
- pi = self._pagesInfoVec[i]
- item = wx.MenuItem(popupMenu, i+1, pi.GetCaption(), pi.GetCaption(), wx.ITEM_NORMAL)
- self.Bind(wx.EVT_MENU, self.OnTabMenuSelection, item)
-
- # There is an alignment problem with wx2.6.3 & Menus so only use
- # images for versions above 2.6.3
- if wx.VERSION > (2, 6, 3, 0) and self.TabHasImage(i):
- item.SetBitmap(self.GetImageList().GetBitmap(pi.GetImageIndex()))
-
- popupMenu.AppendItem(item)
- item.Enable(pi.GetEnabled())
-
- self.PopupMenu(popupMenu)
-
-
- def OnTabMenuSelection(self, event):
- """ Handles the wx.EVT_MENU event for L{PageContainer}. """
-
- selection = event.GetId() - 1
- self.FireEvent(selection)
-
-
- def FireEvent(self, selection):
- """
- Fires the wxEVT_FLATNOTEBOOK_PAGE_CHANGING and wxEVT_FLATNOTEBOOK_PAGE_CHANGED events
- called from other methods (from menu selection or Smart Tabbing).
- Utility function.
- """
-
- if selection == self._iActivePage:
- # No events for the same selection
- return
-
- oldSelection = self._iActivePage
-
- event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId())
- event.SetSelection(selection)
- event.SetOldSelection(oldSelection)
- event.SetEventObject(self.GetParent())
-
- if not self.GetParent().GetEventHandler().ProcessEvent(event) or event.IsAllowed():
-
- self.SetSelection(selection)
-
- # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
- event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
- event.SetOldSelection(oldSelection)
- self.GetParent().GetEventHandler().ProcessEvent(event)
-# self.SetFocus()
-
-
- def SetImageList(self, imglist):
- """ Sets the image list for the page control. """
-
- self._ImageList = imglist
-
-
- def AssignImageList(self, imglist):
- """ Assigns the image list for the page control. """
-
- self._ImageList = imglist
-
-
- def GetImageList(self):
- """ Returns the image list for the page control. """
-
- return self._ImageList
-
-
- def GetSelection(self):
- """ Returns the current selected page. """
-
- return self._iActivePage
-
-
- def GetPageCount(self):
- """ Returns the number of tabs in the L{FlatNotebook} control. """
-
- return len(self._pagesInfoVec)
-
-
- def GetPageText(self, page):
- """ Returns the tab caption of the page. """
-
- return self._pagesInfoVec[page].GetCaption()
-
-
- def SetPageText(self, page, text):
- """ Sets the tab caption of the page. """
-
- self._pagesInfoVec[page].SetCaption(text)
- return True
-
-
- def DrawDragHint(self):
- """ Draws small arrow at the place that the tab will be placed. """
-
- # get the index of tab that will be replaced with the dragged tab
- pt = wx.GetMousePosition()
- client_pt = self.ScreenToClient(pt)
- where, tabIdx = self.HitTest(client_pt)
- self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag()).DrawDragHint(self, tabIdx)
-
-
diff --git a/utils/PyoDoc.py b/utils/PyoDoc.py
index 03e145f..9628f9a 100644
--- a/utils/PyoDoc.py
+++ b/utils/PyoDoc.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# encoding: utf-8
from __future__ import with_statement
-import subprocess, threading, os
+import subprocess, threading, os, sys, unicodedata
import wx
import wx.stc as stc
from wx.lib.embeddedimage import PyEmbeddedImage
@@ -9,6 +9,10 @@ from pyo import *
DOC_AS_SINGLE_APP = False
+PLATFORM = sys.platform
+DEFAULT_ENCODING = sys.getdefaultencoding()
+ENCODING = sys.getfilesystemencoding()
+
TEMP_PATH = os.path.join(os.path.expanduser('~'), '.epyo')
if not os.path.isdir(TEMP_PATH):
os.mkdir(TEMP_PATH)
@@ -19,14 +23,14 @@ DOC_STYLES = {'Default': {'default': '#000000', 'comment': '#007F7F', 'commentbl
'number': '#005000', 'string': '#7F007F', 'triple': '#7F0000', 'keyword': '#00007F', 'keyword2': '#007F9F',
'class': '#0000FF', 'function': '#007F7F', 'identifier': '#000000', 'caret': '#00007E',
'background': '#EEEEEE', 'linenumber': '#000000', 'marginback': '#B0B0B0', 'markerfg': '#CCCCCC',
- 'markerbg': '#000000', 'bracelight': '#AABBDD', 'bracebad': '#DD0000', 'lineedge': '#CCCCCC'}}
+ 'markerbg': '#000000', 'bracelight': '#AABBDD', 'bracebad': '#DD0000', 'lineedge': '#CCCCCC'}}
if wx.Platform == '__WXMSW__':
DOC_FACES = {'face': 'Verdana', 'size' : 8, 'size2': 7}
elif wx.Platform == '__WXMAC__':
DOC_FACES = {'face': 'Monaco', 'size' : 12, 'size2': 9}
else:
- DOC_FACES = {'face': 'Courier New', 'size' : 8, 'size2': 7}
+ DOC_FACES = {'face': 'Monospace', 'size' : 8, 'size2': 7}
DOC_FACES['size3'] = DOC_FACES['size2'] + 4
for key, value in DOC_STYLES['Default'].items():
DOC_FACES[key] = value
@@ -206,11 +210,10 @@ functions : Miscellaneous functions.
""" % PYO_VERSION
_DOC_KEYWORDS = ['Attributes', 'Examples', 'Methods', 'Notes', 'Methods details',
- 'Parentclass', 'Overview', 'Initline', 'Description']
+ 'Parentclass', 'Overview', 'Initline', 'Description', 'Parameters']
_HEADERS = ["Server", "PyoObjectBase", "Map", "Stream", "TableStream", "functions"]
-_KEYWORDS_LIST = ['Parameters']
+_KEYWORDS_LIST = ['SLMap']
_KEYWORDS_LIST.extend(_HEADERS)
-_KEYWORDS_LIST.append("SLMap")
_NUM_PAGES = 1
_NUM_PAGES += len(_HEADERS)
for k1 in _HEADERS:
@@ -786,7 +789,7 @@ class ManualPanel(wx.Treebook):
if not panel.isLoad:
panel.isLoad = True
panel.win = stc.StyledTextCtrl(panel, -1, size=panel.GetSize(), style=wx.SUNKEN_BORDER)
- panel.win.LoadFile(os.path.join(DOC_PATH, word))
+ panel.win.LoadFile(os.path.join(ensureNFD(DOC_PATH), word))
panel.win.SetMarginWidth(1, 0)
panel.win.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
if self.searchKey != None:
@@ -925,7 +928,8 @@ class ManualFrame(wx.Frame):
self.searchMenu.Append(id, txt)
self.Bind(wx.EVT_MENU, self.onSearchScope, id=id)
- self.search = wx.SearchCtrl(self.toolbar, 200, size=(200,-1), style=wx.WANTS_CHARS | wx.TE_PROCESS_ENTER)
+ tw, th = self.GetTextExtent("Q")
+ self.search = wx.SearchCtrl(self.toolbar, 200, size=(200,th+6), style=wx.WANTS_CHARS | wx.TE_PROCESS_ENTER)
self.search.ShowCancelButton(True)
self.search.SetMenu(self.searchMenu)
self.toolbar.AddControl(self.search)
@@ -1080,6 +1084,42 @@ class RunningThread(threading.Thread):
while self.proc.poll() == None and not self.terminated:
time.sleep(.25)
+def ensureNFD(unistr):
+ if PLATFORM in ['linux2', 'win32']:
+ encodings = [DEFAULT_ENCODING, ENCODING,
+ 'cp1252', 'iso-8859-1', 'utf-16']
+ format = 'NFC'
+ else:
+ encodings = [DEFAULT_ENCODING, ENCODING,
+ 'macroman', 'iso-8859-1', 'utf-16']
+ format = 'NFC'
+ decstr = unistr
+ if type(decstr) != UnicodeType:
+ for encoding in encodings:
+ try:
+ decstr = decstr.decode(encoding)
+ break
+ except UnicodeDecodeError:
+ continue
+ except:
+ decstr = "UnableToDecodeString"
+ print "Unicode encoding not in a recognized format..."
+ break
+ if decstr == "UnableToDecodeString":
+ return unistr
+ else:
+ return unicodedata.normalize(format, decstr)
+
+def toSysEncoding(unistr):
+ try:
+ if PLATFORM == "win32":
+ unistr = unistr.encode(ENCODING)
+ else:
+ unistr = unicode(unistr)
+ except:
+ pass
+ return unistr
+
if __name__ == "__main__":
DOC_AS_SINGLE_APP = True
app = wx.PySimpleApp()
diff --git a/utils/epyo_builder_OSX.sh b/utils/epyo_builder_OSX.sh
index a715ead..463cbf8 100755
--- a/utils/epyo_builder_OSX.sh
+++ b/utils/epyo_builder_OSX.sh
@@ -1,6 +1,5 @@
mkdir Resources
cp PyoDoc.py Resources/
-cp FlatNoteBook.py Resources/
cp Tutorial_01_RingMod.py Resources/
cp Tutorial_02_Flanger.py Resources/
cp Tutorial_03_TriTable.py Resources/
@@ -27,20 +26,19 @@ else
exit;
fi
-ditto --rsrc --arch i386 E-Pyo.app E-Pyo-i386.app
+# keep only 64-bit arch
+ditto --rsrc --arch x86_64 E-Pyo.app E-Pyo-x86_64.app
rm -rf E-Pyo.app
-mv E-Pyo-i386.app E-Pyo.app
+mv E-Pyo-x86_64.app E-Pyo.app
cd ..
cp -R E-Pyo_OSX/E-Pyo.app .
-# Fixed wrong path in Info.plist
-cd E-Pyo.app/Contents
-awk '{gsub("Library/Frameworks/Python.framework/Versions/2.6/Resources/Python.app/Contents/MacOS/Python", "@executable_path/../Frameworks/Python.framework/Versions/2.6/Python")}1' Info.plist > Info.plist_tmp && mv Info.plist_tmp Info.plist
+# Fixed wrong path in Info.plist (no more needed python 2.7.8, py2app 0.9)
+#cd E-Pyo.app/Contents
+#awk '{gsub("Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python", "@executable_path/../Frameworks/Python.framework/Versions/2.7/Python")}1' Info.plist > Info.plist_tmp && mv Info.plist_tmp Info.plist
+#cd ../..
-cd ../..
-#tar -cjvf E-Pyo_OSX-0.6.1.tar.bz2 E-Pyo.app
-#rm -rf E-Pyo.app
rm -rf E-Pyo_OSX
rm -rf Resources
rm -rf examples
diff --git a/utils/epyo_builder_win32.py b/utils/epyo_builder_win32.py
index e4265c3..8241966 100644
--- a/utils/epyo_builder_win32.py
+++ b/utils/epyo_builder_win32.py
@@ -4,7 +4,6 @@ version = sys.version_info[:2]
os.mkdir("Resources")
shutil.copy("PyoDoc.py", "Resources")
-shutil.copy("FlatNoteBook.py", "Resources")
shutil.copy("Tutorial_01_RingMod.py", "Resources")
shutil.copy("Tutorial_02_Flanger.py", "Resources")
shutil.copy("Tutorial_03_TriTable.py", "Resources")
@@ -15,9 +14,9 @@ os.system("svn export ../examples Resources/examples/")
os.system("svn export snippets Resources/snippets/")
os.system("svn export styles Resources/styles/")
-os.system("C:\Python%d%d\python ..\..\pyinstaller\Configure.py" % version)
-os.system('C:\Python%d%d\python ..\..\pyinstaller\Makespec.py -F -c --icon=Resources\E-PyoIcon.ico "E-Pyo.py"' % version)
-os.system('C:\Python%d%d\python ..\..\pyinstaller\Build.py "E-Pyo.spec"' % version)
+#os.system("C:\Python%d%d\python ..\..\pyinstaller\Configure.py" % version)
+os.system('C:\Python%d%d\Scripts\pyi-makespec -F -c --icon=Resources\E-PyoIcon.ico "E-Pyo.py"' % version)
+os.system('C:\Python%d%d\Scripts\pyi-build "E-Pyo.spec"' % version)
os.mkdir("E-Pyo_py%d%d" % version)
shutil.copytree("Resources", "E-Pyo_py%d%d/Resources" % version)
diff --git a/utils/info.plist b/utils/info.plist
index b43497a..0abb41b 100644
--- a/utils/info.plist
+++ b/utils/info.plist
@@ -32,17 +32,17 @@
<key>CFBundleIdentifier</key>
<string>org.pythonmac.unspecified.E-Pyo</string>
<key>CFBundleInfoDictionaryVersion</key>
- <string>0.6.8</string>
+ <string>0.7.4</string>
<key>CFBundleName</key>
<string>E-Pyo</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>0.6.8</string>
+ <string>0.7.4</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
- <string>0.6.8</string>
+ <string>0.7.4</string>
<key>LSHasLocalizedDisplayName</key>
<false/>
<key>NSAppleScriptEnabled</key>
@@ -78,17 +78,16 @@
<array/>
<key>PyRuntimeLocations</key>
<array>
- <string>@executable_path/../Frameworks/Python.framework/Versions/2.6/Python</string>
+ <string>@executable_path/../Frameworks/Python.framework/Versions/2.7/Python</string>
</array>
<key>PythonInfoDict</key>
<dict>
<key>PythonExecutable</key>
- <string>@executable_path/../Frameworks/Python.framework/Versions/2.6/Python</string>
+ <string>@executable_path/../Frameworks/Python.framework/Versions/2.7/Python</string>
<key>PythonLongVersion</key>
- <string>2.6.5 (r265:79359, Mar 24 2010, 01:32:55)
-[GCC 4.0.1 (Apple Inc. build 5493)]</string>
+ <string>2.7.8 (v2.7.8:ee879c0ffa11, Jun 29 2014, 21:07:35) \n[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]</string>
<key>PythonShortVersion</key>
- <string>2.6</string>
+ <string>2.7</string>
<key>py2app</key>
<dict>
<key>alias</key>
@@ -96,7 +95,7 @@
<key>template</key>
<string>app</string>
<key>version</key>
- <string>0.4.4</string>
+ <string>0.9</string>
</dict>
</dict>
</dict>
--
python-pyo packaging
More information about the pkg-multimedia-commits
mailing list