[SCM] python-pyo/master: New release
tiago at users.alioth.debian.org
tiago at users.alioth.debian.org
Tue Jan 19 16:39:00 UTC 2016
The following commit has been merged in the master branch:
commit b3d707a6fbb74bcfa9ce14df796eaf843eedba63
Author: Tiago Bortoletto Vaz <tiago at debian.org>
Date: Tue Jan 19 09:49:23 2016 -0500
New release
diff --git a/ChangeLog b/ChangeLog
index c933e3b..4d9772e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,76 @@
+2016-01-08 belangeo <belangeo at gmail.com>
+
+ * Final revision for version 0.7.8.
+ - SHA: e71cb0b5254da456bea129113da3d258a5b75dea
+
+2016-01-07 belangeo <belangeo at gmail.com>
+
+ * Added new object: Expr, sample-based prefix expression evaluator.
+
+2015-12-04 belangeo <belangeo at gmail.com>
+
+ * Added new object: Resample, allow multi-rate DSP chains.
+
+2015-12-04 belangeo <belangeo at gmail.com>
+
+ * Added Juce PyoPlugin framework in the embedded folder.
+
+2015-10-26 belangeo <belangeo at gmail.com>
+
+ * Fixed memory leak when using PyFloat_AS_DOUBLE(PyNumber_Float(x))
+ to fill table data.
+
+2015-10-25 belangeo <belangeo at gmail.com>
+
+ * Added a closeGui() method to the Server object. This allow to
+ programatically close the Server window.
+
+2015-10-24 belangeo <belangeo at gmail.com>
+
+ * Added a method addMidiEvent to the Server object. This allow to
+ programatically simulate MIDI events. Added the functionnaility
+ to the embedded framework and modify the puredata pyo~ object help
+ patch to illustrate how to generate MIDI events from the host program.
+
+2015-10-18 belangeo <belangeo at gmail.com>
+
+ * Fixed triangle waveform amplitude in LFO object. Fixed calculation
+ of Follower/Follower2 lowpass cutoff frequencies.
+
+2015-10-12 belangeo <belangeo at gmail.com>
+
+ * Final revision for version 0.7.7.
+ - SHA : 217b0cb40c8b82dad8c66718910fcd6e8f983034
+
+2015-10-11 belangeo <belangeo at gmail.com>
+
+ * Fixed clicks at the end of the Adsr envelope.
+
+2015-09-25 belangeo <belangeo at gmail.com>
+
+ * Added a trigger stream to Looper to signal the beginning of a new loop.
+
+2015-09-15 belangeo <belangeo at gmail.com>
+
+ * Automatically add the current working directory in sys.path when the
+ background server is started.
+
+2015-09-03 belangeo <belangeo at gmail.com>
+
+ * Added a pause() method to Linseg and Expseg objects (keep the internal phase).
+
+2015-09-03 belangeo <belangeo at gmail.com>
+
+ * All OSC objects now accept string or unicode types as address parameter.
+
+2015-09-03 belangeo <belangeo at gmail.com>
+
+ * Fixed crash (OSX) when the server GUI is closed with the red button.
+
+2015-09-02 belangeo <belangeo at gmail.com>
+
+ * Fixed crash on server shutdown.
+
2015-08-25 belangeo <belangeo at gmail.com>
* Added new objects: MidiListener and OscListener (self-contained MIDI and OSC servers).
diff --git a/debian/E-Pyo.desktop b/debian/E-Pyo.desktop
deleted file mode 100644
index 247bc88..0000000
--- a/debian/E-Pyo.desktop
+++ /dev/null
@@ -1,9 +0,0 @@
-[Desktop Entry]
-Name=E-Pyo
-GenericName=Digital signal processing script creation with Pyo
-Comment=Sound synthesis and audio signal processing environment
-Icon=/usr/share/pixmaps/E-Pyo.xpm
-Type=Application
-Categories=AudioVideo;Audio;
-Exec=/usr/lib/python-pyo/E-Pyo.py
-Terminal=false
diff --git a/debian/E-Pyo.xpm b/debian/E-Pyo.xpm
deleted file mode 100644
index 6ea01d4..0000000
--- a/debian/E-Pyo.xpm
+++ /dev/null
@@ -1,263 +0,0 @@
-/* XPM */
-static char * E_Pyo_3_xpm[] = {
-"48 48 212 2",
-" c None",
-". c #0E0F19",
-"+ c #0F101A",
-"@ c #10111B",
-"# c #11121C",
-"$ c #12131D",
-"% c #13141E",
-"& c #14151F",
-"* c #151620",
-"= c #161721",
-"- c #171822",
-"; c #181923",
-"> c #141620",
-", c #1A1B25",
-"' c #1B1C26",
-") c #1C1D27",
-"! c #191A24",
-"~ c #1E1F29",
-"{ c #20212B",
-"] c #21222C",
-"^ c #23242E",
-"/ c #252630",
-"( c #262731",
-"_ c #0D0E18",
-": c #24252F",
-"< c #282933",
-"[ c #2B2C36",
-"} c #2E2F39",
-"| c #090C15",
-"1 c #1A1A24",
-"2 c #0C0D17",
-"3 c #090A14",
-"4 c #2D2E38",
-"5 c #33343E",
-"6 c #373842",
-"7 c #34353F",
-"8 c #1F202A",
-"9 c #292932",
-"0 c #D2CED1",
-"a c #89878C",
-"b c #47464E",
-"c c #86848A",
-"d c #3C3D47",
-"e c #454650",
-"f c #3E3F49",
-"g c #2C2D37",
-"h c #3A3A42",
-"i c #D1CCCF",
-"j c #9A979B",
-"k c #706E75",
-"l c #D7D3D6",
-"m c #D7D1D5",
-"n c #35353E",
-"o c #54555F",
-"p c #565761",
-"q c #464751",
-"r c #383943",
-"s c #2F303A",
-"t c #272832",
-"u c #22232D",
-"v c #0D0F19",
-"w c #2D2D36",
-"x c #D2CDD0",
-"y c #908D93",
-"z c #706D73",
-"A c #D7D2D5",
-"B c #E2DDDF",
-"C c #6F6D74",
-"D c #575862",
-"E c #474852",
-"F c #393A44",
-"G c #2E2E37",
-"H c #D6D1D3",
-"I c #A09DA2",
-"J c #737178",
-"K c #E2DDE0",
-"L c #D9D3D6",
-"M c #807E84",
-"N c #69686F",
-"O c #9C999E",
-"P c #3F404A",
-"Q c #353640",
-"R c #3E3E46",
-"S c #A29FA4",
-"T c #817E85",
-"U c #D8D3D6",
-"V c #88858B",
-"W c #858288",
-"X c #DBD6D9",
-"Y c #414049",
-"Z c #292A34",
-"` c #12131E",
-" . c #313039",
-".. c #979499",
-"+. c #79777D",
-"@. c #DED9DC",
-"#. c #928F94",
-"$. c #89868C",
-"%. c #3C3C44",
-"&. c #31323A",
-"*. c #D6D0D4",
-"=. c #A4A0A6",
-"-. c #7A787F",
-";. c #E2DCE0",
-">. c #949196",
-",. c #727177",
-"'. c #DDD9DB",
-"). c #3F3E47",
-"!. c #0A0B15",
-"~. c #1D1E28",
-"{. c #41414A",
-"]. c #A6A2A7",
-"^. c #868388",
-"/. c #D8D2D5",
-"(. c #908D92",
-"_. c #8A888E",
-":. c #DED9DB",
-"<. c #4E4D54",
-"[. c #0C0D18",
-"}. c #33333B",
-"|. c #9B979D",
-"1. c #7E7B81",
-"2. c #DDD8DB",
-"3. c #8B888E",
-"4. c #E0DBDE",
-"5. c #43424A",
-"6. c #A6A3A8",
-"7. c #7F7C82",
-"8. c #E1DCDE",
-"9. c #99959A",
-"0. c #747278",
-"a. c #44434B",
-"b. c #090B15",
-"c. c #404049",
-"d. c #D0CCD0",
-"e. c #A7A3A9",
-"f. c #939095",
-"g. c #8C898E",
-"h. c #DFD9DC",
-"i. c #504F56",
-"j. c #303139",
-"k. c #9D9A9F",
-"l. c #7D7B82",
-"m. c #9A989D",
-"n. c #8B898F",
-"o. c #E2DCDF",
-"p. c #45454D",
-"q. c #2F2F38",
-"r. c #D4D0D2",
-"s. c #A8A5A9",
-"t. c #7D7B81",
-"u. c #9B989D",
-"v. c #DFDADD",
-"w. c #46454E",
-"x. c #CFCACD",
-"y. c #A9A6AA",
-"z. c #87848A",
-"A. c #959197",
-"B. c #8B898E",
-"C. c #525159",
-"D. c #0E101A",
-"E. c #2C2C35",
-"F. c #CECACD",
-"G. c #7C7980",
-"H. c #9C999D",
-"I. c #48474F",
-"J. c #24242D",
-"K. c #D4CFD2",
-"L. c #AEA9AE",
-"M. c #7C7A81",
-"N. c #726F77",
-"O. c #E0DBDD",
-"P. c #494850",
-"Q. c #090A15",
-"R. c #504F57",
-"S. c #9E9BA0",
-"T. c #838187",
-"U. c #98959A",
-"V. c #8A888D",
-"W. c #54535A",
-"X. c #B8B4B8",
-"Y. c #A7A3A8",
-"Z. c #4C4B53",
-"`. c #10111A",
-" + c #20212A",
-".+ c #6C6A70",
-"++ c #838087",
-"@+ c #77757B",
-"#+ c #E1DBDF",
-"$+ c #4F4E56",
-"%+ c #080914",
-"&+ c #1E1E27",
-"*+ c #C5C1C5",
-"=+ c #040510",
-"-+ c #191A23",
-";+ c #D3CED2",
-">+ c #5B5A62",
-",+ c #4A4951",
-"'+ c #E1DCDF",
-")+ c #848187",
-"!+ c #050611",
-"~+ c #1F2029",
-"{+ c #C7C3C6",
-"]+ c #8F8C92",
-"^+ c #070812",
-"/+ c #0B0C17",
-"(+ c #48484F",
-"_+ c #47464F",
-":+ c #04050F",
-"<+ c #0F0F19",
-"[+ c #0D0E19",
-"}+ c #0F1019",
-" ",
-" . + + + + . ",
-" . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . + + + + + + + + . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . + + + @ @ @ @ + + + + . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . + + + @ @ # # # # @ @ @ @ + + . . . . . . . . . . . . ",
-" . . . . . . . . . . . . + + @ @ # $ $ % % % % $ $ # @ @ + + . . . . . . . . . . . . ",
-" . . . . . . . . . . . + + @ @ # % % & * * * * & % % # # @ + + . . . . . . . . . . . ",
-" . . . . . . . . . . . + @ # # % & = - ; ; ; ; - = > % $ # @ + + . . . . . . . . . . ",
-" . . . . . . . . . . + @ @ # % * - ; , ' ) ) ' ' ; - * % $ # @ + . . . . . . . . . . ",
-" . . . . . . . . . . . + @ # % * - ! ) ~ { ] ] { ~ ) ! - * % # @ @ + . . . . . . . . . . ",
-" . . . . . . . . . . + + # % & - ! ) { ^ / ( ( / ^ { ) ! - > % # @ + . . . . _ . . . . . ",
-" . . . . . . . . . + + @ $ % = ; ) { : < [ } } [ < : { ) ; = % $ @ + + . _ | 1 2 3 . . . ",
-" . . . . . . . . . + + @ $ & - , ~ ^ < 4 5 6 6 7 } < ^ 8 ' - & % @ + + 2 9 0 a b c - . . _ ",
-" _ . . . . . . . . . + @ # % * ; ' { / [ 5 d e e f 7 g / { ) ; * % # @ _ h i j k l m n _ . . ",
-" _ . . . . . . . . . + @ # % * ; ) ] ( } 6 e o p q r s t u ) ! * % $ v w x y z A B C - . . . ",
-" _ . . . . . . . . . + @ # % * ; ) ] ( } 6 e p D E F s t u ) ! * % + G H I J K L M N O % . . ",
-" . . . . . . . . . + @ # % * ; ' { / [ 7 f q q P Q g ( { ) ; * # R x S T U U V W X Y _ . . ",
-" . . . . . . . . . + + @ $ & - ' ~ ^ < } 7 r r 7 } Z ^ 8 ' - ` .x ..+.U @.#.$. at .%.2 . . ",
-" . . . . . . . . . + + @ $ % = ; ) { : < g s s g Z : { ) ! & &.*.=.-.;.U >.,.'.).!.. . . ",
-" . . . . . . . . . . + @ # % > - ! ) { ^ / t t ( ^ { ~., * {.x ].^./.U (._.:.<.[.. . . . ",
-" . . . . . . . . . . + @ @ # % * - ! ) 8 { u u { 8 ) , = }.x |.1.A 2...3.4.5.2 . . . . . ",
-" . . . . . . . . . . + @ # $ % * - ; ' ) ) ) ) ' ! * }.*.6.7.8.U 9.0. at .a.b.. . . . . ",
-" . . . . . . . . . . + + @ # $ % > = - ; ! ! ; - & c.d.e.V A U f.g.h.i.2 . . . . . . ",
-" . . . . . . . . . . . + + @ # # % % & * * * * % j.i k.l.A 2.m.n.o.p.2 . . . . . . . ",
-" + . . . . . . . . . . . + + @ @ # $ % % % % # q.r.s.t.8.U u.J v.w.3 . . . . . . . . ",
-" . . . . . . . . . . . . + + @ @ @ @ # $ + %.x.y.z./.U A.B.v.C.2 . . . . . . . . ",
-" . . . . . . . . . . . . . + + + + @ D.E.F.S G./.2.H.3.B I.2 . . . . . . . . ",
-" . . . . . . . . . . . . . . . + + _ J.K.L.M.o.U k.N.O.P.3 . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . Q.R.S.T.U U U.V.4.W.2 . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . @ J.X.h.Y._.K Z.2 . . . . . . . . . . ",
-" . . . . . . . . . . . . . `. +$ # .+++ at +#+$+%+. . . . . . . . . ",
-" . . . . . . . . . . . . &+*+(.# =+-+;+>+2 . . . . . . . . . ",
-" . . . . . . . . . . 2 ,+'+X )+!+@ ~+@ . . . . . . . . . ",
-" . . . . . . . . 3 3.K.{+]+^+. . . . . . . . . . . ",
-" . . . . . . . /+(+_+, :+<+. . . . . . . . . ",
-" . . . . . . . _ _ [+. . . . . . . . . }+ ",
-" . . . . . . . . . . . . ",
-" ",
-" "};
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index 5e65c8b..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,127 +0,0 @@
-python-pyo (0.7.6+git20150826.1f0dc1aa93-1) unstable; urgency=medium
-
- * Added new objects: MidiListener and OscListener
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Wed, 26 Aug 2015 00:51:50 -0400
-
-python-pyo (0.7.6-1) unstable; urgency=medium
-
- * New upstream release.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Tue, 28 Jul 2015 17:02:57 -0400
-
-python-pyo (0.7.5-1) experimental; urgency=medium
-
- * New upstream version.
- * License changed from GPL to LGPL
- * Build-depends on libjack-jackd2-dev (was libjack-dev)
- * Recommends jackd2
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Mon, 23 Mar 2015 20:16:04 -0400
-
-python-pyo (0.7.4-1) experimental; urgency=medium
-
- * New upstream version.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Thu, 29 Jan 2015 22:49:12 -0500
-
-python-pyo (0.7-2.1) unstable; urgency=medium
-
- * Non-maintainer upload.
- * Updates for wxPython 3.0 compatibility (Closes: #759092):
- - Fix deprecation warnings with wxPython 3.0.
- - Fix check for wxPython not to insist that 2.8 is installed before picking
- something that's 2.8 or newer.
- - Update uses of removed alias wx.Color to wx.Colour.
- - Update FileDialog flags to use the non-deprecated "FD_" prefixed form.
-
- -- Olly Betts <olly at survex.com> Sat, 20 Sep 2014 01:34:09 +0000
-
-python-pyo (0.7-2) unstable; urgency=low
-
- * Depends on python-wxgtk3.0 instead of python-wxgtk2.8 to have the
- graphical IDE (E-Pyo) working.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Sat, 30 Aug 2014 20:13:47 -0400
-
-python-pyo (0.7-1) unstable; urgency=medium
-
- * New upstream version.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Sat, 30 Aug 2014 17:12:30 -0400
-
-python-pyo (0.6.9-1) unstable; urgency=medium
-
- * New upstream version.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Sun, 13 Apr 2014 00:15:48 -0400
-
-python-pyo (0.6.8-1) unstable; urgency=low
-
- * New upstream version.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Sat, 26 Oct 2013 10:35:58 -0400
-
-python-pyo (0.6.6+svn1132-2) unstable; urgency=low
-
- * Don't compress sample audio files.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Thu, 05 Sep 2013 10:19:57 -0400
-
-python-pyo (0.6.6+svn1132-1) unstable; urgency=low
-
- * Added new objects:
- - PVMix, Mix the most prominent components from two phase vocoder streaming
- objects.
- - TableScale, Scales values from a table and writes them into another table.
- - Granule, another granular synthesis generator.
- - PVBufTabLoops, phase vocoder buffer with bin independent speed playback.
- - PVBufLoops, phase vocoder buffer with bin independent speed playback.
- - PVShift, spectral frequency shifter. PVAmpMod and PVFreqMod, frequency
- independent modulations.
- - PVDelay, spectral delays and PVBuffer, pv recorder and playback.
- - PVFilter. Spectral filtering.
- - PVCross, PVMult, PVMorph. Spectral morphing.
- - PVAddSynth, Phase Vocoder additive synthesis object.
- * Added E-Pyo binary to the package, accessible via Sound & Video menu.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Mon, 02 Sep 2013 17:25:57 -0400
-
-python-pyo (0.6.6+svn1108-1) unstable; urgency=low
-
- * New upstream commits adding 6 new filters and a couple of bug fixes.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Tue, 28 May 2013 14:27:12 -0400
-
-python-pyo (0.6.6-1) unstable; urgency=low
-
- * New upstream release. It includes two new objects: CvlVerb: convolution
- based multi-channel reverberation and Spectrum: spectrum analyzer with
- multi-channel display.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Tue, 14 May 2013 21:37:45 -0400
-
-python-pyo (0.6.4-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Tue, 26 Feb 2013 23:40:59 -0500
-
-python-pyo (0.6.3+svn1068-1) unstable; urgency=low
-
- * New upstream release.
- * Start tracking upstream svn.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Wed, 30 Jan 2013 00:41:56 -0500
-
-python-pyo (0.6.2-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Tue, 03 Jul 2012 23:45:41 -0400
-
-python-pyo (0.6.1-1) unstable; urgency=low
-
- * Initial release. (Closes: #676712)
-
- -- Tiago Bortoletto Vaz <tiago at debian.org> Fri, 08 Jun 2012 20:35:45 -0400
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index 7f8f011..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-7
diff --git a/debian/control b/debian/control
deleted file mode 100644
index b980170..0000000
--- a/debian/control
+++ /dev/null
@@ -1,31 +0,0 @@
-Source: python-pyo
-Section: python
-Priority: optional
-Maintainer: Debian Multimedia Maintainers <pkg-multimedia-maintainers at lists.alioth.debian.org>
-Uploaders: Tiago Bortoletto Vaz <tiago at debian.org>
-Build-Depends: debhelper (>=7.0.50~), python-all-dev, portaudio19-dev, libportmidi-dev, liblo-dev, libsndfile1-dev, libjack-jackd2-dev
-Standards-Version: 3.9.6
-XS-Python-Version: >= 2.6
-Vcs-Browser: https://anonscm.debian.org/git/pkg-multimedia/python-pyo.git
-Vcs-Git: git://anonscm.debian.org/pkg-multimedia/python-pyo.git
-Homepage: http://ajaxsoundstudio.com/software/pyo/
-
-Package: python-pyo
-Architecture: any
-Depends: python (>= 2.6), ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}
-Recommends: python-tk, python-imaging-tk, python-wxgtk3.0, jackd2
-Description: Python module written in C to help digital signal processing script creation
- pyo is a Python module containing classes for a wide variety of audio signal
- processing types. With pyo, user will be able to include signal processing
- chains directly in Python scripts or projects, and to manipulate them in real
- time through the interpreter. Tools in pyo module offer primitives, like
- mathematical operations on audio signal, basic signal processing (filters,
- delays, synthesis generators, etc.), but also complex algorithms to create
- sound granulation and others creative audio manipulations.
- .
- pyo supports OSC protocol (Open Sound Control), to ease communications between
- softwares, and MIDI protocol, for generating sound events and controlling
- process parameters.
- .
- pyo allows creation of sophisticated signal processing chains with all the
- benefits of a mature, and wildly used, general programming language.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index 551b27a..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,44 +0,0 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: pyo
-Upstream-Contact: Olivier Bélanger <belangeo at gmail.com>
-Source: http://code.google.com/p/pyo/
-
-Files: *
-Copyright: 2015 Olivier Bélanger
-License: LGPL-3
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
- .
- pyo is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- .
- You should have received a copy of the GNU Lesser General Public
- License along with pyo. If not, see <http://www.gnu.org/licenses/>.
- .
- On Debian systems, the full text of the GNU Lesser General Public
- License version 3 can be found in the file
- `/usr/share/common-licenses/LGPL-3'.
-
-Files: debian/*
-Copyright: 2015 Tiago Bortoletto Vaz <tiago at debian.org>
-License: GPL-3+
- 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/>.
- .
- On Debian systems, the full text of the GNU General Public
- License version 2 can be found in the file
- `/usr/share/common-licenses/GPL-3'.
diff --git a/debian/dirs b/debian/dirs
deleted file mode 100644
index 4c727a5..0000000
--- a/debian/dirs
+++ /dev/null
@@ -1 +0,0 @@
-usr/lib/python-pyo
diff --git a/debian/examples b/debian/examples
deleted file mode 100644
index e39721e..0000000
--- a/debian/examples
+++ /dev/null
@@ -1 +0,0 @@
-examples/*
diff --git a/debian/install b/debian/install
deleted file mode 100644
index 94ab968..0000000
--- a/debian/install
+++ /dev/null
@@ -1,3 +0,0 @@
-utils/* usr/lib/python-pyo
-debian/E-Pyo.desktop usr/share/applications
-debian/E-Pyo.xpm usr/share/pixmaps
diff --git a/debian/patches/ePyo_paths.patch b/debian/patches/ePyo_paths.patch
deleted file mode 100644
index 7572640..0000000
--- a/debian/patches/ePyo_paths.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-Index: python-pyo/utils/E-Pyo.py
-===================================================================
---- python-pyo.orig/utils/E-Pyo.py
-+++ python-pyo/utils/E-Pyo.py
-@@ -226,7 +226,7 @@ if OSX_APP_BUNDLED:
- elif WIN_APP_BUNDLED:
- EXAMPLE_PATH = os.path.join(os.getcwd(), "Resources", "examples")
- else:
-- EXAMPLE_PATH = os.path.join(os.getcwd(), "../examples")
-+ EXAMPLE_PATH = "/usr/share/doc/python-pyo/examples"
- EXAMPLE_FOLDERS = [folder.capitalize() for folder in os.listdir(EXAMPLE_PATH) if folder[0] != "." and folder not in ["snds", "fft"]]
- EXAMPLE_FOLDERS.append("FFT")
- EXAMPLE_FOLDERS.sort()
-@@ -243,7 +243,7 @@ if not os.path.isdir(SNIPPETS_PATH):
- for file in files:
- shutil.copy(os.path.join(os.getcwd(), "Resources", "snippets", rep, file), os.path.join(SNIPPETS_PATH, rep))
- else:
-- files = [f for f in os.listdir(os.path.join(os.getcwd(), "snippets", rep)) if f[0] != "."]
-+ files = [f for f in os.listdir(os.path.join("/usr/lib/python-pyo", "snippets", rep)) if f[0] != "."]
- for file in files:
- shutil.copy(os.path.join(os.getcwd(), "snippets", rep, file), os.path.join(SNIPPETS_PATH, rep))
- SNIPPETS_CATEGORIES = [rep for rep in os.listdir(SNIPPETS_PATH) if os.path.isdir(os.path.join(SNIPPETS_PATH, rep))]
-@@ -274,12 +274,12 @@ if not os.path.isdir(STYLES_PATH):
- for file in files:
- shutil.copy(os.path.join(os.getcwd(), "Resources", "styles", file), os.path.join(STYLES_PATH, file))
- else:
-- files = [f for f in os.listdir(os.path.join(os.getcwd(), "styles")) if f[0] != "."]
-+ files = [f for f in os.listdir(os.path.join("/usr/lib/python-pyo", "styles")) if f[0] != "."]
- for file in files:
-- shutil.copy(os.path.join(os.getcwd(), "styles", file), os.path.join(STYLES_PATH, file))
-+ shutil.copy(os.path.join("/usr/lib/python-pyo", "styles", file), os.path.join(STYLES_PATH, file))
- 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)
-+ shutil.copy(os.path.join("/usr/lib/python-pyo", "styles", "Default"), DEFAULT_STYLE)
- if PREFERENCES.has_key("pref_style"):
- PREF_STYLE = os.path.join(ensureNFD(STYLES_PATH), PREFERENCES["pref_style"])
- else:
-@@ -293,7 +293,7 @@ if not os.path.isfile(MARKERS_FILE):
- with open(MARKERS_FILE, "w") as f:
- f.write("=\n")
-
--BACKGROUND_SERVER_DEFAULT_ARGS = 'sr=44100, nchnls=2, buffersize=256, duplex=1, audio="portaudio", jackname="pyo"'
-+BACKGROUND_SERVER_DEFAULT_ARGS = 'sr=44100, nchnls=2, buffersize=256, duplex=1, audio="jack", jackname="pyo"'
- BACKGROUND_SERVER_ARGS = PREFERENCES.get("background_server_args", BACKGROUND_SERVER_DEFAULT_ARGS)
-
- ################## TEMPLATES ##################
diff --git a/debian/patches/series b/debian/patches/series
deleted file mode 100644
index dacddd8..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1 +0,0 @@
-ePyo_paths.patch
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index fc58ab6..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/make -f
-
-export PYTHONWARNINGS=d
-buildvers := $(shell pyversions -rv)
-
-%:
- dh $@ --with python2
-
-override_dh_auto_build:
- set -e; \
- for i in $(buildvers); do \
- python$$i setup.py build --use-jack --use-double; \
- done
-
-override_dh_auto_install:
- set -e; \
- for i in $(buildvers); do \
- python$$i ./setup.py install --skip-build --root $(CURDIR)/debian/python-pyo --install-layout=deb; \
- done
-override_dh_compress:
- dh_compress -X.wav -X.aif -X.py
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides
deleted file mode 100644
index 6e9a659..0000000
--- a/debian/source/lintian-overrides
+++ /dev/null
@@ -1 +0,0 @@
-python-pyo source: source-is-missing scripts/prettify.js
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index 561f270..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,2 +0,0 @@
-version=3
-http://pyo.googlecode.com/files/pyo_(.*)\-src.tar\.bz2
diff --git a/doc-sphinx/source/about.rst b/doc-sphinx/source/about.rst
index b7488f9..c79d72d 100644
--- a/doc-sphinx/source/about.rst
+++ b/doc-sphinx/source/about.rst
@@ -1,15 +1,27 @@
About Pyo
=================
-Pyo is a Python module written in C to help digital signal processing script creation.
+Pyo is a Python module written in C to help digital signal processing script
+creation.
-Pyo is a Python module containing classes for a wide variety of audio signal processing types. With pyo, user will be able to include signal processing chains directly in Python scripts or projects, and to manipulate them in real time through the interpreter. Tools in pyo module offer primitives, like mathematical operations on audio signal, basic signal processing (filters, delays, synthesis generators, etc.), but also complex algorithms to create sound granulation and others creative sound manipulations. Pyo supports OSC protocol (Open Sound Control), to ease communications between softwares, and MIDI protocol, for generating sound events and controlling process parameters. Pyo allows creation of sophisticated signal processing chains with all the benefits of a mature, and wild used, general programming language.
+Pyo is a Python module written in C to help DSP script creation. Pyo contains
+classes for a wide variety of audio signal processing. With pyo, the user will
+be able to include signal processing chains directly in Python scripts or
+projects, and to manipulate them in real time through the interpreter. Tools
+in the pyo module offer primitives, like mathematical operations on audio
+signals, basic signal processing (filters, delays, synthesis generators, etc.),
+but also complex algorithms to create sound granulation and other creative
+audio manipulations. pyo supports the OSC protocol (Open Sound Control) to ease
+communications between softwares, and the MIDI protocol for generating sound
+events and controlling process parameters. pyo allows the creation of
+sophisticated signal processing chains with all the benefits of a mature and
+widely used general programming language.
Pyo is developed by Olivier Bélanger < belangeo at gmail.com >
For questions and comments, please subscribe to the `pyo-discuss <http://groups.google.com/group/pyo-discuss>`_ mailing list.
-To report a bug or to request a feature, use the `issues tracker <http://code.google.com/p/pyo/issues/list>`_ on googlecode.
+To report a bug or to request a feature, use the `issues tracker <https://github.com/belangeo/pyo/issues>`_ on github.
Sources and binaries can be downloaded at:
http://ajaxsoundstudio.com/software/pyo/
diff --git a/doc-sphinx/source/api/alphabetical.rst b/doc-sphinx/source/api/alphabetical.rst
index ad48bdc..6ae547a 100644
--- a/doc-sphinx/source/api/alphabetical.rst
+++ b/doc-sphinx/source/api/alphabetical.rst
@@ -69,6 +69,8 @@ Alphabetical class reference
- :py:class:`EQ` : Equalizer filter.
- :py:class:`Euclide` : Euclidean rhythm generator.
- :py:class:`ExpTable` : Construct a table from exponential interpolated segments.
+- :py:class:`Expr` : Prefix audio expression evaluator.
+- :py:class:`Expr` : Prefix audio expression evaluator.
- :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.
@@ -182,6 +184,7 @@ Alphabetical class reference
- :py:class:`Randi` : Periodic pseudo-random generator with interpolation.
- :py:class:`RawMidi` : Raw Midi handler.
- :py:class:`Record` : Writes input sound in an audio file on the disk.
+- :py:class:`Resample` : Realtime upsampling or downsampling of an audio signal.
- :py:class:`Reson` : A second-order resonant bandpass filter.
- :py:class:`Resonx` : A multi-stages second-order resonant bandpass filter.
- :py:class:`Rossler` : Chaotic attractor for the Rossler system.
diff --git a/doc-sphinx/source/api/classes/expression.rst b/doc-sphinx/source/api/classes/expression.rst
new file mode 100644
index 0000000..c2e5e3a
--- /dev/null
+++ b/doc-sphinx/source/api/classes/expression.rst
@@ -0,0 +1,247 @@
+Prefix expression evaluators
+=============================
+
+.. module:: pyo
+
+Prefix audio expression evaluator.
+
+This family implements a tiny functional programming language that
+can be used to write synthesis or signal processing algorithms.
+
+**API documentation**
+---------------------
+
+This API is in alpha stage and subject to future changes!
+
+Builtin functions
+-----------------
+
+**Arithmetic operators**
+
+- (+ x y) : returns the sum of two values.
+- (- x y) : substracts the second value to the first and returns the result.
+- (* x y) : returns the multiplication of two values.
+- (/ x y) : returns the quotient of x/y.
+- (^ x y) : returns x to the power y.
+- (% x y) : returns the floating-point remainder of x/y.
+- (neg x) : returns the negative of x.
+
+**Moving phase operators**
+
+- (++ x y) : increments its internal state by x and wrap around 0.0 and y.
+- (-- x y) : decrements its internal state by x and wrap around 0.0 and y.
+- (~ x y) : generates a periodic ramp from 0 to 1 with frequency x and phase y.
+
+**Conditional operators**
+
+- (< x y) : returns 1 if x is less than y, otherwise returns 0.
+- (<= x y) : returns 1 if x is less than or equal to y, otherwise returns 0.
+- (> x y) : returns 1 if x is greater than y, otherwise returns 0.
+- (>= x y) : returns 1 if x is greater than or equal to y, otherwise returns 0.
+- (== x y) : returns 1 if x is equal to y, otherwise returns 0.
+- (!= x y) : returns 1 if x is not equal to y, otherwise returns 0.
+- (if (cond) (then) (else)) : returns then for any non-zero value of cond, otherwise returns else.
+- (and x y) : returns 1 if both x and y are not 0, otherwise returns 0.
+- (or x y) : returns 1 if one of x or y are not 0, otherwise returns 0.
+
+**Trigonometric functions**
+
+- (sin x) : returns the sine of an angle of x radians.
+- (cos x) : returns the cosine of an angle of x radians.
+- (tan x) : returns the tangent of x radians.
+- (tanh x) : returns the hyperbolic tangent of x radians.
+- (atan x) : returns the principal value of the arc tangent of x, expressed in radians.
+- (atan2 x y) : returns the principal value of the arc tangent of y/x, expressed in radians.
+
+**Power and logarithmic functions**
+
+- (sqrt x) : returns the square root of x.
+- (log x) : returns the natural logarithm of x.
+- (log2 x) : returns the binary (base-2) logarithm of x.
+- (log10 x) : returns the common (base-10) logarithm of x.
+- (pow x y) : returns x to the power y.
+
+**Clipping functions**
+
+- (abs x) : returns the absolute value of x.
+- (floor x) : rounds x downward, returning the largest integral value that is not greater than x.
+- (ceil x) : rounds x upward, returning the smallest integral value that is not less than x.
+- (exp x) : returns the constant e to the power x.
+- (round x) : returns the integral value that is nearest to x.
+- (min x y) : returns the smaller of its arguments: either x or y.
+- (max x y) : returns the larger of its arguments: either x or y.
+- (wrap x) : wraps x between 0 and 1.
+
+**Random fuctions**
+
+- (randf x y) : returns a pseudo-random floating-point number in the range between x and y.
+- (randi x y) : returns a pseudo-random integral number in the range between x and y.
+
+**Filter functions**
+
+- (sah x y) : samples and holds x value whenever y is smaller than its previous state.
+- (rpole x y) : real one-pole recursive filter. returns x + last_out * y.
+- (rzero x y) : real one-zero non-recursive filter. returns x - last_x * y.
+
+**Constants**
+
+- (const x) : returns x.
+- (pi) : returns an approximated value of pi.
+- (twopi) : returns a constant with value pi*2.
+- \(e\) : returns an approximated value of e.
+
+
+Comments
+--------
+
+A comment start with two slashs ( // ) and ends at the end of the line::
+
+ // This is a comment!
+
+Input and Output signals
+------------------------
+
+User has access to the last buffer size of input and output samples.
+
+To use samples from past input, use $x[n] notation, where n is the position
+from the current time. $x[0] is the current input, $x[-1] is the previous
+one and $x[-buffersize] is the last available input sample.
+
+To use samples from past output, use $y[n] notation, where n is the position
+from the current time. $y[-1] is the previous output and $y[-buffersize] is
+the last available output sample.
+
+Here an example of a first-order IIR lowpass filter expression::
+
+ // A first-order IIR lowpass filter
+ + $x[0] (* (- $y[-1] $x[0]) 0.99)
+
+
+Defining custom functions
+-------------------------
+
+The define keyword starts the definition of a custom function::
+
+ (define funcname (body))
+
+funcname is the name used to call the function in the expression and body
+is the sequence of functions to execute. Arguments of the function are
+extracted directly from the body. They must be named $1, $2, $3, ..., $9.
+
+Example of a sine wave function::
+
+ (define osc (
+ sin (* (twopi) (~ $1))
+ )
+ )
+ // play a sine wave
+ * (osc 440) 0.3
+
+
+State variables
+---------------
+
+User can create state variable with the keyword "let". This is useful
+to set an intermediate state to be used in multiple places in the
+processing chain. The syntax is::
+
+ (let #var (body))
+
+The variable name must begin with a "#"::
+
+ (let #sr 44100)
+ (let #freq 1000)
+ (let #coeff (
+ ^ (e) (/ (* (* -2 (pi)) #freq) #sr)
+ )
+ )
+ + $x[0] (* (- $y[-1] $x[0]) #coeff)
+
+The variable is private to a function if created inside a custom function::
+
+ (let #freq 250) // global #freq variable
+ (define osc (
+ (let #freq (* $1 $2)) // local #freq variable
+ sin (* (twopi) (~ #freq))
+ )
+ )
+ * (+ (osc 1 #freq) (osc 2 #freq)) 0.2
+
+State variables can be used to do 1 sample feedback if used before created.
+Undefined variables are initialized to 0::
+
+ (define oscloop (
+ (let #xsin
+ (sin (+ (* (~ $1) (twopi)) (* #xsin $2))) // #xsin used before...
+ ) // ... "let" statement finished!
+ #xsin // oscloop function outputs #xsin variable
+ )
+ )
+ * (oscloop 200 0.7) 0.3
+
+User variables
+--------------
+
+User variables are created with the keyword "var"::
+
+ (var #var (init))
+
+The variable name must begin with a "#".
+
+They are computed only at initialization, but can be changed from the python
+script with method calls (varname is a string and value is a float)::
+
+ obj.setVar(varname, value)
+
+Library importation
+-------------------
+
+Custom functions can be defined in an external file and imported with the
+"load" function::
+
+ (load path/to/the/file)
+
+The content of the file will be inserted where the load function is called
+and all functions defined inside the file will then be accessible. The path
+can be absolute or relative to the current working directory.
+
+Examples
+--------
+
+Here is some expression examples.
+
+A first-order IIR lowpass filter::
+
+ (var #sr 44100)
+ (var #cutoff 1000)
+ (let #coeff (exp (/ (* (* -2 (pi)) #cutoff) #sr)))
+ + $x[0] (* (- $y[-1] $x[0]) #coeff)
+
+A LFO'ed hyperbolic tangent distortion::
+
+ // $1 = lfo frequency, $2 = lfo depth
+ (define lfo (
+ (+ (* (sin (* (twopi) (~ $1))) (- $2 1)) $2)
+ )
+ )
+ tanh (* $x[0] (lfo .25 10))
+
+A triangle waveform generator (use Sig(0) as input argument to bypass input)::
+
+ (var #freq 440)
+ // $1 = oscillator frequency
+ (define triangle (
+ (let #ph (~ $1))
+ (- (* (min #ph (- 1 #ph)) 4) 1)
+ )
+ )
+ triangle #freq
+
+**Objects**
+-----------
+
+*Expr*
+----------
+
+.. autoclass:: Expr
+ :members:
diff --git a/doc-sphinx/source/api/classes/index.rst b/doc-sphinx/source/api/classes/index.rst
index 2f5052d..3fb9d7c 100644
--- a/doc-sphinx/source/api/classes/index.rst
+++ b/doc-sphinx/source/api/classes/index.rst
@@ -12,6 +12,7 @@ Classes by category
controls
dynamics
effects
+ expression
filters
fourier
pvoc
diff --git a/doc-sphinx/source/api/classes/listener.rst b/doc-sphinx/source/api/classes/listener.rst
index 2f5052d..c3406b6 100644
--- a/doc-sphinx/source/api/classes/listener.rst
+++ b/doc-sphinx/source/api/classes/listener.rst
@@ -1,33 +1,19 @@
-Classes by category
-===============================
+Controller listeners
+===================================
-.. toctree::
- :maxdepth: 2
+.. module:: pyo
- server
- listener
- _core
- analysis
- arithmetic
- controls
- dynamics
- effects
- filters
- fourier
- pvoc
- generators
- internals
- matrixprocess
- midi
- opensndctrl
- pan
- pattern
- players
- randoms
- tableprocess
- triggers
- utils
- tables
- matrices
- map
+These objects can be used to create MIDI and/or OSC listeners without the
+need to boot ands start an audio server before receiving messages.
+*MidiListener*
+-----------------------------------
+
+.. autoclass:: MidiListener
+ :members:
+
+*OscListener*
+-----------------------------------
+
+.. autoclass:: OscListener
+ :members:
diff --git a/doc-sphinx/source/api/classes/utils.rst b/doc-sphinx/source/api/classes/utils.rst
index c84bbab..360e6e7 100644
--- a/doc-sphinx/source/api/classes/utils.rst
+++ b/doc-sphinx/source/api/classes/utils.rst
@@ -131,3 +131,8 @@ Miscellaneous objects.
.. autoclass:: TrackHold
:members:
+*Resample*
+-----------------------------------
+
+.. autoclass:: Resample
+ :members:
diff --git a/doc-sphinx/source/compiling.rst b/doc-sphinx/source/compiling.rst
index b984826..4f26874 100644
--- a/doc-sphinx/source/compiling.rst
+++ b/doc-sphinx/source/compiling.rst
@@ -8,27 +8,13 @@ Dependencies
To compile pyo, you will need the following dependencies:
-- `Python 2.6 or 2.7 <http://www.python.org/download/releases/>`_
+- `Python 2.6 or 2.7 <https://www.python.org/downloads/>`_
- `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.
-
-First, install Homebrew with this command:
-
-.. code-block:: bash
-
- ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"
-
-Then, install packages:
-
-.. code-block:: bash
-
- brew install python liblo libsndfile portaudio portmidi --universal
-
Getting sources
-------------------
@@ -36,18 +22,19 @@ You can download pyo's source checking out the source code here:
.. code-block:: bash
- svn checkout http://pyo.googlecode.com/svn/trunk/ pyo-read-only
+ git clone https://github.com/belangeo/pyo.git
Compilation
---------------
-Please note that under Mac OS X you will need to install the **Apple's developer tools** to compile pyo.
+Please note that under Mac OS X you will need to install the
+**Apple's developer tools** to compile pyo.
Once you have all the required dependencies, go in pyo's directory:
.. code-block:: bash
- cd pyo-read-only
+ cd path/to/pyo
You then need to build the extension:
@@ -74,7 +61,8 @@ If you want JACK support (Linux, Mac OS X):
--use-jack
-If you want to be able to use a 64-bit pyo (All platforms), this will build both single and double precision:
+If you want to be able to use a 64-bit pyo (All platforms, this is the sample
+resolution, not the architecture), this will build both single and double precision:
.. code-block:: bash
@@ -120,23 +108,41 @@ Under Ubuntu you can type the following commands to get pyo up and running:
.. code-block:: bash
- sudo apt-get install libjack-jack2-dev libportmidi-dev portaudio19-dev liblo-dev
- sudo apt-get install libsndfile-dev python-dev python-tk subversion
- sudo apt-get install python-imaging-tk python-wxgtk2.8
- svn checkout http://pyo.googlecode.com/svn/trunk/ pyo-read-only
- cd pyo-read-only
+ sudo apt-get install libjack-jackd2-dev libportmidi-dev portaudio19-dev liblo-dev
+ sudo apt-get install libsndfile-dev python-dev python-tk
+ sudo apt-get install python-imaging-tk python-wxgtk3.0
+ git clone https://github.com/belangeo/pyo.git
+ cd pyo
sudo python setup.py install --install-layout=deb --use-jack --use-double
+* On Ubuntu system prior to vivid, wxpython 3.0 must be compiled from sources.
+
OSX (Homebrew)
--------------------
-Under OS X, it is very simple to build pyo from sources with the Homebrew package mananger:
+Under OS X, it is very simple to build pyo from sources with the Homebrew package mananger.
+
+First, you need to install `Homebrew <http://brew.sh/>`. Then, in a terminal window:
.. code-block:: bash
brew install python liblo libsndfile portaudio portmidi --universal
- svn checkout http://pyo.googlecode.com/svn/trunk/ pyo
+ git clone https://github.com/belangeo/pyo.git
cd pyo
python setup.py install --use-coreaudio --use-double
+* To build a universal portmidi library with homebrew, the formula must be modified like this:
+
+Add the option "universal":
+
+.. code-block:: bash
+
+ option :universal
+
+And modify the "install function" to add the universal variable:
+
+.. code-block:: bash
+
+ def install
+ ENV.universal_binary if build.universal?
diff --git a/doc-sphinx/source/conf.py b/doc-sphinx/source/conf.py
index c2779e5..0d8b3c1 100644
--- a/doc-sphinx/source/conf.py
+++ b/doc-sphinx/source/conf.py
@@ -43,7 +43,7 @@ master_doc = 'index'
# General information about the project.
project = u'Pyo'
-copyright = u'2014, Olivier Bélanger'
+copyright = u'2015, 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
diff --git a/doc-sphinx/source/download.rst b/doc-sphinx/source/download.rst
index fb5024b..2865006 100644
--- a/doc-sphinx/source/download.rst
+++ b/doc-sphinx/source/download.rst
@@ -1,7 +1,7 @@
Downloading
=================
-Installers are available for Windows (Win 7/8) and for Max OS X (from 10.6 to 10.9).
+Installers are available for Windows (Win 7/8/10) and for Max OS X (from 10.6 to 10.10).
To download the latest pre-compiled version of pyo, go to the pyo's `web page <http://ajaxsoundstudio.com/software/pyo/>`_.
diff --git a/doc-sphinx/source/index.rst b/doc-sphinx/source/index.rst
index c2c953b..a07f281 100644
--- a/doc-sphinx/source/index.rst
+++ b/doc-sphinx/source/index.rst
@@ -3,9 +3,12 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
-Welcome to the Pyo 0.7.6 documentation
+Welcome to the Pyo 0.7.8 documentation
===================================================
+Pyo is a Python module written in C to help digital signal processing script
+creation.
+
.. toctree::
:maxdepth: 1
diff --git a/embedded/openframeworks/PyoTemplate/src/PyoClass.cpp b/embedded/juceplugin/PyoClass.cpp
similarity index 58%
rename from embedded/openframeworks/PyoTemplate/src/PyoClass.cpp
rename to embedded/juceplugin/PyoClass.cpp
index 972541c..167d04e 100644
--- a/embedded/openframeworks/PyoTemplate/src/PyoClass.cpp
+++ b/embedded/juceplugin/PyoClass.cpp
@@ -16,7 +16,7 @@ void Pyo::setup(int _nChannels, int _bufferSize, int _sampleRate) {
nChannels = _nChannels;
bufferSize = _bufferSize;
sampleRate = _sampleRate;
- interpreter = pyo_new_interpreter(nChannels);
+ interpreter = pyo_new_interpreter(sampleRate, bufferSize, 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));
@@ -32,28 +32,28 @@ Pyo::~Pyo() {
}
/*
-** This function fills pyo's input buffers with new samples. Should be called
-** once per process block, inside the host's audioIn function.
+** This function fills pyo's input buffers with new samples, 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
+** processBlock function.
**
** arguments:
-** *buffer : float *, float pointer pointing to the host's input buffers.
+** buffer : AudioSampleBuffer&, Juce's audio buffer object.
*/
-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) {
+void Pyo::process(AudioSampleBuffer& buffer) {
+ for (int channel = 0; channel < nChannels; ++channel) {
+ float *channelData = buffer.getWritePointer(channel);
+ for (int sample = 0; sample < bufferSize; sample++) {
+ pyoInBuffer[sample*nChannels+channel] = channelData[sample];
+ }
+ }
pyoCallback(pyoId);
- for (int i=0; i<(bufferSize*nChannels); i++) buffer[i] = pyoOutBuffer[i];
+ for (int channel = 0; channel < nChannels; ++channel) {
+ float *channelData = buffer.getWritePointer(channel);
+ for (int sample = 0; sample < bufferSize; sample++) {
+ channelData[sample] = pyoOutBuffer[sample*nChannels+channel];
+ }
+ }
}
/*
@@ -62,23 +62,29 @@ void Pyo::process(float *buffer) {
** 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.
+** file : const char * or const String &,
+** 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.
+** cleared before executing the file.
*/
int Pyo::loadfile(const char *file, int add) {
return pyo_exec_file(interpreter, file, pyoMsg, add);
}
+int Pyo::loadfile(const String &file, int add) {
+ return pyo_exec_file(interpreter, file.getCharPointer(), 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.
+** name : const char * or const String &,
+** variable name of the object.
+** value : float, value to be assigned.
**
** Example:
**
@@ -95,11 +101,18 @@ int Pyo::value(const char *name, float value) {
return pyo_exec_statement(interpreter, pyoMsg, 0);
}
+int Pyo::value(const String &name, float value) {
+ const char * _name = name.getCharPointer();
+ 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.
+** name : const char * or const String &,
+** variable name of the object.
** value : float *, array of floats.
** len : int, number of elements in the array.
**
@@ -125,12 +138,25 @@ int Pyo::value(const char *name, float *value, int len) {
return pyo_exec_statement(interpreter, pyoMsg, 0);
}
+int Pyo::value(const String &name, float *value, int len) {
+ char fchar[32];
+ const char * _name = name.getCharPointer();
+ 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.
+** name : const char * or const String &,
+** object name and attribute separated by a dot.
+** value : float, value to be assigned.
**
** Example:
**
@@ -147,11 +173,18 @@ int Pyo::set(const char *name, float value) {
return pyo_exec_statement(interpreter, pyoMsg, 0);
}
+int Pyo::set(const String &name, float value) {
+ const char * _name = name.getCharPointer();
+ 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.
+** name : const char * or const String &,
+** object name and attribute separated by a dot.
** value : float *, array of floats.
** len : int, number of elements in the array.
**
@@ -177,12 +210,25 @@ int Pyo::set(const char *name, float *value, int len) {
return pyo_exec_statement(interpreter, pyoMsg, 0);
}
+int Pyo::set(const String &name, float *value, int len) {
+ char fchar[32];
+ const char * _name = name.getCharPointer();
+ 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.
+** 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.
+** msg : const char * or const String &
+** pointer to a string containing the statement to execute.
**
** Example (for a Pyo object named `pyo`):
**
@@ -195,6 +241,11 @@ int Pyo::exec(const char *_msg) {
return pyo_exec_statement(interpreter, pyoMsg, 0);
}
+int Pyo::exec(const String &_msg) {
+ strcpy(pyoMsg, _msg.getCharPointer());
+ 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.
diff --git a/embedded/openframeworks/PyoTemplate/src/PyoClass.h b/embedded/juceplugin/PyoClass.h
similarity index 58%
rename from embedded/openframeworks/PyoTemplate/src/PyoClass.h
rename to embedded/juceplugin/PyoClass.h
index 2ca65b4..6487748 100644
--- a/embedded/openframeworks/PyoTemplate/src/PyoClass.h
+++ b/embedded/juceplugin/PyoClass.h
@@ -1,31 +1,40 @@
-#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();
+#ifndef PYOCLASS_H_INCLUDED
+#define PYOCLASS_H_INCLUDED
+
+#include "m_pyo.h"
+#include "../JuceLibraryCode/JuceHeader.h"
+
+typedef int callPtr(int);
+
+class Pyo {
+ public:
+ ~Pyo();
+ void setup(int nChannels, int bufferSize, int sampleRate);
+ void process(AudioSampleBuffer& buffer);
+ void clear();
int loadfile(const char *file, int add);
- int exec(const char *msg);
+ int loadfile(const String &file, int add);
+ int exec(const char *msg);
+ int exec(const String &msg);
int value(const char *name, float value);
+ int value(const String &name, float value);
int value(const char *name, float *value, int len);
+ int value(const String &name, float *value, int len);
int set(const char *name, float value);
+ int set(const String &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];
-};
+ int set(const String &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];
+};
+
+#endif // PYOCLASS_H_INCLUDED
diff --git a/embedded/juceplugin/README b/embedded/juceplugin/README
new file mode 100644
index 0000000..5e6e7e5
--- /dev/null
+++ b/embedded/juceplugin/README
@@ -0,0 +1,162 @@
+Introduction on how to use pyo inside a Juce audio plugin.
+==========================================================
+
+To use pyo inside a Juce audio plugin, first you need a working
+install of pyo on your system. After installing pyo, you can move
+on and create a Juce audio plugin project.
+
+------------------------------------------------------------------------------
+Step 1 - Create an Audio Plug-In project with the Introjucer.
+
+------------------------------------------------------------------------------
+Step 2 - Add pyo files to your project. You only need to copy
+these files in your project "Source" 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. Within the Introjucer, you can set extra
+flags in the "Config" tab. For example, on linux, if you select "Linux
+Makefile", you can add extra compiler and linker flags. Add these in
+the specific fields:
+
+Extra linker flags : `python-config --ldflags`
+Extra compiler flags : `python-config --cflags`
+
+------------------------------------------------------------------------------
+Step 4 - Make sure that your project links to the Steinberg's VST SDK.
+VST SDK can be freely downloaded from Steinberg web site:
+http://www.steinberg.net/en/company/developers/
+Enter the path in the field "VST Folder" in the export configuration.
+
+------------------------------------------------------------------------------
+Step 5 - Create a python file, named "stereoDelay.py", with these lines in
+it:
+
+# Retrieve the stereo input of the plugin.
+st_input = Input([0,1])
+# Parameters to change.
+dtime = SigTo(.5, 0.05, .5)
+feed = SigTo(.5, 0.05, .5)
+# Simple process. Stereo delay -> reverb.
+st_delay = SmoothDelay(st_input, delay=dtime, feedback=feed)
+st_rev = WGVerb(st_delay, feedback=0.8, cutoff=4000, bal=0.25).out()
+
+Save "stereoDelay.py" in the "Source" folder, add it to the project in the
+Introjucer and ensure that the option "Add to Binary Resources" is checked.
+Save your project. This should add two files, "BinaryData.h" and
+"BinaryData.cpp", in the "JuceLibraryCode" folder.
+
+------------------------------------------------------------------------------
+Step 6 - Edit Source/PluginProcessor.h
+
+- Include PyoClass definition:
+
+#include "PyoClass.h"
+
+- Add a Pyo object to the public attributes of the XXXAudioProcessor class:
+
+ Pyo pyo;
+
+------------------------------------------------------------------------------
+Step 7 - Edit Source/PluginProcessor.cpp
+
+- Add these line to XXXAudioProcessor::prepareToPlay method:
+
+ pyo.setup(getNumOutputChannels(), samplesPerBlock, sampleRate);
+ pyo.exec(BinaryData::stereoDelay_py);
+
+- Replace the content of XXXAudioProcessor::processBlock method with
+this line:
+
+ pyo.process(buffer);
+
+------------------------------------------------------------------------------
+Here you go! Compile, Run and Enjoy!
+
+Adding GUI controls to your plugin
+==================================
+
+Now, we will add two sliders to control the delay time and the feedback
+of our process.
+
+------------------------------------------------------------------------------
+Step 8 - Edit Source/PluginEditor.h
+
+- Add the inheritance to Slider::Listener to your XXXAudioProcessorEditor
+class definition:
+
+class XXXAudioProcessorEditor : public AudioProcessorEditor,
+ private Slider::Listener
+
+- Add the default callback function in the public attributes of the class:
+
+ void sliderValueChanged(Slider* slider) override;
+
+- Create two sliders in the public attributes of the class:
+
+ Slider p1;
+ Slider p2;
+
+------------------------------------------------------------------------------
+Step 9 - Edit Source/PluginEditor.cpp
+
+- Set the sliders properties in the editor constructor function named
+XXXAudioProcessorEditor::XXXAudioProcessorEditor (this is the first function
+in the PluginEditor.cpp file). Add these lines at the end of the function:
+
+ // these define the parameters of our slider object
+ p1.setSliderStyle(Slider::LinearBarVertical);
+ p1.setRange(0.0, 1.0, 0.01);
+ p1.setTextBoxStyle(Slider::NoTextBox, false, 90, 0);
+ p1.setPopupDisplayEnabled(true, this);
+ p1.setTextValueSuffix(" Delay Time");
+ p1.setValue(0.5);
+ p1.addListener(this);
+ // this function adds the slider to the editor
+ addAndMakeVisible(&p1);
+
+ p2.setSliderStyle(Slider::LinearBarVertical);
+ p2.setRange(0.0, 1.0, 0.01);
+ p2.setTextBoxStyle(Slider::NoTextBox, false, 90, 0);
+ p2.setPopupDisplayEnabled(true, this);
+ p2.setTextValueSuffix(" Delay Feedback");
+ p2.setValue(0.5);
+ p2.addListener(this);
+ addAndMakeVisible(&p2);
+
+- Set the size and position of the sliders. Add these lines in
+XXXAudioProcessorEditor::resized() function:
+
+ p1.setBounds(40, 30, 20, getHeight() - 60);
+ p2.setBounds(70, 30, 20, getHeight() - 60);
+
+------------------------------------------------------------------------------
+Step 10 - Connect the sliders to the audio proces
+
+- At the end of the file PluginEditor.cpp, create the slider's callback
+function which will pass the values to the audio processing objects:
+
+void XXXAudioProcessorEditor::sliderValueChanged (Slider* slider)
+{
+ processor.pyo.value("dtime", p1.getValue());
+ processor.pyo.value("feed", p2.getValue());
+}
+
+------------------------------------------------------------------------------
+That's it! Compile and Run...
+
+Documentation
+=============
+
+For a complete description of functions used to communicate with the pyo
+embedded processes, see documentation comments in the file PyoClass.cpp.
+
+
+(c) 2015 - belangeo
diff --git a/embedded/juceplugin/test.py b/embedded/juceplugin/test.py
new file mode 100644
index 0000000..ad0a4ed
--- /dev/null
+++ b/embedded/juceplugin/test.py
@@ -0,0 +1,9 @@
+import random
+
+# Get the input sound and apply a stereo delay on it.
+feed = SigTo(0, 0.05, 0)
+freq = SigTo(0.1, 0.05, 0.1)
+freq_sc = Scale(freq, 0, 1, 100, 10000, 4)
+st_input = Input([0,1])
+st_filter = ButBP(st_input, freq_sc)
+st_delay = Delay(st_filter, delay=[random.uniform(.1, .9) for i in range(2)], feedback=feed).out()
diff --git a/embedded/m_pyo.h b/embedded/m_pyo.h
index c0a5235..74afaca 100644
--- a/embedded/m_pyo.h
+++ b/embedded/m_pyo.h
@@ -14,11 +14,13 @@ extern "C" {
** can be an object in a programming language or a plugin in a daw.
**
** arguments:
+** sr : float, host sampling rate.
+** bufsize : int, host buffer size.
** 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) {
+inline PyThreadState * pyo_new_interpreter(float sr, int bufsize, int chnls) {
char msg[64];
PyThreadState *interp;
if(!Py_IsInitialized()) {
@@ -29,7 +31,7 @@ inline PyThreadState * pyo_new_interpreter(int chnls) {
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);
+ sprintf(msg, "_s_ = Server(%f, %d, %d, 1, 'embedded')", sr, chnls, bufsize);
PyRun_SimpleString(msg);
PyRun_SimpleString("_s_.boot()\n_s_.start()\n_s_.setServer()");
PyRun_SimpleString("_in_address_ = _s_.getInputAddr()");
@@ -161,9 +163,15 @@ inline int pyo_get_server_id(PyThreadState *interp) {
** interp : pointer, pointer to the targeted Python thread state.
*/
inline void pyo_end_interpreter(PyThreadState *interp) {
- PyEval_AcquireThread(interp);
- Py_EndInterpreter(interp);
- PyEval_ReleaseLock();
+ /* Old method (causing segfault) */
+ //PyEval_AcquireThread(interp);
+ //Py_EndInterpreter(interp);
+ //PyEval_ReleaseLock();
+ /* New method (seems to be ok) */
+ PyThreadState_Swap(interp);
+ PyThreadState_Swap(NULL);
+ PyThreadState_Clear(interp);
+ PyThreadState_Delete(interp);
}
/*
@@ -200,6 +208,26 @@ inline void pyo_set_server_params(PyThreadState *interp, float sr, int bufsize)
}
/*
+** Add a MIDI event in the pyo server processing chain. When used in
+** an embedded framework, pyo can't open MIDI ports by itself. MIDI
+** inputs must be handled by the host program and sent to pyo with
+** the pyo_add_midi_event function.
+**
+** arguments:
+** interp : pointer, pointer to the targeted Python thread state.
+** status : int, status byte.
+** data1 : int, first data byte.
+** data2 : int, second data byte.
+*/
+inline void pyo_add_midi_event(PyThreadState *interp, int status, int data1, int data2) {
+ char msg[64];
+ PyEval_AcquireThread(interp);
+ sprintf(msg, "_s_.addMidiEvent(%d, %d, %d)", status, data1, data2);
+ PyRun_SimpleString(msg);
+ PyEval_ReleaseThread(interp);
+}
+
+/*
** Returns 1 if the pyo server is started for the given thread,
** Otherwise returns 0.
**
diff --git a/embedded/openframeworks/PyoClass.cpp b/embedded/openframeworks/PyoClass.cpp
index 972541c..bed1d65 100644
--- a/embedded/openframeworks/PyoClass.cpp
+++ b/embedded/openframeworks/PyoClass.cpp
@@ -16,12 +16,11 @@ void Pyo::setup(int _nChannels, int _bufferSize, int _sampleRate) {
nChannels = _nChannels;
bufferSize = _bufferSize;
sampleRate = _sampleRate;
- interpreter = pyo_new_interpreter(nChannels);
+ interpreter = pyo_new_interpreter(sampleRate, bufferSize, 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);
}
/*
@@ -67,7 +66,7 @@ void Pyo::process(float *buffer) {
** 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.
+** cleared before executing the file.
*/
int Pyo::loadfile(const char *file, int add) {
return pyo_exec_file(interpreter, file, pyoMsg, add);
@@ -78,7 +77,7 @@ int Pyo::loadfile(const char *file, int add) {
**
** arguments:
** name : const char *, variable name of the object.
-** value : float, value to be assign.
+** value : float, value to be assigned.
**
** Example:
**
@@ -129,8 +128,8 @@ int Pyo::value(const char *name, float *value, int len) {
** 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.
+** name : const char *, object name and attribute separated by a dot.
+** value : float, value to be assigned.
**
** Example:
**
@@ -151,7 +150,7 @@ int Pyo::set(const char *name, float value) {
** Sends an array of numerical values to a Pyo object's attribute.
**
** arguments:
-** name : const char *, object name and attribute separated by a point.
+** name : const char *, object name and attribute separated by a dot.
** value : float *, array of floats.
** len : int, number of elements in the array.
**
diff --git a/embedded/openframeworks/PyoTemplate/Makefile b/embedded/openframeworks/PyoTemplate/Makefile
deleted file mode 100644
index 7a7fe8b..0000000
--- a/embedded/openframeworks/PyoTemplate/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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
deleted file mode 100644
index 2a5b520..0000000
--- a/embedded/openframeworks/PyoTemplate/config.make
+++ /dev/null
@@ -1,141 +0,0 @@
-################################################################################
-# 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
deleted file mode 100644
index 0d98f4e..0000000
--- a/embedded/openframeworks/PyoTemplate/scripts/stereoDelay.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# 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/m_pyo.h b/embedded/openframeworks/PyoTemplate/src/m_pyo.h
deleted file mode 100644
index c0a5235..0000000
--- a/embedded/openframeworks/PyoTemplate/src/m_pyo.h
+++ /dev/null
@@ -1,312 +0,0 @@
-#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
deleted file mode 100644
index a7d241d..0000000
--- a/embedded/openframeworks/PyoTemplate/src/main.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#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
deleted file mode 100644
index 882cec7..0000000
--- a/embedded/openframeworks/PyoTemplate/src/testApp.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-#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
deleted file mode 100644
index 4a98213..0000000
--- a/embedded/openframeworks/PyoTemplate/src/testApp.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#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
index 7879578..da83818 100644
--- a/embedded/openframeworks/README
+++ b/embedded/openframeworks/README
@@ -3,10 +3,12 @@ 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.
+you can move on and create an OpenFrameworks project.
------------------------------------------------------------------------
-Step 1 - Create a default project with project generator.
+Step 1 - Create a default project with the project generator. To avoid
+any include or linking problem, you should save your project in the
+default location (OF_ROOT/apps/myApps).
------------------------------------------------------------------------
Step 2 - Add pyo files to your project. You only need to copy
@@ -37,31 +39,31 @@ 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.
+Step 5 - Edit src/ofApp.h
- Include PyoClass definition:
#include "PyoClass.h"
-- Add audio in/out callbacks to the public attributes of the testApp class:
+- Add audio in/out callbacks to the public attributes of the ofApp 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:
+- Add an ofSoundStream object to the public attributes of the ofApp class:
ofSoundStream soundStream;
-- Add a Pyo object to the public attributes of the testApp class:
+- Add a Pyo object to the public attributes of the ofApp class:
Pyo pyo;
------------------------------------------------------------------------
-Step 6 - Edit src/testApp.cpp.
+Step 6 - Edit src/ofApp.cpp
- Creates the setup() function:
-void testApp::setup(){
+void ofApp::setup(){
// define audio properties
int sampleRate = 44100;
int bufferSize = 256;
@@ -71,17 +73,19 @@ void testApp::setup(){
// load a python file
pyo.loadfile("../scripts/stereoDelay.py", 0);
// initialize OpenFrameworks audio streaming channels
+ //soundStream.listDevices() // Uncomment if you need to
+ //soundStream.setDeviceID(1); // change the audio device.
soundStream.setup(this, nChannels, nChannels, sampleRate, bufferSize, 4);
}
- Creates audio in/out functions:
-void testApp::audioIn(float * input, int bufferSize, int nChannels){
+void ofApp::audioIn(float * input, int bufferSize, int nChannels){
// send audio samples to pyo
pyo.fillin(input);
}
-void testApp::audioOut(float * output, int bufferSize, int nChannels){
+void ofApp::audioOut(float * output, int bufferSize, int nChannels){
// process and get new audio samples from pyo
pyo.process(output);
}
@@ -96,6 +100,7 @@ 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
+
+(c) 2015 - belangeo
diff --git a/embedded/puredata/examples/midi_synth.py b/embedded/puredata/examples/midi_synth.py
new file mode 100644
index 0000000..518e1ed
--- /dev/null
+++ b/embedded/puredata/examples/midi_synth.py
@@ -0,0 +1,11 @@
+notein = Notein(scale=1)
+modwheel = Midictl(1, maxscale=0.2)
+
+amp = MidiAdsr(notein["velocity"], 0.001, 0.01, 0.7, 0.05)
+
+lfo = Sine(5, mul=modwheel, add=1)
+synth1 = RCOsc(freq=notein["pitch"]*lfo, sharp=0.75, mul=amp)
+synth2 = RCOsc(freq=notein["pitch"]*lfo*1.01, sharp=0.74, mul=amp)
+stereo = Mix([synth1.mix(1), synth2.mix(1)], voices=2)
+rev = STRev(stereo, inpos=[0,1], revtime=2, bal=0.25, mul=0.2).out()
+
diff --git a/embedded/puredata/pyo~-help.pd b/embedded/puredata/pyo~-help.pd
index d1f07d9..9ba3bef 100644
--- a/embedded/puredata/pyo~-help.pd
+++ b/embedded/puredata/pyo~-help.pd
@@ -1,20 +1,20 @@
-#N canvas 295 147 1007 365 10;
-#X obj 28 108 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+#N canvas 249 157 1013 410 10;
+#X obj 28 118 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 0
+#X obj 144 118 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
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 0
+#X obj 13 244 *~;
+#X obj 51 244 *~;
+#X obj 13 266 dac~;
+#X obj 72 223 hsl 128 15 0 1 0 1 empty empty master_gain -2 -8 0 10
+-262144 -1 -1 12700 1;
+#X obj 274 233 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
+#X msg 274 253 \; pd dsp \$1;
+#X obj 13 69 r msg_to_pyo;
+#X text 161 117 play;
+#X obj 13 176 pyo~ 2;
+#X text 66 178 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
@@ -89,7 +89,7 @@ input;
#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 restore 531 36 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;
@@ -173,27 +173,27 @@ input;
#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 restore 531 60 pd synthesis_example;
+#N canvas 2 85 629 295 loop_soundfile 0;
#X obj 43 42 openpanel;
#X obj 43 64 t a b;
-#X obj 43 170 soundfiler;
+#X obj 43 172 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 419 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 366 163 spigot 1;
+#X obj 43 128 pack s s s;
+#X obj 76 86 symbol \$0-table_l;
+#X obj 110 106 symbol \$0-table_r;
+#X msg 43 150 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 442 206 outlet~;
#X obj 236 140 tabplay~ \$0-table_l;
-#X obj 424 140 tabplay~ \$0-table_r;
+#X obj 443 140 tabplay~ \$0-table_r;
#X connect 0 0 1 0;
#X connect 1 0 9 0;
#X connect 1 1 10 0;
@@ -213,9 +213,9 @@ input;
#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 restore 28 136 pd loop_soundfile;
+#X text 44 118 load file;
+#N canvas 302 92 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 - - -, f 5;
@@ -229,11 +229,21 @@ in pyo~ inputs).;
#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 restore 531 12 pd conv_reverb_example;
+#X text 26 96 play a soundfile to send audio signals to pyo;
+#N canvas 193 300 450 300 README 0;
+#X text 14 33 Author : Olivier Belanger;
+#X text 14 81 Last update : October 2015;
+#X text 14 57 Version : 0.7.8;
+#X text 15 108 pyo website : http://ajaxsoundstudio.com/software/pyo/
+;
+#X text 15 10 pyo~ : Embedded pyo scripting inside puredata.;
+#X text 15 135 pyo sources : https://github.com/belangeo/pyo;
+#X text 15 163 For more details about how pyo can be embedded inside
+an host program \, see m_pyo.h in the "embedded" folder of pyo sources.
+;
+#X restore 406 237 pd README;
+#N canvas 182 106 1046 508 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.
@@ -242,23 +252,21 @@ 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
+#X text 19 379 call function [arg1 arg2 ...];
+#X text 498 250 clear;
+#X text 515 271 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
+#X text 36 399 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 35 439 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
+#X text 499 56 create varname object [\$1 \$2 ...];
+#X text 513 75 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
@@ -269,13 +277,22 @@ 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
+#X text 498 312 debug \$1;
+#X text 515 333 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 498 161 midi \$1 [\$2 \$3];
+#X text 512 180 The message "midi" sends a MIDI event to the object
+processing. Arguments are the status byte (\$1) \, the first data byte
+(\$2) and the second data byte (\$3). Data bytes can be ommited and
+defaults to 0;
+#X text 7 3 Here are the messages that can be used to control the internal
+processing of the pyo~ object.;
+#X text 4 31 --------------------------------------------------------
+;
+#X restore 406 258 pd MESSAGES;
+#X msg 567 321 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.;
@@ -284,12 +301,64 @@ channels.;
#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 obj 532 347 s msg_to_pyo;
+#X msg 567 258 set pits 0.001 0.002 0.003 0.004;
+#X msg 567 279 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 msg 567 300 create b SumOsc freq=fr ratio=0.499 index=0.4 mul=0.2
;
+#N canvas 669 129 722 427 midi_synth_example 0;
+#X obj 34 365 s msg_to_pyo;
+#X msg 34 56 read examples/midi_synth.py;
+#X msg 97 108 midi 144 72 127;
+#X obj 129 172 hsl 128 15 0 127 0 0 empty empty empty -2 -8 0 10 -262144
+-1 -1 700 1;
+#X msg 126 195 midi 176 1 \$1;
+#X obj 448 43 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X obj 448 63 metro 125;
+#X obj 448 249 makenote 127 100;
+#X obj 448 271 pack;
+#X msg 448 293 midi 144 \$1 \$2;
+#X msg 111 130 midi 144 72 0;
+#X text 212 108 note on;
+#X text 213 131 note off;
+#X text 228 196 control change (mod wheel);
+#X floatatom 448 228 5 0 0 0 - - -, f 5;
+#X obj 448 183 int;
+#X obj 448 161 + 0.5;
+#X obj 448 139 * 1.76;
+#X obj 448 115 random 8;
+#X obj 448 85 t b b;
+#X obj 526 115 random 3;
+#X obj 526 137 + 5;
+#X obj 526 159 * 12;
+#X obj 448 206 +;
+#X text 467 43 random melody;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 4 0;
+#X connect 4 0 0 0;
+#X connect 5 0 6 0;
+#X connect 6 0 19 0;
+#X connect 7 0 8 0;
+#X connect 7 1 8 1;
+#X connect 8 0 9 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X connect 14 0 7 0;
+#X connect 15 0 23 0;
+#X connect 16 0 15 0;
+#X connect 17 0 16 0;
+#X connect 18 0 17 0;
+#X connect 19 0 18 0;
+#X connect 19 1 20 0;
+#X connect 20 0 21 0;
+#X connect 21 0 22 0;
+#X connect 22 0 23 1;
+#X connect 23 0 14 0;
+#X restore 531 84 pd midi_synth_example;
+#X text 563 238 Create a pyo script from scratch!;
#X connect 0 0 17 0;
#X connect 1 0 17 1;
#X connect 2 0 4 0;
diff --git a/embedded/puredata/pyo~.c b/embedded/puredata/pyo~.c
index 972f66e..2434653 100644
--- a/embedded/puredata/pyo~.c
+++ b/embedded/puredata/pyo~.c
@@ -1,5 +1,5 @@
#include <stdlib.h>
-#include <pd/m_pd.h>
+#include <m_pd.h>
#include "Python.h"
#include "m_pyo.h"
@@ -73,8 +73,8 @@ void *pyo_tilde_new(t_floatarg f) {
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->bs = 64;
+ x->sr = 44100.0;
x->file = NULL;
x->add = 0;
x->debug = 0;
@@ -93,7 +93,7 @@ void *pyo_tilde_new(t_floatarg f) {
for (i=0; i<x->chnls; i++)
x->in[i] = x->out[i] = 0;
- x->interp = pyo_new_interpreter(x->chnls);
+ x->interp = pyo_new_interpreter(x->sr, x->bs, x->chnls);
x->inbuf = (float *)pyo_get_input_buffer_address(x->interp);
x->outbuf = (float *)pyo_get_output_buffer_address(x->interp);
@@ -177,6 +177,17 @@ void pyo_tilde_create(t_pyo_tilde *x, t_symbol *s, int argc, t_atom *argv) {
post("pyo~: %s", x->msg);
}
+void pyo_tilde_midi_event(t_pyo_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+ int status, data1 = 0, data2 = 0;
+ if (argc > 0)
+ status = (int)atom_getfloat(argv);
+ if (argc > 1)
+ data1 = (int)atom_getfloat(++argv);
+ if (argc > 2)
+ data2 = (int)atom_getfloat(++argv);
+ pyo_add_midi_event(x->interp, status, data1, data2);
+}
+
void pyo_tilde_clear(t_pyo_tilde *x) {
pyo_server_reboot(x->interp);
}
@@ -244,6 +255,8 @@ void pyo_tilde_setup(void) {
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_midi_event, gensym("midi"),
+ 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/effects/05_fuzz_disto.py b/examples/effects/05_fuzz_disto.py
index db9360e..1976ff8 100644
--- a/examples/effects/05_fuzz_disto.py
+++ b/examples/effects/05_fuzz_disto.py
@@ -12,33 +12,33 @@ s = Server(duplex=0).boot()
SOURCE = "../snds/flute.aif"
BP_CENTER_FREQ = 250
BP_Q = 2
-BOOST = 5
+BOOST = 25
LP_CUTOFF_FREQ = 3500
-BALANCE = 0.8
+BALANCE = 1
src = SfPlayer(SOURCE, loop=True).mix(2)
# Transfert function for signal lower than 0
-low_table = ExpTable([(0,-.25),(4096,0),(8192,0)], exp=10)
+table = ExpTable([(0,-.25),(4096,0),(8192,0)], exp=10)
+table.view()
# Transfert function for signal higher than 0
high_table = CosTable([(0,0),(4096,0),(4598,1),(8192,1)])
+table.add(high_table)
+
# Bandpass filter and boost gain applied on input signal
bp = Biquad(src, freq=BP_CENTER_FREQ, q=BP_Q, type=2)
boost = Sig(bp, mul=BOOST)
-# Split signal into positive and negative part
-sign = Compare(boost, comp=0, mode=">=")
-sw = Switch(boost, outs=2, voice=sign)
-
# Apply transfert function
-lowsig = Lookup(low_table, sw[0])
-highsig = Lookup(high_table, sw[1])
+sig = Lookup(table, boost)
# Lowpass filter on distorted signal
-lp = Tone(lowsig+highsig, freq=LP_CUTOFF_FREQ, mul=.3)
+lp = Tone(sig, freq=LP_CUTOFF_FREQ, mul=.7)
# Balance between dry and wet signals
out = Interp(src, lp, interp=BALANCE).out()
+sc = Scope(out)
+
s.gui(locals())
\ No newline at end of file
diff --git a/include/pyomodule.h b/include/pyomodule.h
index bc385fa..fea78b9 100644
--- a/include/pyomodule.h
+++ b/include/pyomodule.h
@@ -21,7 +21,7 @@
#include "Python.h"
#include <math.h>
-#define PYO_VERSION "0.7.6"
+#define PYO_VERSION "0.7.8"
#ifndef __MYFLT_DEF
#define __MYFLT_DEF
@@ -108,7 +108,6 @@
#define MYATAN2 atan2f
#define MYEXP expf
#define MYROUND roundf
-#define MYTANH tanhf
#else
#define LIB_BASE_NAME "_pyo64"
@@ -192,7 +191,6 @@
#define MYATAN2 atan2
#define MYEXP exp
#define MYROUND round
-#define MYTANH tanh
#endif
#endif
@@ -488,6 +486,8 @@ extern PyTypeObject MainParticleType;
extern PyTypeObject ParticleType;
extern PyTypeObject AtanTableType;
extern PyTypeObject RawMidiType;
+extern PyTypeObject ResampleType;
+extern PyTypeObject ExprType;
/* Constants */
#define E M_E
@@ -683,7 +683,7 @@ extern PyTypeObject RawMidiType;
TableStream_setSize(self->tablestream, self->size+1); \
\
for (i=0; i<(self->size); i++) { \
- self->data[i] = PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(arg, i))); \
+ self->data[i] = PyFloat_AsDouble(PyList_GET_ITEM(arg, i)); \
} \
self->data[self->size] = self->data[0]; \
TableStream_setData(self->tablestream, self->data); \
@@ -711,7 +711,7 @@ extern PyTypeObject RawMidiType;
for(i=0; i<self->height; i++) { \
innerlist = PyList_GetItem(arg, i); \
for (j=0; j<self->width; j++) { \
- self->data[i][j] = PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(innerlist, j))); \
+ self->data[i][j] = PyFloat_AsDouble(PyList_GET_ITEM(innerlist, j)); \
} \
} \
\
@@ -735,7 +735,7 @@ extern PyTypeObject RawMidiType;
MYFLT *list = NULL; \
PyObject *table = NULL; \
if (PyNumber_Check(arg)) { \
- x = PyFloat_AsDouble(PyNumber_Float(arg)); \
+ x = PyFloat_AsDouble(arg); \
for (i=0; i<self->size; i++) { \
self->data[i] += x; \
} \
@@ -756,7 +756,7 @@ extern PyTypeObject RawMidiType;
if (self->size < tabsize) \
tabsize = self->size; \
for (i=0; i<tabsize; i++) { \
- self->data[i] += PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(arg, i))); \
+ self->data[i] += PyFloat_AsDouble(PyList_GET_ITEM(arg, i)); \
} \
} \
\
@@ -771,7 +771,7 @@ extern PyTypeObject RawMidiType;
MYFLT *list = NULL; \
PyObject *table = NULL; \
if (PyNumber_Check(arg)) { \
- x = PyFloat_AsDouble(PyNumber_Float(arg)); \
+ x = PyFloat_AsDouble(arg); \
for (i=0; i<self->size; i++) { \
self->data[i] -= x; \
} \
@@ -792,7 +792,7 @@ extern PyTypeObject RawMidiType;
if (self->size < tabsize) \
tabsize = self->size; \
for (i=0; i<tabsize; i++) { \
- self->data[i] -= PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(arg, i))); \
+ self->data[i] -= PyFloat_AsDouble(PyList_GET_ITEM(arg, i)); \
} \
} \
\
@@ -807,7 +807,7 @@ extern PyTypeObject RawMidiType;
MYFLT *list = NULL; \
PyObject *table = NULL; \
if (PyNumber_Check(arg)) { \
- x = PyFloat_AsDouble(PyNumber_Float(arg)); \
+ x = PyFloat_AsDouble(arg); \
for (i=0; i<self->size; i++) { \
self->data[i] *= x; \
} \
@@ -828,7 +828,7 @@ extern PyTypeObject RawMidiType;
if (self->size < tabsize) \
tabsize = self->size; \
for (i=0; i<tabsize; i++) { \
- self->data[i] *= PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(arg, i))); \
+ self->data[i] *= PyFloat_AsDouble(PyList_GET_ITEM(arg, i)); \
} \
} \
\
@@ -853,7 +853,7 @@ extern PyTypeObject RawMidiType;
return PyInt_FromLong(-1); \
} \
for(i=0; i<self->size; i++) { \
- self->data[i] = PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(arg, i))); \
+ self->data[i] = PyFloat_AsDouble(PyList_GET_ITEM(arg, i)); \
} \
self->data[self->size] = self->data[0]; \
Py_RETURN_NONE; \
@@ -1405,7 +1405,7 @@ extern PyTypeObject RawMidiType;
tmp = arg; \
Py_INCREF(tmp); \
if (isNumber == 1) { \
- if (PyFloat_AsDouble(PyNumber_Float(tmp)) != 0.) { \
+ if (PyFloat_AsDouble(tmp) != 0.) { \
Py_DECREF(self->mul); \
self->mul = PyNumber_Divide(PyFloat_FromDouble(1.), PyNumber_Float(tmp)); \
self->modebuffer[0] = 0; \
@@ -1493,11 +1493,17 @@ extern PyTypeObject RawMidiType;
Stream_setStreamActive(self->stream, 1); \
} \
else { \
- Stream_setStreamActive(self->stream, 0); \
- for (i=0; i<self->bufsize; i++) \
- self->data[i] = 0.0; \
nearestBuf = (int)roundf((del * self->sr) / self->bufsize); \
- Stream_setBufferCountWait(self->stream, nearestBuf); \
+ if (nearestBuf <= 0) { \
+ Stream_setBufferCountWait(self->stream, 0); \
+ Stream_setStreamActive(self->stream, 1); \
+ } \
+ else { \
+ Stream_setStreamActive(self->stream, 0); \
+ for (i=0; i<self->bufsize; i++) \
+ self->data[i] = 0.0; \
+ Stream_setBufferCountWait(self->stream, nearestBuf); \
+ } \
} \
if (dur == 0) \
Stream_setDuration(self->stream, 0); \
diff --git a/include/servermodule.h b/include/servermodule.h
index 761529c..31f22a1 100644
--- a/include/servermodule.h
+++ b/include/servermodule.h
@@ -82,6 +82,8 @@ typedef struct {
int nchnls;
int ichnls;
int bufferSize;
+ int currentResampling;
+ int lastResampling;
int duplex;
int input;
int output;
@@ -147,6 +149,8 @@ extern PyObject * Server_removeStream(Server *self, int sid);
extern MYFLT * Server_getInputBuffer(Server *self);
extern PmEvent * Server_getMidiEventBuffer(Server *self);
extern int Server_getMidiEventCount(Server *self);
+extern int Server_getCurrentResamplingFactor(Server *self);
+extern int Server_getLastResamplingFactor(Server *self);
extern int Server_generateSeed(Server *self, int oid);
extern PyTypeObject ServerType;
diff --git a/installers/osx/release_x86_64.sh b/installers/osx/release_x86_64.sh
index 2275a10..1a8eadb 100644
--- a/installers/osx/release_x86_64.sh
+++ b/installers/osx/release_x86_64.sh
@@ -5,11 +5,11 @@
# 1. update pyo sources
# 2. compile and install pyo float and double
# 3. cd utils and build E-Pyo
-# 4. cd installer/osx and build the realease, only x86_64 version
+# 4. cd installers/osx and build the realease, only x86_64 version
-export PACKAGE_NAME=pyo_0.7.6_x86_64.pkg
-export DMG_DIR="pyo 0.7.6 Universal"
-export DMG_NAME="pyo_0.7.6_OSX-universal.dmg"
+export PACKAGE_NAME=pyo_0.7.8_x86_64.pkg
+export DMG_DIR="pyo 0.7.8 Universal"
+export DMG_NAME="pyo_0.7.8_OSX-universal.dmg"
export 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
@@ -24,8 +24,9 @@ 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
+cd ../..
+git checkout-index -a -f --prefix=installers/osx/installer/pyo-build/
+cd installers/osx/installer/pyo-build
echo "building pyo for python 2.6 (64-bit)..."
sudo /usr/bin/python setup.py install --use-coreaudio
diff --git a/installers/win/win_installer_py26.iss b/installers/win/win_installer_py26.iss
index 54c1ced..3fe3d1c 100644
--- a/installers/win/win_installer_py26.iss
+++ b/installers/win/win_installer_py26.iss
@@ -3,7 +3,7 @@
#define appName "pyo"
#define pyVer "2.6"
-#define appVer "0.7.6"
+#define appVer "0.7.8"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
@@ -12,24 +12,24 @@
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
+AppPublisher=ajaxsoundstudio.com
+AppPublisherURL=https://github.com/belangeo/pyo
+AppSupportURL=https://github.com/belangeo/pyo
+AppUpdatesURL=https://github.com/belangeo/pyo
DefaultDirName={code:GetDirName}
DisableDirPage=no
AlwaysShowDirOnReadyPage=yes
DefaultGroupName={#appName}
AllowNoIcons=yes
-InfoBeforeFile=C:\Users\olivier\svn\pyo\installers\win\\README-win32-py26.txt
-LicenseFile=C:\Users\olivier\svn\pyo\COPYING.txt
+InfoBeforeFile=C:\Users\olivier\git\pyo\installers\win\\README-win32-py26.txt
+LicenseFile=C:\Users\olivier\git\pyo\COPYING.txt
OutputBaseFilename={#appName}_{#appVer}_py{#pyVer}_setup
Compression=lzma
SolidCompression=yes
ChangesAssociations=yes
ChangesEnvironment=yes
DirExistsWarning=no
-SetupIconFile=C:\Users\olivier\svn\pyo\utils\E-PyoIcon.ico
+SetupIconFile=C:\Users\olivier\git\pyo\utils\E-PyoIcon.ico
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -51,13 +51,12 @@ Source: "C:\Python26\Lib\site-packages\msvcr90.dll"; DestDir: "{app}\Lib\site-pa
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\olivier\svn\pyo\examples\*"; DestDir: "{userdesktop}\pyo_examples\"; Flags: ignoreversion recursesubdirs createallsubdirs
-Source: "C:\Users\olivier\svn\pyo\installers\win\README-win32-py26.txt"; DestDir: "{userdesktop}"; Flags: ignoreversion
+Source: "C:\Users\olivier\git\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:\Users\olivier\svn\pyo\utils\E-Pyo_py26\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
-Source: "C:\Users\olivier\svn\pyo\utils\E-Pyo_py26\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Users\olivier\git\pyo\utils\E-Pyo_py26\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
+Source: "C:\Users\olivier\git\pyo\utils\E-Pyo_py26\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
diff --git a/installers/win/win_installer_py27.iss b/installers/win/win_installer_py27.iss
index e90ddda..2c55a83 100644
--- a/installers/win/win_installer_py27.iss
+++ b/installers/win/win_installer_py27.iss
@@ -3,7 +3,7 @@
#define appName "pyo"
#define pyVer "2.7"
-#define appVer "0.7.6"
+#define appVer "0.7.8"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
@@ -12,24 +12,24 @@
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
+AppPublisher=ajaxsoundstudio.com
+AppPublisherURL=https://github.com/belangeo/pyo
+AppSupportURL=https://github.com/belangeo/pyo
+AppUpdatesURL=https://github.com/belangeo/pyo
DefaultDirName={code:GetDirName}
DisableDirPage=no
AlwaysShowDirOnReadyPage=yes
DefaultGroupName={#appName}
AllowNoIcons=yes
-InfoBeforeFile=C:\Users\olivier\svn\pyo\installers\win\\README-win32-py27.txt
-LicenseFile=C:\Users\olivier\svn\pyo\COPYING.txt
+InfoBeforeFile=C:\Users\olivier\git\pyo\installers\win\\README-win32-py27.txt
+LicenseFile=C:\Users\olivier\git\pyo\COPYING.txt
OutputBaseFilename={#appName}_{#appVer}_py{#pyVer}_setup
Compression=lzma
SolidCompression=yes
ChangesAssociations=yes
ChangesEnvironment=yes
DirExistsWarning=no
-SetupIconFile=C:\Users\olivier\svn\pyo\utils\E-PyoIcon.ico
+SetupIconFile=C:\Users\olivier\git\pyo\utils\E-PyoIcon.ico
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -50,12 +50,12 @@ Source: "C:\Python27\Lib\site-packages\msvcr90.dll"; DestDir: "{app}\Lib\site-pa
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\olivier\svn\pyo\examples\*"; DestDir: "{userdesktop}\pyo_examples\"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Users\olivier\git\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:\Users\olivier\svn\pyo\utils\E-Pyo_py27\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
-Source: "C:\Users\olivier\svn\pyo\utils\E-Pyo_py27\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Users\olivier\git\pyo\utils\E-Pyo_py27\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
+Source: "C:\Users\olivier\git\pyo\utils\E-Pyo_py27\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
diff --git a/pyo.py b/pyo.py
index 187247a..b0fb79c 100644
--- a/pyo.py
+++ b/pyo.py
@@ -56,6 +56,8 @@ import pyolib.triggers as triggers
from pyolib.triggers import *
import pyolib.utils as utils
from pyolib.utils import *
+import pyolib.expression as expression
+from pyolib.expression import *
import pyolib.fourier as fourier
from pyolib.fourier import *
import pyolib.phasevoc as phasevoc
@@ -114,7 +116,8 @@ OBJECTS_TREE = {'functions': sorted(['pa_count_devices', 'pa_get_default_input',
'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', 'FToM', 'MToT', 'TrackHold']),
+ 'TranspoToCents', 'MToF', 'FToM', 'MToT', 'TrackHold', 'Resample', 'Expr']),
+ 'expression': sorted(['Expr']),
'fourier': sorted(['FFT', 'IFFT', 'CarToPol', 'PolToCar', 'FrameDelta', 'FrameAccum', 'Vectral', 'CvlVerb'])}},
'Map': {'SLMap': sorted(['SLMapFreq', 'SLMapMul', 'SLMapPhase', 'SLMapQ', 'SLMapDur', 'SLMapPan'])},
'Server': [],
diff --git a/pyolib/_core.py b/pyolib/_core.py
index 5549858..7575fb9 100644
--- a/pyolib/_core.py
+++ b/pyolib/_core.py
@@ -473,7 +473,7 @@ class PyoObjectBase(object):
return self._base_objs[0].getServer().getBufferSize()
def __getitem__(self, i):
- if i == 'trig':
+ if i == 'trig': # not safe...
return self._trig_objs
if type(i) == SliceType or i < len(self._base_objs):
return self._base_objs[i]
diff --git a/pyolib/_widgets.py b/pyolib/_widgets.py
index 912a041..2cfb089 100644
--- a/pyolib/_widgets.py
+++ b/pyolib/_widgets.py
@@ -72,6 +72,7 @@ SNDTABLEWINDOWS = []
MATRIXWINDOWS = []
SPECTRUMWINDOWS = []
SCOPEWINDOWS = []
+EXPREDITORWINDOWS = []
WX_APP = False
def createRootWindow():
@@ -198,6 +199,13 @@ def wxCreateDelayedScopeWindows():
win[0]._setViewFrame(f)
wxDisplayWindow(f, title)
+def wxCreateDelayedExprEditorWindows():
+ for win in EXPREDITORWINDOWS:
+ f = ExprEditorFrame(None, win[0])
+ if win[1] == None: title = win[0].__class__.__name__
+ else: title = win[1]
+ wxDisplayWindow(f, title)
+
def createCtrlWindow(obj, map_list, title, wxnoserver=False):
if not PYO_USE_WX:
createRootWindow()
@@ -325,6 +333,18 @@ def createScopeWindow(object, title, wxnoserver=False):
else:
SCOPEWINDOWS.append([object, title])
+def createExprEditorWindow(object, title, wxnoserver=False):
+ if not PYO_USE_WX:
+ print "WxPython must be installed to use the Expr editor display."
+ else:
+ if wxnoserver or WX_APP:
+ root = createRootWindow()
+ f = ExprEditorFrame(None, object)
+ if title == None: title = object.__class__.__name__
+ wxShowWindow(f, title, root)
+ else:
+ EXPREDITORWINDOWS.append([object, title])
+
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:
@@ -352,5 +372,6 @@ def createServerGUI(nchnls, start, stop, recstart, recstop, setAmp, started, loc
wx.CallAfter(wxCreateDelayedCtrlWindows)
wx.CallAfter(wxCreateDelayedSpectrumWindows)
wx.CallAfter(wxCreateDelayedScopeWindows)
+ wx.CallAfter(wxCreateDelayedExprEditorWindows)
wx.CallAfter(f.Raise)
return f, win
diff --git a/pyolib/_wxwidgets.py b/pyolib/_wxwidgets.py
index 137eb23..50a81b5 100644
--- a/pyolib/_wxwidgets.py
+++ b/pyolib/_wxwidgets.py
@@ -17,8 +17,9 @@ GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with pyo. If not, see <http://www.gnu.org/licenses/>.
"""
-import wx, os, sys, math, time, random
-from types import ListType, FloatType, IntType
+import wx, os, sys, math, time, random, unicodedata
+from types import ListType, FloatType, IntType, UnicodeType
+import wx.stc as stc
try:
from PIL import Image, ImageDraw, ImageTk
@@ -2358,9 +2359,273 @@ class DataTableGrapher(wx.Frame):
def update(self, samples):
wx.CallAfter(self.multi.update, samples)
+class ExprLexer(object):
+ """Defines simple interface for custom lexer objects."""
+ STC_EXPR_DEFAULT, STC_EXPR_KEYWORD, STC_EXPR_KEYWORD2, STC_EXPR_COMMENT, \
+ STC_EXPR_VARIABLE, STC_EXPR_LETVARIABLE = range(6)
+ def __init__(self):
+ super(ExprLexer, self).__init__()
+
+ self.alpha = "abcdefghijklmnopqrstuvwxyz"
+ self.digits = "0123456789"
+ self.keywords = ["sin", "cos", "tan", "tanh", "atan", "atan2", "sqrt", "log",
+ "log2", "log10", "pow", "abs", "floor", "ceil", "exp", "round",
+ "min", "max", "randf", "randi", "sah", "count", "pi", "twopi",
+ "e", "if", "rpole", "rzero", "neg", "and", "or", "wrap"]
+ self.keywords2 = ["define", "load", "var", "let"]
+
+ def StyleText(self, evt):
+ """Handle the EVT_STC_STYLENEEDED event."""
+ stc = evt.GetEventObject()
+ last_styled_pos = stc.GetEndStyled()
+ line = stc.LineFromPosition(last_styled_pos)
+ start_pos = stc.PositionFromLine(line)
+ end_pos = evt.GetPosition()
+ var = letvar = False
+ while start_pos < end_pos:
+ stc.StartStyling(start_pos, 0x1f)
+ curchar = chr(stc.GetCharAt(start_pos))
+ if curchar == "$":
+ var = True
+ elif var and curchar in " \t\n()":
+ var = False
+ if curchar == "#":
+ letvar = True
+ elif letvar and curchar in " \t\n()":
+ letvar = False
+
+ if var:
+ style = self.STC_EXPR_VARIABLE
+ stc.SetStyling(1, style)
+ start_pos += 1
+ elif letvar:
+ style = self.STC_EXPR_LETVARIABLE
+ stc.SetStyling(1, style)
+ start_pos += 1
+ elif curchar in self.alpha:
+ start = stc.WordStartPosition(start_pos, True)
+ end = stc.WordEndPosition(start, True)
+ word = stc.GetTextRange(start, end)
+ if word in self.keywords:
+ style = self.STC_EXPR_KEYWORD
+ stc.SetStyling(len(word), style)
+ elif word in self.keywords2:
+ style = self.STC_EXPR_KEYWORD2
+ stc.SetStyling(len(word), style)
+ else:
+ style = self.STC_EXPR_DEFAULT
+ stc.SetStyling(len(word), style)
+ start_pos += len(word)
+ elif curchar == "/" and chr(stc.GetCharAt(start_pos+1)) == "/":
+ eol = stc.GetLineEndPosition(stc.LineFromPosition(start_pos))
+ style = self.STC_EXPR_COMMENT
+ stc.SetStyling(eol-start_pos, style)
+ start_pos = eol
+ else:
+ style = self.STC_EXPR_DEFAULT
+ stc.SetStyling(1, style)
+ start_pos += 1
+
+class ExprEditor(stc.StyledTextCtrl):
+ def __init__(self, parent, id=-1, obj=None):
+ stc.StyledTextCtrl.__init__(self, parent, id)
+
+ self.obj = obj
+
+ if sys.platform == "darwin":
+ accel_ctrl = wx.ACCEL_CMD
+ self.faces = {'mono' : 'Monospace', 'size' : 16}
+ else:
+ accel_ctrl = wx.ACCEL_CTRL
+ self.faces = {'mono' : 'Monospace', 'size' : 10}
+
+ atable = wx.AcceleratorTable([(accel_ctrl, wx.WXK_RETURN, 10000),
+ (accel_ctrl, ord("z"), wx.ID_UNDO),
+ (accel_ctrl|wx.ACCEL_SHIFT, ord("z"), wx.ID_REDO)])
+ self.SetAcceleratorTable(atable)
+
+ self.Bind(wx.EVT_MENU, self.onExecute, id=10000)
+ self.Bind(wx.EVT_MENU, self.undo, id=wx.ID_UNDO)
+ self.Bind(wx.EVT_MENU, self.redo, id=wx.ID_REDO)
+ self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
+
+ self.lexer = ExprLexer()
+
+ self.currentfile = ""
+ self.modified = False
+
+ self.setup()
+ self.setCmdKeys()
+ self.setStyle()
+
+ self.SetText(self.obj.expr)
+
+ def undo(self, evt):
+ self.Undo()
+
+ def redo(self, evt):
+ self.Redo()
+
+ def setup(self):
+ self.SetUseAntiAliasing(True)
+ self.SetIndent(2)
+ self.SetBackSpaceUnIndents(True)
+ self.SetTabIndents(True)
+ self.SetTabWidth(2)
+ self.SetUseTabs(False)
+ self.SetMargins(2, 2)
+ self.SetMarginWidth(1, 1)
+
+ def setCmdKeys(self):
+ self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
+ self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
+
+ def setStyle(self):
+ self.SetLexer(wx.stc.STC_LEX_CONTAINER)
+ self.SetStyleBits(5)
+ self.Bind(wx.stc.EVT_STC_STYLENEEDED, self.OnStyling)
+
+ self.SetCaretForeground("#000000")
+ self.SetCaretWidth(2)
+ # Global default styles for all languages
+ self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % self.faces)
+ self.StyleClearAll()
+
+ self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % self.faces)
+ self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(mono)s" % self.faces)
+ self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
+ self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
+
+ # Expr specific styles
+ self.StyleSetSpec(self.lexer.STC_EXPR_DEFAULT, "fore:#000000,face:%(mono)s,size:%(size)d" % self.faces)
+ self.StyleSetSpec(self.lexer.STC_EXPR_KEYWORD, "fore:#3300DD,face:%(mono)s,size:%(size)d,bold" % self.faces)
+ self.StyleSetSpec(self.lexer.STC_EXPR_KEYWORD2, "fore:#0033FF,face:%(mono)s,size:%(size)d,bold" % self.faces)
+ self.StyleSetSpec(self.lexer.STC_EXPR_VARIABLE, "fore:#006600,face:%(mono)s,size:%(size)d,bold" % self.faces)
+ self.StyleSetSpec(self.lexer.STC_EXPR_LETVARIABLE, "fore:#555500,face:%(mono)s,size:%(size)d,bold" % self.faces)
+ self.StyleSetSpec(self.lexer.STC_EXPR_COMMENT, "fore:#444444,face:%(mono)s,size:%(size)d,italic" % self.faces)
+
+ self.SetSelBackground(1, "#CCCCDD")
+
+ def OnStyling(self, evt):
+ self.lexer.StyleText(evt)
+
+ def loadfile(self, filename):
+ self.LoadFile(filename)
+ self.currentfile = filename
+ self.GetParent().SetTitle(self.currentfile)
+
+ def savefile(self, filename):
+ self.currentfile = filename
+ self.GetParent().SetTitle(self.currentfile)
+ self.SaveFile(filename)
+ self.OnUpdateUI(None)
+
+ def OnUpdateUI(self, evt):
+ # check for matching braces
+ braceAtCaret = -1
+ braceOpposite = -1
+ charBefore = None
+ caretPos = self.GetCurrentPos()
+
+ if caretPos > 0:
+ charBefore = self.GetCharAt(caretPos - 1)
+ styleBefore = self.GetStyleAt(caretPos - 1)
+
+ # check before
+ if charBefore and chr(charBefore) in "[]{}()":
+ braceAtCaret = caretPos - 1
+
+ # check after
+ if braceAtCaret < 0:
+ charAfter = self.GetCharAt(caretPos)
+ styleAfter = self.GetStyleAt(caretPos)
+
+ if charAfter and chr(charAfter) in "[]{}()":
+ braceAtCaret = caretPos
+ if braceAtCaret >= 0:
+ braceOpposite = self.BraceMatch(braceAtCaret)
+
+ if braceAtCaret != -1 and braceOpposite == -1:
+ self.BraceBadLight(braceAtCaret)
+ else:
+ self.BraceHighlight(braceAtCaret, braceOpposite)
+ # Check if horizontal scrollbar is needed
+ self.checkScrollbar()
+
+ def checkScrollbar(self):
+ lineslength = [self.LineLength(i)+1 for i in range(self.GetLineCount())]
+ maxlength = max(lineslength)
+ width = self.GetCharWidth() + (self.GetZoom() * 0.5)
+ if (self.GetSize()[0]) < (maxlength * width):
+ self.SetUseHorizontalScrollBar(True)
+ else:
+ self.SetUseHorizontalScrollBar(False)
+
+ def onExecute(self, evt):
+ pos = self.GetCurrentPos()
+ self.obj.expr = self.GetTextRaw()
+ self.SetCurrentPos(pos)
+ self.SetSelection(pos, pos)
+
+class ExprEditorFrame(wx.Frame):
+ def __init__(self, parent=None, obj=None):
+ wx.Frame.__init__(self, parent, size=(500,350))
+ self.obj = obj
+ self.obj._editor = self
+ self.editor = ExprEditor(self, -1, self.obj)
+ self.menubar = wx.MenuBar()
+ self.fileMenu = wx.Menu()
+ self.fileMenu.Append(wx.ID_OPEN, "Open\tCtrl+O")
+ self.Bind(wx.EVT_MENU, self.open, id=wx.ID_OPEN)
+ self.fileMenu.Append(wx.ID_CLOSE, 'Close\tCtrl+W', kind=wx.ITEM_NORMAL)
+ self.Bind(wx.EVT_MENU, self.close, id=wx.ID_CLOSE)
+ self.fileMenu.AppendSeparator()
+ self.fileMenu.Append(wx.ID_SAVE, "Save\tCtrl+S")
+ self.Bind(wx.EVT_MENU, self.save, id=wx.ID_SAVE)
+ self.fileMenu.Append(wx.ID_SAVEAS, "Save As...\tShift+Ctrl+S")
+ self.Bind(wx.EVT_MENU, self.saveas, id=wx.ID_SAVEAS)
+ self.menubar.Append(self.fileMenu, "&File")
+ self.SetMenuBar(self.menubar)
+
+ def open(self, evt):
+ dlg = wx.FileDialog(self, message="Choose a file",
+ defaultDir=os.path.expanduser("~"),
+ defaultFile="", style=wx.OPEN)
+ if dlg.ShowModal() == wx.ID_OK:
+ path = ensureNFD(dlg.GetPath())
+ self.editor.loadfile(path)
+ dlg.Destroy()
+
+ def close(self, evt):
+ self.obj._editor = None
+ self.Destroy()
+
+ def save(self, evt):
+ path = self.editor.currentfile
+ if not path:
+ self.saveas(None)
+ else:
+ self.editor.savefile(path)
+
+ def saveas(self, evt):
+ deffile = os.path.split(self.editor.currentfile)[1]
+ dlg = wx.FileDialog(self, message="Save file as ...",
+ defaultDir=os.path.expanduser("~"),
+ defaultFile=deffile, style=wx.SAVE)
+ dlg.SetFilterIndex(0)
+ if dlg.ShowModal() == wx.ID_OK:
+ path = ensureNFD(dlg.GetPath())
+ self.editor.savefile(path)
+ dlg.Destroy()
+
+ def update(self, text):
+ self.editor.SetText(text)
+
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., exit=True):
+ 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.,
+ exit=True):
wx.Frame.__init__(self, parent, style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
self.SetTitle("pyo server")
@@ -2447,6 +2712,8 @@ class ServerGUI(wx.Frame):
panel.SetSizerAndFit(box)
self.SetClientSize(panel.GetSize())
+ self.Bind(wx.EVT_CLOSE, self.on_quit)
+
if started == 1:
self.start(None, True)
@@ -2478,6 +2745,9 @@ class ServerGUI(wx.Frame):
self._recstarted = False
self.recButton.SetLabel('Rec Start')
+ def quit_from_code(self):
+ wx.CallAfter(self.on_quit, None)
+
def on_quit(self, evt):
if self.exit:
self.shutdown()
@@ -2525,3 +2795,29 @@ class ServerGUI(wx.Frame):
def setRms(self, *args):
self.meter.setRms(*args)
+
+def ensureNFD(unistr):
+ if sys.platform in ['linux2', 'win32']:
+ encodings = [sys.getdefaultencoding(), sys.getfilesystemencoding(),
+ 'cp1252', 'iso-8859-1', 'utf-16']
+ format = 'NFC'
+ else:
+ encodings = [sys.getdefaultencoding(), sys.getfilesystemencoding(),
+ '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)
diff --git a/pyolib/controls.py b/pyolib/controls.py
index 7385c01..405c4bb 100644
--- a/pyolib/controls.py
+++ b/pyolib/controls.py
@@ -435,6 +435,13 @@ class Linseg(PyoObject):
x, lmax = convertArgsToLists(x)
[obj.setLoop(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+ def pause(self):
+ """
+ Toggles between play and stop mode without reset.
+
+ """
+ [obj.pause() for obj in self._base_objs]
+
def graph(self, xlen=None, yrange=None, title=None, wxnoserver=False):
"""
Opens a grapher window to control the shape of the envelope.
@@ -623,6 +630,13 @@ class Expseg(PyoObject):
"""
self.setList(x)
+ def pause(self):
+ """
+ Toggles between play and stop mode without reset.
+
+ """
+ [obj.pause() for obj in self._base_objs]
+
def getPoints(self):
return self._list
diff --git a/pyolib/expression.py b/pyolib/expression.py
new file mode 100644
index 0000000..4a8e8c0
--- /dev/null
+++ b/pyolib/expression.py
@@ -0,0 +1,526 @@
+"""
+Prefix expression evaluators.
+
+API documentation
+=================
+
+* This API is in alpha stage and subject to future changes!
+
+Builtin functions
+-----------------
+
+Arithmetic operators:
+
+(+ x y) : returns the sum of two values.
+(- x y) : substracts the second value to the first and returns the result.
+(* x y) : returns the multiplication of two values.
+(/ x y) : returns the quotient of x/y.
+(^ x y) : returns x to the power y.
+(% x y) : returns the floating-point remainder of x/y.
+(neg x) : returns the negative of x.
+
+Moving phase operators:
+
+(++ x y) : increments its internal state by x and wrap around 0.0 and y.
+(-- x y) : decrements its internal state by x and wrap around 0.0 and y.
+(~ x y) : generates a periodic ramp from 0 to 1 with frequency x and phase y.
+
+Conditional operators:
+
+(< x y) : returns 1 if x is less than y, otherwise returns 0.
+(<= x y) : returns 1 if x is less than or equal to y, otherwise returns 0.
+(> x y) : returns 1 if x is greater than y, otherwise returns 0.
+(>= x y) : returns 1 if x is greater than or equal to y, otherwise returns 0.
+(== x y) : returns 1 if x is equal to y, otherwise returns 0.
+(!= x y) : returns 1 if x is not equal to y, otherwise returns 0.
+(if (cond) (then) (else)) : returns then for any non-zero value of cond, otherwise returns else.
+(and x y) : returns 1 if both x and y are not 0, otherwise returns 0.
+(or x y) : returns 1 if one of x or y are not 0, otherwise returns 0.
+
+Trigonometric functions:
+
+(sin x) : returns the sine of an angle of x radians.
+(cos x) : returns the cosine of an angle of x radians.
+(tan x) : returns the tangent of x radians.
+(tanh x) : returns the hyperbolic tangent of x radians.
+(atan x) : returns the principal value of the arc tangent of x, expressed in radians.
+(atan2 x y) : returns the principal value of the arc tangent of y/x, expressed in radians.
+
+Power and logarithmic functions:
+
+(sqrt x) : returns the square root of x.
+(log x) : returns the natural logarithm of x.
+(log2 x) : returns the binary (base-2) logarithm of x.
+(log10 x) : returns the common (base-10) logarithm of x.
+(pow x y) : returns x to the power y.
+
+Clipping functions:
+
+(abs x) : returns the absolute value of x.
+(floor x) : rounds x downward, returning the largest integral value that is not greater than x.
+(ceil x) : rounds x upward, returning the smallest integral value that is not less than x.
+(exp x) : returns the constant e to the power x.
+(round x) : returns the integral value that is nearest to x.
+(min x y) : returns the smaller of its arguments: either x or y.
+(max x y) : returns the larger of its arguments: either x or y.
+(wrap x) : wraps x between 0 and 1.
+
+Random fuctions:
+
+(randf x y) : returns a pseudo-random floating-point number in the range between x and y.
+(randi x y) : returns a pseudo-random integral number in the range between x and y.
+
+Filter functions:
+
+(sah x y) : samples and holds x value whenever y is smaller than its previous state.
+(rpole x y) : real one-pole recursive filter. returns x + last_out * y.
+(rzero x y) : real one-zero non-recursive filter. returns x - last_x * y.
+
+Constants:
+
+(const x) : returns x.
+(pi) : returns an approximated value of pi.
+(twopi) : returns a constant with value pi*2.
+(e) : returns an approximated value of e.
+
+Comments
+--------
+
+A comment start with two slashs ( // ) and ends at the end of the line:
+
+ // This is a comment!
+
+Input and Output signals
+------------------------
+
+User has access to the last buffer size of input and output samples.
+
+To use samples from past input, use $x[n] notation, where n is the position
+from the current time. $x[0] is the current input, $x[-1] is the previous
+one and $x[-buffersize] is the last available input sample.
+
+To use samples from past output, use $y[n] notation, where n is the position
+from the current time. $y[-1] is the previous output and $y[-buffersize] is
+the last available output sample.
+
+Here an example of a first-order IIR lowpass filter expression:
+
+ // A first-order IIR lowpass filter
+ + $x[0] (* (- $y[-1] $x[0]) 0.99)
+
+
+Defining custom functions
+-------------------------
+
+The define keyword starts the definition of a custom function.
+
+(define funcname (body))
+
+funcname is the name used to call the function in the expression and
+body is the sequence of functions to execute. Arguments of the function
+are extracted directly from the body. They must be named $1, $2, $3, ..., $9.
+
+Example of a sine wave function:
+
+ (define osc (
+ sin (* (twopi) (~ $1))
+ )
+ )
+ // play a sine wave
+ * (osc 440) 0.3
+
+
+State variables
+---------------
+
+User can create state variable with the keyword "let". This is useful
+to set an intermediate state to be used in multiple places in the
+processing chain. The syntax is:
+
+(let #var (body))
+
+The variable name must begin with a "#".
+
+ (let #sr 44100)
+ (let #freq 1000)
+ (let #coeff (
+ ^ (e) (/ (* (* -2 (pi)) #freq) #sr)
+ )
+ )
+ + $x[0] (* (- $y[-1] $x[0]) #coeff)
+
+The variable is private to a function if created inside a custom function.
+
+ (let #freq 250) // global #freq variable
+ (define osc (
+ (let #freq (* $1 $2)) // local #freq variable
+ sin (* (twopi) (~ #freq))
+ )
+ )
+ * (+ (osc 1 #freq) (osc 2 #freq)) 0.2
+
+State variables can be used to do 1 sample feedback if used before created.
+Undefined variables are initialized to 0.
+
+ (define oscloop (
+ (let #xsin
+ (sin (+ (* (~ $1) (twopi)) (* #xsin $2))) // #xsin used before...
+ ) // ... "let" statement finished!
+ #xsin // oscloop function outputs #xsin variable
+ )
+ )
+ * (oscloop 200 0.7) 0.3
+
+
+User variables
+--------------
+
+User variables are created with the keyword "var".
+
+(var #var (init))
+
+The variable name must begin with a "#".
+
+They are computed only at initialization, but can be changed from the python
+script with method calls (varname is a string and value is a float):
+
+obj.setVar(varname, value)
+
+Library importation
+-------------------
+
+Custom functions can be defined in an external file and imported with the
+"load" function:
+
+(load path/to/the/file)
+
+The content of the file will be inserted where the load function is called
+and all functions defined inside the file will then be accessible. The path
+can be absolute or relative to the current working directory.
+
+Examples
+--------
+
+A first-order IIR lowpass filter:
+
+ (var #sr 44100)
+ (var #cutoff 1000)
+ (let #coeff (exp (/ (* (* -2 (pi)) #cutoff) #sr)))
+ + $x[0] (* (- $y[-1] $x[0]) #coeff)
+
+A LFO'ed hyperbolic tangent distortion:
+
+ // $1 = lfo frequency, $2 = lfo depth
+ (define lfo (
+ (+ (* (sin (* (twopi) (~ $1))) (- $2 1)) $2)
+ )
+ )
+ tanh (* $x[0] (lfo .25 10))
+
+A triangle waveform generator (use Sig(0) as input argument to bypass input):
+
+ (var #freq 440)
+ // $1 = oscillator frequency
+ (define triangle (
+ (let #ph (~ $1))
+ (- (* (min #ph (- 1 #ph)) 4) 1)
+ )
+ )
+ triangle #freq
+
+"""
+
+"""
+Copyright 2015-16 Olivier Belanger
+
+This file is part of pyo, a python module to help digital signal
+processing script creation.
+
+pyo is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+pyo is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with pyo. If not, see <http://www.gnu.org/licenses/>.
+"""
+import os
+from _core import *
+from _maps import *
+from _widgets import createExprEditorWindow
+
+class Expr(PyoObject):
+ """
+ Prefix audio expression evaluator.
+
+ Expr implements a tiny functional programming language that can be
+ used to write synthesis or signal processing algorithms.
+
+ For documentation about the language, see the module's documentation.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal to process.
+ expr : str, optional
+ Expression to evaluate as a string.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> proc = '''
+ >>> (var #boost 1)
+ >>> (tanh (* $x[0] #boost))
+ >>> '''
+ >>> sf = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True)
+ >>> ex = Expr(sf, proc, mul=0.4).out()
+ >>> lfo = Sine(freq=1).range(1, 20)
+ >>> def change():
+ ... ex.setVar("#boost", lfo.get())
+ >>> pat = Pattern(change, 0.02).play()
+
+ """
+ def __init__(self, input, expr='', mul=1, add=0):
+ pyoArgsAssert(self, "osOO", input, expr, mul, add)
+ PyoObject.__init__(self, mul, add)
+ self._editor = None
+ self._input = input
+ self._expr = expr
+ expr = self._preproc(expr)
+ self._in_fader = InputFader(input)
+ in_fader, expr, mul, add, lmax = convertArgsToLists(self._in_fader, expr, mul, add)
+ self._base_objs = [Expr_base(wrap(in_fader,i), wrap(expr,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.
+
+ """
+ pyoArgsAssert(self, "oN", x, fadetime)
+ self._input = x
+ self._in_fader.setInput(x, fadetime)
+
+ def setExpr(self, x):
+ """
+ Replace the `expr` attribute.
+
+ :Args:
+
+ x : string
+ New expression to process.
+
+ """
+ pyoArgsAssert(self, "s", x)
+ self._expr = x
+ if self._editor is not None:
+ self._editor.update(x)
+ x = self._preproc(x)
+ x, lmax = convertArgsToLists(x)
+ [obj.setExpr(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+ def printNodes(self):
+ """
+ Print the list of current nodes.
+
+ """
+ [obj.printNodes() for i, obj in enumerate(self._base_objs)]
+
+ def setVar(self, varname, value):
+ pyoArgsAssert(self, "sn", varname, value)
+ varname, value, lmax = convertArgsToLists(varname, value)
+ [obj.setVar(wrap(varname,j), wrap(value,j)) for i, obj in enumerate(self._base_objs) for j in range(lmax)]
+
+ def _get_matching_bracket_pos(self, x, p1):
+ count = 1
+ p2 = p1 + 1
+ while True:
+ if x[p2] == "(":
+ count += 1
+ elif x[p2] == ")":
+ count -= 1
+ if count == 0:
+ break
+ p2 += 1
+ if p2 == len(x):
+ break
+ if count != 0:
+ return -1
+ else:
+ return p2
+
+ def _replace(self, x, lst):
+ lst.reverse()
+ for key, body in lst:
+ # find how many args waiting in function's body
+ numargs = 0
+ doll = body.find("$")
+ while doll != -1:
+ arg = int(body[doll+1])
+ if arg > numargs:
+ numargs = arg
+ doll = body.find("$", doll+1)
+ occurences = 0
+ pos = x.find(key)
+ while pos != -1:
+ if x[pos-1] in " \t\n()" and x[pos+len(key)] in " \t\n()":
+ # replace "#vars" with unique symbol
+ body2 = body.replace("-%s" % key, ".%s.%d" % (key, occurences))
+ occurences += 1
+ # find limits
+ is_inside_brackets = True
+ start = pos - 1
+ while x[start] != "(":
+ start -= 1
+ if start < 0:
+ start = 0
+ is_inside_brackets = False
+ break
+ if is_inside_brackets:
+ end = self._get_matching_bracket_pos(x, start)
+ else:
+ end = len(x)
+ # retrieve args
+ args = []
+ p1 = pos + len(key)
+ p2 = -1
+ for i in range(numargs):
+ while x[p1] in " \t\n":
+ p1 += 1
+ if x[p1] == "(":
+ p2 = self._get_matching_bracket_pos(x, p1)
+ if p2 == -1 or p2 >= end:
+ raise Exception("Mismatched brackets in function arguments.")
+ p2 += 1
+ else:
+ p2 = p1 + 1
+ if p2 < end:
+ while x[p2] not in " \t\n()":
+ p2 += 1
+ if p2 == end:
+ break
+ if x[p1:p2] != ")":
+ args.append(x[p1:p2])
+ if p2 == end:
+ break
+ else:
+ p1 = p2
+ # discard extra args
+ if p2 != end and p2 != -1:
+ x = x[:p2] + x[end:]
+ # replace args
+ if args != []:
+ newbody = body2
+ for i in range(numargs):
+ if i < len(args):
+ arg = args[i]
+ else:
+ arg = '0.0'
+ newbody = newbody.replace("$%d" % (i+1), arg)
+ x = x[:pos] + newbody + x[p2:]
+ else:
+ x = x[:pos] + body2 + x[pos+len(key):]
+ pos = x.find(key, pos+1)
+ return x
+
+ def _change_var_names(self, funcname, funcbody):
+ d = {}
+ letpos = funcbody.find("let ")
+ while letpos != -1:
+ pos = funcbody.find("#", letpos)
+ if pos == -1:
+ raise Exception("No #var defined inside a let function.")
+ p1 = pos
+ p2 = p1 + 1
+ while funcbody[p2] not in " \t\n()":
+ p2 += 1
+ label = funcbody[p1:p2]
+ d[label] = label + "-" + funcname
+ letpos = funcbody.find("let ", letpos + 4)
+ for label, newlabel in d.items():
+ funcbody = funcbody.replace(label, newlabel)
+ return funcbody
+
+ def _preproc(self, x):
+ # replace load functions with file body
+ while "(load" in x:
+ p1 = x.find("(load")
+ p2 = self._get_matching_bracket_pos(x, p1)
+ p2 += 1
+ text = x[p1:p2]
+ path = text.replace("(load", "").replace(")", "").strip()
+ if os.path.isfile(path):
+ with open(path, "r") as f:
+ text = f.read()
+ x = x[:p1] + text + x[p2:]
+
+ # remove comments
+ while "//" in x:
+ start = x.find("//")
+ end = x.find("\n", start)
+ x = x[:start] + x[end:]
+
+ # expand defined functions
+ _defined = []
+ while "define" in x:
+ start = x.find("(define")
+ p1 = start + 7
+ # get function name
+ while x[p1] in " \t\n":
+ p1 += 1
+ p2 = p1+1
+ while x[p2] not in " \t\n":
+ p2 += 1
+ funcname = x[p1:p2]
+ # get function body
+ p1 = p2 + 1
+ while x[p1] != "(":
+ p1 += 1
+ p2 = self._get_matching_bracket_pos(x, p1)
+ if p2 == -1:
+ raise Exception("Mismatched brackets in function body.")
+ p2 += 1
+ funcbody = x[p1:p2]
+ # get end of the definition
+ while x[p2] in " \t\n":
+ p2 += 1
+ if x[p2] != ")":
+ raise Exception("Missing ending bracket in function definition.")
+ stop = p2
+ # save in dictionary and remove definition from the string
+ funcbody = self._change_var_names(funcname, funcbody)
+ _defined.append([funcname, funcbody])
+ x = x[:start] + x[stop+1:]
+ # replace calls to function with their function body
+ x = self._replace(x, _defined)
+ x = x.strip()
+ return x
+
+ def editor(self, title="Expr Editor", wxnoserver=False):
+ createExprEditorWindow(self, 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 expr(self):
+ """string. New expression to process."""
+ return self._expr
+ @expr.setter
+ def expr(self, x): self.setExpr(x)
diff --git a/pyolib/generators.py b/pyolib/generators.py
index db2fa97..d6f0f01 100644
--- a/pyolib/generators.py
+++ b/pyolib/generators.py
@@ -1127,7 +1127,7 @@ class SumOsc(PyoObject):
index : float or PyoObject, optional
Damping of successive partials, between 0 and 1. With a
value of 0.5, each partial is 6dB lower than the previous
- partial. Defaults to 5.
+ partial. Defaults to 0.5.
>>> s = Server().boot()
>>> s.start()
diff --git a/pyolib/listener.py b/pyolib/listener.py
index 7cb9521..ba210c6 100644
--- a/pyolib/listener.py
+++ b/pyolib/listener.py
@@ -28,7 +28,7 @@ class MidiListener(threading.Thread):
Sets the midi input device (see `pm_list_devices()` for the
available devices). The default, -1, means the system default
device. A number greater than the highest portmidi device index
- will opened all available input devices.
+ will open all available input devices.
>>> s = Server().boot()
>>> s.deactivateMidi()
@@ -52,7 +52,10 @@ class MidiListener(threading.Thread):
"""
self._listener.play()
while True:
- time.sleep(0.001)
+ try:
+ time.sleep(0.001)
+ except:
+ pass
OscListenerLock = threading.Lock()
@@ -103,4 +106,7 @@ class OscListener(threading.Thread):
"""
while True:
self._listener.get()
- time.sleep(0.001)
+ try:
+ time.sleep(0.001)
+ except:
+ pass
diff --git a/pyolib/opensndctrl.py b/pyolib/opensndctrl.py
index 6df3d97..075bf39 100644
--- a/pyolib/opensndctrl.py
+++ b/pyolib/opensndctrl.py
@@ -33,7 +33,7 @@ License along with pyo. If not, see <http://www.gnu.org/licenses/>.
"""
from _core import *
from _maps import *
-from types import ListType
+from types import ListType, StringType, UnicodeType
######################################################################
### Open Sound Control
@@ -179,7 +179,7 @@ class OscReceive(PyoObject):
self._base_objs = [OscReceive_base(self._mainReceiver, wrap(address,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
def __getitem__(self, i):
- if type(i) == type(''):
+ if type(i) in [StringType, UnicodeType]:
return self._base_objs[self._address.index(i)]
elif i < len(self._base_objs):
return self._base_objs[i]
@@ -436,8 +436,9 @@ class OscDataSend(PyoObject):
pyoArgsAssert(self, "s", path)
path, lmax = convertArgsToLists(path)
for p in path:
- self._base_objs.remove(self._addresses[p])
- del self._addresses[p]
+ if p in self._addresses:
+ self._base_objs.remove(self._addresses[p])
+ del self._addresses[p]
def send(self, msg, address=None):
"""
@@ -575,8 +576,10 @@ class OscDataReceive(PyoObject):
pyoArgsAssert(self, "s", path)
path, lmax = convertArgsToLists(path)
for p in path:
- index = self._address.index(p)
- self._base_objs[0].delAddress(index)
+ if p in self._address:
+ index = self._address.index(p)
+ self._base_objs[0].delAddress(index)
+ self._address.remove(p)
class OscListReceive(PyoObject):
"""
@@ -633,7 +636,7 @@ class OscListReceive(PyoObject):
self._base_objs = [OscListReceive_base(self._mainReceiver, wrap(address,i), j, wrap(mul,i), wrap(add,i)) for i in range(lmax) for j in range(self._num)]
def __getitem__(self, i):
- if type(i) == type(''):
+ if type(i) in [StringType, UnicodeType]:
first = self._address.index(i) * self._num
return self._base_objs[first:first+self._num]
elif i < len(self._base_objs):
@@ -685,7 +688,7 @@ class OscListReceive(PyoObject):
pyoArgsAssert(self, "s", path)
path, lmax = convertArgsToLists(path)
self._mainReceiver.delAddress(path)
- indexes = [self._address.index(p) for p in path]
+ indexes = [self._address.index(p) for p in path if p in self._address]
for ind in reversed(indexes):
self._address.pop(ind)
first = ind * self._num
diff --git a/pyolib/players.py b/pyolib/players.py
index 3b5da47..525bac9 100644
--- a/pyolib/players.py
+++ b/pyolib/players.py
@@ -75,6 +75,15 @@ class SfPlayer(PyoObject):
>>> sf = SfPlayer(SNDS_PATH + "/transparent.aif").out()
>>> trig = TrigRand(sf['trig'])
+
+ Note that the object will send as many trigs as there is channels
+ in the sound file. If you want to retrieve only one trig, only give
+ the first stream to the next object:
+
+ >>> def printing():
+ ... print "one trig!"
+ >>> sf = SfPlayer("/stereo/sound/file.aif").out()
+ >>> trig = TrigFunc(sf['trig'][0], printing)
>>> s = Server().boot()
>>> s.start()
diff --git a/pyolib/server.py b/pyolib/server.py
index 8f211b1..5d8ce25 100644
--- a/pyolib/server.py
+++ b/pyolib/server.py
@@ -141,6 +141,7 @@ class Server(object):
Same as in the __init__ method.
"""
+ self._gui_frame = None
self._nchnls = nchnls
if ichnls == None:
self._ichnls = nchnls
@@ -154,6 +155,7 @@ class Server(object):
self._fileformat = 0
self._sampletype = 0
self._globalseed = 0
+ self._resampling = 1
self._server.__init__(sr, nchnls, buffersize, duplex, audio, jackname, self._ichnls)
def gui(self, locals=None, meter=True, timer=True, exit=True):
@@ -177,18 +179,29 @@ class Server(object):
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, exit)
+ self._gui_frame, win = createServerGUI(self._nchnls, self.start, self.stop,
+ self.recstart, self.recstop, self.setAmp,
+ self.getIsStarted(), locals, self.shutdown,
+ meter, timer, self._amp, exit)
if meter:
- self._server.setAmpCallable(f)
+ self._server.setAmpCallable(self._gui_frame)
if timer:
- self._server.setTimeCallable(f)
+ self._server.setTimeCallable(self._gui_frame)
try:
win.mainloop()
except:
if win != None:
win.MainLoop()
+ def closeGui(self):
+ """
+ Programmatically close the server's GUI.
+
+ """
+ if self._gui_frame is not None:
+ self._gui_frame.quit_from_code()
+ self._gui_frame = None
+
def setTimeCallable(self, func):
"""
Set a function callback that will receive the current time as argument.
@@ -507,6 +520,52 @@ class Server(object):
self._amp = x
self._server.setAmp(x)
+ def beginResamplingBlock(self, x):
+ """
+ Starts a resampling block.
+
+ This factor must be a power-of-two. A positive value means
+ upsampling and a negative value means downsampling. After this
+ call, every PyoObject will be created with an internal sampling
+ rate and buffer size relative to the resampling factor. The method
+ `endResamplingBlock()` should be called at the end of the code
+ block using the resampling factor.
+
+ The `Resample` object can be used inside the resampling block to
+ perform up or down resampling of audio signal created before the
+ block.
+
+ :Args:
+
+ x : int, power-of-two
+ Resampling factor. Must be a power-of-two. A positive
+ value starts an upsampling block while a negative value
+ starts a downsampling block.
+
+ """
+ realx = x
+ x = abs(x)
+ if ((x & (x - 1)) == 0) and x != 0:
+ self._resampling = realx
+ self._server.beginResamplingBlock(realx)
+ else:
+ print "Resampling factor must be a power-of-two (positive or negative)."
+
+ def endResamplingBlock(self):
+ """
+ Ends a resampling block.
+
+ This call ends a code block using a sample rate different from
+ the current sampling rate of the system.
+
+ The `Resample` object can be used after the resampling blick to
+ perform up or down resampling of audio signal created inside the
+ block.
+
+ """
+ self._resampling = 1
+ self._server.endResamplingBlock()
+
def shutdown(self):
"""
Shut down and clear the server. This method will erase all objects
@@ -793,6 +852,38 @@ class Server(object):
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 addMidiEvent(self, status, data1=0, data2=0):
+ """
+ Add a MIDI event in the server processing loop.
+
+ This method can be used to programatically simulate incomming
+ MIDI events. In an embedded framework (ie. pyo inside puredata,
+ openframeworks, etc.), this is useful to control a MIDI-driven
+ script from the host program. Arguments can be list of values to
+ generate multiple events in one call.
+
+ :Args:
+
+ status : int
+ The status byte, indicating the type of event and the
+ MIDI channel. Typical event type are:
+ 128 -> 143 : Noteoff
+ 144 -> 159 : Noteon
+ 176 -> 191 : Control change
+ 192 -> 207 : Program change
+ 209 -> 223 : After touch
+ 224 -> 239 : Pitch bend
+ data1 : int, optional
+ The first data byte (pitch for a midi note, controller
+ number for a control change). Defaults to 0.
+ data2 : int, optional
+ The second data byte (velocity for a midi note, value
+ for a control change). Defaults to 0.
+
+ """
+ status, data1, data2, lmax = convertArgsToLists(status, data1, data2)
+ [self._server.addMidiEvent(wrap(status,i), wrap(data1,i), wrap(data2,i)) for i in range(lmax)]
+
def getStreams(self):
"""
Return the list of streams loaded in the server.
diff --git a/pyolib/tableprocess.py b/pyolib/tableprocess.py
index 88ba328..38c85c0 100644
--- a/pyolib/tableprocess.py
+++ b/pyolib/tableprocess.py
@@ -2305,6 +2305,12 @@ class Looper(PyoObject):
to reduce the quantization noise produced by very low transpositions.
Defaults to False.
+ .. note::
+
+ Looper will sends a trigger signal every new playback starting point
+ (i.e. when the object is activated and at the beginning of the crossfade
+ of a loop. User can retrieve the trigger streams by calling obj['trig'].
+
.. seealso::
:py:class:`Granulator`, :py:class:`Pointer`
@@ -2335,6 +2341,7 @@ class Looper(PyoObject):
table, pitch, start, dur, xfade, mode, xfadeshape, startfromloop, interp, autosmooth, mul, add)
self._base_objs = [Looper_base(wrap(table,i), wrap(pitch,i), wrap(start,i), wrap(dur,i), wrap(xfade,i), wrap(mode,i),
wrap(xfadeshape,i), wrap(startfromloop,i), wrap(interp,i), wrap(autosmooth,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+ self._trig_objs = Dummy([TriggerDummy_base(obj) for obj in self._base_objs])
def setTable(self, x):
"""
diff --git a/pyolib/utils.py b/pyolib/utils.py
index 9cfc841..619dbb8 100644
--- a/pyolib/utils.py
+++ b/pyolib/utils.py
@@ -1971,4 +1971,64 @@ class TrackHold(PyoObject):
"""float or PyoObject. Target value."""
return self._value
@value.setter
- def value(self, x): self.setValue(x)
\ No newline at end of file
+ def value(self, x): self.setValue(x)
+
+class Resample(PyoObject):
+ """
+ Realtime upsampling or downsampling of an audio signal.
+
+ This object should be used in the context of a resampling block
+ created with the Server's methods `beginResamplingBlock` and
+ `EndResamplingBlock`.
+
+ If used inside the block, it will resample its input signal according
+ to the resampling factor given to `beginResamplingFactor`. If the factor
+ is a negative value, the new virtual sampling rate will be
+ `current sr / abs(factor)`. If the factor is a postive value, the new
+ virtual sampling rate will be `current sr * factor`.
+
+ If used after `endResamplingBlock`, it will resample its input signal
+ to the current sampling rate of the server.
+
+ The `mode` argument specifies the interpolation/decimation mode used
+ internally.
+
+ :Parent: :py:class:`PyoObject`
+
+ :Args:
+
+ input : PyoObject
+ Input signal to resample.
+ mode : int, optional
+ The interpolation/decimation mode. Defaults to 1.
+ For the upsampling process, possible values are:
+ 0 : zero-padding
+ 1 : sample-and-hold
+ 2 or higher : the formula `mode * resampling factor` gives
+ the FIR lowpass kernel length used to interpolate.
+ For the downsampling process, possible values are:
+ 0 or 1 : discard extra samples
+ 2 or higher : the formula `mode * abs(resampling factor)`
+ gives the FIR lowpass kernel length used for the decimation.
+ Available at initialization time only.
+
+ >>> s = Server().boot()
+ >>> s.start()
+ >>> drv = Sine(.5, phase=[0, 0.5], mul=0.49, add=0.5)
+ >>> sig = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True)
+ >>> s.beginResamplingBlock(8)
+ >>> sigup = Resample(sig, mode=32)
+ >>> drvup = Resample(drv, mode=1)
+ >>> disto = Disto(sigup, drive=drvup, mul=0.5)
+ >>> s.endResamplingBlock()
+ >>> sigdown = Resample(disto, mode=32, mul=0.4).out()
+
+ """
+
+ def __init__(self, input, mode=1, mul=1, add=0):
+ pyoArgsAssert(self, "oiOO", input, mode, mul, add)
+ PyoObject.__init__(self, mul, add)
+ self._input = input
+ self._mode = mode
+ _input, mode, mul, add, lmax = convertArgsToLists(input, mode, mul, add)
+ self._base_objs = [Resample_base(wrap(_input,i), wrap(mode,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
diff --git a/scripts/release_doc_src.sh b/scripts/release_doc_src.sh
old mode 100644
new mode 100755
index 0c9caa2..320ea79
--- a/scripts/release_doc_src.sh
+++ b/scripts/release_doc_src.sh
@@ -6,7 +6,7 @@
# 3. Execute from pyo folder : ./scripts/release_doc_src.sh
#
-version=0.7.6
+version=0.7.8
replace=XXX
doc_rep=pyo_XXX-doc
@@ -21,6 +21,6 @@ tar -cjvf ${doc_tar/$replace/$version} ${doc_rep/$replace/$version}
rm -R ${doc_rep/$replace/$version}
cd ..
-svn export . ${src_rep/$replace/$version}
+git checkout-index -a -f --prefix=${src_rep/$replace/$version}/
tar -cjvf ${src_tar/$replace/$version} ${src_rep/$replace/$version}
rm -R ${src_rep/$replace/$version}
diff --git a/setup.py b/setup.py
index 873ce31..d770190 100644
--- a/setup.py
+++ b/setup.py
@@ -23,7 +23,7 @@ from distutils.core import setup, Extension
import os, sys, getopt
import time
-pyo_version = "0.7.6"
+pyo_version = "0.7.8"
build_osx_with_jack_support = False
compile_externals = False
@@ -71,13 +71,13 @@ files = ['pyomodule.c', 'listenermodule.c', 'servermodule.c', 'pvstreammodule.c'
source_files = [path + f for f in files]
path = 'src/objects/'
-files = ['granulatormodule.c', 'tablemodule.c', 'wgverbmodule.c', 'freeverbmodule.c', 'phasevocmodule.c', 'fftmodule.c',
+files = ['exprmodule.c', 'utilsmodule.c', 'granulatormodule.c', 'tablemodule.c', 'wgverbmodule.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',
'metromodule.c', 'trigmodule.c', 'patternmodule.c', 'bandsplitmodule.c', 'hilbertmodule.c', 'panmodule.c',
- 'selectmodule.c', 'compressmodule.c', 'utilsmodule.c',
+ 'selectmodule.c', 'compressmodule.c', 'freeverbmodule.c', 'phasevocmodule.c', 'fftmodule.c',
'convolvemodule.c', 'arithmeticmodule.c', 'sigmodule.c',
'matrixprocessmodule.c', 'harmonizermodule.c', 'chorusmodule.c']
@@ -120,8 +120,8 @@ setup( name = "pyo",
version = pyo_version,
description = "Python dsp module.",
long_description = "pyo is a Python module written in C to help digital signal processing script creation.",
- url = "http://code.google.com/p/pyo/",
- license = "GPLv3",
+ url = "https://github.com/belangeo/pyo",
+ license = "LGPLv3+",
packages = ['pyolib', 'pyolib.snds'],
py_modules = main_modules,
package_data = {'pyolib.snds': [f for f in os.listdir('pyolib/snds') if f.endswith('aif') or f.endswith('wav')]},
diff --git a/src/engine/listenermodule.c b/src/engine/listenermodule.c
index 0a45024..18e86ab 100644
--- a/src/engine/listenermodule.c
+++ b/src/engine/listenermodule.c
@@ -386,7 +386,9 @@ static PyObject * MidiListener_play(MidiListener *self) {
for (i=0; i<self->midicount; i++) {
Pm_SetFilter(self->midiin[i], PM_FILT_ACTIVE | PM_FILT_CLOCK);
}
- self->active = 1;
+
+ if (self->midicount > 0)
+ self->active = 1;
Py_INCREF(Py_None);
return Py_None;
diff --git a/src/engine/pyomodule.c b/src/engine/pyomodule.c
index 3278ba5..f4a69d3 100644
--- a/src/engine/pyomodule.c
+++ b/src/engine/pyomodule.c
@@ -883,7 +883,7 @@ savefile(PyObject *self, PyObject *args, PyObject *kwds) {
size = PyList_Size(samples);
sampsarray = (MYFLT *)malloc(size * sizeof(MYFLT));
for (i=0; i<size; i++) {
- sampsarray[i] = PyFloat_AS_DOUBLE(PyList_GET_ITEM(samples, i));
+ sampsarray[i] = PyFloat_AsDouble(PyList_GET_ITEM(samples, i));
}
}
else {
@@ -895,7 +895,7 @@ savefile(PyObject *self, PyObject *args, PyObject *kwds) {
sampsarray = (MYFLT *)malloc(size * sizeof(MYFLT));
for (i=0; i<(size/channels); i++) {
for (j=0; j<channels; j++) {
- sampsarray[i*channels+j] = PyFloat_AS_DOUBLE(PyList_GET_ITEM(PyList_GET_ITEM(samples, j), i));
+ sampsarray[i*channels+j] = PyFloat_AsDouble(PyList_GET_ITEM(PyList_GET_ITEM(samples, j), i));
}
}
}
@@ -1121,7 +1121,7 @@ void gen_lp_impulse(MYFLT *array, int size, float freq) {
lp_conv -> convolution lowpass filter.
samples is the samples array to filter.
impulse is the impulse response array.
- num_samps is the number od samples to filter.
+ num_samps is the number of samples to filter.
size is the filter order. Minimum suggested = 16, ideal = 128 or higher.
gain is the gain of the filter.
*/
@@ -1434,16 +1434,16 @@ reducePoints(PyObject *self, PyObject *args, PyObject *kwds)
if (PyTuple_Check(tup) == 1) {
for (i=0; i<nPointsCount; i++) {
tup = PyList_GET_ITEM(pointlist, i);
- pPointsX[i] = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 0)));
- pPointsY[i] = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 1)));
+ pPointsX[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 0));
+ pPointsY[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 1));
pnUseFlag[i] = 0;
}
}
else {
for (i=0; i<nPointsCount; i++) {
tup = PyList_GET_ITEM(pointlist, i);
- pPointsX[i] = PyFloat_AsDouble(PyNumber_Float(PyList_GET_ITEM(tup, 0)));
- pPointsY[i] = PyFloat_AsDouble(PyNumber_Float(PyList_GET_ITEM(tup, 1)));
+ pPointsX[i] = PyFloat_AsDouble(PyList_GET_ITEM(tup, 0));
+ pPointsY[i] = PyFloat_AsDouble(PyList_GET_ITEM(tup, 1));
pnUseFlag[i] = 0;
}
}
@@ -1565,27 +1565,27 @@ distanceToSegment(PyObject *self, PyObject *args, PyObject *kwds)
pf2 = PySequence_Fast(p2, NULL);
if (xlog == 0) {
xscale = xmax - xmin;
- xp[0] = PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(pf, 0))) / xscale;
- xp1[0] = PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(pf1, 0))) / xscale;
- xp2[0] = PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(pf2, 0))) / xscale;
+ xp[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(pf, 0)) / xscale;
+ xp1[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(pf1, 0)) / xscale;
+ xp2[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(pf2, 0)) / xscale;
}
else {
xscale = MYLOG10(xmax / xmin);
- xp[0] = MYLOG10(PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(pf, 0))) / xmin) / xscale;
- xp1[0] = MYLOG10(PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(pf1, 0))) / xmin) / xscale;
- xp2[0] = MYLOG10(PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(pf2, 0))) / xmin) / xscale;
+ xp[0] = MYLOG10(PyFloat_AsDouble(PySequence_Fast_GET_ITEM(pf, 0)) / xmin) / xscale;
+ xp1[0] = MYLOG10(PyFloat_AsDouble(PySequence_Fast_GET_ITEM(pf1, 0)) / xmin) / xscale;
+ xp2[0] = MYLOG10(PyFloat_AsDouble(PySequence_Fast_GET_ITEM(pf2, 0)) / xmin) / xscale;
}
if (ylog == 0) {
yscale = ymax - ymin;
- xp[1] = PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(pf, 1))) / yscale;
- xp1[1] = PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(pf1, 1))) / yscale;
- xp2[1] = PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(pf2, 1))) / yscale;
+ xp[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(pf, 1)) / yscale;
+ xp1[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(pf1, 1)) / yscale;
+ xp2[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(pf2, 1)) / yscale;
}
else {
yscale = MYLOG10(ymax / ymin);
- xp[1] = MYLOG10(PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(pf, 1))) / ymin) / yscale;
- xp1[1] = MYLOG10(PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(pf1, 1))) / ymin) / yscale;
- xp2[1] = MYLOG10(PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(pf2, 1))) / ymin) / yscale;
+ xp[1] = MYLOG10(PyFloat_AsDouble(PySequence_Fast_GET_ITEM(pf, 1)) / ymin) / yscale;
+ xp1[1] = MYLOG10(PyFloat_AsDouble(PySequence_Fast_GET_ITEM(pf1, 1)) / ymin) / yscale;
+ xp2[1] = MYLOG10(PyFloat_AsDouble(PySequence_Fast_GET_ITEM(pf2, 1)) / ymin) / yscale;
}
xDelta = xp2[0] - xp1[0]; yDelta = xp2[1] - xp1[1];
@@ -1640,8 +1640,8 @@ linToCosCurve(PyObject *self, PyObject *args, PyObject *kwds)
if (yrange) {
fyrange = PySequence_Fast(yrange, NULL);
- ymin = PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(fyrange, 0)));
- ymax = PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(fyrange, 1)));
+ ymin = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(fyrange, 0));
+ ymax = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(fyrange, 1));
}
ydiff = ymax - ymin;
log10ymin = log10(ymin);
@@ -1656,18 +1656,18 @@ linToCosCurve(PyObject *self, PyObject *args, PyObject *kwds)
if (log == 0) {
for (i=0; i<datasize; i++) {
ftup = PySequence_Fast(PySequence_Fast_GET_ITEM(fdata, i), NULL);
- tmp = PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(ftup, 0)));
+ tmp = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(ftup, 0));
xdata[i] = tmp / totaldur;
- tmp = PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(ftup, 1)));
+ tmp = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(ftup, 1));
ydata[i] = (tmp - ymin) / ydiff;
}
}
else {
for (i=0; i<datasize; i++) {
ftup = PySequence_Fast(PySequence_Fast_GET_ITEM(fdata, i), NULL);
- tmp = PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(ftup, 0)));
+ tmp = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(ftup, 0));
xdata[i] = tmp / totaldur;
- tmp = PyFloat_AsDouble(PyNumber_Float(PySequence_Fast_GET_ITEM(ftup, 1)));
+ tmp = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(ftup, 1));
ydata[i] = log10(tmp / ymin) / log10(ymax / ymin);
}
}
@@ -1776,14 +1776,14 @@ rescale(PyObject *self, PyObject *args, PyObject *kwds)
curscl = ymax - ymin;
curscl /= datascl;
if (type == 0) {
- val = PyFloat_AsDouble(PyNumber_Float(data));
+ val = PyFloat_AsDouble(data);
return Py_BuildValue("d", (val - xmin) * curscl + ymin);
}
else if (type == 1) {
cnt = PyList_Size(data);
out = PyList_New(cnt);
for (i=0; i<cnt; i++) {
- val = PyFloat_AsDouble(PyNumber_Float(PyList_GET_ITEM(data, i)));
+ val = PyFloat_AsDouble(PyList_GET_ITEM(data, i));
PyList_SET_ITEM(out, i, PyFloat_FromDouble((val - xmin) * curscl + ymin));
}
return out;
@@ -1796,7 +1796,7 @@ rescale(PyObject *self, PyObject *args, PyObject *kwds)
curscl = MYLOG10(ymax / ymin);
ymin = MYLOG10(ymin);
if (type == 0) {
- val = PyFloat_AsDouble(PyNumber_Float(data));
+ val = PyFloat_AsDouble(data);
if (val == 0)
val = 0.000001;
val = (val - xmin) / datascl;
@@ -1806,7 +1806,7 @@ rescale(PyObject *self, PyObject *args, PyObject *kwds)
cnt = PyList_Size(data);
out = PyList_New(cnt);
for (i=0; i<cnt; i++) {
- val = PyFloat_AsDouble(PyNumber_Float(PyList_GET_ITEM(data, i)));
+ val = PyFloat_AsDouble(PyList_GET_ITEM(data, i));
if (val == 0)
val = 0.000001;
val = (val - xmin) / datascl;
@@ -1819,7 +1819,7 @@ rescale(PyObject *self, PyObject *args, PyObject *kwds)
datascl = MYLOG10(xmax / xmin);
curscl = ymax - ymin;
if (type == 0) {
- val = PyFloat_AsDouble(PyNumber_Float(data));
+ val = PyFloat_AsDouble(data);
val = MYLOG10(val / xmin) / datascl;
return Py_BuildValue("d", val * curscl + ymin);
}
@@ -1827,7 +1827,7 @@ rescale(PyObject *self, PyObject *args, PyObject *kwds)
cnt = PyList_Size(data);
out = PyList_New(cnt);
for (i=0; i<cnt; i++) {
- val = PyFloat_AsDouble(PyNumber_Float(PyList_GET_ITEM(data, i)));
+ val = PyFloat_AsDouble(PyList_GET_ITEM(data, i));
val = MYLOG10(val / xmin) / datascl;
PyList_SET_ITEM(out, i, PyFloat_FromDouble(val * curscl + ymin));
}
@@ -1839,7 +1839,7 @@ rescale(PyObject *self, PyObject *args, PyObject *kwds)
curscl = MYLOG10(ymax / ymin);
ymin = MYLOG10(ymin);
if (type == 0) {
- val = PyFloat_AsDouble(PyNumber_Float(data));
+ val = PyFloat_AsDouble(data);
val = MYLOG10(val / xmin) / datascl;
return Py_BuildValue("d", MYPOW(10.0, val * curscl + ymin));
}
@@ -1847,7 +1847,7 @@ rescale(PyObject *self, PyObject *args, PyObject *kwds)
cnt = PyList_Size(data);
out = PyList_New(cnt);
for (i=0; i<cnt; i++) {
- val = PyFloat_AsDouble(PyNumber_Float(PyList_GET_ITEM(data, i)));
+ val = PyFloat_AsDouble(PyList_GET_ITEM(data, i));
val = MYLOG10(val / xmin) / datascl;
PyList_SET_ITEM(out, i, PyFloat_FromDouble(MYPOW(10.0, val * curscl + ymin)));
}
@@ -1921,12 +1921,12 @@ midiToHz(PyObject *self, PyObject *arg) {
double x = 0.0;
PyObject *newseq = NULL;
if (PyNumber_Check(arg))
- return Py_BuildValue("d", 440.0 * MYPOW(2.0, (PyFloat_AsDouble(PyNumber_Float(arg)) - 69) / 12.0));
+ return Py_BuildValue("d", 440.0 * MYPOW(2.0, (PyFloat_AsDouble(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)));
+ x = PyFloat_AsDouble(PyList_GET_ITEM(arg, i));
PyList_SET_ITEM(newseq, i, PyFloat_FromDouble(440.0 * MYPOW(2.0, (x - 69) / 12.0)));
}
return newseq;
@@ -1935,7 +1935,7 @@ midiToHz(PyObject *self, PyObject *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)));
+ x = PyFloat_AsDouble(PyTuple_GET_ITEM(arg, i));
PyTuple_SET_ITEM(newseq, i, PyFloat_FromDouble(440.0 * MYPOW(2.0, (x - 69) / 12.0)));
}
return newseq;
@@ -1966,12 +1966,12 @@ hzToMidi(PyObject *self, PyObject *arg) {
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);
+ return Py_BuildValue("d", 12.0 * MYLOG2(PyFloat_AsDouble(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)));
+ x = PyFloat_AsDouble(PyList_GET_ITEM(arg, i));
PyList_SET_ITEM(newseq, i, PyFloat_FromDouble(12.0 * MYLOG2(x / 440.0) + 69));
}
return newseq;
@@ -1980,7 +1980,7 @@ hzToMidi(PyObject *self, PyObject *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)));
+ x = PyFloat_AsDouble(PyTuple_GET_ITEM(arg, i));
PyTuple_SET_ITEM(newseq, i, PyFloat_FromDouble(12.0 * MYLOG2(x / 440.0) + 69));
}
return newseq;
@@ -2011,12 +2011,12 @@ midiToTranspo(PyObject *self, PyObject *arg) {
double x = 0.0;
PyObject *newseq = NULL;
if (PyNumber_Check(arg))
- return Py_BuildValue("d", pow(1.0594630943593, PyFloat_AsDouble(PyNumber_Float(arg))-60.0));
+ return Py_BuildValue("d", pow(1.0594630943593, PyFloat_AsDouble(arg)-60.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)));
+ x = PyFloat_AsDouble(PyList_GET_ITEM(arg, i));
PyList_SET_ITEM(newseq, i, PyFloat_FromDouble(pow(1.0594630943593, x-60.0)));
}
return newseq;
@@ -2025,7 +2025,7 @@ midiToTranspo(PyObject *self, PyObject *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)));
+ x = PyFloat_AsDouble(PyTuple_GET_ITEM(arg, i));
PyTuple_SET_ITEM(newseq, i, PyFloat_FromDouble(pow(1.0594630943593, x-60.0)));
}
return newseq;
@@ -2063,12 +2063,12 @@ sampsToSec(PyObject *self, PyObject *arg) {
double x = 0.0;
PyObject *newseq = NULL;
if (PyNumber_Check(arg))
- return Py_BuildValue("d", PyFloat_AsDouble(PyNumber_Float(arg)) / sr);
+ return Py_BuildValue("d", PyFloat_AsDouble(arg) / sr);
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)));
+ x = PyFloat_AsDouble(PyList_GET_ITEM(arg, i));
PyList_SET_ITEM(newseq, i, PyFloat_FromDouble(x / sr));
}
return newseq;
@@ -2077,7 +2077,7 @@ sampsToSec(PyObject *self, PyObject *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)));
+ x = PyFloat_AsDouble(PyTuple_GET_ITEM(arg, i));
PyTuple_SET_ITEM(newseq, i, PyFloat_FromDouble(x / sr));
}
return newseq;
@@ -2115,12 +2115,12 @@ secToSamps(PyObject *self, PyObject *arg) {
double x = 0.0;
PyObject *newseq = NULL;
if (PyNumber_Check(arg))
- return Py_BuildValue("l", (long)(PyFloat_AsDouble(PyNumber_Float(arg)) * sr));
+ return Py_BuildValue("l", (long)(PyFloat_AsDouble(arg) * sr));
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)));
+ x = PyFloat_AsDouble(PyList_GET_ITEM(arg, i));
PyList_SET_ITEM(newseq, i, PyInt_FromLong((long)(x * sr)));
}
return newseq;
@@ -2129,7 +2129,7 @@ secToSamps(PyObject *self, PyObject *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)));
+ x = PyFloat_AsDouble(PyTuple_GET_ITEM(arg, i));
PyTuple_SET_ITEM(newseq, i, PyInt_FromLong((long)(x * sr)));
}
return newseq;
@@ -2553,6 +2553,8 @@ init_pyo64(void)
module_add_object(m, "Particle_base", &ParticleType);
module_add_object(m, "AtanTable_base", &AtanTableType);
module_add_object(m, "RawMidi_base", &RawMidiType);
+ module_add_object(m, "Resample_base", &ResampleType);
+ module_add_object(m, "Expr_base", &ExprType);
PyModule_AddStringConstant(m, "PYO_VERSION", PYO_VERSION);
#ifdef COMPILE_EXTERNALS
diff --git a/src/engine/servermodule.c b/src/engine/servermodule.c
index 1cbdb51..9ede3de 100644
--- a/src/engine/servermodule.c
+++ b/src/engine/servermodule.c
@@ -295,7 +295,7 @@ jack_srate_cb (jack_nframes_t nframes, void *arg)
{
Server *s = (Server *) arg;
s->samplingRate = (double) nframes;
- Server_debug(s, "The sample rate is now %lu/sec\n", (unsigned long) nframes);
+ Server_debug(s, "The sample rate is now %lu.\n", (unsigned long) nframes);
return 0;
}
@@ -304,7 +304,7 @@ jack_bufsize_cb (jack_nframes_t nframes, void *arg)
{
Server *s = (Server *) arg;
s->bufferSize = (int) nframes;
- Server_debug(s, "The buffer size is now %lu/sec\n", (unsigned long) nframes);
+ Server_debug(s, "The buffer size is now %lu.\n", (unsigned long) nframes);
return 0;
}
@@ -1258,6 +1258,7 @@ int
Server_embedded_i_start(Server *self)
{
Server_process_buffers(self);
+ self->midi_count = 0;
return 0;
}
@@ -1288,6 +1289,8 @@ Server_embedded_ni_start(Server *self)
}
}
+ self->midi_count = 0;
+
return 0;
}
@@ -1305,6 +1308,7 @@ void
self = (Server *)arg;
Server_process_buffers(self);
+ self->midi_count = 0;
return NULL;
}
@@ -1317,8 +1321,8 @@ Server_embedded_nb_start(Server *self)
return 0;
}
-/* this stop function is not very useful since the processing is stopped at the end
-of every processing callback, but function put to not break pyo */
+/* this stop function is not very useful since the processing is stopped
+at the end of every processing callback, but function put to not break pyo */
int
Server_embedded_stop(Server *self)
{
@@ -1617,6 +1621,8 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->ichnls = 2;
self->record = 0;
self->bufferSize = 256;
+ self->currentResampling = 1;
+ self->lastResampling = 1;
self->duplex = 0;
self->input = -1;
self->output = -1;
@@ -1801,7 +1807,7 @@ Server_setSamplingRate(Server *self, PyObject *arg)
return Py_None;
}
if (arg != NULL && PyNumber_Check(arg)) {
- self->samplingRate = PyFloat_AsDouble(PyNumber_Float(arg));
+ self->samplingRate = PyFloat_AsDouble(arg);
}
else {
Server_error(self, "Sampling rate must be a number.\n");
@@ -1985,7 +1991,7 @@ Server_setAmp(Server *self, PyObject *arg)
int check = PyNumber_Check(arg);
if (check) {
- self->amp = PyFloat_AsDouble(PyNumber_Float(arg));
+ self->amp = PyFloat_AsDouble(arg);
if (self->amp != 0.0)
self->resetAmp = self->amp;
}
@@ -2081,7 +2087,7 @@ Server_setStartOffset(Server *self, PyObject *arg)
int check = PyNumber_Check(arg);
if (check) {
- self->startoffset = PyFloat_AsDouble(PyNumber_Float(arg));
+ self->startoffset = PyFloat_AsDouble(arg);
}
}
@@ -2639,14 +2645,18 @@ Server_removeStream(Server *self, int id)
int i, sid;
Stream *stream_tmp;
- for (i=0; i<self->stream_count; i++) {
- stream_tmp = (Stream *)PyList_GET_ITEM(self->streams, i);
- sid = Stream_getStreamId(stream_tmp);
- if (sid == id) {
- Server_debug(self, "Removed stream id %d\n", id);
- PySequence_DelItem(self->streams, i);
- self->stream_count--;
- break;
+ if (PyObject_HasAttrString((PyObject *)self, "streams")) {
+ for (i=0; i<self->stream_count; i++) {
+ stream_tmp = (Stream *)PyList_GetItem(self->streams, i);
+ if (stream_tmp != NULL) {
+ sid = Stream_getStreamId(stream_tmp);
+ if (sid == id) {
+ Server_debug(self, "Removed stream id %d\n", id);
+ PySequence_DelItem(self->streams, i);
+ self->stream_count--;
+ break;
+ }
+ }
}
}
@@ -2860,9 +2870,38 @@ Server_getMidiEventCount(Server *self) {
}
static PyObject *
+Server_addMidiEvent(Server *self, PyObject *args)
+{
+ int status, data1, data2;
+ PmEvent buffer;
+
+ if (! PyArg_ParseTuple(args, "iii", &status, &data1, &data2))
+ return PyInt_FromLong(-1);
+
+ buffer.timestamp = 0;
+ buffer.message = Pm_Message(status, data1, data2);
+ self->midiEvents[self->midi_count++] = buffer;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+int
+Server_getCurrentResamplingFactor(Server *self) {
+ return self->currentResampling;
+}
+
+int
+Server_getLastResamplingFactor(Server *self) {
+ return self->lastResampling;
+}
+
+static PyObject *
Server_getSamplingRate(Server *self)
{
- return PyFloat_FromDouble(self->samplingRate);
+ if (self->currentResampling < 0)
+ return PyFloat_FromDouble(self->samplingRate / -self->currentResampling);
+ else
+ return PyFloat_FromDouble(self->samplingRate * self->currentResampling);
}
static PyObject *
@@ -2886,7 +2925,30 @@ Server_getGlobalSeed(Server *self)
static PyObject *
Server_getBufferSize(Server *self)
{
- return PyInt_FromLong(self->bufferSize);
+ if (self->currentResampling < 0)
+ return PyInt_FromLong(self->bufferSize / -self->currentResampling);
+ else
+ return PyInt_FromLong(self->bufferSize * self->currentResampling);
+}
+
+static PyObject *
+Server_beginResamplingBlock(Server *self, PyObject *arg)
+{
+ if (PyInt_Check(arg)) {
+ self->lastResampling = self->currentResampling;
+ self->currentResampling = PyInt_AsLong(arg);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+Server_endResamplingBlock(Server *self)
+{
+ self->lastResampling = self->currentResampling;
+ self->currentResampling = 1;
+ Py_INCREF(Py_None);
+ return Py_None;
}
static PyObject *
@@ -2989,6 +3051,8 @@ static PyMethodDef Server_methods[] = {
{"deactivateMidi", (PyCFunction)Server_deactivateMidi, METH_NOARGS, "Deactivates midi callback."},
{"setSamplingRate", (PyCFunction)Server_setSamplingRate, METH_O, "Sets the server's sampling rate."},
{"setBufferSize", (PyCFunction)Server_setBufferSize, METH_O, "Sets the server's buffer size."},
+ {"beginResamplingBlock", (PyCFunction)Server_beginResamplingBlock, METH_O, "Starts a resampling code block."},
+ {"endResamplingBlock", (PyCFunction)Server_endResamplingBlock, METH_NOARGS, "Stops a resampling code block."},
{"setNchnls", (PyCFunction)Server_setNchnls, METH_O, "Sets the server's number of output/input channels."},
{"setIchnls", (PyCFunction)Server_setIchnls, METH_O, "Sets the server's number of input channels."},
{"setDuplex", (PyCFunction)Server_setDuplex, METH_O, "Sets the server's duplex mode (0 = only out, 1 = in/out)."},
@@ -3020,6 +3084,7 @@ static PyMethodDef Server_methods[] = {
{"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."},
+ {"addMidiEvent", (PyCFunction)Server_addMidiEvent, METH_VARARGS, "Add a midi event manually (without using portmidi callback)."},
{"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 output channels."},
diff --git a/src/objects/analysismodule.c b/src/objects/analysismodule.c
index 1ad618b..3bb24de 100644
--- a/src/objects/analysismodule.c
+++ b/src/objects/analysismodule.c
@@ -52,7 +52,9 @@ Follower_filters_i(Follower *self) {
freq = PyFloat_AS_DOUBLE(self->freq);
if (freq != self->last_freq) {
- self->factor = MYEXP(-1.0 / (self->sr / freq));
+ if (freq < 0)
+ freq = 0.0;
+ self->factor = MYEXP(-TWOPI * freq / self->sr);
self->last_freq = freq;
}
@@ -75,7 +77,9 @@ Follower_filters_a(Follower *self) {
for (i=0; i<self->bufsize; i++) {
freq = fr[i];
if (freq != self->last_freq) {
- self->factor = MYEXP(-1.0 / (self->sr / freq));
+ if (freq < 0)
+ freq = 0.0;
+ self->factor = MYEXP(-TWOPI * freq / self->sr);
self->last_freq = freq;
}
absin = in[i];
@@ -411,18 +415,18 @@ Follower2_filters_ii(Follower2 *self) {
MYFLT *in = Stream_getData((Stream *)self->input_stream);
risetime = PyFloat_AS_DOUBLE(self->risetime);
if (risetime <= 0.0)
- risetime = 0.001;
+ risetime = 0.000001;
falltime = PyFloat_AS_DOUBLE(self->falltime);
if (falltime <= 0.0)
- falltime = 0.001;
+ falltime = 0.000001;
if (risetime != self->last_risetime) {
- self->risefactor = MYEXP(-1.0 / (self->sr * risetime));
+ self->risefactor = MYEXP(-TWOPI * (1.0 / risetime) / self->sr);
self->last_risetime = risetime;
}
if (falltime != self->last_falltime) {
- self->fallfactor = MYEXP(-1.0 / (self->sr * falltime));
+ self->fallfactor = MYEXP(-TWOPI * (1.0 / falltime) / self->sr);
self->last_falltime = falltime;
}
@@ -446,19 +450,19 @@ Follower2_filters_ai(Follower2 *self) {
MYFLT *rise = Stream_getData((Stream *)self->risetime_stream);
falltime = PyFloat_AS_DOUBLE(self->falltime);
if (falltime <= 0.0)
- falltime = 0.001;
+ falltime = 0.000001;
if (falltime != self->last_falltime) {
- self->fallfactor = MYEXP(-1.0 / (self->sr * falltime));
+ self->fallfactor = MYEXP(-TWOPI * (1.0 / falltime) / self->sr);
self->last_falltime = falltime;
}
for (i=0; i<self->bufsize; i++) {
risetime = rise[i];
if (risetime <= 0.0)
- risetime = 0.001;
+ risetime = 0.000001;
if (risetime != self->last_risetime) {
- self->risefactor = MYEXP(-1.0 / (self->sr * risetime));
+ self->risefactor = MYEXP(-TWOPI * (1.0 / risetime) / self->sr);
self->last_risetime = risetime;
}
absin = in[i];
@@ -479,20 +483,20 @@ Follower2_filters_ia(Follower2 *self) {
MYFLT *in = Stream_getData((Stream *)self->input_stream);
risetime = PyFloat_AS_DOUBLE(self->risetime);
if (risetime <= 0.0)
- risetime = 0.001;
+ risetime = 0.000001;
MYFLT *fall = Stream_getData((Stream *)self->falltime_stream);
if (risetime != self->last_risetime) {
- self->risefactor = MYEXP(-1.0 / (self->sr * risetime));
+ self->risefactor = MYEXP(-TWOPI * (1.0 / risetime) / self->sr);
self->last_risetime = risetime;
}
for (i=0; i<self->bufsize; i++) {
falltime = fall[i];
if (falltime <= 0.0)
- falltime = 0.001;
+ falltime = 0.000001;
if (falltime != self->last_falltime) {
- self->fallfactor = MYEXP(-1.0 / (self->sr * falltime));
+ self->fallfactor = MYEXP(-TWOPI * (1.0 / falltime) / self->sr);
self->last_falltime = falltime;
}
absin = in[i];
@@ -517,16 +521,16 @@ Follower2_filters_aa(Follower2 *self) {
for (i=0; i<self->bufsize; i++) {
risetime = rise[i];
if (risetime <= 0.0)
- risetime = 0.001;
+ risetime = 0.000001;
if (risetime != self->last_risetime) {
- self->risefactor = MYEXP(-1.0 / (self->sr * risetime));
+ self->risefactor = MYEXP(-TWOPI * (1.0 / risetime) / self->sr);
self->last_risetime = risetime;
}
falltime = fall[i];
if (falltime <= 0.0)
- falltime = 0.001;
+ falltime = 0.000001;
if (falltime != self->last_falltime) {
- self->fallfactor = MYEXP(-1.0 / (self->sr * falltime));
+ self->fallfactor = MYEXP(-TWOPI * (1.0 / falltime) / self->sr);
self->last_falltime = falltime;
}
absin = in[i];
@@ -1078,7 +1082,7 @@ ZCross_setThresh(ZCross *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->thresh = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->thresh = PyFloat_AsDouble(arg);
}
Py_INCREF(Py_None);
@@ -1247,7 +1251,7 @@ typedef struct {
static void
Yin_process(Yin *self) {
int i, j, period, tau = 0;
- MYFLT candidate, tmp = 0.0, tmp2 = 0.0, b = 0.0;
+ MYFLT candidate, tmp = 0.0, tmp2 = 0.0;
MYFLT *in = Stream_getData((Stream *)self->input_stream);
if (self->cutoff != self->last_cutoff) {
@@ -1256,8 +1260,7 @@ Yin_process(Yin *self) {
else if (self->cutoff >= self->sr*0.5)
self->cutoff = self->sr*0.5;
self->last_cutoff = self->cutoff;
- b = 2.0 - MYCOS(TWOPI * self->cutoff / self->sr);
- self->c2 = (b - MYSQRT(b * b - 1.0));
+ self->c2 = MYEXP(-TWOPI * self->cutoff / self->sr);
}
for (i=0; i<self->bufsize; i++) {
@@ -1468,7 +1471,7 @@ Yin_setTolerance(Yin *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->tolerance = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->tolerance = PyFloat_AsDouble(arg);
}
Py_RETURN_NONE;
@@ -1485,7 +1488,7 @@ Yin_setMinfreq(Yin *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->minfreq = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->minfreq = PyFloat_AsDouble(arg);
}
Py_RETURN_NONE;
@@ -1502,7 +1505,7 @@ Yin_setMaxfreq(Yin *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->maxfreq = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->maxfreq = PyFloat_AsDouble(arg);
}
Py_RETURN_NONE;
@@ -1519,7 +1522,7 @@ Yin_setCutoff(Yin *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->cutoff = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->cutoff = PyFloat_AsDouble(arg);
}
Py_RETURN_NONE;
@@ -2239,7 +2242,7 @@ AttackDetector_setDeltime(AttackDetector *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->deltime = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->deltime = PyFloat_AsDouble(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);
@@ -2259,7 +2262,7 @@ AttackDetector_setCutoff(AttackDetector *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->cutoff = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->cutoff = PyFloat_AsDouble(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);
@@ -2279,7 +2282,7 @@ AttackDetector_setMaxthresh(AttackDetector *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->maxthresh = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->maxthresh = PyFloat_AsDouble(arg);
if (self->maxthresh < 0.0) self->maxthresh = 0.0;
else if (self->maxthresh > 18.0) self->maxthresh = 18.0;
}
@@ -2298,7 +2301,7 @@ AttackDetector_setMinthresh(AttackDetector *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->minthresh = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->minthresh = PyFloat_AsDouble(arg);
if (self->minthresh < -90.0) self->minthresh = -90.0;
else if (self->minthresh > 0.0) self->minthresh = 0.0;
}
@@ -2317,7 +2320,7 @@ AttackDetector_setReltime(AttackDetector *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->reltime = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->reltime = PyFloat_AsDouble(arg);
if (self->reltime < 0.001) self->reltime = 0.001;
self->maxtime = (long)(self->reltime * self->sr + 0.5);
}
@@ -2435,9 +2438,9 @@ AttackDetector_members, /* tp_members */
AttackDetector_new, /* tp_new */
};
-/*********************************************************************************************/
-/* Scope ********************************************************************************/
-/*********************************************************************************************/
+/**********************************/
+/********* Scope ******************/
+/**********************************/
typedef struct {
pyo_audio_HEAD
PyObject *input;
@@ -2566,7 +2569,7 @@ Scope_setLength(Scope *self, PyObject *arg)
int maxsize = (int)(self->sr * 0.25);
if (PyNumber_Check(arg)) {
- length = PyFloat_AsDouble(PyNumber_Float(arg));
+ length = PyFloat_AsDouble(arg);
self->size = (int)(length * self->sr);
if (self->size > maxsize)
self->size = maxsize;
@@ -2580,7 +2583,7 @@ static PyObject *
Scope_setGain(Scope *self, PyObject *arg)
{
if (PyNumber_Check(arg)) {
- self->gain = PyFloat_AsDouble(PyNumber_Float(arg));
+ self->gain = PyFloat_AsDouble(arg);
}
Py_INCREF(Py_None);
return Py_None;
diff --git a/src/objects/compressmodule.c b/src/objects/compressmodule.c
index f899ffd..b65373d 100644
--- a/src/objects/compressmodule.c
+++ b/src/objects/compressmodule.c
@@ -481,7 +481,7 @@ Compress_setLookAhead(Compress *self, PyObject *arg)
}
if (PyNumber_Check(arg)) {
- tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ tmp = PyFloat_AsDouble(arg);
if (tmp <= 25.0)
self->lh_delay = (long)(tmp * 0.001 * self->sr);
else
@@ -503,7 +503,7 @@ Compress_setKnee(Compress *self, PyObject *arg)
}
if (PyNumber_Check(arg)) {
- tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ tmp = PyFloat_AsDouble(arg);
if (tmp >= 0.0 && tmp <= 1.0)
self->knee = tmp;
else
@@ -1446,7 +1446,7 @@ Gate_setLookAhead(Gate *self, PyObject *arg)
}
if (PyNumber_Check(arg)) {
- tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ tmp = PyFloat_AsDouble(arg);
if (tmp <= 25.0)
self->lh_delay = (long)(tmp * 0.001 * self->sr);
else
diff --git a/src/objects/delaymodule.c b/src/objects/delaymodule.c
index aad6855..f17cc9f 100644
--- a/src/objects/delaymodule.c
+++ b/src/objects/delaymodule.c
@@ -3620,7 +3620,7 @@ SmoothDelay_setCrossfade(SmoothDelay *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->crossfade = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->crossfade = PyFloat_AsDouble(arg);
}
Py_RETURN_NONE;
diff --git a/src/objects/exprmodule.c b/src/objects/exprmodule.c
new file mode 100644
index 0000000..0f5d70d
--- /dev/null
+++ b/src/objects/exprmodule.c
@@ -0,0 +1,866 @@
+/**************************************************************************
+ * Copyright 2009-2015 Olivier Belanger *
+ * *
+ * This file is part of pyo, a python module to help digital signal *
+ * processing script creation. *
+ * *
+ * pyo is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * pyo is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with pyo. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#include <Python.h>
+#include "structmember.h"
+#include <math.h>
+#include "pyomodule.h"
+#include "streammodule.h"
+#include "servermodule.h"
+#include "dummymodule.h"
+
+// arithmetic operators
+#define OP_ADD 0
+#define OP_SUB 1
+#define OP_MUL 2
+#define OP_DIV 3
+#define OP_EXP 4
+#define OP_MOD 5
+#define OP_NEG 6
+
+// moving phase operators
+#define OP_INC 7
+#define OP_DEC 8
+#define OP_PHS 9
+
+// trigonometric functions
+#define OP_SIN 10
+#define OP_COS 11
+#define OP_TAN 12
+#define OP_TANH 13
+#define OP_ATAN 14
+#define OP_ATAN2 15
+
+// conditional operators
+#define OP_LT 40
+#define OP_LE 41
+#define OP_GT 42
+#define OP_GE 43
+#define OP_EQ 44
+#define OP_NE 45
+#define OP_IF 46
+#define OP_AND 47
+#define OP_OR 48
+
+// power and logarithmic functions
+#define OP_SQRT 50
+#define OP_LOG 51
+#define OP_LOG2 52
+#define OP_LOG10 53
+#define OP_POW 54
+#define OP_FABS 55
+#define OP_FLOOR 56
+#define OP_CEIL 57
+#define OP_EEXP 58
+#define OP_ROUND 59
+#define OP_MIN 60
+#define OP_MAX 61
+#define OP_WRAP 62
+
+// filters
+#define OP_RPOLE 70
+#define OP_RZERO 71
+
+// random functions
+#define OP_RANDF 80
+#define OP_RANDI 81
+
+// sample-and-hold functions
+#define OP_SAH 90
+
+// math constants
+#define OP_CONST 99
+#define OP_PI 100
+#define OP_TWOPI 101
+#define OP_E 102
+
+typedef struct t_expr {
+ int type_op;
+ int num;
+ int *nodes;
+ int *vars;
+ int *input;
+ int *output;
+ MYFLT *values;
+ MYFLT *previous;
+ MYFLT result;
+} expr;
+
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ PyObject *variables;
+ int count;
+ MYFLT oneOverSr;
+ MYFLT *input_buffer;
+ MYFLT *output_buffer;
+ expr lexp[1024];
+ int modebuffer[2];
+} Expr;
+
+void
+clearexpr(expr ex)
+{
+ if (ex.nodes) { free(ex.nodes); }
+ if (ex.vars) { free(ex.vars); }
+ if (ex.input) { free(ex.input); }
+ if (ex.output) { free(ex.output); }
+ if (ex.values) { free(ex.values); }
+ if (ex.previous) { free(ex.previous); }
+}
+
+expr
+initexpr(const char *op, int size)
+{
+ expr ex;
+ int i, value = -1, num = 0;
+ if (strcmp(op, "+") == 0) { value = OP_ADD; num = 2; }
+ else if (strcmp(op, "-") == 0) { value = OP_SUB; num = 2; }
+ else if (strcmp(op, "*") == 0) {value = OP_MUL; num = 2; }
+ else if (strcmp(op, "/") == 0) {value = OP_DIV; num = 2; }
+ else if (strcmp(op, "^") == 0) {value = OP_EXP; num = 2; }
+ else if (strcmp(op, "%") == 0) {value = OP_MOD; num = 2; }
+ else if (strcmp(op, "neg") == 0) {value = OP_NEG; num = 1; }
+ else if (strcmp(op, "++") == 0) {value = OP_INC; num = 2; }
+ else if (strcmp(op, "--") == 0) {value = OP_DEC; num = 2; }
+ else if (strcmp(op, "~") == 0) {value = OP_PHS; num = 2; }
+ else if (strcmp(op, "sin") == 0) {value = OP_SIN; num = 1; }
+ else if (strcmp(op, "cos") == 0) {value = OP_COS; num = 1; }
+ else if (strcmp(op, "tan") == 0) {value = OP_TAN; num = 1; }
+ else if (strcmp(op, "tanh") == 0) {value = OP_TANH; num = 1; }
+ else if (strcmp(op, "atan") == 0) {value = OP_ATAN; num = 1; }
+ else if (strcmp(op, "atan2") == 0) {value = OP_ATAN2; num = 2; }
+ else if (strcmp(op, "<") == 0) {value = OP_LT; num = 2; }
+ else if (strcmp(op, "<=") == 0) {value = OP_LE; num = 2; }
+ else if (strcmp(op, ">") == 0) {value = OP_GT; num = 2; }
+ else if (strcmp(op, ">=") == 0) {value = OP_GE; num = 2; }
+ else if (strcmp(op, "==") == 0) {value = OP_EQ; num = 2; }
+ else if (strcmp(op, "!=") == 0) {value = OP_NE; num = 2; }
+ else if (strcmp(op, "if") == 0) {value = OP_IF; num = 3; }
+ else if (strcmp(op, "and") == 0) {value = OP_AND; num = 2; }
+ else if (strcmp(op, "or") == 0) {value = OP_OR; num = 2; }
+ else if (strcmp(op, "sqrt") == 0) {value = OP_SQRT; num = 1; }
+ else if (strcmp(op, "log") == 0) {value = OP_LOG; num = 1; }
+ else if (strcmp(op, "log2") == 0) {value = OP_LOG2; num = 1; }
+ else if (strcmp(op, "log10") == 0) {value = OP_LOG10; num = 1; }
+ else if (strcmp(op, "pow") == 0) {value = OP_POW; num = 2; }
+ else if (strcmp(op, "abs") == 0) {value = OP_FABS; num = 1; }
+ else if (strcmp(op, "floor") == 0) {value = OP_FLOOR; num = 1; }
+ else if (strcmp(op, "ceil") == 0) {value = OP_CEIL; num = 1; }
+ else if (strcmp(op, "exp") == 0) {value = OP_EEXP; num = 1; }
+ else if (strcmp(op, "round") == 0) {value = OP_ROUND; num = 1; }
+ else if (strcmp(op, "min") == 0) {value = OP_MIN; num = 2; }
+ else if (strcmp(op, "max") == 0) {value = OP_MAX; num = 2; }
+ else if (strcmp(op, "wrap") == 0) {value = OP_WRAP; num = 1; }
+ else if (strcmp(op, "randf") == 0) {value = OP_RANDF; num = 2; }
+ else if (strcmp(op, "randi") == 0) {value = OP_RANDI; num = 2; }
+ else if (strcmp(op, "sah") == 0) {value = OP_SAH; num = 2; } // stream, trigger
+ else if (strcmp(op, "rpole") == 0) {value = OP_RPOLE; num = 2; }
+ else if (strcmp(op, "rzero") == 0) {value = OP_RZERO; num = 2; }
+ else if (strcmp(op, "const") == 0) {value = OP_CONST; num = 1; }
+ else if (strcmp(op, "pi") == 0) {value = OP_PI; num = 0; }
+ else if (strcmp(op, "twopi") == 0) {value = OP_TWOPI; num = 0; }
+ else if (strcmp(op, "e") == 0) {value = OP_E; num = 0; }
+ else if (size == 1) {value = OP_CONST; num = 1; }
+ ex.type_op = value;
+ ex.num = num;
+ ex.nodes = (int *)malloc(num);
+ ex.vars = (int *)malloc(num);
+ ex.input = (int *)malloc(num);
+ ex.output = (int *)malloc(num);
+ ex.values = (MYFLT *)malloc(num);
+ ex.previous = (MYFLT *)malloc(num);
+ for (i=0; i<num; i++) {
+ ex.nodes[i] = ex.vars[i] = -1;
+ ex.input[i] = ex.output[i] = 1;
+ ex.values[i] = ex.previous[i] = 0.0;
+ }
+ ex.result = 0.0;
+ return ex;
+}
+
+void
+print_expr(expr ex, int node)
+{
+ int i;
+ printf("=== Node # %d ===\n", node);
+ printf("Operator: %d\nNodes: ", ex.type_op);
+ for (i=0; i<ex.num; i++) { printf("%d, ", ex.nodes[i]); }
+ printf("\nVars: ");
+ for (i=0; i<ex.num; i++) { printf("%d, ", ex.vars[i]); }
+ printf("\nInputs: ");
+ for (i=0; i<ex.num; i++) { printf("%d, ", ex.input[i]); }
+ printf("\nOutputs: ");
+ for (i=0; i<ex.num; i++) { printf("%d, ", ex.output[i]); }
+ printf("\nValues: ");
+ for (i=0; i<ex.num; i++) { printf("%f, ", ex.values[i]); }
+ printf("\n\n");
+}
+
+static void
+Expr_process(Expr *self) {
+ int i, j, k, pos = 0;
+ MYFLT tmp = 0.0, result = 0.0;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+
+ if (self->count == 0) {
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = in[i];
+ }
+ }
+ else {
+ for (i=0; i<self->bufsize; i++) {
+ self->input_buffer[i] = in[i];
+ for (j=0; j<self->count; j++) {
+ for (k=0; k<self->lexp[j].num; k++) {
+ if (self->lexp[j].nodes[k] != -1) {
+ self->lexp[j].values[k] = self->lexp[self->lexp[j].nodes[k]].result;
+ }
+ else if (self->lexp[j].vars[k] != -1) {
+ self->lexp[j].values[k] = self->lexp[self->lexp[j].vars[k]].result;
+ }
+ else if (self->lexp[j].input[k] < 1) {
+ pos = i + self->lexp[j].input[k];
+ if (pos < 0)
+ pos += self->bufsize;
+ self->lexp[j].values[k] = self->input_buffer[pos];
+ }
+ else if (self->lexp[j].output[k] < 0) {
+ pos = i + self->lexp[j].output[k];
+ if (pos < 0)
+ pos += self->bufsize;
+ self->lexp[j].values[k] = self->output_buffer[pos];
+ }
+ }
+ switch (self->lexp[j].type_op) {
+ case OP_ADD:
+ self->lexp[j].result = self->lexp[j].values[0] + self->lexp[j].values[1];
+ break;
+ case OP_SUB:
+ self->lexp[j].result = self->lexp[j].values[0] - self->lexp[j].values[1];
+ break;
+ case OP_MUL:
+ self->lexp[j].result = self->lexp[j].values[0] * self->lexp[j].values[1];
+ break;
+ case OP_DIV:
+ self->lexp[j].result = self->lexp[j].values[0] / self->lexp[j].values[1];
+ break;
+ case OP_EXP:
+ self->lexp[j].result = MYPOW(self->lexp[j].values[0], self->lexp[j].values[1]);
+ break;
+ case OP_MOD:
+ self->lexp[j].result = MYFMOD(self->lexp[j].values[0], self->lexp[j].values[1]);
+ break;
+ case OP_NEG:
+ self->lexp[j].result = -self->lexp[j].values[0];
+ break;
+ case OP_INC:
+ self->lexp[j].result = self->lexp[j].previous[0];
+ self->lexp[j].previous[0] = MYFMOD(self->lexp[j].previous[0] + self->lexp[j].values[0], self->lexp[j].values[1]);
+ break;
+ case OP_DEC:
+ self->lexp[j].result -= self->lexp[j].values[0];
+ if (self->lexp[j].result < 0) { self->lexp[j].result += self->lexp[j].values[1]; }
+ break;
+ case OP_PHS:
+ tmp = self->lexp[j].previous[0] + self->lexp[j].values[1];
+ if (tmp >= 1) { tmp -= 1.0; }
+ self->lexp[j].result = tmp;
+ self->lexp[j].previous[0] += (self->lexp[j].values[0] * self->oneOverSr);
+ if (self->lexp[j].previous[0] >= 1) { self->lexp[j].previous[0] -= 1.0; }
+ break;
+ case OP_SIN:
+ self->lexp[j].result = MYSIN(self->lexp[j].values[0]);
+ break;
+ case OP_COS:
+ self->lexp[j].result = MYCOS(self->lexp[j].values[0]);
+ break;
+ case OP_TAN:
+ self->lexp[j].result = MYTAN(self->lexp[j].values[0]);
+ break;
+ case OP_TANH:
+ self->lexp[j].result = MYTANH(self->lexp[j].values[0]);
+ break;
+ case OP_ATAN:
+ self->lexp[j].result = MYATAN(self->lexp[j].values[0]);
+ break;
+ case OP_ATAN2:
+ self->lexp[j].result = MYATAN2(self->lexp[j].values[0], self->lexp[j].values[1]);
+ break;
+ case OP_LT:
+ self->lexp[j].result = self->lexp[j].values[0] < self->lexp[j].values[1] ? 1.0 : 0.0;
+ break;
+ case OP_LE:
+ self->lexp[j].result = self->lexp[j].values[0] <= self->lexp[j].values[1] ? 1.0 : 0.0;
+ break;
+ case OP_GT:
+ self->lexp[j].result = self->lexp[j].values[0] > self->lexp[j].values[1] ? 1.0 : 0.0;
+ break;
+ case OP_GE:
+ self->lexp[j].result = self->lexp[j].values[0] >= self->lexp[j].values[1] ? 1.0 : 0.0;
+ break;
+ case OP_EQ:
+ self->lexp[j].result = self->lexp[j].values[0] == self->lexp[j].values[1] ? 1.0 : 0.0;
+ break;
+ case OP_NE:
+ self->lexp[j].result = self->lexp[j].values[0] != self->lexp[j].values[1] ? 1.0 : 0.0;
+ break;
+ case OP_IF:
+ self->lexp[j].result = self->lexp[j].values[0] != 0 ? self->lexp[j].values[1] : self->lexp[j].values[2];
+ break;
+ case OP_AND:
+ self->lexp[j].result = self->lexp[j].values[0] != 0 && self->lexp[j].values[1] != 0 ? 1.0 : 0.0;
+ break;
+ case OP_OR:
+ self->lexp[j].result = self->lexp[j].values[0] != 0 || self->lexp[j].values[1] != 0 ? 1.0 : 0.0;
+ break;
+ case OP_SQRT:
+ self->lexp[j].result = MYSQRT(self->lexp[j].values[0]);
+ break;
+ case OP_LOG:
+ self->lexp[j].result = MYLOG(self->lexp[j].values[0]);
+ break;
+ case OP_LOG2:
+ self->lexp[j].result = MYLOG2(self->lexp[j].values[0]);
+ break;
+ case OP_LOG10:
+ self->lexp[j].result = MYLOG10(self->lexp[j].values[0]);
+ break;
+ case OP_POW:
+ self->lexp[j].result = MYPOW(self->lexp[j].values[0], self->lexp[j].values[1]);
+ break;
+ case OP_FABS:
+ self->lexp[j].result = MYFABS(self->lexp[j].values[0]);
+ break;
+ case OP_FLOOR:
+ self->lexp[j].result = MYFLOOR(self->lexp[j].values[0]);
+ break;
+ case OP_CEIL:
+ self->lexp[j].result = MYCEIL(self->lexp[j].values[0]);
+ break;
+ case OP_EEXP:
+ self->lexp[j].result = MYEXP(self->lexp[j].values[0]);
+ break;
+ case OP_ROUND:
+ self->lexp[j].result = MYROUND(self->lexp[j].values[0]);
+ break;
+ case OP_MIN:
+ self->lexp[j].result = self->lexp[j].values[0] < self->lexp[j].values[1] ? self->lexp[j].values[0] : self->lexp[j].values[1];
+ break;
+ case OP_MAX:
+ self->lexp[j].result = self->lexp[j].values[0] > self->lexp[j].values[1] ? self->lexp[j].values[0] : self->lexp[j].values[1];
+ break;
+ case OP_WRAP:
+ tmp = self->lexp[j].values[0];
+ while (tmp < 0.0) {tmp += 1.0; }
+ while (tmp >= 1.0) {tmp -= 1.0; }
+ self->lexp[j].result = tmp;
+ break;
+ case OP_RANDF:
+ self->lexp[j].result = RANDOM_UNIFORM * (self->lexp[j].values[1] - self->lexp[j].values[0]) + self->lexp[j].values[0];
+ break;
+ case OP_RANDI:
+ self->lexp[j].result = MYFLOOR(RANDOM_UNIFORM * (self->lexp[j].values[1] - self->lexp[j].values[0]) + self->lexp[j].values[0]);
+ break;
+ case OP_SAH:
+ self->lexp[j].result = self->lexp[j].values[1] < self->lexp[j].previous[1] ? self->lexp[j].values[0] : self->lexp[j].result;
+ self->lexp[j].previous[1] = self->lexp[j].values[1];
+ break;
+ case OP_RPOLE:
+ self->lexp[j].result = self->lexp[j].values[0] + self->lexp[j].result * self->lexp[j].values[1];
+ break;
+ case OP_RZERO:
+ self->lexp[j].result = self->lexp[j].values[0] - self->lexp[j].previous[0] * self->lexp[j].values[1];
+ self->lexp[j].previous[0] = self->lexp[j].values[0];
+ break;
+ case OP_CONST:
+ self->lexp[j].result = self->lexp[j].values[0];
+ break;
+ case OP_PI:
+ self->lexp[j].result = PI;
+ break;
+ case OP_TWOPI:
+ self->lexp[j].result = TWOPI;
+ break;
+ case OP_E:
+ self->lexp[j].result = E;
+ break;
+ }
+ result = self->lexp[j].result;
+ }
+ self->data[i] = self->output_buffer[i] = result;
+ }
+ }
+}
+
+static void Expr_postprocessing_ii(Expr *self) { POST_PROCESSING_II };
+static void Expr_postprocessing_ai(Expr *self) { POST_PROCESSING_AI };
+static void Expr_postprocessing_ia(Expr *self) { POST_PROCESSING_IA };
+static void Expr_postprocessing_aa(Expr *self) { POST_PROCESSING_AA };
+static void Expr_postprocessing_ireva(Expr *self) { POST_PROCESSING_IREVA };
+static void Expr_postprocessing_areva(Expr *self) { POST_PROCESSING_AREVA };
+static void Expr_postprocessing_revai(Expr *self) { POST_PROCESSING_REVAI };
+static void Expr_postprocessing_revaa(Expr *self) { POST_PROCESSING_REVAA };
+static void Expr_postprocessing_revareva(Expr *self) { POST_PROCESSING_REVAREVA };
+
+static void
+Expr_setProcMode(Expr *self)
+{
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+ self->proc_func_ptr = Expr_process;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = Expr_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = Expr_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = Expr_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = Expr_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = Expr_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = Expr_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = Expr_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = Expr_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = Expr_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+Expr_compute_next_data_frame(Expr *self)
+{
+ (*self->proc_func_ptr)(self);
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+Expr_traverse(Expr *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ Py_VISIT(self->variables);
+ return 0;
+}
+
+static int
+Expr_clear(Expr *self)
+{
+ int i;
+ pyo_CLEAR
+ for (i=0; i<self->count; i++) {
+ clearexpr(self->lexp[i]);
+ }
+ free(self->input_buffer);
+ free(self->output_buffer);
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->variables);
+ return 0;
+}
+
+static void
+Expr_dealloc(Expr* self)
+{
+ pyo_DEALLOC
+ Expr_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+Expr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i;
+ PyObject *inputtmp, *input_streamtmp, *exprtmp=NULL, *multmp=NULL, *addtmp=NULL;
+ Expr *self;
+ self = (Expr *)type->tp_alloc(type, 0);
+
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, Expr_compute_next_data_frame);
+ self->mode_func_ptr = Expr_setProcMode;
+
+ self->oneOverSr = 1.0 / self->sr;
+
+ self->variables = PyDict_New();
+
+ static char *kwlist[] = {"input", "expr", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OOO", kwlist, &inputtmp, &exprtmp, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ INIT_INPUT_STREAM
+
+ if (exprtmp) {
+ PyObject_CallMethod((PyObject *)self, "setExpr", "O", exprtmp);
+ }
+
+ 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->input_buffer = (MYFLT *)realloc(self->input_buffer, self->bufsize * sizeof(MYFLT));
+ self->output_buffer = (MYFLT *)realloc(self->output_buffer, self->bufsize * sizeof(MYFLT));
+ for (i=0; i<self->bufsize; i++) {
+ self->input_buffer[i] = self->output_buffer[i] = 0.0;
+ }
+
+ (*self->mode_func_ptr)(self);
+
+ return (PyObject *)self;
+}
+
+static PyObject * Expr_getServer(Expr* self) { GET_SERVER };
+static PyObject * Expr_getStream(Expr* self) { GET_STREAM };
+static PyObject * Expr_setMul(Expr *self, PyObject *arg) { SET_MUL };
+static PyObject * Expr_setAdd(Expr *self, PyObject *arg) { SET_ADD };
+static PyObject * Expr_setSub(Expr *self, PyObject *arg) { SET_SUB };
+static PyObject * Expr_setDiv(Expr *self, PyObject *arg) { SET_DIV };
+
+static PyObject * Expr_play(Expr *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * Expr_out(Expr *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * Expr_stop(Expr *self) { STOP };
+
+static PyObject * Expr_multiply(Expr *self, PyObject *arg) { MULTIPLY };
+static PyObject * Expr_inplace_multiply(Expr *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * Expr_add(Expr *self, PyObject *arg) { ADD };
+static PyObject * Expr_inplace_add(Expr *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * Expr_sub(Expr *self, PyObject *arg) { SUB };
+static PyObject * Expr_inplace_sub(Expr *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * Expr_div(Expr *self, PyObject *arg) { DIV };
+static PyObject * Expr_inplace_div(Expr *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+Expr_setExpr(Expr *self, PyObject *arg)
+{
+ int i, j = 0, count = 0;
+ PyObject *sentence = NULL, *exp = NULL, *explist = NULL, *tmpstr = NULL;
+ PyObject *varDict = NULL, *waitingDict = NULL, *waitingList = NULL;
+ Py_ssize_t len, start, end;
+
+ PyDict_Clear(self->variables);
+ varDict = PyDict_New();
+ waitingDict = PyDict_New();
+
+ if (PyString_Check(arg)) {
+ Py_INCREF(arg);
+ Py_XDECREF(sentence);
+ sentence = arg;
+ len = PyString_Size(sentence);
+ if (len == 0) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ if (PyUnicode_Count(sentence, PyString_FromString(")"), 0, len) != PyUnicode_Count(sentence, PyString_FromString("("), 0, len)) {
+ printf("Expr: mismatched brackets, expression bypassed.\n");
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ for (i=0; i<self->count; i++) {
+ clearexpr(self->lexp[i]);
+ }
+ self->count = 0;
+ while (PyUnicode_Find(sentence, PyString_FromString(")"), 0, len, 1) != -1) {
+ end = PyUnicode_Find(sentence, PyString_FromString(")"), 0, len, 1) + 1;
+ start = PyUnicode_Find(sentence, PyString_FromString("("), 0, end, -1);
+ exp = PySequence_GetSlice(sentence, start, end);
+ if (PyUnicode_Contains(exp, PyString_FromString("let ")) || PyUnicode_Contains(exp, PyString_FromString("var "))) {
+ sentence = PyUnicode_Concat(PySequence_GetSlice(sentence, 0, start), PySequence_GetSlice(sentence, end, len));
+ }
+ else {
+ sentence = PyUnicode_Replace(sentence, exp, PyUnicode_Format(PyString_FromString("_%d"), PyInt_FromLong(self->count)), 1);
+ }
+ exp = PyUnicode_Replace(exp, PyString_FromString("("), PyString_FromString(""), -1);
+ exp = PyUnicode_Replace(exp, PyString_FromString(")"), PyString_FromString(""), -1);
+ explist = PyUnicode_Split(exp, NULL, -1);
+ // Prepare variable from "var" function
+ if (PyUnicode_Compare(PyList_GetItem(explist, 0), PyString_FromString("var")) == 0) {
+ PyList_SetItem(explist, 0, PyString_FromString("const"));
+ PyDict_SetItem(self->variables, PyList_GetItem(explist, 1), PyInt_FromLong(self->count));
+ PySequence_DelItem(explist, 1);
+ }
+ // Prepare variable from "let" function
+ if (PyUnicode_Compare(PyList_GetItem(explist, 0), PyString_FromString("let")) == 0) {
+ PyList_SetItem(explist, 0, PyString_FromString("const"));
+ if (PyDict_GetItem(waitingDict, PyList_GetItem(explist, 1)) != NULL) {
+ waitingList = PyDict_GetItem(waitingDict, PyList_GetItem(explist, 1));
+ for (j=0; j<PyList_Size(waitingList); j++) {
+ count = PyInt_AsLong(PyTuple_GetItem(PyList_GetItem(waitingList, j), 0));
+ i = PyInt_AsLong(PyTuple_GetItem(PyList_GetItem(waitingList, j), 1));
+ self->lexp[count].vars[i] = self->count;
+ }
+ PyDict_DelItem(waitingDict, PyList_GetItem(explist, 1));
+ }
+ PyDict_SetItem(varDict, PyList_GetItem(explist, 1), PyInt_FromLong(self->count));
+ PySequence_DelItem(explist, 1);
+ }
+ // Initialize expression node
+ self->lexp[self->count] = initexpr(PyString_AsString(PyList_GetItem(explist, 0)), PyList_Size(explist));
+ if (PyList_Size(explist) == 1 && self->lexp[self->count].type_op == OP_CONST) {
+ PyList_Insert(explist, 0, PyString_FromString("const"));
+ }
+ while (PyList_Size(explist) < (self->lexp[self->count].num+1)) {
+ PyList_Append(explist, PyString_FromString("0.0"));
+ }
+ for (i=0; i<self->lexp[self->count].num; i++) {
+ if (PyUnicode_Contains(PyList_GetItem(explist, i+1), PyString_FromString("_"))) {
+ tmpstr = PyUnicode_Replace(PyList_GetItem(explist, i+1), PyString_FromString("_"), PyString_FromString(""), -1);
+ self->lexp[self->count].nodes[i] = PyInt_AsLong(PyInt_FromString(PyString_AsString(tmpstr), NULL, 0));
+ }
+ else if (PyUnicode_Contains(PyList_GetItem(explist, i+1), PyString_FromString("#"))) {
+ if (PyDict_GetItem(self->variables, PyList_GetItem(explist, i+1)) != NULL) {
+ self->lexp[self->count].vars[i] = PyInt_AsLong(PyDict_GetItem(self->variables, PyList_GetItem(explist, i+1)));
+ }
+ else if (PyDict_GetItem(varDict, PyList_GetItem(explist, i+1)) != NULL) {
+ self->lexp[self->count].vars[i] = PyInt_AsLong(PyDict_GetItem(varDict, PyList_GetItem(explist, i+1)));
+ }
+ else {
+ if (PyDict_GetItem(waitingDict, PyList_GetItem(explist, i+1)) == NULL)
+ waitingList = PyList_New(0);
+ else
+ waitingList = PyDict_GetItem(waitingDict, PyList_GetItem(explist, i+1));
+ PyList_Append(waitingList, PyTuple_Pack(2, PyInt_FromLong(self->count), PyInt_FromLong(i)));
+ PyDict_SetItem(waitingDict, PyList_GetItem(explist, i+1), waitingList);
+ }
+ }
+ else if (PyUnicode_Contains(PyList_GetItem(explist, i+1), PyString_FromString("$x"))) {
+ tmpstr = PyUnicode_Replace(PyList_GetItem(explist, i+1), PyString_FromString("$x"), PyString_FromString(""), -1);
+ tmpstr = PyUnicode_Replace(tmpstr, PyString_FromString("["), PyString_FromString(""), -1);
+ tmpstr = PyUnicode_Replace(tmpstr, PyString_FromString("]"), PyString_FromString(""), -1);
+ self->lexp[self->count].input[i] = PyInt_AsLong(PyInt_FromString(PyString_AsString(tmpstr), NULL, 0));
+ }
+ else if (PyUnicode_Contains(PyList_GetItem(explist, i+1), PyString_FromString("$y"))) {
+ tmpstr = PyUnicode_Replace(PyList_GetItem(explist, i+1), PyString_FromString("$y"), PyString_FromString(""), -1);
+ tmpstr = PyUnicode_Replace(tmpstr, PyString_FromString("["), PyString_FromString(""), -1);
+ tmpstr = PyUnicode_Replace(tmpstr, PyString_FromString("]"), PyString_FromString(""), -1);
+ self->lexp[self->count].output[i] = PyInt_AsLong(PyInt_FromString(PyString_AsString(tmpstr), NULL, 0));
+ }
+ else {
+ self->lexp[self->count].values[i] = PyFloat_AsDouble(PyFloat_FromString(PyList_GetItem(explist, i+1), NULL));
+ }
+ }
+ len = PyString_Size(sentence);
+ self->count++;
+ }
+
+ explist = PyUnicode_Split(sentence, NULL, -1);
+ if (PyList_Size(explist) == 1)
+ PyList_Insert(explist, 0, PyString_FromString("const"));
+ // Initialize last expression node
+ self->lexp[self->count] = initexpr(PyString_AsString(PyList_GetItem(explist, 0)), PyList_Size(explist));
+ for (i=0; i<self->lexp[self->count].num; i++) {
+ if (PyUnicode_Contains(PyList_GetItem(explist, i+1), PyString_FromString("_"))) {
+ tmpstr = PyUnicode_Replace(PyList_GetItem(explist, i+1), PyString_FromString("_"), PyString_FromString(""), -1);
+ self->lexp[self->count].nodes[i] = PyInt_AsLong(PyInt_FromString(PyString_AsString(tmpstr), NULL, 0));
+ }
+ else if (PyUnicode_Contains(PyList_GetItem(explist, i+1), PyString_FromString("#"))) {
+ self->lexp[self->count].vars[i] = PyInt_AsLong(PyDict_GetItem(varDict, PyList_GetItem(explist, i+1)));
+ }
+ else if (PyUnicode_Contains(PyList_GetItem(explist, i+1), PyString_FromString("$x"))) {
+ tmpstr = PyUnicode_Replace(PyList_GetItem(explist, i+1), PyString_FromString("$x"), PyString_FromString(""), -1);
+ tmpstr = PyUnicode_Replace(tmpstr, PyString_FromString("["), PyString_FromString(""), -1);
+ tmpstr = PyUnicode_Replace(tmpstr, PyString_FromString("]"), PyString_FromString(""), -1);
+ self->lexp[self->count].input[i] = PyInt_AsLong(PyInt_FromString(PyString_AsString(tmpstr), NULL, 0));
+ }
+ else if (PyUnicode_Contains(PyList_GetItem(explist, i+1), PyString_FromString("$y"))) {
+ tmpstr = PyUnicode_Replace(PyList_GetItem(explist, i+1), PyString_FromString("$y"), PyString_FromString(""), -1);
+ tmpstr = PyUnicode_Replace(tmpstr, PyString_FromString("["), PyString_FromString(""), -1);
+ tmpstr = PyUnicode_Replace(tmpstr, PyString_FromString("]"), PyString_FromString(""), -1);
+ self->lexp[self->count].output[i] = PyInt_AsLong(PyInt_FromString(PyString_AsString(tmpstr), NULL, 0));
+ }
+ else {
+ self->lexp[self->count].values[i] = PyFloat_AsDouble(PyFloat_FromString(PyList_GetItem(explist, i+1), NULL));
+ }
+ }
+
+ self->count++;
+ }
+
+ Py_XDECREF(sentence);
+ Py_XDECREF(exp);
+ Py_XDECREF(explist);
+ Py_XDECREF(tmpstr);
+ Py_XDECREF(varDict);
+ Py_XDECREF(waitingDict);
+ Py_XDECREF(waitingList);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+Expr_setVar(Expr *self, PyObject *args, PyObject *kwds)
+{
+ int index;
+ PyObject *varname = NULL, *value = NULL;
+ static char *kwlist[] = {"varname", "value", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &varname, &value))
+ Py_RETURN_NONE;
+
+ if (PyDict_GetItem(self->variables, varname)) {
+ index = PyInt_AsLong(PyDict_GetItem(self->variables, varname));
+ self->lexp[index].values[0] = PyFloat_AsDouble(value);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+Expr_printNodes(Expr *self) {
+ int i;
+ for (i=0; i<self->count; i++) {
+ print_expr(self->lexp[i], i);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+};
+
+static PyMemberDef Expr_members[] = {
+ {"server", T_OBJECT_EX, offsetof(Expr, server), 0, "Pyo server."},
+ {"stream", T_OBJECT_EX, offsetof(Expr, stream), 0, "Stream object."},
+ {"input", T_OBJECT_EX, offsetof(Expr, input), 0, "Input sound object."},
+ {"mul", T_OBJECT_EX, offsetof(Expr, mul), 0, "Mul factor."},
+ {"add", T_OBJECT_EX, offsetof(Expr, add), 0, "Add factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef Expr_methods[] = {
+ {"getServer", (PyCFunction)Expr_getServer, METH_NOARGS, "Returns server object."},
+ {"_getStream", (PyCFunction)Expr_getStream, METH_NOARGS, "Returns stream object."},
+ {"play", (PyCFunction)Expr_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+ {"out", (PyCFunction)Expr_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+ {"stop", (PyCFunction)Expr_stop, METH_NOARGS, "Stops computing."},
+ {"printNodes", (PyCFunction)Expr_printNodes, METH_NOARGS, "Print the list of nodes."},
+ {"setVar", (PyCFunction)Expr_setVar, METH_VARARGS|METH_KEYWORDS, "Sets a variable value."},
+ {"setExpr", (PyCFunction)Expr_setExpr, METH_O, "Sets a new expression."},
+ {"setMul", (PyCFunction)Expr_setMul, METH_O, "Sets oscillator mul factor."},
+ {"setAdd", (PyCFunction)Expr_setAdd, METH_O, "Sets oscillator add factor."},
+ {"setSub", (PyCFunction)Expr_setSub, METH_O, "Sets inverse add factor."},
+ {"setDiv", (PyCFunction)Expr_setDiv, METH_O, "Sets inverse mul factor."},
+ {NULL} /* Sentinel */
+};
+
+static PyNumberMethods Expr_as_number = {
+ (binaryfunc)Expr_add, /*nb_add*/
+ (binaryfunc)Expr_sub, /*nb_subtract*/
+ (binaryfunc)Expr_multiply, /*nb_multiply*/
+ (binaryfunc)Expr_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)Expr_inplace_add, /*inplace_add*/
+ (binaryfunc)Expr_inplace_sub, /*inplace_subtract*/
+ (binaryfunc)Expr_inplace_multiply, /*inplace_multiply*/
+ (binaryfunc)Expr_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 ExprType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_pyo.Expr_base", /*tp_name*/
+ sizeof(Expr), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Expr_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ &Expr_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*/
+ "Expr objects. Resolve a prefix notation sentence at audio rate.", /* tp_doc */
+ (traverseproc)Expr_traverse, /* tp_traverse */
+ (inquiry)Expr_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ Expr_methods, /* tp_methods */
+ Expr_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 */
+ Expr_new, /* tp_new */
+};
diff --git a/src/objects/fadermodule.c b/src/objects/fadermodule.c
index 2ea07e5..29e6560 100644
--- a/src/objects/fadermodule.c
+++ b/src/objects/fadermodule.c
@@ -431,6 +431,9 @@ Adsr_generate_auto(Adsr *self) {
MYFLT val, invatt, invdec, invrel;
int i;
+ if (self->currentTime > self->duration)
+ Adsr_internal_stop((Adsr *)self);
+
invatt = 1.0 / self->attack;
invdec = 1.0 / self->decay;
invrel = 1.0 / self->release;
@@ -440,10 +443,8 @@ 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
@@ -669,9 +670,11 @@ static PyObject * Adsr_inplace_div(Adsr *self, PyObject *arg) { INPLACE_DIV };
static PyObject *
Adsr_setAttack(Adsr *self, PyObject *arg)
{
- self->attack = PyFloat_AsDouble(PyNumber_Float(arg));
- if (self->attack < 0.000001)
- self->attack = 0.000001;
+ if (PyNumber_Check(arg)) {
+ self->attack = PyFloat_AsDouble(arg);
+ if (self->attack < 0.000001)
+ self->attack = 0.000001;
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -679,9 +682,11 @@ Adsr_setAttack(Adsr *self, PyObject *arg)
static PyObject *
Adsr_setDecay(Adsr *self, PyObject *arg)
{
- self->decay = PyFloat_AsDouble(PyNumber_Float(arg));
- if (self->decay < 0.000001)
- self->decay = 0.000001;
+ if (PyNumber_Check(arg)) {
+ self->decay = PyFloat_AsDouble(arg);
+ if (self->decay < 0.000001)
+ self->decay = 0.000001;
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -689,11 +694,13 @@ Adsr_setDecay(Adsr *self, PyObject *arg)
static PyObject *
Adsr_setSustain(Adsr *self, PyObject *arg)
{
- self->sustain = PyFloat_AsDouble(PyNumber_Float(arg));
- if (self->sustain < 0.0)
- self->sustain = 0.0;
- else if (self->sustain > 1.0)
- self->sustain = 1.0;
+ if (PyNumber_Check(arg)) {
+ self->sustain = PyFloat_AsDouble(arg);
+ if (self->sustain < 0.0)
+ self->sustain = 0.0;
+ else if (self->sustain > 1.0)
+ self->sustain = 1.0;
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -701,9 +708,11 @@ Adsr_setSustain(Adsr *self, PyObject *arg)
static PyObject *
Adsr_setRelease(Adsr *self, PyObject *arg)
{
- self->release = PyFloat_AsDouble(PyNumber_Float(arg));
- if (self->release < 0.000001)
- self->release = 0.000001;
+ if (PyNumber_Check(arg)) {
+ self->release = PyFloat_AsDouble(arg);
+ if (self->release < 0.000001)
+ self->release = 0.000001;
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -711,7 +720,8 @@ Adsr_setRelease(Adsr *self, PyObject *arg)
static PyObject *
Adsr_setDur(Adsr *self, PyObject *arg)
{
- self->duration = PyFloat_AsDouble(PyNumber_Float(arg));
+ if (PyNumber_Check(arg))
+ self->duration = PyFloat_AsDouble(arg);
Py_INCREF(Py_None);
return Py_None;
}
@@ -840,6 +850,7 @@ typedef struct {
int newlist;
int loop;
int listsize;
+ int okToPause;
} Linseg;
static void
@@ -852,8 +863,8 @@ Linseg_convert_pointslist(Linseg *self) {
self->times = (MYFLT *)realloc(self->times, self->listsize * sizeof(MYFLT));
for (i=0; i<self->listsize; i++) {
tup = PyList_GET_ITEM(self->pointslist, i);
- self->times[i] = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 0)));
- self->targets[i] = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 1)));
+ self->times[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 0));
+ self->targets[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 1));
}
}
@@ -867,6 +878,7 @@ Linseg_reinit(Linseg *self) {
self->currentValue = self->targets[0];
self->which = 0;
self->flag = 1;
+ self->okToPause = 1;
}
static void
@@ -882,6 +894,7 @@ Linseg_generate(Linseg *self) {
Linseg_reinit((Linseg *)self);
else {
self->flag = 0;
+ self->okToPause = 0;
self->currentValue = self->targets[self->which-1];
}
}
@@ -994,6 +1007,7 @@ Linseg_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->loop = 0;
self->newlist = 1;
+ self->okToPause = 0;
self->modebuffer[0] = 0;
self->modebuffer[1] = 0;
@@ -1049,7 +1063,20 @@ static PyObject * Linseg_play(Linseg *self, PyObject *args, PyObject *kwds)
PLAY
};
-static PyObject * Linseg_stop(Linseg *self) { STOP };
+static PyObject * Linseg_stop(Linseg *self)
+{
+ self->okToPause = 0;
+ STOP
+};
+
+static PyObject * Linseg_pause(Linseg *self)
+{
+ if (self->okToPause == 1)
+ self->flag = 1 - self->flag;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+};
static PyObject * Linseg_multiply(Linseg *self, PyObject *arg) { MULTIPLY };
static PyObject * Linseg_inplace_multiply(Linseg *self, PyObject *arg) { INPLACE_MULTIPLY };
@@ -1111,6 +1138,7 @@ static PyMethodDef Linseg_methods[] = {
{"_getStream", (PyCFunction)Linseg_getStream, METH_NOARGS, "Returns stream object."},
{"play", (PyCFunction)Linseg_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
{"stop", (PyCFunction)Linseg_stop, METH_NOARGS, "Starts fadeout and stops computing."},
+{"pause", (PyCFunction)Linseg_pause, METH_NOARGS, "Toggles between play and stop without reset."},
{"setList", (PyCFunction)Linseg_setList, METH_O, "Sets target points list."},
{"setLoop", (PyCFunction)Linseg_setLoop, METH_O, "Sets looping mode."},
{"setMul", (PyCFunction)Linseg_setMul, METH_O, "Sets Linseg mul factor."},
@@ -1226,6 +1254,7 @@ typedef struct {
double exp_tmp;
int inverse;
int inverse_tmp;
+ int okToPause;
} Expseg;
static void
@@ -1238,8 +1267,8 @@ Expseg_convert_pointslist(Expseg *self) {
self->times = (MYFLT *)realloc(self->times, self->listsize * sizeof(MYFLT));
for (i=0; i<self->listsize; i++) {
tup = PyList_GET_ITEM(self->pointslist, i);
- self->times[i] = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 0)));
- self->targets[i] = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 1)));
+ self->times[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 0));
+ self->targets[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 1));
}
}
@@ -1255,6 +1284,7 @@ Expseg_reinit(Expseg *self) {
self->flag = 1;
self->exp = self->exp_tmp;
self->inverse = self->inverse_tmp;
+ self->okToPause = 1;
}
static void
@@ -1272,6 +1302,7 @@ Expseg_generate(Expseg *self) {
else {
self->flag = 0;
self->currentValue = self->targets[self->which-1];
+ self->okToPause = 0;
}
}
else {
@@ -1397,6 +1428,7 @@ Expseg_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->newlist = 1;
self->exp = self->exp_tmp = 10;
self->inverse = self->inverse_tmp = 1;
+ self->okToPause = 0;
self->modebuffer[0] = 0;
self->modebuffer[1] = 0;
@@ -1452,7 +1484,20 @@ static PyObject * Expseg_play(Expseg *self, PyObject *args, PyObject *kwds)
PLAY
};
-static PyObject * Expseg_stop(Expseg *self) { STOP };
+static PyObject * Expseg_stop(Expseg *self)
+{
+ self->okToPause = 0;
+ STOP
+};
+
+static PyObject * Expseg_pause(Expseg *self)
+{
+ if (self->okToPause == 1)
+ self->flag = 1 - self->flag;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+};
static PyObject * Expseg_multiply(Expseg *self, PyObject *arg) { MULTIPLY };
static PyObject * Expseg_inplace_multiply(Expseg *self, PyObject *arg) { INPLACE_MULTIPLY };
@@ -1508,7 +1553,8 @@ Expseg_setExp(Expseg *self, PyObject *arg)
return Py_None;
}
- self->exp_tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ if (PyNumber_Check(arg))
+ self->exp_tmp = PyFloat_AsDouble(arg);
Py_INCREF(Py_None);
return Py_None;
@@ -1522,7 +1568,8 @@ Expseg_setInverse(Expseg *self, PyObject *arg)
return Py_None;
}
- self->inverse_tmp = PyInt_AsLong(PyNumber_Int(arg));
+ if (PyNumber_Check(arg))
+ self->inverse_tmp = PyInt_AsLong(PyNumber_Int(arg));
Py_INCREF(Py_None);
return Py_None;
@@ -1542,6 +1589,7 @@ static PyMethodDef Expseg_methods[] = {
{"_getStream", (PyCFunction)Expseg_getStream, METH_NOARGS, "Returns stream object."},
{"play", (PyCFunction)Expseg_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
{"stop", (PyCFunction)Expseg_stop, METH_NOARGS, "Starts fadeout and stops computing."},
+ {"pause", (PyCFunction)Expseg_pause, METH_NOARGS, "Toggles between play and stop without reset."},
{"setList", (PyCFunction)Expseg_setList, METH_O, "Sets target points list."},
{"setLoop", (PyCFunction)Expseg_setLoop, METH_O, "Sets looping mode."},
{"setExp", (PyCFunction)Expseg_setExp, METH_O, "Sets exponent factor."},
diff --git a/src/objects/fftmodule.c b/src/objects/fftmodule.c
index f8d6f6d..ff84c37 100644
--- a/src/objects/fftmodule.c
+++ b/src/objects/fftmodule.c
@@ -4146,7 +4146,7 @@ Spectrum_setLowbound(Spectrum *self, PyObject *arg)
{
MYFLT tmp;
if (PyNumber_Check(arg)) {
- tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ tmp = PyFloat_AsDouble(arg);
if (tmp >= 0.0 && tmp <= 0.5)
self->freqone = tmp * self->sr;
else
@@ -4169,7 +4169,7 @@ Spectrum_setHighbound(Spectrum *self, PyObject *arg)
{
MYFLT tmp;
if (PyNumber_Check(arg)) {
- tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ tmp = PyFloat_AsDouble(arg);
if (tmp >= 0.0 && tmp <= 0.5)
self->freqtwo = tmp * self->sr;
else
@@ -4231,7 +4231,7 @@ static PyObject *
Spectrum_setGain(Spectrum *self, PyObject *arg)
{
if (PyNumber_Check(arg))
- self->gain = PyFloat_AsDouble(PyNumber_Float(arg));
+ self->gain = PyFloat_AsDouble(arg);
Py_INCREF(Py_None);
return Py_None;
diff --git a/src/objects/granulatormodule.c b/src/objects/granulatormodule.c
index 6610ba3..3d49171 100644
--- a/src/objects/granulatormodule.c
+++ b/src/objects/granulatormodule.c
@@ -945,7 +945,7 @@ static PyObject *
Granulator_setBaseDur(Granulator *self, PyObject *arg)
{
if (arg != NULL)
- self->basedur = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->basedur = PyFloat_AsDouble(arg);
Py_INCREF(Py_None);
return Py_None;
@@ -1109,6 +1109,8 @@ typedef struct {
Stream *dur_stream;
PyObject *xfade;
Stream *xfade_stream;
+ MYFLT *trigsBuffer;
+ TriggerStream *trig_stream;
int xfadeshape;
int startfromloop;
int init;
@@ -1180,6 +1182,9 @@ Looper_reset(Looper *self, int x, int which, int init) {
if (self->tmpmode != self->mode[which])
self->mode[which] = self->tmpmode;
+ if (init == 0)
+ self->trigsBuffer[x] = 1.0;
+
switch (self->mode[which]) {
case 0:
self->loopstart[which] = 0;
@@ -1293,6 +1298,10 @@ Looper_transform_i(Looper *self) {
pit = pitval * tableSr / self->sr;
+ for (i=0; i<self->bufsize; i++) {
+ self->trigsBuffer[i] = 0.0;
+ }
+
if (self->active[0] == 0 && self->active[1] == 0) {
Looper_reset(self, 0, 0, 1);
}
@@ -1465,6 +1474,10 @@ Looper_transform_a(Looper *self) {
}
for (i=0; i<self->bufsize; i++) {
+ self->trigsBuffer[i] = 0.0;
+ }
+
+ for (i=0; i<self->bufsize; i++) {
self->data[i] = 0.0;
pitval = pitch[i];
if (pitval < 0.0)
@@ -1696,6 +1709,7 @@ Looper_traverse(Looper *self, visitproc visit, void *arg)
Py_VISIT(self->dur_stream);
Py_VISIT(self->xfade);
Py_VISIT(self->xfade_stream);
+ Py_VISIT(self->trig_stream);
return 0;
}
@@ -1712,6 +1726,7 @@ Looper_clear(Looper *self)
Py_CLEAR(self->dur_stream);
Py_CLEAR(self->xfade);
Py_CLEAR(self->xfade_stream);
+ Py_CLEAR(self->trig_stream);
return 0;
}
@@ -1719,6 +1734,7 @@ static void
Looper_dealloc(Looper* self)
{
pyo_DEALLOC
+ free(self->trigsBuffer);
Looper_clear(self);
self->ob_type->tp_free((PyObject*)self);
}
@@ -1796,6 +1812,15 @@ Looper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
(*self->mode_func_ptr)(self);
+ self->trigsBuffer = (MYFLT *)realloc(self->trigsBuffer, self->bufsize * sizeof(MYFLT));
+
+ for (i=0; i<self->bufsize; i++) {
+ self->trigsBuffer[i] = 0.0;
+ }
+
+ MAKE_NEW_TRIGGER_STREAM(self->trig_stream, &TriggerStreamType, NULL);
+ TriggerStream_setData(self->trig_stream, self->trigsBuffer);
+
if (self->tmpmode >= 0 && self->tmpmode < 4)
self->mode[0] = self->mode[1] = self->tmpmode;
else
@@ -1808,6 +1833,7 @@ Looper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static PyObject * Looper_getServer(Looper* self) { GET_SERVER };
static PyObject * Looper_getStream(Looper* self) { GET_STREAM };
+static PyObject * Looper_getTriggerStream(Looper* self) { GET_TRIGGER_STREAM };
static PyObject * Looper_setMul(Looper *self, PyObject *arg) { SET_MUL };
static PyObject * Looper_setAdd(Looper *self, PyObject *arg) { SET_ADD };
static PyObject * Looper_setSub(Looper *self, PyObject *arg) { SET_SUB };
@@ -2087,6 +2113,7 @@ Looper_on_reset(Looper *self) {
static PyMemberDef Looper_members[] = {
{"server", T_OBJECT_EX, offsetof(Looper, server), 0, "Pyo server."},
{"stream", T_OBJECT_EX, offsetof(Looper, stream), 0, "Stream object."},
+ {"trig_stream", T_OBJECT_EX, offsetof(Looper, trig_stream), 0, "Trigger Stream object."},
{"table", T_OBJECT_EX, offsetof(Looper, table), 0, "Sound table."},
{"pitch", T_OBJECT_EX, offsetof(Looper, pitch), 0, "Speed of the reading pointer."},
{"start", T_OBJECT_EX, offsetof(Looper, start), 0, "Position in the sound table."},
@@ -2102,6 +2129,7 @@ static PyMethodDef Looper_methods[] = {
{"setTable", (PyCFunction)Looper_setTable, METH_O, "Sets sound table."},
{"getServer", (PyCFunction)Looper_getServer, METH_NOARGS, "Returns server object."},
{"_getStream", (PyCFunction)Looper_getStream, METH_NOARGS, "Returns stream object."},
+ {"_getTriggerStream", (PyCFunction)Looper_getTriggerStream, METH_NOARGS, "Returns trigger stream object."},
{"play", (PyCFunction)Looper_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
{"out", (PyCFunction)Looper_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
{"stop", (PyCFunction)Looper_stop, METH_NOARGS, "Stops computing."},
diff --git a/src/objects/harmonizermodule.c b/src/objects/harmonizermodule.c
index 94f3c6f..2b1a24b 100644
--- a/src/objects/harmonizermodule.c
+++ b/src/objects/harmonizermodule.c
@@ -580,8 +580,16 @@ static PyObject *
Harmonizer_setWinsize(Harmonizer *self, PyObject *arg)
{
MYFLT wintmp;
- if (arg != NULL) {
- wintmp = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+
+ if (arg == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ int isNumber = PyNumber_Check(arg);
+
+ if (isNumber == 1) {
+ wintmp = PyFloat_AsDouble(arg);
if (wintmp > 0.0 && wintmp <= 1.0)
self->winsize = wintmp;
else
diff --git a/src/objects/lfomodule.c b/src/objects/lfomodule.c
index f8ccbcd..0e399e2 100644
--- a/src/objects/lfomodule.c
+++ b/src/objects/lfomodule.c
@@ -67,47 +67,47 @@ LFO_generates_ii(LFO *self) {
numh = sharp * 46.0 + 4.0;
if (numh > maxHarms)
numh = maxHarms;
- for (i=0; i<self->bufsize; i++) {
- pointer = self->pointerPos * 2.0 - 1.0;
- val = pointer - MYTANH(numh * pointer) / MYTANH(numh);
- self->data[i] = val;
- self->pointerPos += inc;
- if (self->pointerPos < 0)
- self->pointerPos += 1.0;
- else if (self->pointerPos >= 1)
- self->pointerPos -= 1.0;
- }
+ for (i=0; i<self->bufsize; i++) {
+ pointer = self->pointerPos * 2.0 - 1.0;
+ val = pointer - MYTANH(numh * pointer) / MYTANH(numh);
+ self->data[i] = val;
+ self->pointerPos += inc;
+ if (self->pointerPos < 0)
+ self->pointerPos += 1.0;
+ else if (self->pointerPos >= 1)
+ self->pointerPos -= 1.0;
+ }
break;
case 1: /* Saw down */
maxHarms = (int)(self->srOverFour/freq);
numh = sharp * 46.0 + 4.0;
if (numh > maxHarms)
numh = maxHarms;
- for (i=0; i<self->bufsize; i++) {
- pointer = self->pointerPos * 2.0 - 1.0;
- val = -(pointer - MYTANH(numh * pointer) / MYTANH(numh));
- self->data[i] = val;
- self->pointerPos += inc;
- if (self->pointerPos < 0)
- self->pointerPos += 1.0;
- else if (self->pointerPos >= 1)
- self->pointerPos -= 1.0;
- }
+ for (i=0; i<self->bufsize; i++) {
+ pointer = self->pointerPos * 2.0 - 1.0;
+ val = -(pointer - MYTANH(numh * pointer) / MYTANH(numh));
+ self->data[i] = val;
+ self->pointerPos += inc;
+ if (self->pointerPos < 0)
+ self->pointerPos += 1.0;
+ else if (self->pointerPos >= 1)
+ self->pointerPos -= 1.0;
+ }
break;
case 2: /* Square */
maxHarms = (int)(self->srOverEight/freq);
numh = sharp * 46.0 + 4.0;
if (numh > maxHarms)
numh = maxHarms;
- for (i=0; i<self->bufsize; i++) {
- val = MYATAN(numh * MYSIN(TWOPI*self->pointerPos));
- self->data[i] = val * self->oneOverPiOverTwo;
- self->pointerPos += inc;
- if (self->pointerPos < 0)
- self->pointerPos += 1.0;
- else if (self->pointerPos >= 1)
- self->pointerPos -= 1.0;
- }
+ for (i=0; i<self->bufsize; i++) {
+ val = MYATAN(numh * MYSIN(TWOPI*self->pointerPos));
+ self->data[i] = val * self->oneOverPiOverTwo;
+ self->pointerPos += inc;
+ if (self->pointerPos < 0)
+ self->pointerPos += 1.0;
+ else if (self->pointerPos >= 1)
+ self->pointerPos -= 1.0;
+ }
break;
case 3: /* Triangle */
maxHarms = (int)(self->srOverFour/freq);
@@ -116,7 +116,7 @@ LFO_generates_ii(LFO *self) {
else
numh = sharp;
for (i=0; i<self->bufsize; i++) {
- v1 = MYTAN(MYSIN(TWOPI*self->pointerPos));
+ v1 = MYTAN(MYSIN(TWOPI*self->pointerPos)) * self->oneOverPiOverTwo;
pointer = self->pointerPos + 0.25;
if (pointer > 1.0)
pointer -= 1.0;
diff --git a/src/objects/matrixmodule.c b/src/objects/matrixmodule.c
index 1b7b068..46671e7 100644
--- a/src/objects/matrixmodule.c
+++ b/src/objects/matrixmodule.c
@@ -361,7 +361,7 @@ NewMatrix_setMatrix(NewMatrix *self, PyObject *value)
for(i=0; i<self->height; i++) {
innerlist = PyList_GetItem(value, i);
for (j=0; j<self->width; j++) {
- self->data[i][j] = PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(innerlist, j)));
+ self->data[i][j] = PyFloat_AsDouble(PyList_GET_ITEM(innerlist, j));
}
}
diff --git a/src/objects/metromodule.c b/src/objects/metromodule.c
index 8efc518..a07505b 100644
--- a/src/objects/metromodule.c
+++ b/src/objects/metromodule.c
@@ -3980,7 +3980,7 @@ static PyObject *
TrigBurster_setTime(TrigBurster *self, PyObject *arg)
{
if (PyNumber_Check(arg))
- self->time = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->time = PyFloat_AsDouble(arg);
if (self->time <= 0.01)
self->time = 0.01;
@@ -4004,7 +4004,7 @@ static PyObject *
TrigBurster_setExpand(TrigBurster *self, PyObject *arg)
{
if (PyNumber_Check(arg))
- self->expand = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->expand = PyFloat_AsDouble(arg);
if (self->expand <= 0.1)
self->expand = 0.1;
@@ -4016,7 +4016,7 @@ static PyObject *
TrigBurster_setAmpfade(TrigBurster *self, PyObject *arg)
{
if (PyNumber_Check(arg))
- self->ampfade = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->ampfade = PyFloat_AsDouble(arg);
if (self->ampfade <= 0.1)
self->ampfade = 0.1;
diff --git a/src/objects/midimodule.c b/src/objects/midimodule.c
index 0bf5a3d..3997a13 100644
--- a/src/objects/midimodule.c
+++ b/src/objects/midimodule.c
@@ -664,7 +664,7 @@ Midictl_setValue(Midictl *self, PyObject *arg)
int isNum = PyNumber_Check(arg);
if (isNum == 1) {
- tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ tmp = PyFloat_AsDouble(arg);
self->oldValue = self->value = tmp;
}
@@ -685,7 +685,7 @@ Midictl_setMinScale(Midictl *self, PyObject *arg)
int isNum = PyNumber_Check(arg);
if (isNum == 1) {
- tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ tmp = PyFloat_AsDouble(arg);
self->minscale = tmp;
}
@@ -706,7 +706,7 @@ Midictl_setMaxScale(Midictl *self, PyObject *arg)
int isNum = PyNumber_Check(arg);
if (isNum == 1) {
- tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ tmp = PyFloat_AsDouble(arg);
self->maxscale = tmp;
}
@@ -1080,7 +1080,7 @@ Bendin_setBrange(Bendin *self, PyObject *arg)
int isNum = PyNumber_Check(arg);
if (isNum == 1) {
- tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ tmp = PyFloat_AsDouble(arg);
if (tmp >= 0.0 && tmp < 128.0)
self->range = tmp;
}
@@ -1447,7 +1447,7 @@ Touchin_setMinScale(Touchin *self, PyObject *arg)
int isNum = PyNumber_Check(arg);
if (isNum == 1) {
- tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ tmp = PyFloat_AsDouble(arg);
self->minscale = tmp;
}
@@ -1468,7 +1468,7 @@ Touchin_setMaxScale(Touchin *self, PyObject *arg)
int isNum = PyNumber_Check(arg);
if (isNum == 1) {
- tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ tmp = PyFloat_AsDouble(arg);
self->maxscale = tmp;
}
@@ -3030,11 +3030,13 @@ static PyObject * MidiAdsr_inplace_div(MidiAdsr *self, PyObject *arg) { INPLACE_
static PyObject *
MidiAdsr_setAttack(MidiAdsr *self, PyObject *arg)
{
- self->attack = PyFloat_AsDouble(PyNumber_Float(arg));
- if (self->attack < 0.000001)
- self->attack = 0.000001;
- self->invAttack = 1.0 / self->attack;
- self->attackPlusDecay = self->attack + self->decay;
+ if (PyNumber_Check(arg)) {
+ self->attack = PyFloat_AsDouble(arg);
+ if (self->attack < 0.000001)
+ self->attack = 0.000001;
+ self->invAttack = 1.0 / self->attack;
+ self->attackPlusDecay = self->attack + self->decay;
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -3042,11 +3044,13 @@ MidiAdsr_setAttack(MidiAdsr *self, PyObject *arg)
static PyObject *
MidiAdsr_setDecay(MidiAdsr *self, PyObject *arg)
{
- self->decay = PyFloat_AsDouble(PyNumber_Float(arg));
- if (self->decay < 0.000001)
- self->decay = 0.000001;
- self->invDecay = 1.0 / self->decay;
- self->attackPlusDecay = self->attack + self->decay;
+ if (PyNumber_Check(arg)) {
+ self->decay = PyFloat_AsDouble(arg);
+ if (self->decay < 0.000001)
+ self->decay = 0.000001;
+ self->invDecay = 1.0 / self->decay;
+ self->attackPlusDecay = self->attack + self->decay;
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -3054,11 +3058,13 @@ MidiAdsr_setDecay(MidiAdsr *self, PyObject *arg)
static PyObject *
MidiAdsr_setSustain(MidiAdsr *self, PyObject *arg)
{
- self->sustain = PyFloat_AsDouble(PyNumber_Float(arg));
- if (self->sustain < 0.0)
- self->sustain = 0.0;
- else if (self->sustain > 1.0)
- self->sustain = 1.0;
+ if (PyNumber_Check(arg)) {
+ self->sustain = PyFloat_AsDouble(arg);
+ if (self->sustain < 0.0)
+ self->sustain = 0.0;
+ else if (self->sustain > 1.0)
+ self->sustain = 1.0;
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -3066,10 +3072,12 @@ MidiAdsr_setSustain(MidiAdsr *self, PyObject *arg)
static PyObject *
MidiAdsr_setRelease(MidiAdsr *self, PyObject *arg)
{
- self->release = PyFloat_AsDouble(PyNumber_Float(arg));
- if (self->release < 0.000001)
- self->release = 0.000001;
- self->invRelease = 1.0 / self->release;
+ if (PyNumber_Check(arg)) {
+ self->release = PyFloat_AsDouble(arg);
+ if (self->release < 0.000001)
+ self->release = 0.000001;
+ self->invRelease = 1.0 / self->release;
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -3422,9 +3430,11 @@ static PyObject * MidiDelAdsr_inplace_div(MidiDelAdsr *self, PyObject *arg) { IN
static PyObject *
MidiDelAdsr_setDelay(MidiDelAdsr *self, PyObject *arg)
{
- self->delay = PyFloat_AsDouble(PyNumber_Float(arg));
- self->delayPlusAttack = self->delay + self->attack;
- self->delayPlusAttackPlusDecay = self->delay + self->attack + self->decay;
+ if (PyNumber_Check(arg)) {
+ self->delay = PyFloat_AsDouble(arg);
+ self->delayPlusAttack = self->delay + self->attack;
+ self->delayPlusAttackPlusDecay = self->delay + self->attack + self->decay;
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -3432,12 +3442,14 @@ MidiDelAdsr_setDelay(MidiDelAdsr *self, PyObject *arg)
static PyObject *
MidiDelAdsr_setAttack(MidiDelAdsr *self, PyObject *arg)
{
- self->attack = PyFloat_AsDouble(PyNumber_Float(arg));
- if (self->attack < 0.000001)
- self->attack = 0.000001;
- self->invAttack = 1.0 / self->attack;
- self->delayPlusAttack = self->delay + self->attack;
- self->delayPlusAttackPlusDecay = self->delay + self->attack + self->decay;
+ if (PyNumber_Check(arg)) {
+ self->attack = PyFloat_AsDouble(arg);
+ if (self->attack < 0.000001)
+ self->attack = 0.000001;
+ self->invAttack = 1.0 / self->attack;
+ self->delayPlusAttack = self->delay + self->attack;
+ self->delayPlusAttackPlusDecay = self->delay + self->attack + self->decay;
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -3445,11 +3457,13 @@ MidiDelAdsr_setAttack(MidiDelAdsr *self, PyObject *arg)
static PyObject *
MidiDelAdsr_setDecay(MidiDelAdsr *self, PyObject *arg)
{
- self->decay = PyFloat_AsDouble(PyNumber_Float(arg));
- if (self->decay < 0.000001)
- self->decay = 0.000001;
- self->invDecay = 1.0 / self->decay;
- self->delayPlusAttackPlusDecay = self->delay + self->attack + self->decay;
+ if (PyNumber_Check(arg)) {
+ self->decay = PyFloat_AsDouble(arg);
+ if (self->decay < 0.000001)
+ self->decay = 0.000001;
+ self->invDecay = 1.0 / self->decay;
+ self->delayPlusAttackPlusDecay = self->delay + self->attack + self->decay;
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -3457,11 +3471,13 @@ MidiDelAdsr_setDecay(MidiDelAdsr *self, PyObject *arg)
static PyObject *
MidiDelAdsr_setSustain(MidiDelAdsr *self, PyObject *arg)
{
- self->sustain = PyFloat_AsDouble(PyNumber_Float(arg));
- if (self->sustain < 0.0)
- self->sustain = 0.0;
- else if (self->sustain > 1.0)
- self->sustain = 1.0;
+ if (PyNumber_Check(arg)) {
+ self->sustain = PyFloat_AsDouble(arg);
+ if (self->sustain < 0.0)
+ self->sustain = 0.0;
+ else if (self->sustain > 1.0)
+ self->sustain = 1.0;
+ }
Py_INCREF(Py_None);
return Py_None;
}
@@ -3469,10 +3485,12 @@ MidiDelAdsr_setSustain(MidiDelAdsr *self, PyObject *arg)
static PyObject *
MidiDelAdsr_setRelease(MidiDelAdsr *self, PyObject *arg)
{
- self->release = PyFloat_AsDouble(PyNumber_Float(arg));
- if (self->release < 0.000001)
- self->release = 0.000001;
- self->invRelease = 1.0 / self->release;
+ if (PyNumber_Check(arg)) {
+ self->release = PyFloat_AsDouble(arg);
+ if (self->release < 0.000001)
+ self->release = 0.000001;
+ self->invRelease = 1.0 / self->release;
+ }
Py_INCREF(Py_None);
return Py_None;
}
diff --git a/src/objects/oscmodule.c b/src/objects/oscmodule.c
index 0cf9f58..c7417a0 100644
--- a/src/objects/oscmodule.c
+++ b/src/objects/oscmodule.c
@@ -109,24 +109,19 @@ OscReceiver_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->dict = PyDict_New();
- if (PyString_Check(pathtmp) || PyList_Check(pathtmp)) {
+ if (PyList_Check(pathtmp)) {
Py_INCREF(pathtmp);
Py_XDECREF(self->address_path);
self->address_path = pathtmp;
}
else {
- PyErr_SetString(PyExc_TypeError, "The address attributes must be a string or a list of strings.");
+ PyErr_SetString(PyExc_TypeError, "The OscReceiver_base 'address' attributes must be a list of strings and/or unicodes.");
Py_RETURN_NONE;
}
- if (PyString_Check(self->address_path)) {
- PyDict_SetItem(self->dict, self->address_path, PyFloat_FromDouble(0.));
- }
- else if (PyList_Check(self->address_path)) {
- int lsize = PyList_Size(self->address_path);
- for (i=0; i<lsize; i++) {
- PyDict_SetItem(self->dict, PyList_GET_ITEM(self->address_path, i), PyFloat_FromDouble(0.));
- }
+ int lsize = PyList_Size(self->address_path);
+ for (i=0; i<lsize; i++) {
+ PyDict_SetItem(self->dict, PyList_GET_ITEM(self->address_path, i), PyFloat_FromDouble(0.));
}
char buf[20];
@@ -142,7 +137,7 @@ static PyObject *
OscReceiver_addAddress(OscReceiver *self, PyObject *arg)
{
int i;
- if (PyString_Check(arg)) {
+ if (PyString_Check(arg) || PyUnicode_Check(arg)) {
PyDict_SetItem(self->dict, arg, PyFloat_FromDouble(0.));
}
else if (PyList_Check(arg)) {
@@ -159,7 +154,7 @@ static PyObject *
OscReceiver_delAddress(OscReceiver *self, PyObject *arg)
{
int i;
- if (PyString_Check(arg)) {
+ if (PyString_Check(arg) || PyUnicode_Check(arg)) {
PyDict_DelItem(self->dict, arg);
}
else if (PyList_Check(arg)) {
@@ -390,8 +385,8 @@ OscReceive_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
- if (! PyString_Check(pathtmp)) {
- PyErr_SetString(PyExc_TypeError, "The address attributes must be a string.");
+ if (!PyString_Check(pathtmp) && !PyUnicode_Check(pathtmp)) {
+ PyErr_SetString(PyExc_TypeError, "The address attributes must be a string or a unicode.");
Py_RETURN_NONE;
}
@@ -558,16 +553,21 @@ typedef struct {
static void
OscSend_compute_next_data_frame(OscSend *self)
{
+ char *path=NULL;
self->count++;
if (self->count >= self->bufrate) {
self->count = 0;
MYFLT *in = Stream_getData((Stream *)self->input_stream);
float value = (float)in[0];
- char *path = PyString_AsString(self->address_path);
+ if (PyString_Check(self->address_path))
+ path = PyString_AsString(self->address_path);
+ else
+ path = PyString_AsString(PyUnicode_AsASCIIString(self->address_path));
if (lo_send(self->address, path, "f", value) == -1) {
- printf("OSC error %d: %s\n", lo_address_errno(self->address), lo_address_errstr(self->address));
+ printf("OSC error %d: %s\n", lo_address_errno(self->address),
+ lo_address_errstr(self->address));
}
}
}
@@ -624,8 +624,8 @@ OscSend_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
- if (! PyString_Check(pathtmp)) {
- PyErr_SetString(PyExc_TypeError, "The address attributes must be a string.");
+ if (!PyString_Check(pathtmp) && !PyUnicode_Check(pathtmp)) {
+ PyErr_SetString(PyExc_TypeError, "The address attributes must be a string or a unicode.");
Py_RETURN_NONE;
}
@@ -742,11 +742,14 @@ OscDataSend_compute_next_data_frame(OscDataSend *self)
char *blobdata = NULL;
uint8_t midi[4];
lo_blob *blob = NULL;
-
+ char *path=NULL;
lo_message *msg;
- char *path = PyString_AsString(self->address_path);
if (self->something_to_send == 1) {
+ if (PyString_Check(self->address_path))
+ path = PyString_AsString(self->address_path);
+ else
+ path = PyString_AsString(PyUnicode_AsASCIIString(self->address_path));
msg = lo_message_new();
for (i=0; i<self->num_items; i++) {
@@ -758,10 +761,10 @@ OscDataSend_compute_next_data_frame(OscDataSend *self)
lo_message_add_int64(msg, (long)PyLong_AsLong(PyList_GET_ITEM(self->value, i)));
break;
case LO_FLOAT:
- lo_message_add_float(msg, PyFloat_AS_DOUBLE(PyList_GET_ITEM(self->value, i)));
+ lo_message_add_float(msg, (float)PyFloat_AsDouble(PyList_GET_ITEM(self->value, i)));
break;
case LO_DOUBLE:
- lo_message_add_double(msg, (double)PyFloat_AS_DOUBLE(PyList_GET_ITEM(self->value, i)));
+ lo_message_add_double(msg, (double)PyFloat_AsDouble(PyList_GET_ITEM(self->value, i)));
break;
case LO_STRING:
lo_message_add_string(msg, PyString_AsString(PyList_GET_ITEM(self->value, i)));
@@ -800,7 +803,8 @@ OscDataSend_compute_next_data_frame(OscDataSend *self)
}
}
if (lo_send_message(self->address, path, msg) == -1) {
- printf("OSC error %d: %s\n", lo_address_errno(self->address), lo_address_errstr(self->address));
+ printf("OSC error %d: %s\n", lo_address_errno(self->address),
+ lo_address_errstr(self->address));
}
self->something_to_send = 0;
lo_message_free(msg);
@@ -857,8 +861,8 @@ OscDataSend_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
- if (! PyString_Check(pathtmp)) {
- PyErr_SetString(PyExc_TypeError, "The address attributes must be a string.");
+ if (!PyString_Check(pathtmp) && !PyUnicode_Check(pathtmp)) {
+ PyErr_SetString(PyExc_TypeError, "The address attributes must be of type string or unicode.");
Py_RETURN_NONE;
}
@@ -899,7 +903,7 @@ OscDataSend_send(OscDataSend *self, PyObject *arg)
self->something_to_send = 1;
}
else
- printf("argument to send() method must be a list of values.\n");
+ printf("OscDataSend: argument to send() method must be a list of values.\n");
Py_INCREF(Py_None);
return Py_None;
@@ -975,7 +979,7 @@ int OscDataReceive_handler(const char *path, const char *types, lo_arg **argv, i
void *data, void *user_data)
{
OscDataReceive *self = user_data;
- PyObject *tup, *result=NULL;
+ PyObject *tup, *result=NULL, *address=NULL;
lo_blob *blob = NULL;
char *blobdata = NULL;
uint32_t blobsize = 0;
@@ -985,12 +989,15 @@ int OscDataReceive_handler(const char *path, const char *types, lo_arg **argv, i
Py_ssize_t lsize = PyList_Size(self->address_path);
for (i=0; i<lsize; i++) {
- if (lo_pattern_match(path, PyString_AsString(PyList_GET_ITEM(self->address_path, i)))) {
+ if (PyString_Check(PyList_GET_ITEM(self->address_path, i)))
+ address = PyList_GET_ITEM(self->address_path, i);
+ else
+ address = PyUnicode_AsASCIIString(PyList_GET_ITEM(self->address_path, i));
+ if (lo_pattern_match(path, PyString_AsString(address))) {
ok = 1;
break;
}
}
-
if (ok) {
PyTuple_SET_ITEM(tup, 0, PyString_FromString(path));
for (i=0; i<argc; i++) {
@@ -1053,6 +1060,7 @@ int OscDataReceive_handler(const char *path, const char *types, lo_arg **argv, i
Py_XDECREF(tup);
Py_XDECREF(result);
Py_XDECREF(charlist);
+ Py_XDECREF(address);
return 0;
}
@@ -1110,13 +1118,13 @@ OscDataReceive_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_XDECREF(self->callable);
self->callable = calltmp;
- if (PyString_Check(pathtmp) || PyList_Check(pathtmp)) {
+ if (PyList_Check(pathtmp)) {
Py_INCREF(pathtmp);
Py_XDECREF(self->address_path);
self->address_path = pathtmp;
}
else {
- PyErr_SetString(PyExc_TypeError, "The address attributes must be a string or a list of strings.");
+ PyErr_SetString(PyExc_TypeError, "The address attributes must be a list of strings and/or unicodes.");
Py_RETURN_NONE;
}
@@ -1138,7 +1146,7 @@ static PyObject *
OscDataReceive_addAddress(OscDataReceive *self, PyObject *arg) {
int i;
if (arg != NULL) {
- if (PyString_Check(arg))
+ if (PyString_Check(arg) || PyUnicode_Check(arg))
PyList_Append(self->address_path, arg);
else if (PyList_Check(arg)) {
Py_ssize_t len = PyList_Size(arg);
@@ -1311,32 +1319,23 @@ OscListReceiver_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->dict = PyDict_New();
- if (PyString_Check(pathtmp) || PyList_Check(pathtmp)) {
+ if (PyList_Check(pathtmp)) {
Py_INCREF(pathtmp);
Py_XDECREF(self->address_path);
self->address_path = pathtmp;
}
else {
- PyErr_SetString(PyExc_TypeError, "The address attributes must be a string or a list of strings.");
+ PyErr_SetString(PyExc_TypeError, "The address attributes must be a list of strings and/or unicodes.");
Py_RETURN_NONE;
}
- if (PyString_Check(self->address_path)) {
+ int lsize = PyList_Size(self->address_path);
+ for (i=0; i<lsize; i++) {
flist = PyList_New(self->num);
for (j=0; j<self->num; j++) {
PyList_SET_ITEM(flist, j, PyFloat_FromDouble(0.));
}
- PyDict_SetItem(self->dict, self->address_path, flist);
- }
- else if (PyList_Check(self->address_path)) {
- int lsize = PyList_Size(self->address_path);
- for (i=0; i<lsize; i++) {
- flist = PyList_New(self->num);
- for (j=0; j<self->num; j++) {
- PyList_SET_ITEM(flist, j, PyFloat_FromDouble(0.));
- }
- PyDict_SetItem(self->dict, PyList_GET_ITEM(self->address_path, i), flist);
- }
+ PyDict_SetItem(self->dict, PyList_GET_ITEM(self->address_path, i), flist);
}
char buf[20];
@@ -1354,7 +1353,7 @@ OscListReceiver_addAddress(OscListReceiver *self, PyObject *arg)
PyObject *flist;
int i, j;
- if (PyString_Check(arg)) {
+ if (PyString_Check(arg) || PyUnicode_Check(arg)) {
flist = PyList_New(self->num);
for (j=0; j<self->num; j++) {
PyList_SET_ITEM(flist, j, PyFloat_FromDouble(0.));
@@ -1379,13 +1378,14 @@ static PyObject *
OscListReceiver_delAddress(OscListReceiver *self, PyObject *arg)
{
int i;
- if (PyString_Check(arg)) {
+ if (PyString_Check(arg) || PyUnicode_Check(arg)) {
PyDict_DelItem(self->dict, arg);
}
else if (PyList_Check(arg)) {
Py_ssize_t lsize = PyList_Size(arg);
for (i=0; i<lsize; i++) {
- PyDict_DelItem(self->dict, PyList_GET_ITEM(arg, i));
+ if (PyDict_Contains(self->dict, PyList_GET_ITEM(arg, i)))
+ PyDict_DelItem(self->dict, PyList_GET_ITEM(arg, i));
}
}
Py_INCREF(Py_None);
@@ -1613,8 +1613,8 @@ OscListReceive_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
PyObject_CallMethod(self->server, "addStream", "O", self->stream);
- if (! PyString_Check(pathtmp)) {
- PyErr_SetString(PyExc_TypeError, "The address attributes must be a string.");
+ if (!PyString_Check(pathtmp) && !PyUnicode_Check(pathtmp)) {
+ PyErr_SetString(PyExc_TypeError, "OscListReceive: the address attributes must be a string or a unicode.");
Py_RETURN_NONE;
}
diff --git a/src/objects/panmodule.c b/src/objects/panmodule.c
index 4b5d858..3136b6a 100644
--- a/src/objects/panmodule.c
+++ b/src/objects/panmodule.c
@@ -2383,7 +2383,7 @@ Mixer_setTime(Mixer *self, PyObject *arg)
tmp = arg;
Py_INCREF(tmp);
if (isNumber == 1) {
- self->time = PyFloat_AS_DOUBLE(PyNumber_Float(tmp));
+ self->time = PyFloat_AsDouble(tmp);
self->timeStep = (long)(self->time * self->sr);
keys = PyDict_Keys(self->inputs);
diff --git a/src/objects/randommodule.c b/src/objects/randommodule.c
index 5fccbab..02756ee 100644
--- a/src/objects/randommodule.c
+++ b/src/objects/randommodule.c
@@ -1486,7 +1486,7 @@ Choice_setChoice(Choice *self, PyObject *arg)
self->chSize = PyList_Size(tmp);
self->choice = (MYFLT *)realloc(self->choice, self->chSize * sizeof(MYFLT));
for (i=0; i<self->chSize; i++) {
- self->choice[i] = PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(tmp, i)));
+ self->choice[i] = PyFloat_AsDouble(PyList_GET_ITEM(tmp, i));
}
(*self->mode_func_ptr)(self);
diff --git a/src/objects/recordmodule.c b/src/objects/recordmodule.c
index b612fe4..00c0fd8 100644
--- a/src/objects/recordmodule.c
+++ b/src/objects/recordmodule.c
@@ -747,7 +747,7 @@ ControlRead_setValues(ControlRead *self, PyObject *arg)
self->size = PyList_Size(arg);
self->values = (MYFLT *)realloc(self->values, self->size * sizeof(MYFLT));
for (i=0; i<self->size; i++) {
- self->values[i] = PyFloat_AS_DOUBLE(PyList_GET_ITEM(arg, i));
+ self->values[i] = PyFloat_AsDouble(PyList_GET_ITEM(arg, i));
}
Py_INCREF(Py_None);
@@ -1361,7 +1361,7 @@ NoteinRead_setValues(NoteinRead *self, PyObject *arg)
self->size = PyList_Size(arg);
self->values = (MYFLT *)realloc(self->values, self->size * sizeof(MYFLT));
for (i=0; i<self->size; i++) {
- self->values[i] = PyFloat_AS_DOUBLE(PyList_GET_ITEM(arg, i));
+ self->values[i] = PyFloat_AsDouble(PyList_GET_ITEM(arg, i));
}
Py_INCREF(Py_None);
@@ -1381,7 +1381,7 @@ NoteinRead_setTimestamps(NoteinRead *self, PyObject *arg)
self->size = PyList_Size(arg);
self->timestamps = (long *)realloc(self->timestamps, self->size * sizeof(long));
for (i=0; i<self->size; i++) {
- self->timestamps[i] = (long)(PyFloat_AS_DOUBLE(PyList_GET_ITEM(arg, i)) * self->sr);
+ self->timestamps[i] = (long)(PyFloat_AsDouble(PyList_GET_ITEM(arg, i)) * self->sr);
}
Py_INCREF(Py_None);
diff --git a/src/objects/sfplayermodule.c b/src/objects/sfplayermodule.c
index 0a9c2e7..80d94bf 100644
--- a/src/objects/sfplayermodule.c
+++ b/src/objects/sfplayermodule.c
@@ -471,7 +471,7 @@ SfPlayer_setOffset(SfPlayer *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->startPos = PyFloat_AsDouble(PyNumber_Float(arg)) * self->sr * self->srScale;
+ self->startPos = PyFloat_AsDouble(arg) * self->sr * self->srScale;
if (self->startPos < 0.0 || self->startPos >= self->sndSize)
self->startPos = 0.0;
}
diff --git a/src/objects/sigmodule.c b/src/objects/sigmodule.c
index dcc0aa0..d9cf4f6 100644
--- a/src/objects/sigmodule.c
+++ b/src/objects/sigmodule.c
@@ -589,7 +589,7 @@ SigTo_setTime(SigTo *self, PyObject *arg)
tmp = arg;
Py_INCREF(tmp);
if (isNumber == 1) {
- self->time = PyFloat_AS_DOUBLE(PyNumber_Float(tmp));
+ self->time = PyFloat_AsDouble(tmp);
}
Py_INCREF(Py_None);
@@ -959,7 +959,7 @@ VarPort_setValue(VarPort *self, PyObject *arg)
tmp = arg;
Py_INCREF(tmp);
if (isNumber == 1)
- self->value = PyFloat_AsDouble(PyNumber_Float(tmp));
+ self->value = PyFloat_AsDouble(tmp);
else
self->value = self->lastValue;
@@ -982,7 +982,7 @@ VarPort_setTime(VarPort *self, PyObject *arg)
tmp = arg;
Py_INCREF(tmp);
if (isNumber == 1) {
- self->time = PyFloat_AS_DOUBLE(PyNumber_Float(tmp));
+ self->time = PyFloat_AsDouble(tmp);
self->timeStep = (long)(self->time * self->sr);
self->timeout = (long)((self->time + 0.1) * self->sr);
}
diff --git a/src/objects/tablemodule.c b/src/objects/tablemodule.c
index d4169c2..d7f9ee4 100644
--- a/src/objects/tablemodule.c
+++ b/src/objects/tablemodule.c
@@ -143,7 +143,7 @@ HarmTable_generate(HarmTable *self) {
ampsize = PyList_Size(self->amplist);
MYFLT array[ampsize];
for(j=0; j<ampsize; j++) {
- array[j] = PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(self->amplist, j)));
+ array[j] = PyFloat_AsDouble(PyList_GET_ITEM(self->amplist, j));
}
factor = 1. / (self->size * 0.5) * PI;
@@ -398,7 +398,7 @@ ChebyTable_generate(ChebyTable *self) {
ampsize = 12;
MYFLT array[ampsize];
for(j=0; j<ampsize; j++) {
- array[j] = PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(self->amplist, j)));
+ array[j] = PyFloat_AsDouble(PyList_GET_ITEM(self->amplist, j));
}
halfsize = self->size / 2;
@@ -1077,7 +1077,7 @@ SincTable_setFreq(SincTable *self, PyObject *value)
return PyInt_FromLong(-1);
}
- self->freq = PyFloat_AsDouble(PyNumber_Float(value));
+ self->freq = PyFloat_AsDouble(value);
SincTable_generate(self);
@@ -1663,10 +1663,10 @@ LinTable_generate(LinTable *self) {
for(i=0; i<(listsize-1); i++) {
tup = PyList_GET_ITEM(self->pointslist, i);
x1 = PyInt_AsLong(PyNumber_Long(PyTuple_GET_ITEM(tup, 0)));
- x2 = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 1)));
+ x2 = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 1));
tup2 = PyList_GET_ITEM(self->pointslist, i+1);
y1 = PyInt_AsLong(PyNumber_Long(PyTuple_GET_ITEM(tup2, 0)));
- y2 = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup2, 1)));
+ y2 = PyFloat_AsDouble(PyTuple_GET_ITEM(tup2, 1));
steps = y1 - x1;
if (steps <= 0)
continue;
@@ -1963,10 +1963,10 @@ LogTable_generate(LogTable *self) {
for(i=0; i<(listsize-1); i++) {
tup = PyList_GET_ITEM(self->pointslist, i);
x1 = PyInt_AsLong(PyNumber_Long(PyTuple_GET_ITEM(tup, 0)));
- x2 = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 1)));
+ x2 = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 1));
tup2 = PyList_GET_ITEM(self->pointslist, i+1);
y1 = PyInt_AsLong(PyNumber_Long(PyTuple_GET_ITEM(tup2, 0)));
- y2 = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup2, 1)));
+ y2 = PyFloat_AsDouble(PyTuple_GET_ITEM(tup2, 1));
if (x2 <= 0)
x2 = 0.000001;
if (y2 <= 0)
@@ -2287,10 +2287,10 @@ CosTable_generate(CosTable *self) {
for(i=0; i<(listsize-1); i++) {
tup = PyList_GET_ITEM(self->pointslist, i);
x1 = PyInt_AsLong(PyNumber_Long(PyTuple_GET_ITEM(tup, 0)));
- x2 = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 1)));
+ x2 = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 1));
tup2 = PyList_GET_ITEM(self->pointslist, i+1);
y1 = PyInt_AsLong(PyNumber_Long(PyTuple_GET_ITEM(tup2, 0)));
- y2 = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup2, 1)));
+ y2 = PyFloat_AsDouble(PyTuple_GET_ITEM(tup2, 1));
steps = y1 - x1;
if (steps <= 0)
@@ -2589,10 +2589,10 @@ CosLogTable_generate(CosLogTable *self) {
for(i=0; i<(listsize-1); i++) {
tup = PyList_GET_ITEM(self->pointslist, i);
x1 = PyInt_AsLong(PyNumber_Long(PyTuple_GET_ITEM(tup, 0)));
- x2 = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 1)));
+ x2 = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 1));
tup2 = PyList_GET_ITEM(self->pointslist, i+1);
y1 = PyInt_AsLong(PyNumber_Long(PyTuple_GET_ITEM(tup2, 0)));
- y2 = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup2, 1)));
+ y2 = PyFloat_AsDouble(PyTuple_GET_ITEM(tup2, 1));
if (x2 <= 0)
x2 = 0.000001;
if (y2 <= 0)
@@ -2922,7 +2922,7 @@ CurveTable_generate(CurveTable *self) {
for (i=0; i<listsize; i++) {
tup = PyList_GET_ITEM(self->pointslist, i);
times[i+1] = PyInt_AsLong(PyNumber_Long(PyTuple_GET_ITEM(tup, 0)));
- values[i+1] = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 1)));
+ values[i+1] = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 1));
}
// sets imaginary points
@@ -3070,7 +3070,7 @@ CurveTable_setTension(CurveTable *self, PyObject *value)
return PyInt_FromLong(-1);
}
- self->tension = PyFloat_AsDouble(PyNumber_Float(value));
+ self->tension = PyFloat_AsDouble(value);
CurveTable_generate(self);
@@ -3091,7 +3091,7 @@ CurveTable_setBias(CurveTable *self, PyObject *value)
return PyInt_FromLong(-1);
}
- self->bias = PyFloat_AsDouble(PyNumber_Float(value));
+ self->bias = PyFloat_AsDouble(value);
CurveTable_generate(self);
@@ -3293,7 +3293,7 @@ ExpTable_generate(ExpTable *self) {
for (i=0; i<listsize; i++) {
tup = PyList_GET_ITEM(self->pointslist, i);
times[i] = PyInt_AsLong(PyNumber_Long(PyTuple_GET_ITEM(tup, 0)));
- values[i] = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 1)));
+ values[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 1));
}
y1 = y2 = 0.0;
@@ -3440,7 +3440,7 @@ ExpTable_setExp(ExpTable *self, PyObject *value)
return PyInt_FromLong(-1);
}
- self->exp = PyFloat_AsDouble(PyNumber_Float(value));
+ self->exp = PyFloat_AsDouble(value);
ExpTable_generate(self);
@@ -4705,7 +4705,7 @@ NewTable_setFeedback(NewTable *self, PyObject *value)
MYFLT feed;
if (PyNumber_Check(value)) {
- feed = PyFloat_AsDouble(PyNumber_Float(value));
+ feed = PyFloat_AsDouble(value);
if (feed < -1.0)
feed = -1.0;
else if (feed > 1.0)
@@ -5097,7 +5097,7 @@ AtanTable_setSlope(AtanTable *self, PyObject *value)
return PyInt_FromLong(-1);
}
- self->slope = PyFloat_AsDouble(PyNumber_Float(value));
+ self->slope = PyFloat_AsDouble(value);
if (self->slope < 0.0)
self->slope = 0.0;
else if (self->slope > 1.0)
diff --git a/src/objects/trigmodule.c b/src/objects/trigmodule.c
index 50c0a16..1c20d7b 100644
--- a/src/objects/trigmodule.c
+++ b/src/objects/trigmodule.c
@@ -201,7 +201,7 @@ TrigRandInt_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Server_generateSeed((Server *)self->server, TRIGRANDINT_ID);
if (self->modebuffer[2] == 0)
- ma = PyFloat_AS_DOUBLE(PyNumber_Float(self->max));
+ ma = PyFloat_AsDouble(self->max);
else
ma = Stream_getData((Stream *)self->max_stream)[0];
self->value = (MYFLT)((int)(rand()/((MYFLT)(RAND_MAX)+1)*ma));
@@ -779,7 +779,7 @@ TrigRand_setPort(TrigRand *self, PyObject *arg)
tmp = arg;
Py_INCREF(tmp);
if (isNumber == 1) {
- self->time = PyFloat_AS_DOUBLE(PyNumber_Float(tmp));
+ self->time = PyFloat_AsDouble(tmp);
self->timeStep = (int)(self->time * self->sr);
}
@@ -1114,7 +1114,7 @@ TrigChoice_setChoice(TrigChoice *self, PyObject *arg)
self->chSize = PyList_Size(tmp);
self->choice = (MYFLT *)realloc(self->choice, self->chSize * sizeof(MYFLT));
for (i=0; i<self->chSize; i++) {
- self->choice[i] = PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(tmp, i)));
+ self->choice[i] = PyFloat_AsDouble(PyList_GET_ITEM(tmp, i));
}
(*self->mode_func_ptr)(self);
@@ -1138,7 +1138,7 @@ TrigChoice_setPort(TrigChoice *self, PyObject *arg)
tmp = arg;
Py_INCREF(tmp);
if (isNumber == 1) {
- self->time = PyFloat_AS_DOUBLE(PyNumber_Float(tmp));
+ self->time = PyFloat_AsDouble(tmp);
self->timeStep = (int)(self->time * self->sr);
}
@@ -1974,8 +1974,8 @@ TrigLinseg_convert_pointslist(TrigLinseg *self) {
self->times = (MYFLT *)realloc(self->times, self->listsize * sizeof(MYFLT));
for (i=0; i<self->listsize; i++) {
tup = PyList_GET_ITEM(self->pointslist, i);
- self->times[i] = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 0)));
- self->targets[i] = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 1)));
+ self->times[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 0));
+ self->targets[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 1));
}
}
@@ -2359,8 +2359,8 @@ TrigExpseg_convert_pointslist(TrigExpseg *self) {
self->times = (MYFLT *)realloc(self->times, self->listsize * sizeof(MYFLT));
for (i=0; i<self->listsize; i++) {
tup = PyList_GET_ITEM(self->pointslist, i);
- self->times[i] = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 0)));
- self->targets[i] = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(tup, 1)));
+ self->times[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 0));
+ self->targets[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(tup, 1));
}
}
@@ -2622,7 +2622,8 @@ TrigExpseg_setExp(TrigExpseg *self, PyObject *arg)
return Py_None;
}
- self->exp_tmp = PyFloat_AsDouble(PyNumber_Float(arg));
+ // TODO: PyNumber_Check()
+ self->exp_tmp = PyFloat_AsDouble(arg);
Py_INCREF(Py_None);
return Py_None;
@@ -5964,7 +5965,7 @@ Iter_setChoice(Iter *self, PyObject *arg)
self->chSize = PyList_Size(tmp);
self->choice = (MYFLT *)realloc(self->choice, self->chSize * sizeof(MYFLT));
for (i=0; i<self->chSize; i++) {
- self->choice[i] = PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(tmp, i)));
+ self->choice[i] = PyFloat_AsDouble(PyList_GET_ITEM(tmp, i));
}
(*self->mode_func_ptr)(self);
diff --git a/src/objects/utilsmodule.c b/src/objects/utilsmodule.c
index 3e97eb8..1225c49 100644
--- a/src/objects/utilsmodule.c
+++ b/src/objects/utilsmodule.c
@@ -25,6 +25,7 @@
#include "streammodule.h"
#include "servermodule.h"
#include "dummymodule.h"
+#include "interpolation.h"
/************/
/* Print */
@@ -193,7 +194,7 @@ Print_setInterval(Print *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->time = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->time = PyFloat_AsDouble(arg);
}
Py_INCREF(Py_None);
@@ -507,7 +508,7 @@ Snap_setChoice(Snap *self, PyObject *arg)
self->choice = (MYFLT *)realloc(self->choice, self->chSize * sizeof(MYFLT));
for (i=0; i<self->chSize; i++) {
- self->choice[i] = PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(tmp, i)));
+ self->choice[i] = PyFloat_AsDouble(PyList_GET_ITEM(tmp, i));
}
max = self->choice[self->chSize-1];
@@ -5323,7 +5324,7 @@ MToT_setCentralKey(MToT *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- self->centralkey = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ self->centralkey = PyFloat_AsDouble(arg);
}
Py_INCREF(Py_None);
@@ -5455,4 +5456,441 @@ PyTypeObject MToTType = {
0, /* tp_init */
0, /* tp_alloc */
MToT_new, /* tp_new */
-};
\ No newline at end of file
+};
+
+/************/
+/* Resample */
+/************/
+typedef struct {
+ pyo_audio_HEAD
+ PyObject *input;
+ Stream *input_stream;
+ MYFLT **pimpulse;
+ MYFLT **pinput;
+ int factor;
+ int count;
+ int dir; // Up = 1, DOWN = 0
+ int size; // UP: 0 = zero-padding, 1 = sample-and-hold, 2+ polyphase lowpass filtering
+ // DOWN: <2 = discard extra samples, 2+ polyphase lowpass filtering
+ int modebuffer[2]; // need at least 2 slots for mul & add
+} Resample;
+
+static void
+Resample_create_impulse(Resample *self) {
+ int i, half;
+ MYFLT val, scl, sum, invSum, env, w;
+ MYFLT impulse[self->size];
+
+ half = self->size / 2;
+ sum = 0.0;
+ w = TWOPI * 0.49 / self->factor;
+
+ for (i=0; i<half; i++) {
+ env = 0.5 * (1.0 - MYCOS(TWOPI * i / self->size));
+ scl = i - half;
+ val = (MYSIN(w * scl) / scl) * env;
+ sum += val;
+ impulse[i] = val;
+ }
+ sum *= 2.0;
+ sum += w;
+ invSum = 1.0 / sum;
+ impulse[half] = w * invSum;
+ for (i=0; i<half; i++) {
+ impulse[i] *= invSum;
+ }
+ for (i=half+1; i<self->size; i++) {
+ impulse[i] = impulse[self->size-i];
+ }
+
+ /* Create sub-filters. */
+ for (i=0; i<self->size; i++) {
+ self->pimpulse[i%self->factor][(int)(i/self->factor)] = impulse[i];
+ }
+}
+
+static void
+Resample_downsample(Resample *self) {
+ int i, j, k, tmp_count, len;
+ MYFLT filtout;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+
+ len = self->size / self->factor;
+
+ if (self->size <= self->factor) {
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = in[i * self->factor];
+ }
+ }
+ else {
+ for (i=0; i<self->bufsize; i++) {
+ self->data[i] = 0.0;
+ for (j=0; j<self->factor; j++) { // for each polyphase sub-filter...
+ filtout = 0.0;
+ tmp_count = self->count;
+ for (k=0; k<len; k++) { // ... apply filter...
+ if (tmp_count < 0)
+ tmp_count += len;
+ filtout += self->pinput[j][tmp_count--] * self->pimpulse[j][k];
+ }
+ self->data[i] += filtout; // ... and sum.
+ }
+
+ // Input decomposition (input delay line in reverse order).
+ self->count++;
+ if (self->count == len)
+ self->count = 0;
+ for (j=0; j<self->factor; j++) {
+ self->pinput[self->factor-1-j][self->count] = in[i*self->factor+j];
+ }
+ }
+ }
+}
+
+static void
+Resample_upsample(Resample *self) {
+ int i, j, k, tmp_count, len;
+ MYFLT filtout;
+ MYFLT *in = Stream_getData((Stream *)self->input_stream);
+
+ len = self->size / self->factor;
+
+ if (self->size == 0) {
+ for (i=0; i<(self->bufsize/self->factor); i++) {
+ j = i*self->factor;
+ self->data[j] = in[i];
+ for (k=1; k<self->factor; k++) {
+ self->data[j+k] = 0.0;
+ }
+ }
+ } else if (self->size == self->factor) {
+ for (i=0; i<(self->bufsize/self->factor); i++) {
+ for (k=0; k<self->factor; k++) {
+ self->data[i*self->factor+k] = in[i];
+ }
+ }
+ } else {
+ for (i=0; i<self->bufsize/self->factor; i++) {
+ for(j=0; j<self->factor; j++) { // for each polyphase sub-filter...
+ filtout = 0.0;
+ tmp_count = self->count;
+ for (k=0; k<len; k++) { // ... apply filter...
+ if (tmp_count < 0)
+ tmp_count += len;
+ filtout += self->pinput[j][tmp_count--] * self->pimpulse[j][k];
+ }
+ self->data[i*self->factor+j] = filtout;
+ }
+
+ self->count++;
+ if (self->count == len)
+ self->count = 0;
+ for (j=0; j<self->factor; j++) {
+ self->pinput[self->factor-1-j][self->count] = in[i];
+ }
+ }
+ }
+}
+
+static void
+Resample_process(Resample *self) {
+ if (self->dir == 0)
+ Resample_downsample(self);
+ else
+ Resample_upsample(self);
+}
+
+static void Resample_postprocessing_ii(Resample *self) { POST_PROCESSING_II };
+static void Resample_postprocessing_ai(Resample *self) { POST_PROCESSING_AI };
+static void Resample_postprocessing_ia(Resample *self) { POST_PROCESSING_IA };
+static void Resample_postprocessing_aa(Resample *self) { POST_PROCESSING_AA };
+static void Resample_postprocessing_ireva(Resample *self) { POST_PROCESSING_IREVA };
+static void Resample_postprocessing_areva(Resample *self) { POST_PROCESSING_AREVA };
+static void Resample_postprocessing_revai(Resample *self) { POST_PROCESSING_REVAI };
+static void Resample_postprocessing_revaa(Resample *self) { POST_PROCESSING_REVAA };
+static void Resample_postprocessing_revareva(Resample *self) { POST_PROCESSING_REVAREVA };
+
+static void
+Resample_setProcMode(Resample *self)
+{
+ int muladdmode;
+ muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+ self->proc_func_ptr = Resample_process;
+
+ switch (muladdmode) {
+ case 0:
+ self->muladd_func_ptr = Resample_postprocessing_ii;
+ break;
+ case 1:
+ self->muladd_func_ptr = Resample_postprocessing_ai;
+ break;
+ case 2:
+ self->muladd_func_ptr = Resample_postprocessing_revai;
+ break;
+ case 10:
+ self->muladd_func_ptr = Resample_postprocessing_ia;
+ break;
+ case 11:
+ self->muladd_func_ptr = Resample_postprocessing_aa;
+ break;
+ case 12:
+ self->muladd_func_ptr = Resample_postprocessing_revaa;
+ break;
+ case 20:
+ self->muladd_func_ptr = Resample_postprocessing_ireva;
+ break;
+ case 21:
+ self->muladd_func_ptr = Resample_postprocessing_areva;
+ break;
+ case 22:
+ self->muladd_func_ptr = Resample_postprocessing_revareva;
+ break;
+ }
+}
+
+static void
+Resample_compute_next_data_frame(Resample *self)
+{
+ (*self->proc_func_ptr)(self);
+ (*self->muladd_func_ptr)(self);
+}
+
+static int
+Resample_traverse(Resample *self, visitproc visit, void *arg)
+{
+ pyo_VISIT
+ Py_VISIT(self->input);
+ Py_VISIT(self->input_stream);
+ return 0;
+}
+
+static int
+Resample_clear(Resample *self)
+{
+ pyo_CLEAR
+ Py_CLEAR(self->input);
+ Py_CLEAR(self->input_stream);
+ return 0;
+}
+
+static void
+Resample_dealloc(Resample* self)
+{
+ int i;
+ pyo_DEALLOC
+ if (self->size > 0) {
+ for (i=0; i<self->factor; i++) {
+ free(self->pimpulse[i]);
+ free(self->pinput[i]);
+ }
+ free(self->pimpulse);
+ free(self->pinput);
+ }
+ Resample_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+Resample_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int i, j, lfac, cfac, mode;
+ PyObject *inputtmp, *input_streamtmp, *multmp=NULL, *addtmp=NULL;
+ Resample *self;
+ self = (Resample *)type->tp_alloc(type, 0);
+
+ self->factor = 1;
+ self->size = 0;
+ self->count = 0;
+ self->dir = 0;
+ self->modebuffer[0] = 0;
+ self->modebuffer[1] = 0;
+
+ static char *kwlist[] = {"input", "mode", "mul", "add", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|iOO", kwlist, &inputtmp, &mode, &multmp, &addtmp))
+ Py_RETURN_NONE;
+
+ INIT_INPUT_STREAM
+
+ lfac = Server_getLastResamplingFactor((Server *)PyServer_get_server());
+ cfac = Server_getCurrentResamplingFactor((Server *)PyServer_get_server());
+
+ if (lfac == 1) {
+ if (cfac < 0) {
+ self->dir = 0;
+ cfac = -cfac;
+ }
+ else
+ self->dir = 1;
+ self->factor = cfac;
+ }
+ else if (cfac == 1) {
+ if (lfac < 0) {
+ self->dir = 1;
+ lfac = -lfac;
+ }
+ else
+ self->dir = 0;
+ self->factor = lfac;
+ }
+
+ self->size = self->factor * mode;
+
+ INIT_OBJECT_COMMON
+ Stream_setFunctionPtr(self->stream, Resample_compute_next_data_frame);
+ self->mode_func_ptr = Resample_setProcMode;
+
+ if (self->size > self->factor) {
+ self->pimpulse = (MYFLT **)realloc(self->pimpulse, self->factor * sizeof(MYFLT *));
+ self->pinput = (MYFLT **)realloc(self->pinput, self->factor * sizeof(MYFLT *));
+ for (j=0; j<self->factor; j++) {
+ self->pimpulse[j] = (MYFLT *)malloc(self->size / self->factor * sizeof(MYFLT));
+ self->pinput[j] = (MYFLT *)malloc(self->size / self->factor * sizeof(MYFLT));
+ for (i=0; i<self->size/self->factor; i++) {
+ self->pinput[j][i] = 0.0;
+ }
+ }
+ Resample_create_impulse(self);
+ }
+
+ 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 * Resample_getServer(Resample* self) { GET_SERVER };
+static PyObject * Resample_getStream(Resample* self) { GET_STREAM };
+static PyObject * Resample_setMul(Resample *self, PyObject *arg) { SET_MUL };
+static PyObject * Resample_setAdd(Resample *self, PyObject *arg) { SET_ADD };
+static PyObject * Resample_setSub(Resample *self, PyObject *arg) { SET_SUB };
+static PyObject * Resample_setDiv(Resample *self, PyObject *arg) { SET_DIV };
+
+static PyObject * Resample_play(Resample *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * Resample_out(Resample *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * Resample_stop(Resample *self) { STOP };
+
+static PyObject * Resample_multiply(Resample *self, PyObject *arg) { MULTIPLY };
+static PyObject * Resample_inplace_multiply(Resample *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * Resample_add(Resample *self, PyObject *arg) { ADD };
+static PyObject * Resample_inplace_add(Resample *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * Resample_sub(Resample *self, PyObject *arg) { SUB };
+static PyObject * Resample_inplace_sub(Resample *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * Resample_div(Resample *self, PyObject *arg) { DIV };
+static PyObject * Resample_inplace_div(Resample *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef Resample_members[] = {
+{"server", T_OBJECT_EX, offsetof(Resample, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(Resample, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(Resample, input), 0, "Input sound object."},
+{"mul", T_OBJECT_EX, offsetof(Resample, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(Resample, add), 0, "Add factor."},
+{NULL} /* Sentinel */
+};
+
+static PyMethodDef Resample_methods[] = {
+{"getServer", (PyCFunction)Resample_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)Resample_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)Resample_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)Resample_stop, METH_NOARGS, "Stops computing."},
+{"out", (PyCFunction)Resample_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"setMul", (PyCFunction)Resample_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)Resample_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)Resample_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)Resample_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL} /* Sentinel */
+};
+
+static PyNumberMethods Resample_as_number = {
+(binaryfunc)Resample_add, /*nb_add*/
+(binaryfunc)Resample_sub, /*nb_subtract*/
+(binaryfunc)Resample_multiply, /*nb_multiply*/
+(binaryfunc)Resample_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)Resample_inplace_add, /*inplace_add*/
+(binaryfunc)Resample_inplace_sub, /*inplace_subtract*/
+(binaryfunc)Resample_inplace_multiply, /*inplace_multiply*/
+(binaryfunc)Resample_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 ResampleType = {
+PyObject_HEAD_INIT(NULL)
+0, /*ob_size*/
+"_pyo.Resample_base", /*tp_name*/
+sizeof(Resample), /*tp_basicsize*/
+0, /*tp_itemsize*/
+(destructor)Resample_dealloc, /*tp_dealloc*/
+0, /*tp_print*/
+0, /*tp_getattr*/
+0, /*tp_setattr*/
+0, /*tp_compare*/
+0, /*tp_repr*/
+&Resample_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*/
+"Resample objects. Performs resampling of an audio signal.", /* tp_doc */
+(traverseproc)Resample_traverse, /* tp_traverse */
+(inquiry)Resample_clear, /* tp_clear */
+0, /* tp_richcompare */
+0, /* tp_weaklistoffset */
+0, /* tp_iter */
+0, /* tp_iternext */
+Resample_methods, /* tp_methods */
+Resample_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 */
+Resample_new, /* tp_new */
+};
diff --git a/src/objects/wgverbmodule.c b/src/objects/wgverbmodule.c
index b1b304d..0b9dba5 100644
--- a/src/objects/wgverbmodule.c
+++ b/src/objects/wgverbmodule.c
@@ -1725,7 +1725,7 @@ STReverb_setRoomSize(STReverb *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- roomSize = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ roomSize = PyFloat_AsDouble(arg);
if (roomSize < 0.25)
roomSize = 0.25;
else if (roomSize > 4.0)
@@ -1777,7 +1777,7 @@ STReverb_setFirstRefGain(STReverb *self, PyObject *arg)
int isNumber = PyNumber_Check(arg);
if (isNumber == 1) {
- tmp = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+ tmp = PyFloat_AsDouble(arg);
self->firstRefGain = MYPOW(10.0, tmp * 0.05);
}
diff --git a/utils/E-Pyo.py b/utils/E-Pyo.py
index 011ffad..dc85faa 100755
--- a/utils/E-Pyo.py
+++ b/utils/E-Pyo.py
@@ -928,9 +928,9 @@ class RunningThread(threading.Thread):
self.terminated = True
if PLATFORM == "win32":
try:
- os.system("tskill %d" % self.proc.pid)
+ os.system("Taskkill /PID %d /F" % self.proc.pid)
except:
- print "'tskill' doesn't seem to be installed on the system. It is needed to be able to kill a process."
+ print '"Taskkill" does not succeed to kill the process %d.' % self.proc.pid
else:
self.proc.terminate()
if self.proc.poll() == None:
@@ -954,7 +954,7 @@ class RunningThread(threading.Thread):
self.proc = subprocess.Popen(['%s -u "%s"' % (WHICH_PYTHON, self.path)], cwd=self.cwd,
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
elif PLATFORM == "win32":
- self.proc = subprocess.Popen([WHICH_PYTHON, "-u", self.path], cwd=self.cwd, shell=False,
+ self.proc = subprocess.Popen([WHICH_PYTHON, "-u", self.path], cwd=self.cwd, shell=False, # TODO: shell=True ?
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
self.proc = subprocess.Popen([WHICH_PYTHON, "-u", self.path], cwd=self.cwd,
@@ -3217,7 +3217,7 @@ class MainFrame(wx.Frame):
midiInDriverIndex = driverIndexes[driverList.index(preferedDriver)]
with open(os.path.join(TEMP_PATH, "background_server.py"), "w") as f:
- f.write("print 'Starting background server...'\nimport time\nfrom pyo import *\n")
+ f.write("print 'Starting background server...'\nimport time, sys, os\nsys.path.append(os.getcwd())\nfrom pyo import *\n")
f.write("s = Server(%s)\n" % BACKGROUND_SERVER_ARGS)
if outDriverIndex != -1:
f.write("s.setOutputDevice(%d)\n" % outDriverIndex)
diff --git a/utils/epyo_builder_OSX.sh b/utils/epyo_builder_OSX.sh
index 463cbf8..74cfebf 100755
--- a/utils/epyo_builder_OSX.sh
+++ b/utils/epyo_builder_OSX.sh
@@ -4,13 +4,12 @@ cp Tutorial_01_RingMod.py Resources/
cp Tutorial_02_Flanger.py Resources/
cp Tutorial_03_TriTable.py Resources/
cp *.icns Resources/
-svn export ../examples examples/
-cp -R examples Resources/
+cp -R ../examples Resources/
cp -R snippets Resources/
cp -R styles Resources/
rm -rf build dist
-py2applet --make-setup E-Pyo.py Resources/*
+py2applet --make-setup --argv-emulation=0 E-Pyo.py Resources/*
python setup.py py2app --plist=info.plist
rm -f setup.py
rm -rf build
@@ -18,7 +17,7 @@ mv dist E-Pyo_OSX
if cd E-Pyo_OSX;
then
- find . -name .svn -depth -exec rm -rf {} \
+ find . -name .git -depth -exec rm -rf {} \
find . -name *.pyc -depth -exec rm -f {} \
find . -name .* -depth -exec rm -f {} \;
else
@@ -41,4 +40,3 @@ cp -R E-Pyo_OSX/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 8241966..eeb85e7 100644
--- a/utils/epyo_builder_win32.py
+++ b/utils/epyo_builder_win32.py
@@ -9,12 +9,10 @@ shutil.copy("Tutorial_02_Flanger.py", "Resources")
shutil.copy("Tutorial_03_TriTable.py", "Resources")
shutil.copy("E-PyoIcon.ico", "Resources")
shutil.copy("E-PyoIconDoc.ico", "Resources")
+shutil.copytree("../examples", "Resources/examples")
+shutil.copytree("snippets", "Resources/snippets")
+shutil.copytree("styles", "Resources/styles")
-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\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)
diff --git a/utils/info.plist b/utils/info.plist
index 70c56f7..843e284 100644
--- a/utils/info.plist
+++ b/utils/info.plist
@@ -32,17 +32,17 @@
<key>CFBundleIdentifier</key>
<string>org.pythonmac.unspecified.E-Pyo</string>
<key>CFBundleInfoDictionaryVersion</key>
- <string>0.7.6</string>
+ <string>0.7.8</string>
<key>CFBundleName</key>
<string>E-Pyo</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>0.7.6</string>
+ <string>0.7.8</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
- <string>0.7.6</string>
+ <string>0.7.8</string>
<key>LSHasLocalizedDisplayName</key>
<false/>
<key>NSAppleScriptEnabled</key>
--
python-pyo packaging
More information about the pkg-multimedia-commits
mailing list