[SCM] python-pyo/master: New release: 0.8.4.
tiago at users.alioth.debian.org
tiago at users.alioth.debian.org
Wed May 10 00:22:33 UTC 2017
The following commit has been merged in the master branch:
commit abf21f925615014c94e9ffd3c61db46bf1f118be
Author: Tiago Bortoletto Vaz <tiago at debian.org>
Date: Tue Mar 28 12:19:35 2017 -0400
New release: 0.8.4.
diff --git a/ChangeLog b/ChangeLog
index 6a5832f..c55041e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2017-03-24 belangeo <belangeo at gmail.com>
+
+ * Upgraded version number to 0.8.4.
+
+2017-03-23 belangeo <belangeo at gmail.com>
+
+ * Added `id` and `object` attributes to wxgui's object events.
+
+2017-03-22 belangeo <belangeo at gmail.com>
+
+ * Added setJackInputPortNames and setJackOutputPortNames methods to the
+ Server object. This allow the user to rename jack input/output ports.
+
+2017-03-21 belangeo <belangeo at gmail.com>
+
+ * Updated portaudio interface to make it much more secure.
+
+2017-03-20 belangeo <belangeo at gmail.com>
+
+ * Added setIsJackTransportSlave method to Server object (it allows to
+ start/stop the Server from jack transport).
+
+2017-03-17 belangeo <belangeo at gmail.com>
+
+ * Fixed GIL conflicts with portaudio, portmidi and jack library calls.
+
2017-03-11 belangeo <belangeo at gmail.com>
* Added a setKeepLast method to TableRead object (will hold last value).
@@ -30,6 +56,11 @@
* Added examples about multicore audio programming with pyo.
+2017-02-14 belangeo <belangeo at gmail.com>
+
+ * Fixed segfault in MidiListener callback function with python3.
+ * Fixed string versus unicode in MidiDispatcher's getDeviceInfos method.
+
2017-02-13 belangeo <belangeo at gmail.com>
* Final revision for version 0.8.3.
diff --git a/TODO.md b/TODO.md
index 6a0fe34..c0942fc 100644
--- a/TODO.md
+++ b/TODO.md
@@ -22,7 +22,6 @@ Server
- Remove, if possible, PyGILState_Ensure/PyGILState_Release from
the process_buffers function.
-
Examples
--------
@@ -37,7 +36,9 @@ Objects
Where `inputs` are a list of trigger objects and `values` (list of floats)
the corresponding values to output depending which trigger has been detected.
A trigger from the second object will make the object output the second value
- from the list.
+ from the list.
+
+- Added random distribution in SfMarkerShuffler.
MIDI
----
diff --git a/debian/changelog b/debian/changelog
index 58547a2..c8d1062 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+python-pyo (0.8.4-1) unstable; urgency=medium
+
+ * New upstream release.
+
+ -- Tiago Bortoletto Vaz <tiago at debian.org> Tue, 28 Mar 2017 12:16:45 -0400
+
python-pyo (0.8.3+git20170311.01-1) unstable; urgency=medium
* Added a setKeepLast method to TableRead object (will hold last value).
diff --git a/doc-sphinx/source/index.rst b/doc-sphinx/source/index.rst
index 7cb051b..936df77 100644
--- a/doc-sphinx/source/index.rst
+++ b/doc-sphinx/source/index.rst
@@ -3,7 +3,7 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
-Welcome to the pyo 0.8.3 documentation
+Welcome to the pyo 0.8.4 documentation
===================================================
.. image:: E-PyoIcon.png
diff --git a/examples/algorithmic/03_melody_algo.py b/examples/algorithmic/03_melody_algo.py
index c989dc3..bdda065 100644
--- a/examples/algorithmic/03_melody_algo.py
+++ b/examples/algorithmic/03_melody_algo.py
@@ -7,7 +7,7 @@ The Melo class records 16 notes in a table and reads it at variable speed.
from pyo import *
import random
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
SCALES = [[0,2,5,7,9,11], [0,2,3,7,8,11], [0,3,5,7,8,10]]
diff --git a/examples/algorithmic/04_drum_machine.py b/examples/algorithmic/04_drum_machine.py
index bff2b6a..3b52f29 100644
--- a/examples/algorithmic/04_drum_machine.py
+++ b/examples/algorithmic/04_drum_machine.py
@@ -25,7 +25,7 @@ presets = [[[16, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0],
[16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0],
[16, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1]]]
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
tm = Xnoise(dist=9, freq=2.34, x1=.5, x2=3, mul=.0025, add=.12)
b = Beat(time=tm, w1=[90,30,30,20], w2=[30,90,50,40], w3=[0,30,30,40])
diff --git a/examples/control/03_table_grapher.py b/examples/control/03_table_grapher.py
index 5e9b05c..f33128f 100644
--- a/examples/control/03_table_grapher.py
+++ b/examples/control/03_table_grapher.py
@@ -18,7 +18,7 @@ http://www.wxpython.org/
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
NOTE_DUR = 2
diff --git a/examples/control/04_set_example.py b/examples/control/04_set_example.py
index 8e86ab9..dd303f3 100644
--- a/examples/control/04_set_example.py
+++ b/examples/control/04_set_example.py
@@ -9,7 +9,7 @@ call reset() to get back initial values.
from pyo import *
from random import uniform
-s = Server(sr=44100, nchnls=2, buffersize=1024, duplex=0).boot()
+s = Server(duplex=0).boot()
a = FM(carrier=[uniform(197,203) for i in range(10)],
ratio=[uniform(0.49,0.51) for i in range(10)],
diff --git a/examples/control/05_mixer.py b/examples/control/05_mixer.py
index 108ea2b..4cf4f52 100644
--- a/examples/control/05_mixer.py
+++ b/examples/control/05_mixer.py
@@ -7,7 +7,7 @@ Mixing multiple inputs to multiple outputs with fade time.
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
# Inputs
a = SfPlayer("../snds/ounkmaster.aif", loop=True, mul=.3)
diff --git a/examples/control/06_lfo_controls.py b/examples/control/06_lfo_controls.py
index 3a92ca2..893363c 100644
--- a/examples/control/06_lfo_controls.py
+++ b/examples/control/06_lfo_controls.py
@@ -6,7 +6,7 @@ Audio control with LFOs.
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
# LFO (sine wave) +/- 5 (mul) around 10 (add), range = 5 -> 15.
# Control the frequency of the square wave LFO.
diff --git a/examples/effects/01_flanger.py b/examples/effects/01_flanger.py
index 860f5d6..c77d411 100644
--- a/examples/effects/01_flanger.py
+++ b/examples/effects/01_flanger.py
@@ -6,7 +6,7 @@ Simple flanger.
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
#-->
src = BrownNoise(.1).mix(2).out()
diff --git a/examples/effects/02_chorus.py b/examples/effects/02_chorus.py
index 90fff48..cd592ed 100644
--- a/examples/effects/02_chorus.py
+++ b/examples/effects/02_chorus.py
@@ -6,7 +6,7 @@ Hand-written 8 delay lines chorus.
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
#--> Start a sound
sf = SfPlayer('../snds/baseballmajeur_m.aif', speed=1, loop=True, mul=.3)
diff --git a/examples/effects/03_detuned_waveguides.py b/examples/effects/03_detuned_waveguides.py
index 2a73e27..ec294c3 100644
--- a/examples/effects/03_detuned_waveguides.py
+++ b/examples/effects/03_detuned_waveguides.py
@@ -7,7 +7,7 @@ Detuned waveguide bank.
from pyo import *
import random
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
src = SfPlayer("../snds/ounkmaster.aif", loop=True, mul=.1)
diff --git a/examples/effects/04_harmonizer.py b/examples/effects/04_harmonizer.py
index 43676fc..3082d67 100644
--- a/examples/effects/04_harmonizer.py
+++ b/examples/effects/04_harmonizer.py
@@ -6,7 +6,7 @@ Hand-written harmonizer.
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
sf = SfPlayer('../snds/flute.aif', speed=1, loop=True, mul=.5).out()
diff --git a/examples/fft/07_fft_stretch.py b/examples/fft/07_fft_stretch.py
index 5bcfbad..8b3e9c7 100644
--- a/examples/fft/07_fft_stretch.py
+++ b/examples/fft/07_fft_stretch.py
@@ -7,7 +7,7 @@ Time stretching using FFT/IFFT.
from __future__ import division
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
# Settings #
snd = '../snds/flute.aif'
diff --git a/examples/matrix/01_wave_terrain.py b/examples/matrix/01_wave_terrain.py
index fbe0d24..d9fee03 100644
--- a/examples/matrix/01_wave_terrain.py
+++ b/examples/matrix/01_wave_terrain.py
@@ -7,7 +7,7 @@ Simple wave terrain synthesis. The terrain is generated with sin functions.
from pyo import *
import random, math
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
def terrain(size=256, freq=1, phase=16):
l = []
diff --git a/examples/matrix/02_matrix_record.py b/examples/matrix/02_matrix_record.py
index 5c2c6c8..7acd679 100644
--- a/examples/matrix/02_matrix_record.py
+++ b/examples/matrix/02_matrix_record.py
@@ -7,7 +7,7 @@ Wave terrain synthesis of a live recording of FM synthesis in the matrix.
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
SIZE = 256
mm = NewMatrix(SIZE, SIZE)
diff --git a/examples/matrix/03_matrix_algo.py b/examples/matrix/03_matrix_algo.py
index 5b9d1cc..6877382 100644
--- a/examples/matrix/03_matrix_algo.py
+++ b/examples/matrix/03_matrix_algo.py
@@ -7,7 +7,7 @@ algorithmic generation of notes.
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
mat = [[36,41,43,48], [48,51,53,57], [60,62,67,68], [70,72,74,77]]
diff --git a/examples/sampling/01_sound_cloud.py b/examples/sampling/01_sound_cloud.py
index 99bc296..0ce20c3 100644
--- a/examples/sampling/01_sound_cloud.py
+++ b/examples/sampling/01_sound_cloud.py
@@ -7,7 +7,7 @@ Exponential cloud of sounds...
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
snds = ['../snds/snd_%d.aif' % i for i in range(1,7)]
num = len(snds)
diff --git a/examples/sampling/02_live_looper.py b/examples/sampling/02_live_looper.py
index 0d38569..ff73058 100644
--- a/examples/sampling/02_live_looper.py
+++ b/examples/sampling/02_live_looper.py
@@ -9,7 +9,7 @@ The buffer is looped with some funny parameters...
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=1).boot()
+s = Server(duplex=1).boot()
tab = NewTable(4)
rec = TableRec(Input(), tab)
diff --git a/examples/sampling/03_rec_and_loop.py b/examples/sampling/03_rec_and_loop.py
index 5264d19..61999fd 100644
--- a/examples/sampling/03_rec_and_loop.py
+++ b/examples/sampling/03_rec_and_loop.py
@@ -8,7 +8,7 @@ Call r.play() (as many times as you want) to record a buffer from the input mic.
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=1).boot()
+s = Server(duplex=1).boot()
buffer_length = 1 # seconds
diff --git a/examples/sampling/04_live_convolution.py b/examples/sampling/04_live_convolution.py
index 7022ddc..6f5f0f5 100644
--- a/examples/sampling/04_live_convolution.py
+++ b/examples/sampling/04_live_convolution.py
@@ -14,7 +14,7 @@ Circular convolution is very expensive, so keep TLEN (in samples) small.
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=1).boot()
+s = Server(duplex=1).boot()
sf = Noise(.5)
diff --git a/examples/sequencing/01_starttime_duration.py b/examples/sequencing/01_starttime_duration.py
index 307fec2..cd13f98 100644
--- a/examples/sequencing/01_starttime_duration.py
+++ b/examples/sequencing/01_starttime_duration.py
@@ -7,7 +7,7 @@ methods to sequence events over time.
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
num = 70
freqs = [random.uniform(100,1000) for i in range(num)]
diff --git a/examples/sequencing/02_random_score.py b/examples/sequencing/02_random_score.py
index bd829b2..60c3026 100644
--- a/examples/sequencing/02_random_score.py
+++ b/examples/sequencing/02_random_score.py
@@ -7,7 +7,7 @@ Calling Python function from an audio stream with the Score object.
from pyo import *
import random
-s = Server(sr=44100, nchnls=2, buffersize=256, duplex=0).boot()
+s = Server(duplex=0).boot()
# Frequency of event generation in Hz
GEN_FREQ = .25
diff --git a/examples/synthesis/01_pulsar_synthesis.py b/examples/synthesis/01_pulsar_synthesis.py
index 690b676..eb7a2bb 100644
--- a/examples/synthesis/01_pulsar_synthesis.py
+++ b/examples/synthesis/01_pulsar_synthesis.py
@@ -7,7 +7,7 @@ Hand-written pulsar synthesis.
from pyo import *
import random
-s = Server(sr=48000, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
# simple pulsar waveform
t = HarmTable([1,0,.3,0,.2,0,0,.1], size=32768)
diff --git a/examples/synthesis/02_FM3.py b/examples/synthesis/02_FM3.py
index 9c8fbdf..02b2bc2 100644
--- a/examples/synthesis/02_FM3.py
+++ b/examples/synthesis/02_FM3.py
@@ -7,7 +7,7 @@
from pyo import *
import math
-s = Server(sr=48000, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
t = HarmTable([1,0.1])
class FM3:
diff --git a/examples/synthesis/07_split_sideband_synthesis.py b/examples/synthesis/07_split_sideband_synthesis.py
index 80eeee2..0ca80ee 100644
--- a/examples/synthesis/07_split_sideband_synthesis.py
+++ b/examples/synthesis/07_split_sideband_synthesis.py
@@ -12,7 +12,7 @@ Ann Arbor, MPublishing, University of Michigan Library, August 2008
from pyo import *
import math
-s = Server(sr=48000, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
twopi = 2 * math.pi
oneOverTwoPi = 1.0 / twopi
diff --git a/examples/synthesis/08_bucket_brigade_device.py b/examples/synthesis/08_bucket_brigade_device.py
index c78d799..a1534ee 100644
--- a/examples/synthesis/08_bucket_brigade_device.py
+++ b/examples/synthesis/08_bucket_brigade_device.py
@@ -8,7 +8,7 @@ filter inside each delay line. The delay lines are feeded with a sine wave.
"""
from pyo import *
-s = Server(sr=48000, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
t = HarmTable(size=32768)
src = Osc(t, 100)
diff --git a/examples/tables/01_curve_table.py b/examples/tables/01_curve_table.py
index 1acdd44..e351c6c 100644
--- a/examples/tables/01_curve_table.py
+++ b/examples/tables/01_curve_table.py
@@ -6,7 +6,7 @@ Curve table variations used as an amplitude envelope.
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
t = CurveTable([(0,0),(2048,.5),(4096, .2),(6144,.5),(8192,0)], tension=0, bias=20).normalize()
t.view(title="Waveform at initialization")
diff --git a/examples/tables/02_scrubbing.py b/examples/tables/02_scrubbing.py
index f0c2fb1..13bb1ef 100644
--- a/examples/tables/02_scrubbing.py
+++ b/examples/tables/02_scrubbing.py
@@ -9,7 +9,7 @@ Give the focus to the Scrubbing window then click and move the mouse...
"""
from pyo import *
-s = Server(buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
def mouse(mpos):
print("X = %.2f, Y = %.2f" % tuple(mpos))
diff --git a/examples/tables/03_granulation.py b/examples/tables/03_granulation.py
index 8a5728b..8681cb3 100644
--- a/examples/tables/03_granulation.py
+++ b/examples/tables/03_granulation.py
@@ -8,7 +8,7 @@ Classical granulation stretching...
from pyo import *
-s = Server(buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
snd = SndTable('../snds/baseballmajeur_m.aif')
snd.view()
diff --git a/examples/tables/05_table_maker.py b/examples/tables/05_table_maker.py
index dd24b93..f93bfff 100644
--- a/examples/tables/05_table_maker.py
+++ b/examples/tables/05_table_maker.py
@@ -7,7 +7,7 @@ Creates a new sound table from random chunks of a soundfile.
from pyo import *
import random, os
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
path = "../snds/baseballmajeur_m.aif"
dur = sndinfo(path)[1]
diff --git a/examples/utilities/01_get_example.py b/examples/utilities/01_get_example.py
index 49bbe3f..d049da2 100644
--- a/examples/utilities/01_get_example.py
+++ b/examples/utilities/01_get_example.py
@@ -8,7 +8,7 @@ The PyoObject.get() method can be used to convert audio stream to usable python
"""
from pyo import *
-s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
+s = Server(duplex=0).boot()
lfos = Sine(freq=[.1,.2,.4,.3], mul=100, add=500)
synth = SineLoop(freq=lfos, feedback=.07, mul=.05).out()
diff --git a/include/ad_jack.h b/include/ad_jack.h
index afac2de..c41b874 100644
--- a/include/ad_jack.h
+++ b/include/ad_jack.h
@@ -35,6 +35,8 @@ int jack_srate_cb(jack_nframes_t nframes, void *arg);
int jack_bufsize_cb(jack_nframes_t nframes, void *arg);
void jack_error_cb(const char *desc);
void jack_shutdown_cb(void *arg);
+int jack_input_port_set_names(Server *self);
+int jack_output_port_set_names(Server *self);
void Server_jack_autoconnect(Server *self);
int Server_jack_init(Server *self);
int Server_jack_deinit(Server *self);
diff --git a/include/pyomodule.h b/include/pyomodule.h
index ab23153..9e3cb24 100644
--- a/include/pyomodule.h
+++ b/include/pyomodule.h
@@ -21,7 +21,7 @@
#include "Python.h"
#include <math.h>
-#define PYO_VERSION "0.8.3"
+#define PYO_VERSION "0.8.4"
#ifndef __MYFLT_DEF
#define __MYFLT_DEF
diff --git a/include/servermodule.h b/include/servermodule.h
index 6a9c0ad..46ae7da 100644
--- a/include/servermodule.h
+++ b/include/servermodule.h
@@ -76,6 +76,10 @@ typedef struct {
int jackautoout; /* jack port auto-connection (on by default) */
PyObject *jackAutoConnectInputPorts; /* list of lists of jack auto-connection ports to pyo inputs */
PyObject *jackAutoConnectOutputPorts; /* list of lists of jack auto-connection ports from pyo outputs */
+ PyObject *jackInputPortNames; /* string or list of strings (input port short names for jack server */
+ PyObject *jackOutputPortNames; /* string or list of strings (output port short names for jack server */
+ int isJackTransportSlave;
+ int jack_transport_state; /* 0 = stopped, 1 = started */
PyoMidiEvent midiEvents[200];
int midiin_count;
int midiout_count;
@@ -174,7 +178,9 @@ void Server_message(Server *self, char * format, ...);
void Server_warning(Server *self, char * format, ...);
void Server_debug(Server *self, char * format, ...);
PyObject * Server_shutdown(Server *self);
-PyObject *Server_stop(Server *self);
+PyObject * Server_stop(Server *self);
+PyObject * Server_start(Server *self);
+PyObject * Server_boot(Server *self, PyObject *arg);
void Server_process_gui(Server *server);
void Server_process_time(Server *server);
int Server_start_rec_internal(Server *self, char *filename);
diff --git a/installers/osx/PkgResources_x86_64_py2/ReadMe.rtf b/installers/osx/PkgResources_x86_64_py2/ReadMe.rtf
index 79476ad..b93fbc8 100755
--- a/installers/osx/PkgResources_x86_64_py2/ReadMe.rtf
+++ b/installers/osx/PkgResources_x86_64_py2/ReadMe.rtf
@@ -1,97 +1,82 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
-{\fonttbl\f0\fnil\fcharset0 LucidaGrande;\f1\froman\fcharset0 Times-Roman;}
-{\colortbl;\red255\green255\blue255;}
-{\info
-{\author Olivier }}\margl1440\margr1440\vieww10800\viewh8400\viewkind0
-\deftab720
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\f0\fs26 \cf0 Python-pyo (version 0.8.3) for python 2.7
-\f1\fs24 \
-
-\f0\fs26 \
-System requirements : macOS 10.6 to 10.12
-\f1\fs24 \
-
-\f0\fs26 \
-This package installs all the required components to run pyo inside your current Python installation. Python 2.7 (32/64 bit) must be already installed on your system.
-\f1\fs24 \
-
-\f0\fs26 \
-This package is divided into two separate installers. If you do not require one of them, please unselect the package in custom installation mode.
-\f1\fs24 \
-
-\f0\fs26 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\b \cf0 1. pyo extension:
-\f1\b0\fs24 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\f0\fs26 \cf0 The following components will be installed in the site-packages folder of the current Python Framework:
-\f1\fs24 \
-
-\f0\fs26 \
-_pyo.so
-\f1\fs24 \
-
-\f0\fs26 _pyo64.so
-\f1\fs24 \
-
-\f0\fs26 pyo.py
-\f1\fs24 \
-
-\f0\fs26 pyo64.py
-\f1\fs24 \
-
-\f0\fs26 pyolib (folder)
-\f1\fs24 \
-
-\f0\fs26 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\b \cf0 2. Support libraries (i386 and x86_64):
-\f1\b0\fs24 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\f0\fs26 \cf0 This component will install a number of dynamic libraries on which pyo depends. If you already have these, then you can skip this installation.
-\f1\fs24 \
-
-\f0\fs26 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\b \cf0 Warning:
-\b0 this installation will overwrite any previously installed libraries. These are the libraries that will be installed in your /usr/local/lib directory:
-\f1\fs24 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\f0\fs26 \cf0 \
-liblo.7.dylib
-\f1\fs24 \
-
-\f0\fs26 libportaudio.2.dylib
-\f1\fs24 \
-
-\f0\fs26 libportmidi.dylib
-\f1\fs24 \
-
-\f0\fs26 libsndfile.1.dylib
-\f1\fs24 \
-
-\f0\fs26 libFLAC.8.dylib
-\f1\fs24 \
-
-\f0\fs26 libvorbisenc.2.dylib
-\f1\fs24 \
-
-\f0\fs26 libvorbis.0.dylib
-\f1\fs24 \
-
-\f0\fs26 libogg.0.dylib
-\f1\fs24 \
-
-\f0\fs26 \
-\pard\pardeftab720
-\cf0 Olivier B\'e9langer, 2016
-\f1\fs24 \
-}
\ No newline at end of file
+{\rtf1\ansi\deff3\adeflang1025
+{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\fswiss\fprq2\fcharset0 Liberation Sans{\*\falt Arial};}{\f5\froman\fprq2\fcharset0 LucidaGrande;}{\f6\fnil\fprq2\fcharset0 WenQuanYi Micro Hei;}{\f7\fnil\fprq2\fcharset0 FreeSans;}{\f8\fswiss\fprq0\fcharset128 FreeSans;}}
+{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}
+{\stylesheet{\s0\snext0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105 Normal;}
+{\s15\sbasedon0\snext16\sb240\sa120\keepn\dbch\af6\dbch\af7\afs28\loch\f4\fs28 Heading;}
+{\s16\sbasedon0\snext16\sl288\slmult1\sb0\sa140 Text Body;}
+{\s17\sbasedon16\snext17\sl288\slmult1\sb0\sa140\dbch\af8 List;}
+{\s18\sbasedon0\snext18\sb120\sa120\noline\i\dbch\af8\afs24\ai\fs24 Caption;}
+{\s19\sbasedon0\snext19\noline\dbch\af8 Index;}
+}{\*\generator LibreOffice/5.2.5.1$Linux_X86_64 LibreOffice_project/20m0$Build-1}{\info{\author Olivier }{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr2017\mo3\dy23\hr20\min36}{\printim\yr0\mo0\dy0\hr0\min0}}{\*\userprops}\deftab720
+\viewscale120
+{\*\pgdsctbl
+{\pgdsc0\pgdscuse451\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Default Style;}}
+\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
+{\*\ftnsep}\pgndec\pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+Python-pyo (version 0.8.}{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+4}{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+) for python 2.7}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+System requirements : macOS 10.6 to 10.12}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+This package installs all the required components to run pyo inside your current Python installation. Python 2.7 (32/64 bit) must be already installed on your system.}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+This package is divided into two separate installers. If you do not require one of them, please unselect the package in custom installation mode.}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+1. pyo extension:}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+The following components will be installed in the site-packages folder of the current Python Framework:}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+_pyo.so}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+_pyo64.so}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+pyo.py}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+pyo64.py}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+pyolib (folder)}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+2. Support libraries (i386 and x86_64):}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+This component will install a number of dynamic libraries on which pyo depends. If you already have these, then you can skip this installation.}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+Warning:}{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+ this installation will overwrite any previously installed libraries. These are the libraries that will be installed in your /usr/local/lib directory:}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+liblo.7.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libportaudio.2.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libportmidi.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libsndfile.1.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libFLAC.8.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libvorbisenc.2.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libvorbis.0.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libogg.0.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+Olivier B\u233\'e9langer, 2016}
+\par }
\ No newline at end of file
diff --git a/installers/osx/PkgResources_x86_64_py3/ReadMe.rtf b/installers/osx/PkgResources_x86_64_py3/ReadMe.rtf
index 1a3f0e0..57d208c 100755
--- a/installers/osx/PkgResources_x86_64_py3/ReadMe.rtf
+++ b/installers/osx/PkgResources_x86_64_py3/ReadMe.rtf
@@ -1,97 +1,82 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
-{\fonttbl\f0\fnil\fcharset0 LucidaGrande;\f1\froman\fcharset0 Times-Roman;}
-{\colortbl;\red255\green255\blue255;}
-{\info
-{\author Olivier }}\margl1440\margr1440\vieww10800\viewh8400\viewkind0
-\deftab720
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\f0\fs26 \cf0 Python-pyo (version 0.8.3) for python 3.5
-\f1\fs24 \
-
-\f0\fs26 \
-System requirements : macOS 10.8 to 10.12
-\f1\fs24 \
-
-\f0\fs26 \
-This package installs all the required components to run pyo inside your current Python installation. Python 3.5 (32/64 bit) must be already installed on your system.
-\f1\fs24 \
-
-\f0\fs26 \
-This package is divided into two separate installers. If you do not require one of them, please unselect the package in custom installation mode.
-\f1\fs24 \
-
-\f0\fs26 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\b \cf0 1. pyo extension:
-\f1\b0\fs24 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\f0\fs26 \cf0 The following components will be installed in the site-packages folder of the current Python Framework:
-\f1\fs24 \
-
-\f0\fs26 \
-_pyo.cpython-35m-darwin.so
-\f1\fs24 \
-
-\f0\fs26 _pyo64.cpython-35m-darwin.so
-\f1\fs24 \
-
-\f0\fs26 pyo.py
-\f1\fs24 \
-
-\f0\fs26 pyo64.py
-\f1\fs24 \
-
-\f0\fs26 pyolib (folder)
-\f1\fs24 \
-
-\f0\fs26 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\b \cf0 2. Support libraries (i386 and x86_64):
-\f1\b0\fs24 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\f0\fs26 \cf0 This component will install a number of dynamic libraries on which pyo depends. If you already have these, then you can skip this installation.
-\f1\fs24 \
-
-\f0\fs26 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\b \cf0 Warning:
-\b0 this installation will overwrite any previously installed libraries. These are the libraries that will be installed in your /usr/local/lib directory:
-\f1\fs24 \
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720
-
-\f0\fs26 \cf0 \
-liblo.7.dylib
-\f1\fs24 \
-
-\f0\fs26 libportaudio.2.dylib
-\f1\fs24 \
-
-\f0\fs26 libportmidi.dylib
-\f1\fs24 \
-
-\f0\fs26 libsndfile.1.dylib
-\f1\fs24 \
-
-\f0\fs26 libFLAC.8.dylib
-\f1\fs24 \
-
-\f0\fs26 libvorbisenc.2.dylib
-\f1\fs24 \
-
-\f0\fs26 libvorbis.0.dylib
-\f1\fs24 \
-
-\f0\fs26 libogg.0.dylib
-\f1\fs24 \
-
-\f0\fs26 \
-\pard\pardeftab720
-\cf0 Olivier B\'e9langer, 2016
-\f1\fs24 \
-}
\ No newline at end of file
+{\rtf1\ansi\deff3\adeflang1025
+{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\fswiss\fprq2\fcharset0 Liberation Sans{\*\falt Arial};}{\f5\froman\fprq2\fcharset0 LucidaGrande;}{\f6\fnil\fprq2\fcharset0 WenQuanYi Micro Hei;}{\f7\fnil\fprq2\fcharset0 FreeSans;}{\f8\fswiss\fprq0\fcharset128 FreeSans;}}
+{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}
+{\stylesheet{\s0\snext0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105 Normal;}
+{\s15\sbasedon0\snext16\sb240\sa120\keepn\dbch\af6\dbch\af7\afs28\loch\f4\fs28 Heading;}
+{\s16\sbasedon0\snext16\sl288\slmult1\sb0\sa140 Text Body;}
+{\s17\sbasedon16\snext17\sl288\slmult1\sb0\sa140\dbch\af8 List;}
+{\s18\sbasedon0\snext18\sb120\sa120\noline\i\dbch\af8\afs24\ai\fs24 Caption;}
+{\s19\sbasedon0\snext19\noline\dbch\af8 Index;}
+}{\*\generator LibreOffice/5.2.5.1$Linux_X86_64 LibreOffice_project/20m0$Build-1}{\info{\author Olivier }{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr2017\mo3\dy23\hr20\min36}{\printim\yr0\mo0\dy0\hr0\min0}}{\*\userprops}\deftab720
+\viewscale120
+{\*\pgdsctbl
+{\pgdsc0\pgdscuse451\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Default Style;}}
+\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
+{\*\ftnsep}\pgndec\pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+Python-pyo (version 0.8.}{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+4}{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+) for python 3.5}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+System requirements : macOS 10.8 to 10.12}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+This package installs all the required components to run pyo inside your current Python installation. Python 3.5 (32/64 bit) must be already installed on your system.}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+This package is divided into two separate installers. If you do not require one of them, please unselect the package in custom installation mode.}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+1. pyo extension:}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+The following components will be installed in the site-packages folder of the current Python Framework:}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+_pyo.cpython-35m-darwin.so}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+_pyo64.cpython-35m-darwin.so}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+pyo.py}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+pyo64.py}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+pyolib (folder)}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+2. Support libraries (i386 and x86_64):}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+This component will install a number of dynamic libraries on which pyo depends. If you already have these, then you can skip this installation.}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+Warning:}{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+ this installation will overwrite any previously installed libraries. These are the libraries that will be installed in your /usr/local/lib directory:}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+liblo.7.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libportaudio.2.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libportmidi.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libsndfile.1.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libFLAC.8.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libvorbisenc.2.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libvorbis.0.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+libogg.0.dylib}
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+
+\par \pard\plain \s0\nowidctlpar\hyphpar0\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\hich\af3\fs24\lang4105{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+Olivier B\u233\'e9langer, 2016}
+\par }
\ No newline at end of file
diff --git a/installers/osx/release_x86_64_py2.sh b/installers/osx/release_x86_64_py2.sh
index acf1b3f..e550ba9 100755
--- a/installers/osx/release_x86_64_py2.sh
+++ b/installers/osx/release_x86_64_py2.sh
@@ -8,9 +8,9 @@
# 3. cd utils and build E-Pyo for python2
# 4. cd installers/osx and build the release for python2
-export PACKAGE_NAME=pyo_0.8.3_x86_64_py2.pkg
-export DMG_DIR="pyo 0.8.3 py2 Universal"
-export DMG_NAME="pyo_0.8.3_OSX_py2-universal.dmg"
+export PACKAGE_NAME=pyo_0.8.4_x86_64_py2.pkg
+export DMG_DIR="pyo 0.8.4 py2 Universal"
+export DMG_NAME="pyo_0.8.4_OSX_py2-universal.dmg"
export INSTALLER_DIR=`pwd`/installer
export PYO_MODULE_DIR=$INSTALLER_DIR/PyoModule/Package_Contents/tmp
export SUPPORT_LIBS_DIR=$INSTALLER_DIR/SupportLibs/Package_Contents/usr/local/lib
diff --git a/installers/osx/release_x86_64_py3.sh b/installers/osx/release_x86_64_py3.sh
index 4abc0a7..964d611 100755
--- a/installers/osx/release_x86_64_py3.sh
+++ b/installers/osx/release_x86_64_py3.sh
@@ -8,9 +8,9 @@
# 3. cd utils and build E-Pyo for python3
# 4. cd installers/osx and build the release for python3
-export PACKAGE_NAME=pyo_0.8.3_x86_64_py3.pkg
-export DMG_DIR="pyo 0.8.3 py3 Universal"
-export DMG_NAME="pyo_0.8.3_OSX_py3-universal.dmg"
+export PACKAGE_NAME=pyo_0.8.4_x86_64_py3.pkg
+export DMG_DIR="pyo 0.8.4 py3 Universal"
+export DMG_NAME="pyo_0.8.4_OSX_py3-universal.dmg"
export INSTALLER_DIR=`pwd`/installer
export PYO_MODULE_DIR=$INSTALLER_DIR/PyoModule/Package_Contents/tmp
export SUPPORT_LIBS_DIR=$INSTALLER_DIR/SupportLibs/Package_Contents/usr/local/lib
diff --git a/installers/win/win_installer_py27.iss b/installers/win/win_installer_py27.iss
index a9eb776..c57e86e 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.8.3"
+#define appVer "0.8.4"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
diff --git a/installers/win/win_installer_py35.iss b/installers/win/win_installer_py35.iss
index d95583e..c326010 100644
--- a/installers/win/win_installer_py35.iss
+++ b/installers/win/win_installer_py35.iss
@@ -3,7 +3,7 @@
#define appName "pyo"
#define pyVer "3.5"
-#define appVer "0.8.3"
+#define appVer "0.8.4"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
diff --git a/pyolib/_tkwidgets.py b/pyolib/_tkwidgets.py
index 854a2a7..4216428 100644
--- a/pyolib/_tkwidgets.py
+++ b/pyolib/_tkwidgets.py
@@ -457,3 +457,13 @@ class ServerGUI(tk.Frame):
self.vumeter.coords(self.green[i], 0, y, self.B1, y)
self.vumeter.coords(self.yellow[i], self.B1, y, self.B2, y)
self.vumeter.coords(self.red[i], self.B2, y, amp, y)
+
+ def setStartButtonState(self, state):
+ if state:
+ self._started = True
+ self.startStringVar.set('Stop')
+ self.quitButton.configure(state=tk.DISABLED)
+ else:
+ self._started = False
+ self.startStringVar.set('Start')
+ self.quitButton.configure(state=tk.NORMAL)
diff --git a/pyolib/_wxwidgets.py b/pyolib/_wxwidgets.py
index e9ecb04..8a1c71d 100644
--- a/pyolib/_wxwidgets.py
+++ b/pyolib/_wxwidgets.py
@@ -2960,6 +2960,18 @@ class ServerGUI(wx.Frame):
def setRms(self, *args):
self.meter.setRms(*args)
+ def setStartButtonState(self, state):
+ if state:
+ self._started = True
+ wx.CallAfter(self.startButton.SetLabel, 'Stop')
+ if self.exit:
+ wx.CallAfter(self.quitButton.Disable)
+ else:
+ self._started = False
+ wx.CallAfter(self.startButton.SetLabel, 'Start')
+ if self.exit:
+ wx.CallAfter(self.quitButton.Enable)
+
def ensureNFD(unistr):
if sys.platform == 'win32' or sys.platform.startswith('linux'):
encodings = [sys.getdefaultencoding(), sys.getfilesystemencoding(),
diff --git a/pyolib/server.py b/pyolib/server.py
index 35891d7..278b047 100644
--- a/pyolib/server.py
+++ b/pyolib/server.py
@@ -102,7 +102,8 @@ class Server(object):
- setDuplex(x): Set the duplex mode used by the server.
- setVerbosity(x): Set the server's verbosity.
- reinit(sr, nchnls, buffersize, duplex, audio, jackname): Reinit the server's settings.
- - deactivateMidi(): Deactivate Midi callback.
+ - deactivateMidi(): Deactivate Midi callback.
+ - setIsJackTransportSlave(x): Set if pyo's server is slave to jack transport or not.
>>> # For an 8 channels server in duplex mode with
>>> # a sampling rate of 48000 Hz and buffer size of 512
@@ -127,6 +128,9 @@ class Server(object):
self._filename = None
self._fileformat = 0
self._sampletype = 0
+ self._globalseed = 0
+ self._resampling = 1
+ self._isJackTransportSlave = False
self._server = Server_base(sr, nchnls, buffersize, duplex, audio, jackname, self._ichnls)
self._server._setDefaultRecPath(os.path.join(os.path.expanduser("~"), "pyo_rec.wav"))
@@ -165,6 +169,7 @@ class Server(object):
self._sampletype = 0
self._globalseed = 0
self._resampling = 1
+ self._isJackTransportSlave = False
self._server.__init__(sr, nchnls, buffersize, duplex, audio, jackname, self._ichnls)
def setCallback(self, callback):
@@ -539,6 +544,56 @@ class Server(object):
ports, lmax = convertArgsToLists(ports)
self._server.setJackAutoConnectOutputPorts(ports)
+ def setJackInputPortNames(self, name):
+ """
+ Change the short name of pyo's input ports for the jack server.
+
+ This method must be called after the server is booted.
+
+ :Args:
+
+ name: string or list of strings
+ New name of input ports for the jack server. If `name` is a string,
+ '_xxx' (where xxx is the channel number) will be added to it for
+ each input channel. If `name` is a list of strings, They will be
+ used as is and there must be one for each input channel.
+
+ """
+ self._server.setJackInputPortNames(name)
+
+ def setJackOutputPortNames(self, name):
+ """
+ Change the short name of pyo's output ports for the jack server.
+
+ This method must be called after the server is booted.
+
+ :Args:
+
+ name: string or list of strings
+ New name of output ports for the jack server. If `name` is a string,
+ '_xxx' (where xxx is the channel number) will be added to it for
+ each output channel. If `name` is a list of strings, They will be
+ used as is and there must be one for each output channel.
+
+ """
+ self._server.setJackOutputPortNames(name)
+
+ def setIsJackTransportSlave(self, x):
+ """
+ Set if pyo's server is slave to jack transport or not.
+
+ This method must be called before booting the server.
+
+ :Args:
+
+ x: boolean
+ If True, the server's start and stop command will be slave to
+ Jack transport. If False (the default) jack transport is ignored.
+
+ """
+ self._isJackTransportSlave = x
+ self._server.setIsJackTransportSlave(x)
+
def setGlobalSeed(self, x):
"""
Set the server's global seed used by random objects.
diff --git a/pyolib/tables.py b/pyolib/tables.py
index 6e223f6..fcad96a 100644
--- a/pyolib/tables.py
+++ b/pyolib/tables.py
@@ -1479,7 +1479,8 @@ class SndTable(PyoTableObject):
Full path name of the sound. The defaults, None, creates an empty
table.
chnl: int, optional
- Channel number to read in. Available at initialization time only.
+ Channel number to read in. The count starts at 0 (first channel is
+ is 0, second is 1 and so on). Available at initialization time only.
The default (None) reads all channels.
start: float, optional
Begins reading at `start` seconds into the file. Available at
diff --git a/pyolib/wxgui.py b/pyolib/wxgui.py
index 6821400..2f4ff70 100644
--- a/pyolib/wxgui.py
+++ b/pyolib/wxgui.py
@@ -65,7 +65,9 @@ else:
EVT_PYO_GUI_CONTROL_SLIDER
Sent after any change of the slider position. The current
value of the slider can be retrieve with the `value`
- attribute of the generated event.
+ attribute of the generated event. The object itself can be
+ retrieve with the `object` attribute of the event and the
+ object's id with the `id` attrbute.
:Args:
@@ -107,7 +109,7 @@ else:
orient)
def _outFunction(self, value):
- evt = PyoGuiControlSliderEvent(value=value)
+ evt = PyoGuiControlSliderEvent(value=value, id=self.GetId(), object=self)
wx.QueueEvent(self, evt)
def enable(self):
@@ -284,7 +286,9 @@ else:
EVT_PYO_GUI_GRAPHER
Sent after any change of the grapher function. The current
list of points of the grapher can be retrieve with the `value`
- attribute of the generated event.
+ attribute of the generated event. The object itself can be
+ retrieve with the `object` attribute of the event and the
+ object's id with the `id` attrbute.
:Args:
@@ -336,7 +340,7 @@ else:
self._outFunction, pos, size, style)
def _outFunction(self, value):
- evt = PyoGuiGrapherEvent(value=value)
+ evt = PyoGuiGrapherEvent(value=value, id=self.GetId(), object=self)
wx.QueueEvent(self, evt)
def _refresh(self):
@@ -498,7 +502,9 @@ else:
EVT_PYO_GUI_MULTI_SLIDER
Sent after any change of the multi-sliders values. The current
list of values of the multi-sliders can be retrieve with the
- `value` attribute of the generated event.
+ `value` attribute of the generated event. The object itself can
+ be retrieve with the `object` attribute of the event and the
+ object's id with the `id` attrbute.
:Args:
@@ -535,7 +541,7 @@ else:
size, style)
def _outFunction(self, value):
- evt = PyoGuiMultiSliderEvent(value=value)
+ evt = PyoGuiMultiSliderEvent(value=value, id=self.GetId(), object=self)
wx.QueueEvent(self, evt)
def reset(self):
@@ -858,7 +864,9 @@ else:
hold the normalized position of the mouse into the sound.
For X-axis value, 0.0 is the beginning of the sound and 1.0
is the end of the sound. For the Y-axis, 0.0 is the bottom
- of the panel and 1.0 is the top.
+ of the panel and 1.0 is the top. The object itself can be
+ retrieve with the `object` attribute of the event and the
+ object's id with the `id` attrbute.
EVT_PYO_GUI_SNDVIEW_SELECTION
Sent when a new region is selected on the panel. A new
selection is created with a Right-click and drag on the panel.
@@ -866,7 +874,9 @@ else:
drag. Ctrl+Right-click (Cmd on OSX) remove the selected region.
The `value` attribute of the event will hold the normalized
selection as a tuple (min, max). 0.0 means the beginning of
- the sound and 1.0 means the end of the sound.
+ the sound and 1.0 means the end of the sound. The object itself
+ can be retrieve with the `object` attribute of the event and the
+ object's id with the `id` attrbute.
:Args:
@@ -904,12 +914,12 @@ else:
self.update()
def _position_callback(self, pos):
- evt = PyoGuiSndViewMousePositionEvent(value=pos)
+ evt = PyoGuiSndViewMousePositionEvent(value=pos, id=self.GetId(), object=self)
wx.QueueEvent(self, evt)
def _select_callback(self, selection):
selection = (max(0.0, min(selection)), min(max(selection), 1.0))
- evt = PyoGuiSndViewSelectionEvent(value=selection)
+ evt = PyoGuiSndViewSelectionEvent(value=selection, id=self.GetId(), object=self)
wx.QueueEvent(self, evt)
def __del__(self):
diff --git a/scripts/release_doc_src.sh b/scripts/release_doc_src.sh
index f908f09..4756d28 100755
--- a/scripts/release_doc_src.sh
+++ b/scripts/release_doc_src.sh
@@ -6,7 +6,7 @@
# 3. Execute from pyo folder : ./scripts/release_doc_src.sh
#
-version=0.8.3
+version=0.8.4
replace=XXX
doc_rep=pyo_XXX-doc
diff --git a/scripts/test_portaudio_functions.py b/scripts/test_portaudio_functions.py
new file mode 100644
index 0000000..eefaa2e
--- /dev/null
+++ b/scripts/test_portaudio_functions.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+# encoding: utf-8
+from pyo import *
+
+print("------------- PA Version ---------------------")
+print('pa_get_version:', pa_get_version())
+print('pa_get_version_text:', pa_get_version_text())
+
+print("------------- Host API ---------------------")
+print('pa_count_host_apis:', pa_count_host_apis())
+print('pa_list_host_apis:')
+pa_list_host_apis()
+print('pa_get_default_host_api:', pa_get_default_host_api())
+
+print("--------------- Devices -------------------")
+print('pa_count_devices:', pa_count_devices())
+print('pa_list_devices:')
+pa_list_devices()
+print('pa_get_input_devices:')
+print(pa_get_input_devices())
+print('pa_get_default_input:', pa_get_default_input())
+print('pa_get_output_devices:')
+print(pa_get_output_devices())
+print('pa_get_default_output:', pa_get_default_output())
+
+print("--------------- Device Infos -------------------")
+print('pa_get_devices_infos:')
+inputs, outputs = pa_get_devices_infos()
+print('- Inputs:')
+for index in sorted(list(inputs.keys())):
+ print(' Device index:', index)
+ for key in ['name', 'host api index', 'default sr', 'latency']:
+ print(' %s:' % key, inputs[index][key])
+print('- Outputs:')
+for index in sorted(list(outputs.keys())):
+ print(' Device index:', index)
+ for key in ['name', 'host api index', 'default sr', 'latency']:
+ print(' %s:' % key, outputs[index][key])
+
+print("--------------- Channels -------------------")
+dev_list, dev_index = pa_get_output_devices()
+for dev in dev_index:
+ print('Device index:', dev, 'Max outputs:', pa_get_output_max_channels(dev))
+
+dev_list, dev_index = pa_get_input_devices()
+for dev in dev_index:
+ print('Device index:', dev, 'Max inputs:', pa_get_input_max_channels(dev))
diff --git a/setup.py b/setup.py
index 8bf6a36..a6b987a 100644
--- a/setup.py
+++ b/setup.py
@@ -22,7 +22,7 @@ from distutils.sysconfig import get_python_lib
from distutils.core import setup, Extension
import os, sys, py_compile
-pyo_version = "0.8.3"
+pyo_version = "0.8.4"
build_with_jack_support = False
compile_externals = False
diff --git a/src/engine/ad_jack.c b/src/engine/ad_jack.c
index 69e7734..05fa6b0 100644
--- a/src/engine/ad_jack.c
+++ b/src/engine/ad_jack.c
@@ -72,48 +72,106 @@ jack_callback(jack_nframes_t nframes, void *arg) {
}
int
+jack_transport_cb(jack_transport_state_t state, jack_position_t *pos, void *arg) {
+ Server *server = (Server *) arg;
+
+ if (server->jack_transport_state == state)
+ return 0;
+
+ switch (state) {
+ case JackTransportStopped:
+ if (server->server_started) {
+ PyGILState_STATE s = PyGILState_Ensure();
+ Server_stop(server);
+ PyGILState_Release(s);
+ }
+ break;
+ case JackTransportRolling:
+ if (!server->server_started) {
+ PyGILState_STATE s = PyGILState_Ensure();
+ Server_start(server);
+ PyGILState_Release(s);
+ }
+ break;
+ case JackTransportStarting:
+ break;
+ case JackTransportLooping:
+ break;
+ case JackTransportNetStarting:
+ break;
+ }
+
+ server->jack_transport_state = state;
+
+ return 0;
+}
+
+int
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.\n", (unsigned long) nframes);
+ Server *server = (Server *) arg;
+ server->samplingRate = (double) nframes;
+
+ PyGILState_STATE s = PyGILState_Ensure();
+ Server_debug(server, "The sample rate is now %lu.\n", (unsigned long) nframes);
+ PyGILState_Release(s);
+
return 0;
}
int
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.\n", (unsigned long) nframes);
+ Server *server = (Server *) arg;
+ server->bufferSize = (int) nframes;
+
+ PyGILState_STATE s = PyGILState_Ensure();
+ Server_debug(server, "The buffer size is now %lu.\n", (unsigned long) nframes);
+ PyGILState_Release(s);
+
return 0;
}
void
jack_error_cb(const char *desc) {
+ PyGILState_STATE s = PyGILState_Ensure();
PySys_WriteStdout("JACK error: %s\n", desc);
+ PyGILState_Release(s);
}
void
jack_shutdown_cb(void *arg) {
- Server *s = (Server *) arg;
- Server_shutdown(s);
- Server_warning(s, "JACK server shutdown. Pyo Server shut down.\n");
+ Server *server = (Server *) arg;
+
+ PyGILState_STATE s = PyGILState_Ensure();
+ Server_shutdown(server);
+ Server_warning(server, "JACK server shutdown. Pyo Server shut down.\n");
+ PyGILState_Release(s);
}
void
Server_jack_autoconnect(Server *self) {
const char **ports;
char *portname;
- int i, j, num;
+ int i, j, num, err = 0;
PyoJackBackendData *be_data = (PyoJackBackendData *) self->audio_be_data;
if (self->jackautoin) {
- if ((ports = jack_get_ports(be_data->jack_client, "system", NULL, JackPortIsOutput)) == NULL) {
+
+ Py_BEGIN_ALLOW_THREADS
+ ports = jack_get_ports(be_data->jack_client, "system", NULL, JackPortIsOutput);
+ Py_END_ALLOW_THREADS
+
+ if (ports == NULL) {
Server_error(self, "Jack: Cannot find any physical capture ports called 'system'\n");
}
- i=0;
+ i = 0;
while(ports[i] != NULL && be_data->jack_in_ports[i] != NULL){
- if (jack_connect(be_data->jack_client, ports[i], jack_port_name(be_data->jack_in_ports[i]))) {
+
+ Py_BEGIN_ALLOW_THREADS
+ err = jack_connect(be_data->jack_client, ports[i], jack_port_name(be_data->jack_in_ports[i]));
+ Py_END_ALLOW_THREADS
+
+ if (err) {
Server_error(self, "Jack: cannot connect 'system' to input ports\n");
}
i++;
@@ -122,13 +180,23 @@ Server_jack_autoconnect(Server *self) {
}
if (self->jackautoout) {
- if ((ports = jack_get_ports(be_data->jack_client, "system", NULL, JackPortIsInput)) == NULL) {
+
+ Py_BEGIN_ALLOW_THREADS
+ ports = jack_get_ports(be_data->jack_client, "system", NULL, JackPortIsInput);
+ Py_END_ALLOW_THREADS
+
+ if (ports == NULL) {
Server_error(self, "Jack: Cannot find any physical playback ports called 'system'\n");
}
- i=0;
+ i = 0;
while(ports[i] != NULL && be_data->jack_out_ports[i] != NULL){
- if (jack_connect(be_data->jack_client, jack_port_name (be_data->jack_out_ports[i]), ports[i])) {
+
+ Py_BEGIN_ALLOW_THREADS
+ jack_connect(be_data->jack_client, jack_port_name (be_data->jack_out_ports[i]), ports[i]);
+ Py_END_ALLOW_THREADS
+
+ if (err) {
Server_error(self, "Jack: cannot connect output ports to 'system'\n");
}
i++;
@@ -146,8 +214,14 @@ Server_jack_autoconnect(Server *self) {
num = PyList_Size(PyList_GetItem(self->jackAutoConnectInputPorts, j));
for (i=0; i<num; i++) {
portname = PY_STRING_AS_STRING(PyList_GetItem(PyList_GetItem(self->jackAutoConnectInputPorts, j), i));
+
if (jack_port_by_name(be_data->jack_client, portname) != NULL) {
- if (jack_connect(be_data->jack_client, portname, jack_port_name(be_data->jack_in_ports[j]))) {
+
+ Py_BEGIN_ALLOW_THREADS
+ err = jack_connect(be_data->jack_client, portname, jack_port_name(be_data->jack_in_ports[j]));
+ Py_END_ALLOW_THREADS
+
+ if (err) {
Server_error(self, "Jack: cannot connect '%s' to input port %d\n", portname, j);
}
}
@@ -169,7 +243,12 @@ Server_jack_autoconnect(Server *self) {
for (i=0; i<num; i++) {
portname = PY_STRING_AS_STRING(PyList_GetItem(PyList_GetItem(self->jackAutoConnectOutputPorts, j), i));
if (jack_port_by_name(be_data->jack_client, portname) != NULL) {
- if (jack_connect(be_data->jack_client, jack_port_name(be_data->jack_out_ports[j]), portname)) {
+
+ Py_BEGIN_ALLOW_THREADS
+ jack_connect(be_data->jack_client, jack_port_name(be_data->jack_out_ports[j]), portname);
+ Py_END_ALLOW_THREADS
+
+ if (err) {
Server_error(self, "Jack: cannot connect output port %d to '%s'\n", j, portname);
}
}
@@ -198,10 +277,14 @@ Server_jack_init(Server *self) {
assert(self->audio_be_data == NULL);
PyoJackBackendData *be_data = (PyoJackBackendData *) malloc(sizeof(PyoJackBackendData *));
self->audio_be_data = (void *) be_data;
+ strncpy(client_name, self->serverName, 32);
+
+ Py_BEGIN_ALLOW_THREADS
be_data->jack_in_ports = (jack_port_t **) calloc(self->ichnls + self->input_offset, sizeof(jack_port_t *));
be_data->jack_out_ports = (jack_port_t **) calloc(self->nchnls + self->output_offset, sizeof(jack_port_t *));
- strncpy(client_name,self->serverName, 32);
be_data->jack_client = jack_client_open(client_name, options, &status, server_name);
+ Py_END_ALLOW_THREADS
+
if (be_data->jack_client == NULL) {
Server_error(self, "Jack error: Unable to create JACK client\n");
if (status & JackServerFailed) {
@@ -218,7 +301,7 @@ Server_jack_init(Server *self) {
Server_warning(self, "Jack name `%s' assigned\n", self->serverName);
}
- sampleRate = jack_get_sample_rate (be_data->jack_client);
+ sampleRate = jack_get_sample_rate(be_data->jack_client);
if (sampleRate != self->samplingRate) {
self->samplingRate = (double)sampleRate;
Server_warning(self, "Sample rate set to Jack engine sample rate: %" PRIu32 "\n", sampleRate);
@@ -228,9 +311,14 @@ Server_jack_init(Server *self) {
}
if (sampleRate <= 0) {
Server_error(self, "Invalid Jack engine sample rate.");
+
+ Py_BEGIN_ALLOW_THREADS
jack_client_close(be_data->jack_client);
+ Py_END_ALLOW_THREADS
+
return -1;
}
+
bufferSize = jack_get_buffer_size(be_data->jack_client);
if (bufferSize != self->bufferSize) {
self->bufferSize = bufferSize;
@@ -245,9 +333,14 @@ Server_jack_init(Server *self) {
index = total_nchnls - nchnls - 1;
ret = sprintf(name, "input_%i", index + 1);
if (ret > 0) {
- be_data->jack_in_ports[index]
- = jack_port_register(be_data->jack_client, name,
- JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
+
+ Py_BEGIN_ALLOW_THREADS
+ be_data->jack_in_ports[index] = jack_port_register(be_data->jack_client,
+ name,
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput, 0);
+ Py_END_ALLOW_THREADS
+
}
if ((be_data->jack_in_ports[index] == NULL)) {
@@ -261,9 +354,14 @@ Server_jack_init(Server *self) {
index = total_nchnls - nchnls - 1;
ret = sprintf(name, "output_%i", index + 1);
if (ret > 0) {
- be_data->jack_out_ports[index]
- = jack_port_register(be_data->jack_client, name,
- JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+
+ Py_BEGIN_ALLOW_THREADS
+ be_data->jack_out_ports[index] = jack_port_register(be_data->jack_client,
+ name,
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
+ Py_END_ALLOW_THREADS
+
}
if ((be_data->jack_out_ports[index] == NULL)) {
Server_error(self, "Jack: no more JACK output ports available\n");
@@ -276,9 +374,15 @@ Server_jack_init(Server *self) {
jack_set_buffer_size_callback(be_data->jack_client, jack_bufsize_cb, (void *) self);
jack_set_process_callback(be_data->jack_client, jack_callback, (void *) self);
- if (jack_activate(be_data->jack_client)) {
+ if (self->isJackTransportSlave)
+ jack_set_sync_callback(be_data->jack_client, jack_transport_cb, (void *) self);
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = jack_activate(be_data->jack_client);
+ Py_END_ALLOW_THREADS
+
+ if (ret) {
Server_error(self, "Jack error: cannot activate jack client.\n");
- //Server_shutdown(self);
return -1;
}
@@ -291,19 +395,107 @@ int
Server_jack_deinit(Server *self) {
int ret;
PyoJackBackendData *be_data = (PyoJackBackendData *) self->audio_be_data;
+
+ Py_BEGIN_ALLOW_THREADS
ret = jack_deactivate(be_data->jack_client);
+ Py_END_ALLOW_THREADS
+
if (ret)
Server_error(self, "Jack error: cannot deactivate jack client.\n");
+
+ Py_BEGIN_ALLOW_THREADS
ret = jack_client_close(be_data->jack_client);
+ Py_END_ALLOW_THREADS
+
if (ret)
Server_error(self, "Jack error: cannot close client.\n");
+
free(be_data->jack_in_ports);
free(be_data->jack_out_ports);
free(self->audio_be_data);
+
return ret;
}
int
+jack_input_port_set_names(Server *self) {
+ int i, err, lsize;
+ char *name;
+ char result[128];
+ PyoJackBackendData *be_data = (PyoJackBackendData *) self->audio_be_data;
+
+ if (PyList_Check(self->jackInputPortNames)) {
+ lsize = PyList_Size(self->jackInputPortNames);
+ for (i=0; i<self->ichnls && i<lsize; i++) {
+ name = PY_STRING_AS_STRING(PyList_GetItem(self->jackInputPortNames, i));
+
+ Py_BEGIN_ALLOW_THREADS
+ err = jack_port_rename(be_data->jack_client, be_data->jack_in_ports[i], name);
+ Py_END_ALLOW_THREADS
+
+ if (err)
+ Server_error(self, "Jack error: cannot change port short name.\n");
+ }
+ }
+ else if (PY_STRING_CHECK(self->jackInputPortNames)) {
+ name = PY_STRING_AS_STRING(self->jackInputPortNames);
+ for (i=0; i<self->ichnls; i++) {
+ sprintf(result, "%s_%d", name, i);
+
+ Py_BEGIN_ALLOW_THREADS
+ err = jack_port_rename(be_data->jack_client, be_data->jack_in_ports[i], result);
+ Py_END_ALLOW_THREADS
+
+ if (err)
+ Server_error(self, "Jack error: cannot change port short name.\n");
+ }
+ }
+ else
+ Server_error(self, "Jack error: input port names must be a string or a list of strings.\n");
+
+ return 0;
+}
+
+int
+jack_output_port_set_names(Server *self) {
+ int i, err, lsize;
+ char *name;
+ char result[128];
+ PyoJackBackendData *be_data = (PyoJackBackendData *) self->audio_be_data;
+
+ if (PyList_Check(self->jackOutputPortNames)) {
+ lsize = PyList_Size(self->jackOutputPortNames);
+ for (i=0; i<self->nchnls && i<lsize; i++) {
+ name = PY_STRING_AS_STRING(PyList_GetItem(self->jackOutputPortNames, i));
+
+ Py_BEGIN_ALLOW_THREADS
+ err = jack_port_rename(be_data->jack_client, be_data->jack_out_ports[i], name);
+ Py_END_ALLOW_THREADS
+
+ if (err)
+ Server_error(self, "Jack error: cannot change port short name.\n");
+ }
+ }
+ else if (PY_STRING_CHECK(self->jackOutputPortNames)) {
+ name = PY_STRING_AS_STRING(self->jackOutputPortNames);
+ for (i=0; i<self->nchnls; i++) {
+ sprintf(result, "%s_%d", name, i);
+
+ Py_BEGIN_ALLOW_THREADS
+ err = jack_port_rename(be_data->jack_client, be_data->jack_out_ports[i], result);
+ Py_END_ALLOW_THREADS
+
+ if (err)
+ Server_error(self, "Jack error: cannot change port short name.\n");
+ }
+ }
+ else
+ Server_error(self, "Jack error: output port names must be a string or a list of strings.\n");
+
+ return 0;
+}
+
+int
Server_jack_start(Server *self) {
return 0;
}
diff --git a/src/engine/ad_portaudio.c b/src/engine/ad_portaudio.c
index 5d3dc89..064210b 100644
--- a/src/engine/ad_portaudio.c
+++ b/src/engine/ad_portaudio.c
@@ -30,7 +30,14 @@ static void portaudio_assert(PaError ecode, const char* cmdName) {
eText = "???";
}
PySys_WriteStdout("portaudio error in %s: %s\n", cmdName, eText);
- Pa_Terminate();
+
+ if (strcmp(cmdName, "Pa_Initialize") != 0) {
+
+ Py_BEGIN_ALLOW_THREADS
+ Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
+ }
}
}
@@ -146,7 +153,10 @@ Server_pa_init(Server *self)
PaSampleFormat sampleFormat;
PaStreamCallback *streamCallback;
+ Py_BEGIN_ALLOW_THREADS
err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
portaudio_assert(err, "Pa_Initialize");
n = Pa_GetDeviceCount();
@@ -211,7 +221,9 @@ Server_pa_init(Server *self)
}
if (self->input == -1 && self->output == -1) {
- if (self->duplex == 1)
+ if (self->duplex == 1) {
+
+ Py_BEGIN_ALLOW_THREADS
err = Pa_OpenDefaultStream(&be_data->stream,
self->ichnls + self->input_offset,
self->nchnls + self->output_offset,
@@ -220,7 +232,12 @@ Server_pa_init(Server *self)
self->bufferSize,
streamCallback,
(void *) self);
- else
+ Py_END_ALLOW_THREADS
+
+ }
+ else {
+
+ Py_BEGIN_ALLOW_THREADS
err = Pa_OpenDefaultStream(&be_data->stream,
0,
self->nchnls + self->output_offset,
@@ -229,9 +246,14 @@ Server_pa_init(Server *self)
self->bufferSize,
streamCallback,
(void *) self);
+ Py_END_ALLOW_THREADS
+
+ }
}
else {
- if (self->duplex == 1)
+ if (self->duplex == 1) {
+
+ Py_BEGIN_ALLOW_THREADS
err = Pa_OpenStream(&be_data->stream,
&inputParameters,
&outputParameters,
@@ -240,7 +262,12 @@ Server_pa_init(Server *self)
paNoFlag,
streamCallback,
(void *) self);
- else
+ Py_END_ALLOW_THREADS
+
+ }
+ else {
+
+ Py_BEGIN_ALLOW_THREADS
err = Pa_OpenStream(&be_data->stream,
(PaStreamParameters *) NULL,
&outputParameters,
@@ -249,6 +276,9 @@ Server_pa_init(Server *self)
paNoFlag,
streamCallback,
(void *) self);
+ Py_END_ALLOW_THREADS
+
+ }
}
portaudio_assert(err, "Pa_OpenStream");
if (err < 0) {
@@ -264,17 +294,31 @@ Server_pa_deinit(Server *self)
PaError err;
PyoPaBackendData *be_data = (PyoPaBackendData *) self->audio_be_data;
- if (!Pa_IsStreamStopped(be_data->stream)) {
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_IsStreamStopped(be_data->stream);
+ Py_END_ALLOW_THREADS
+
+ if (!err) {
self->server_started = 0;
+
+ Py_BEGIN_ALLOW_THREADS
err = Pa_AbortStream(be_data->stream);
- portaudio_assert(err, "Pa_AbortStream");
+ Py_END_ALLOW_THREADS
+
+ portaudio_assert(err, "Pa_AbortStream (pa_deinit)");
}
+ Py_BEGIN_ALLOW_THREADS
err = Pa_CloseStream(be_data->stream);
- portaudio_assert(err, "Pa_CloseStream");
+ Py_END_ALLOW_THREADS
+ portaudio_assert(err, "Pa_CloseStream (pa_deinit)");
+
+ Py_BEGIN_ALLOW_THREADS
err = Pa_Terminate();
- portaudio_assert(err, "Pa_Terminate");
+ Py_END_ALLOW_THREADS
+
+ portaudio_assert(err, "Pa_Terminate (pa_deinit)");
free(self->audio_be_data);
return err;
@@ -286,26 +330,49 @@ Server_pa_start(Server *self)
PaError err;
PyoPaBackendData *be_data = (PyoPaBackendData *) self->audio_be_data;
- if (!Pa_IsStreamStopped(be_data->stream)) {
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_IsStreamStopped(be_data->stream);
+ Py_END_ALLOW_THREADS
+
+ if (!err) {
+
+ Py_BEGIN_ALLOW_THREADS
err = Pa_AbortStream(be_data->stream);
- portaudio_assert(err, "Pa_AbortStream");
+ Py_END_ALLOW_THREADS
+
+ portaudio_assert(err, "Pa_AbortStream (pa_start)");
}
+
+ Py_BEGIN_ALLOW_THREADS
err = Pa_StartStream(be_data->stream);
- portaudio_assert(err, "Pa_StartStream");
+ Py_END_ALLOW_THREADS
+
+ portaudio_assert(err, "Pa_StartStream (pa_start)");
+
return err;
}
int
Server_pa_stop(Server *self)
{
+ PaError err;
PyoPaBackendData *be_data = (PyoPaBackendData *) self->audio_be_data;
- if (!Pa_IsStreamStopped(be_data->stream)) {
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_IsStreamStopped(be_data->stream);
+ Py_END_ALLOW_THREADS
+
+ if (!err) {
#ifndef _OSX_
- PaError err = Pa_AbortStream(be_data->stream);
- portaudio_assert(err, "Pa_AbortStream");
+
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_AbortStream(be_data->stream);
+ Py_END_ALLOW_THREADS
+
+ portaudio_assert(err, "Pa_AbortStream (pa_stop)");
#endif
}
+
self->server_started = 0;
self->server_stopped = 1;
return 0;
@@ -328,7 +395,10 @@ portaudio_count_host_apis(){
PaError err;
PaHostApiIndex numApis;
+ Py_BEGIN_ALLOW_THREADS
err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
if (err != paNoError) {
portaudio_assert(err, "Pa_Initialize");
Py_RETURN_NONE;
@@ -337,6 +407,11 @@ portaudio_count_host_apis(){
numApis = Pa_GetHostApiCount();
if( numApis < 0 )
portaudio_assert(numApis, "Pa_GetHostApiCount");
+
+ Py_BEGIN_ALLOW_THREADS
+ Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
return PyInt_FromLong(numApis);
}
}
@@ -346,7 +421,10 @@ portaudio_list_host_apis(){
PaError err;
PaHostApiIndex n, i;
+ Py_BEGIN_ALLOW_THREADS
err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
if (err != paNoError) {
portaudio_assert(err, "Pa_Initialize");
}
@@ -364,6 +442,11 @@ portaudio_list_host_apis(){
(int)info->defaultOutputDevice);
}
}
+
+ Py_BEGIN_ALLOW_THREADS
+ Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
}
Py_RETURN_NONE;
}
@@ -373,13 +456,21 @@ portaudio_get_default_host_api(){
PaError err;
PaHostApiIndex i;
+ Py_BEGIN_ALLOW_THREADS
err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
if (err != paNoError) {
portaudio_assert(err, "Pa_Initialize");
Py_RETURN_NONE;
}
else {
i = Pa_GetDefaultHostApi();
+
+ Py_BEGIN_ALLOW_THREADS
+ Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
return PyInt_FromLong(i);
}
}
@@ -389,7 +480,10 @@ portaudio_count_devices(){
PaError err;
PaDeviceIndex numDevices;
- err = Pa_Initialize();
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
if (err != paNoError) {
portaudio_assert(err, "Pa_Initialize");
Py_RETURN_NONE;
@@ -398,6 +492,11 @@ portaudio_count_devices(){
numDevices = Pa_GetDeviceCount();
if( numDevices < 0 )
portaudio_assert(numDevices, "Pa_GetDeviceCount");
+
+ Py_BEGIN_ALLOW_THREADS
+ Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
return PyInt_FromLong(numDevices);
}
@@ -408,7 +507,10 @@ portaudio_list_devices(){
PaError err;
PaDeviceIndex n, i;
- err = Pa_Initialize();
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
if (err != paNoError) {
portaudio_assert(err, "Pa_Initialize");
Py_RETURN_NONE;
@@ -436,6 +538,11 @@ portaudio_list_devices(){
}
PySys_WriteStdout("\n");
}
+
+ Py_BEGIN_ALLOW_THREADS
+ Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
}
Py_RETURN_NONE;
}
@@ -448,16 +555,17 @@ portaudio_get_devices_infos(){
inDict = PyDict_New();
outDict = PyDict_New();
- err = Pa_Initialize();
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
if (err != paNoError) {
portaudio_assert(err, "Pa_Initialize");
- Py_RETURN_NONE;
}
else {
n = Pa_GetDeviceCount();
if (n < 0){
portaudio_assert(n, "Pa_GetDeviceCount");
- Py_RETURN_NONE;
}
else {
for (i=0; i < n; ++i){
@@ -465,23 +573,34 @@ portaudio_get_devices_infos(){
assert(info);
tmpDict = PyDict_New();
if (info->maxInputChannels > 0) {
- PyDict_SetItemString(tmpDict, "name", PyUnicode_FromString(info->name));
+ if (PyUnicode_FromString(info->name) == NULL)
+ PyDict_SetItemString(tmpDict, "name", PyUnicode_FromString("???"));
+ else
+ PyDict_SetItemString(tmpDict, "name", PyUnicode_FromString(info->name));
PyDict_SetItemString(tmpDict, "host api index", PyInt_FromLong((int)info->hostApi));
PyDict_SetItemString(tmpDict, "default sr", PyInt_FromLong((int)info->defaultSampleRate));
PyDict_SetItemString(tmpDict, "latency", PyFloat_FromDouble((float)info->defaultLowInputLatency));
PyDict_SetItem(inDict, PyInt_FromLong(i), PyDict_Copy(tmpDict));
}
if (info->maxOutputChannels > 0) {
- PyDict_SetItemString(tmpDict, "name", PyUnicode_FromString(info->name));
+ if (PyUnicode_FromString(info->name) == NULL)
+ PyDict_SetItemString(tmpDict, "name", PyUnicode_FromString("???"));
+ else
+ PyDict_SetItemString(tmpDict, "name", PyUnicode_FromString(info->name));
PyDict_SetItemString(tmpDict, "host api index", PyInt_FromLong((int)info->hostApi));
PyDict_SetItemString(tmpDict, "default sr", PyInt_FromLong((int)info->defaultSampleRate));
PyDict_SetItemString(tmpDict, "latency", PyFloat_FromDouble((float)info->defaultLowOutputLatency));
PyDict_SetItem(outDict, PyInt_FromLong(i), PyDict_Copy(tmpDict));
}
}
- return Py_BuildValue("(OO)", inDict, outDict);
}
+
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
}
+ return Py_BuildValue("(OO)", inDict, outDict);
}
PyObject *
@@ -493,29 +612,38 @@ portaudio_get_output_devices(){
list = PyList_New(0);
list_index = PyList_New(0);
- err = Pa_Initialize();
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
if (err != paNoError) {
portaudio_assert(err, "Pa_Initialize");
- Py_RETURN_NONE;
}
else {
n = Pa_GetDeviceCount();
if (n < 0){
portaudio_assert(n, "Pa_GetDeviceCount");
- Py_RETURN_NONE;
}
else {
for (i=0; i < n; ++i){
const PaDeviceInfo *info=Pa_GetDeviceInfo(i);
assert(info);
- if (info->maxOutputChannels > 0){
- PyList_Append(list, PyUnicode_FromString(info->name));
+ if (info->maxOutputChannels > 0) {
PyList_Append(list_index, PyInt_FromLong(i));
+ if (PyUnicode_FromString(info->name) == NULL)
+ PyList_Append(list, PyUnicode_FromString("???"));
+ else
+ PyList_Append(list, PyUnicode_FromString(info->name));
}
}
- return Py_BuildValue("OO", list, list_index);
}
+
+ Py_BEGIN_ALLOW_THREADS
+ Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
}
+ return Py_BuildValue("OO", list, list_index);
}
PyObject *
@@ -523,7 +651,10 @@ portaudio_get_output_max_channels(PyObject *self, PyObject *arg){
PaError err;
PaDeviceIndex n, i = PyInt_AsLong(arg);
- err = Pa_Initialize();
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
if (err != paNoError) {
portaudio_assert(err, "Pa_Initialize");
Py_RETURN_NONE;
@@ -536,6 +667,11 @@ portaudio_get_output_max_channels(PyObject *self, PyObject *arg){
}
else {
const PaDeviceInfo *info=Pa_GetDeviceInfo(i);
+
+ Py_BEGIN_ALLOW_THREADS
+ Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
assert(info);
return PyInt_FromLong(info->maxOutputChannels);
}
@@ -547,7 +683,10 @@ portaudio_get_input_max_channels(PyObject *self, PyObject *arg){
PaError err;
PaDeviceIndex n, i = PyInt_AsLong(arg);
- err = Pa_Initialize();
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
if (err != paNoError) {
portaudio_assert(err, "Pa_Initialize");
Py_RETURN_NONE;
@@ -560,6 +699,11 @@ portaudio_get_input_max_channels(PyObject *self, PyObject *arg){
}
else {
const PaDeviceInfo *info=Pa_GetDeviceInfo(i);
+
+ Py_BEGIN_ALLOW_THREADS
+ Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
assert(info);
return PyInt_FromLong(info->maxInputChannels);
}
@@ -575,29 +719,38 @@ portaudio_get_input_devices(){
list = PyList_New(0);
list_index = PyList_New(0);
- err = Pa_Initialize();
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
if (err != paNoError) {
portaudio_assert(err, "Pa_Initialize");
- Py_RETURN_NONE;
}
else {
n = Pa_GetDeviceCount();
if (n < 0){
portaudio_assert(n, "Pa_GetDeviceCount");
- Py_RETURN_NONE;
}
else {
for (i=0; i < n; ++i){
const PaDeviceInfo *info=Pa_GetDeviceInfo(i);
assert(info);
- if (info->maxInputChannels > 0){
- PyList_Append(list, PyUnicode_FromString(info->name));
+ if (info->maxInputChannels > 0) {
PyList_Append(list_index, PyInt_FromLong(i));
+ if (PyUnicode_FromString(info->name) == NULL)
+ PyList_Append(list, PyUnicode_FromString("???"));
+ else
+ PyList_Append(list, PyUnicode_FromString(info->name));
}
}
- return Py_BuildValue("OO", list, list_index);
}
+
+ Py_BEGIN_ALLOW_THREADS
+ Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
}
+ return Py_BuildValue("OO", list, list_index);
}
PyObject *
@@ -605,16 +758,23 @@ portaudio_get_default_input(){
PaError err;
PaDeviceIndex i;
- err = Pa_Initialize();
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
if (err != paNoError) {
portaudio_assert(err, "Pa_Initialize");
Py_RETURN_NONE;
}
else {
i = Pa_GetDefaultInputDevice();
+
+ Py_BEGIN_ALLOW_THREADS
+ Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
return PyInt_FromLong(i);
}
-
}
PyObject *
@@ -622,14 +782,21 @@ portaudio_get_default_output(){
PaError err;
PaDeviceIndex i;
- err = Pa_Initialize();
+ Py_BEGIN_ALLOW_THREADS
+ err = Pa_Initialize();
+ Py_END_ALLOW_THREADS
+
if (err != paNoError) {
portaudio_assert(err, "Pa_Initialize");
Py_RETURN_NONE;
}
else {
i = Pa_GetDefaultOutputDevice();
- return PyInt_FromLong(i);
+ Py_BEGIN_ALLOW_THREADS
+ Pa_Terminate();
+ Py_END_ALLOW_THREADS
+
+ return PyInt_FromLong(i);
}
}
diff --git a/src/engine/md_portmidi.c b/src/engine/md_portmidi.c
index 92cae50..9910305 100644
--- a/src/engine/md_portmidi.c
+++ b/src/engine/md_portmidi.c
@@ -61,7 +61,10 @@ Server_pm_init(Server *self)
return 0;
}
+ Py_BEGIN_ALLOW_THREADS
pmerr = Pm_Initialize();
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
Server_warning(self, "Portmidi warning: could not initialize Portmidi: %s\n", Pm_GetErrorText(pmerr));
self->withPortMidi = 0;
@@ -89,8 +92,12 @@ Server_pm_init(Server *self)
const PmDeviceInfo *info = Pm_GetDeviceInfo(self->midi_input);
if (info != NULL) {
if (info->input) {
+
+ Py_BEGIN_ALLOW_THREADS
Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
pmerr = Pm_OpenInput(&be_data->midiin[0], self->midi_input, NULL, 100, NULL, NULL);
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
Server_warning(self,
"Portmidi warning: could not open midi input %d (%s): %s\n",
@@ -115,12 +122,20 @@ Server_pm_init(Server *self)
else if (self->midi_input >= num_devices) {
Server_debug(self, "Midi input device : all!\n");
self->midiin_count = 0;
+
+ Py_BEGIN_ALLOW_THREADS
Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+ Py_END_ALLOW_THREADS
+
for (i=0; i<num_devices; i++) {
const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
if (info != NULL) {
if (info->input) {
+
+ Py_BEGIN_ALLOW_THREADS
pmerr = Pm_OpenInput(&be_data->midiin[self->midiin_count], i, NULL, 100, NULL, NULL);
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
Server_warning(self,
"Portmidi warning: could not open midi input %d (%s): %s\n",
@@ -148,16 +163,24 @@ Server_pm_init(Server *self)
const PmDeviceInfo *outinfo = Pm_GetDeviceInfo(self->midi_output);
if (outinfo != NULL) {
if (outinfo->output) {
+
+ Py_BEGIN_ALLOW_THREADS
if (!Pt_Started())
Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
pmerr = Pm_OpenOutput(&be_data->midiout[0], self->midi_output, NULL, 100, NULL, NULL, 1);
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
Server_warning(self,
"Portmidi warning: could not open midi output %d (%s): %s\n",
self->midi_output, outinfo->name, Pm_GetErrorText(pmerr));
self->withPortMidiOut = 0;
+
+ Py_BEGIN_ALLOW_THREADS
if (Pt_Started())
Pt_Stop();
+ Py_END_ALLOW_THREADS
+
}
else {
Server_debug(self, "Midi output (%s) opened.\n", outinfo->name);
@@ -177,13 +200,21 @@ Server_pm_init(Server *self)
else if (self->midi_output >= num_devices) {
Server_debug(self, "Midi output device : all!\n");
self->midiout_count = 0;
+
+ Py_BEGIN_ALLOW_THREADS
if (!Pt_Started())
Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+ Py_END_ALLOW_THREADS
+
for (i=0; i<num_devices; i++) {
const PmDeviceInfo *outinfo = Pm_GetDeviceInfo(i);
if (outinfo != NULL) {
if (outinfo->output) {
+
+ Py_BEGIN_ALLOW_THREADS
pmerr = Pm_OpenOutput(&be_data->midiout[self->midiout_count], i, NULL, 100, NULL, NULL, 1);
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
Server_warning(self,
"Portmidi warning: could not open midi output %d (%s): %s\n",
@@ -206,9 +237,13 @@ Server_pm_init(Server *self)
}
if (self->withPortMidi == 0 && self->withPortMidiOut == 0) {
+
+ Py_BEGIN_ALLOW_THREADS
if (Pt_Started())
Pt_Stop();
Pm_Terminate();
+ Py_END_ALLOW_THREADS
+
Server_warning(self, "Portmidi closed.\n");
ret = -1;
}
@@ -217,7 +252,11 @@ Server_pm_init(Server *self)
Server_warning(self, "Portmidi warning: no midi device found!\nPortmidi closed.\n");
self->withPortMidi = 0;
self->withPortMidiOut = 0;
+
+ Py_BEGIN_ALLOW_THREADS
Pm_Terminate();
+ Py_END_ALLOW_THREADS
+
ret = -1;
}
}
@@ -235,28 +274,43 @@ Server_pm_deinit(Server *self)
{
int i = 0;
- //PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data;
+ PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data;
/* An opened stream should be properly closed
but Pm_Close segfaults now and then so...
This hack need to be tested on Windows and OSX. */
+ /* Restored with macros to protect Close statements. */
+
if (self->withPortMidi == 1) {
for (i=0; i<self->midiin_count; i++) {
- //if (be_data->midiin[i] != NULL)
- //Pm_Close(be_data->midiin[i]);
+ if (be_data->midiin[i] != NULL) {
+
+ Py_BEGIN_ALLOW_THREADS
+ Pm_Close(be_data->midiin[i]);
+ Py_END_ALLOW_THREADS
+
+ }
}
}
if (self->withPortMidiOut == 1) {
for (i=0; i<self->midiout_count; i++) {
- //if (be_data->midiout[i] != NULL)
- //Pm_Close(be_data->midiout[i]);
+ if (be_data->midiout[i] != NULL)
+
+ Py_BEGIN_ALLOW_THREADS
+ Pm_Close(be_data->midiout[i]);
+ Py_END_ALLOW_THREADS
+
}
}
if (self->withPortMidi == 1 || self->withPortMidiOut == 1) {
+
+ Py_BEGIN_ALLOW_THREADS
if (Pt_Started())
Pt_Stop();
Pm_Terminate();
+ Py_END_ALLOW_THREADS
+
}
self->withPortMidi = 0;
self->withPortMidiOut = 0;
diff --git a/src/engine/midilistenermodule.c b/src/engine/midilistenermodule.c
index 3c9deac..df3f47d 100644
--- a/src/engine/midilistenermodule.c
+++ b/src/engine/midilistenermodule.c
@@ -136,10 +136,13 @@ static PyObject * MidiListener_play(MidiListener *self) {
int i, num_devices, lsize, mididev;
PmError pmerr;
+ Py_BEGIN_ALLOW_THREADS
/* always start the timer before you start midi */
Pt_Start(1, &process_midi, (void *)self);
pmerr = Pm_Initialize();
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
PySys_WriteStdout("Portmidi warning: could not initialize Portmidi: %s\n", Pm_GetErrorText(pmerr));
}
@@ -156,7 +159,11 @@ static PyObject * MidiListener_play(MidiListener *self) {
const PmDeviceInfo *info = Pm_GetDeviceInfo(mididev);
if (info != NULL) {
if (info->input) {
+
+ Py_BEGIN_ALLOW_THREADS
pmerr = Pm_OpenInput(&self->midiin[0], mididev, NULL, 100, NULL, NULL);
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
PySys_WriteStdout("Portmidi warning: could not open midi input %d (%s): %s\n",
mididev, info->name, Pm_GetErrorText(pmerr));
@@ -174,7 +181,11 @@ static PyObject * MidiListener_play(MidiListener *self) {
const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
if (info != NULL) {
if (info->input) {
+
+ Py_BEGIN_ALLOW_THREADS
pmerr = Pm_OpenInput(&self->midiin[self->midicount], i, NULL, 100, NULL, NULL);
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
PySys_WriteStdout("Portmidi warning: could not open midi input %d (%s): %s\n",
i, info->name, Pm_GetErrorText(pmerr));
@@ -196,7 +207,11 @@ static PyObject * MidiListener_play(MidiListener *self) {
const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
if (info != NULL) {
if (info->input) {
+
+ Py_BEGIN_ALLOW_THREADS
pmerr = Pm_OpenInput(&self->midiin[self->midicount], i, NULL, 100, NULL, NULL);
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
PySys_WriteStdout("Portmidi warning: could not open midi input %d (%s): %s\n",
i, info->name, Pm_GetErrorText(pmerr));
@@ -224,11 +239,15 @@ static PyObject * MidiListener_play(MidiListener *self) {
static PyObject * MidiListener_stop(MidiListener *self) {
int i;
+
+ Py_BEGIN_ALLOW_THREADS
Pt_Stop();
for (i=0; i<self->midicount; i++) {
Pm_Close(self->midiin[i]);
}
- Pm_Terminate();
+ Pm_Terminate();
+ Py_END_ALLOW_THREADS
+
self->active = 0;
Py_INCREF(Py_None);
return Py_None;
@@ -375,10 +394,13 @@ static PyObject * MidiDispatcher_play(MidiDispatcher *self) {
int i, num_devices, lsize, mididev;
PmError pmerr;
+ Py_BEGIN_ALLOW_THREADS
/* always start the timer before you start midi */
Pt_Start(1, 0, 0);
pmerr = Pm_Initialize();
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
PySys_WriteStdout("Portmidi warning: could not initialize Portmidi: %s\n", Pm_GetErrorText(pmerr));
}
@@ -395,7 +417,11 @@ static PyObject * MidiDispatcher_play(MidiDispatcher *self) {
const PmDeviceInfo *info = Pm_GetDeviceInfo(mididev);
if (info != NULL) {
if (info->output) {
+
+ Py_BEGIN_ALLOW_THREADS
pmerr = Pm_OpenOutput(&self->midiout[0], mididev, NULL, 100, NULL, NULL, 1);
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
PySys_WriteStdout("Portmidi warning: could not open midi output %d (%s): %s\n",
mididev, info->name, Pm_GetErrorText(pmerr));
@@ -413,7 +439,11 @@ static PyObject * MidiDispatcher_play(MidiDispatcher *self) {
const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
if (info != NULL) {
if (info->output) {
+
+ Py_BEGIN_ALLOW_THREADS
pmerr = Pm_OpenOutput(&self->midiout[self->midicount], i, NULL, 100, NULL, NULL, 1);
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
PySys_WriteStdout("Portmidi warning: could not open midi output %d (%s): %s\n",
i, info->name, Pm_GetErrorText(pmerr));
@@ -435,7 +465,11 @@ static PyObject * MidiDispatcher_play(MidiDispatcher *self) {
const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
if (info != NULL) {
if (info->output) {
+
+ Py_BEGIN_ALLOW_THREADS
pmerr = Pm_OpenOutput(&self->midiout[self->midicount], i, NULL, 100, NULL, NULL, 1);
+ Py_END_ALLOW_THREADS
+
if (pmerr) {
PySys_WriteStdout("Portmidi warning: could not open midi output %d (%s): %s\n",
i, info->name, Pm_GetErrorText(pmerr));
@@ -459,11 +493,15 @@ static PyObject * MidiDispatcher_play(MidiDispatcher *self) {
static PyObject * MidiDispatcher_stop(MidiDispatcher *self) {
int i;
+
+ Py_BEGIN_ALLOW_THREADS
Pt_Stop();
for (i=0; i<self->midicount; i++) {
Pm_Close(self->midiout[i]);
}
Pm_Terminate();
+ Py_END_ALLOW_THREADS
+
self->active = 0;
Py_INCREF(Py_None);
return Py_None;
diff --git a/src/engine/pyomodule.c b/src/engine/pyomodule.c
index 7b3da65..a80a56b 100644
--- a/src/engine/pyomodule.c
+++ b/src/engine/pyomodule.c
@@ -138,7 +138,7 @@ AUDIO devices:\n\
#define portaudio_get_devices_infos_info \
"\nReturns informations about all devices found by Portaudio.\n\n\
-This function returns two dictionaries, one containing a dictionary for each input device and one containing a dictionary for each output device.\
+This function returns two dictionaries, one containing a dictionary for each input device and one containing a dictionary for each output device. \
Keys of outer dictionaries are the device index as returned by Portaudio. Keys of inner dictionaries are: 'name', 'host api index', 'default sr' and 'latency'.\n\n\
>>> inputs, outputs = pa_get_devices_infos()\n\
>>> print '- Inputs:'\n\
diff --git a/src/engine/servermodule.c b/src/engine/servermodule.c
index 7823c76..99d7e9a 100644
--- a/src/engine/servermodule.c
+++ b/src/engine/servermodule.c
@@ -49,6 +49,9 @@ int Server_jack_init(Server *self) { return -10; };
int Server_jack_deinit(Server *self) { return 0; };
int Server_jack_start(Server *self) { return 0; };
int Server_jack_stop(Server *self) { return 0; };
+int jack_input_port_set_names(Server *self) { return 0; };
+int jack_output_port_set_names(Server *self) { return 0; };
+
#endif
#ifdef USE_COREAUDIO
@@ -570,6 +573,8 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->jackautoout = 1;
self->jackAutoConnectInputPorts = PyList_New(0);
self->jackAutoConnectOutputPorts = PyList_New(0);
+ self->isJackTransportSlave = 0;
+ self->jack_transport_state = 0;
self->samplingRate = 44100.0;
self->nchnls = 2;
self->ichnls = 2;
@@ -907,6 +912,58 @@ Server_setJackAutoConnectOutputPorts(Server *self, PyObject *arg)
}
static PyObject *
+Server_setJackInputPortNames(Server *self, PyObject *arg)
+{
+ PyObject *tmp;
+
+ if (arg != NULL) {
+ if (PyList_Check(arg) || PY_STRING_CHECK(arg)) {
+ tmp = arg;
+ Py_XDECREF(self->jackInputPortNames);
+ Py_INCREF(tmp);
+ self->jackInputPortNames = tmp;
+
+ jack_input_port_set_names(self);
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+Server_setJackOutputPortNames(Server *self, PyObject *arg)
+{
+ PyObject *tmp;
+
+ if (arg != NULL) {
+ if (PyList_Check(arg) || PY_STRING_CHECK(arg)) {
+ tmp = arg;
+ Py_XDECREF(self->jackOutputPortNames);
+ Py_INCREF(tmp);
+ self->jackOutputPortNames = tmp;
+
+ jack_output_port_set_names(self);
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+Server_setIsJackTransportSlave(Server *self, PyObject *arg)
+{
+ if (self->server_booted) {
+ Server_warning(self,"Can't change isJackTransportSlave mode for booted server.\n");
+ Py_RETURN_NONE;
+ }
+ if (arg != NULL) {
+ if (PyInt_Check(arg))
+ self->isJackTransportSlave = PyInt_AsLong(arg);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *
Server_setGlobalSeed(Server *self, PyObject *arg)
{
self->globalSeed = 0;
@@ -1110,7 +1167,7 @@ Server_shutdown(Server *self)
Py_RETURN_NONE;
}
-static PyObject *
+PyObject *
Server_boot(Server *self, PyObject *arg)
{
int i, audioerr = 0, midierr = 0;
@@ -1221,7 +1278,7 @@ Server_boot(Server *self, PyObject *arg)
Py_RETURN_NONE;
}
-static PyObject *
+PyObject *
Server_start(Server *self)
{
int err = -1;
@@ -1278,6 +1335,9 @@ Server_start(Server *self)
Server_error(self, "Error starting server.\n");
}
+ if (self->withGUI && PyObject_HasAttrString((PyObject *)self->GUI, "setStartButtonState"))
+ PyObject_CallMethod((PyObject *)self->GUI, "setStartButtonState", "i", 1);
+
Py_RETURN_NONE;
}
@@ -1312,9 +1372,8 @@ Server_stop(Server *self)
self->server_started = 0;
}
- /* This call is needed to recover from thread fork with python3/jack on debian.*/
- /* TODO: Need to be tested with other OSes and audio driver. */
- //PyOS_AfterFork();
+ if (self->withGUI && PyObject_HasAttrString((PyObject *)self->GUI, "setStartButtonState"))
+ PyObject_CallMethod((PyObject *)self->GUI, "setStartButtonState", "i", 0);
Py_RETURN_NONE;
}
@@ -1953,6 +2012,9 @@ static PyMethodDef Server_methods[] = {
{"setJackAuto", (PyCFunction)Server_setJackAuto, METH_VARARGS, "Tells the server to auto-connect Jack ports (0 = disable, 1 = enable)."},
{"setJackAutoConnectInputPorts", (PyCFunction)Server_setJackAutoConnectInputPorts, METH_O, "Sets a list of ports to auto-connect inputs when using Jack."},
{"setJackAutoConnectOutputPorts", (PyCFunction)Server_setJackAutoConnectOutputPorts, METH_O, "Sets a list of ports to auto-connect outputs when using Jack."},
+ {"setJackInputPortNames", (PyCFunction)Server_setJackInputPortNames, METH_O, "Sets the short name of input ports for jack server."},
+ {"setJackOutputPortNames", (PyCFunction)Server_setJackOutputPortNames, METH_O, "Sets the short name of output ports for jack server."},
+ {"setIsJackTransportSlave", (PyCFunction)Server_setIsJackTransportSlave, METH_O, "Sets if the server's start/stop is slave of jack transport."},
{"setGlobalSeed", (PyCFunction)Server_setGlobalSeed, METH_O, "Sets the server's global seed for random objects."},
{"setAmp", (PyCFunction)Server_setAmp, METH_O, "Sets the overall amplitude."},
{"setAmpCallable", (PyCFunction)Server_setAmpCallable, METH_O, "Sets the Server's GUI callable object."},
diff --git a/utils/setup.py b/utils/setup.py
index e9e05e9..29ccb3b 100644
--- a/utils/setup.py
+++ b/utils/setup.py
@@ -16,11 +16,11 @@ OPTIONS = {'argv_emulation': False,
'CFBundleExecutable': 'E-Pyo',
'CFBundleIconFile': 'E-PyoIcon.icns',
'CFBundleIdentifier': 'com.ajaxsoundstudio.E-Pyo',
- 'CFBundleInfoDictionaryVersion': '0.8.3',
+ 'CFBundleInfoDictionaryVersion': '0.8.4',
'CFBundleName': 'E-Pyo',
'CFBundlePackageType': 'APPL',
- 'CFBundleShortVersionString': '0.8.3',
- 'CFBundleVersion': '0.8.3',
+ 'CFBundleShortVersionString': '0.8.4',
+ 'CFBundleVersion': '0.8.4',
'CFBundleDocumentTypes': [{'CFBundleTypeOSTypes': ['TEXT'],
'CFBundleTypeExtensions': ['py'],
'CFBundleTypeRole': 'Editor',
diff --git a/work-in-progress/EventParser.py b/work-in-progress/EventParser.py
new file mode 100644
index 0000000..6d36144
--- /dev/null
+++ b/work-in-progress/EventParser.py
@@ -0,0 +1,63 @@
+"""
+EventParser first draft (very very alpha stage!).
+
+Score format:
+
+Class_name => starttime duration *args **kwargs
+
+Class_name {class reference}: The name of the class which should play the event,
+starttime {float}: Start time of the event, in seconds.
+duration {float}: Start time of the event, in seconds.
+*args {list of floats}: user-defined arguments (optional).
+**kwargs {dictionary}: user-defined keyword arguments (optional).
+
+"""
+# Notes:
+# We should be able to define an event using multiple lines.
+# Actually, the parser uses splitlines() to separate events.
+# How to automatically use globals() from the __main__ module, I don't
+# want to ask the user to pass globals() to have access to instrument classes.
+
+class EventParser:
+ def __init__(self, server, score="", globals=None):
+ self.server = server
+ self.globals = globals
+ self._instruments = {}
+ self.parse(score)
+
+ def extractKwArgs(self, args):
+ kwargs = ""
+ if "{" in args:
+ p1 = args.find("{")
+ args, kwargs = args[:p1], args[p1:]
+ if kwargs:
+ kwargs = eval(kwargs)
+ return args, kwargs
+
+ def parse(self, score):
+ for line in score.splitlines():
+ if line.strip() == "":
+ continue
+ instr, args = line.split("=>")
+ instr = instr.strip()
+ args, kwargs = self.extractKwArgs(args)
+ args = [float(x) for x in args.split()] # should also eval variable
+ # names, not just numbers
+ if instr not in self._instruments:
+ self._instruments[instr] = [{"args": args, "kwargs": kwargs}]
+ else:
+ self._instruments[instr].append({"args": args, "kwargs": kwargs})
+
+ def play(self):
+ self._playing = []
+ for instr in self._instruments:
+ for event in self._instruments[instr]:
+ self.server.setGlobalDel(event["args"][0])
+ self.server.setGlobalDur(event["args"][1] + 0.2)
+ if not event["kwargs"]:
+ self._playing.append(self.globals[instr](*event["args"][1:]))
+ else:
+ self._playing.append(self.globals[instr](*event["args"][1:],
+ **event["kwargs"]))
+ self.server.setGlobalDel(0)
+ self.server.setGlobalDur(0)
diff --git a/work-in-progress/keyboard_widget.py b/work-in-progress/keyboard_widget.py
new file mode 100644
index 0000000..bfa1693
--- /dev/null
+++ b/work-in-progress/keyboard_widget.py
@@ -0,0 +1,292 @@
+import sys
+import wx
+
+KEYBOARD_BACKGROUND_COLOUR = "#CCCCCC"
+
+class Keyboard(wx.Panel):
+ def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
+ size=wx.DefaultSize, poly=64, style=wx.TAB_TRAVERSAL):
+ wx.Panel.__init__(self, parent, id, pos, size, style)
+ self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+ self.SetBackgroundColour(KEYBOARD_BACKGROUND_COLOUR)
+ self.parent = parent
+
+ self.poly = poly
+ self.gap = 0
+ self.offset = 12
+ self.w1 = 15
+ self.w2 = self.w1 // 2 + 1
+ self.hold = 1
+ self.keyPressed = None
+
+ self.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
+ self.Bind(wx.EVT_LEFT_UP, self.MouseUp)
+ self.Bind(wx.EVT_PAINT, self.OnPaint)
+ self.Bind(wx.EVT_SIZE, self.OnSize)
+
+ self.white = (0, 2, 4, 5, 7, 9, 11)
+ self.black = (1, 3, 6, 8, 10)
+ self.whiteSelected = []
+ self.blackSelected = []
+ self.whiteVelocities = {}
+ self.blackVelocities = {}
+ self.whiteKeys = []
+ self.blackKeys = []
+
+ wx.CallAfter(self.setRects)
+
+ def getNotes(self):
+ notes = []
+ for key in self.whiteSelected:
+ notes.append((self.white[key % 7] + key // 7 * 12 + self.offset,
+ 127 - self.whiteVelocities[key]))
+ for key in self.blackSelected:
+ notes.append((self.black[key % 5] + key // 5 * 12 + self.offset,
+ 127 - self.blackVelocities[key]))
+ notes.sort()
+ return notes
+
+ def reset(self):
+ self.whiteSelected = []
+ self.blackSelected = []
+ self.whiteVelocities = {}
+ self.blackVelocities = {}
+ wx.CallAfter(self.Refresh)
+
+ def setPoly(self, poly):
+ self.poly = poly
+
+ def setRects(self):
+ w, h = self.GetSize()
+ self.offRec = wx.Rect(w - 55, 0, 21, h)
+ self.holdRec = wx.Rect(w - 34, 0, 21, h)
+ num = w // self.w1
+ self.gap = w - num * self.w1
+ self.whiteKeys = [wx.Rect(i * self.w1, 0, self.w1 - 1, h) for i in range(num)]
+ self.blackKeys = []
+ height2 = h * 4 // 7
+ for i in range(num // 7 + 1):
+ space2 = self.w1 * 7 * i
+ off = self.w1 // 2 + space2 + 3
+ self.blackKeys.append(wx.Rect(off, 0, self.w2, height2))
+ off += self.w1
+ self.blackKeys.append(wx.Rect(off, 0, self.w2, height2))
+ off += self.w1 * 2
+ self.blackKeys.append(wx.Rect(off, 0, self.w2, height2))
+ off += self.w1
+ self.blackKeys.append(wx.Rect(off, 0, self.w2, height2))
+ off += self.w1
+ self.blackKeys.append(wx.Rect(off, 0, self.w2, height2))
+ wx.CallAfter(self.Refresh)
+
+ def OnSize(self, evt):
+ self.setRects()
+ wx.CallAfter(self.Refresh)
+
+ def MouseUp(self, evt):
+ if not self.hold and self.keyPressed is not None:
+ key = self.keyPressed[0]
+ pit = self.keyPressed[1]
+ if key in self.blackSelected:
+ self.blackSelected.remove(key)
+ del self.blackVelocities[key]
+ if key in self.whiteSelected:
+ self.whiteSelected.remove(key)
+ del self.whiteVelocities[key]
+ note = (pit, 0)
+ self.keyPressed = None
+ wx.CallAfter(self.Refresh)
+
+ def MouseDown(self, evt):
+ w,h = self.GetSize()
+ pos = evt.GetPosition()
+ if self.holdRec.Contains(pos):
+ if self.hold:
+ self.hold = 0
+ else:
+ self.hold = 1
+ wx.CallAfter(self.Refresh)
+ return
+ if self.offUpRec.Contains(pos):
+ self.offset += 12
+ if self.offset > 60:
+ self.offset = 60
+ wx.CallAfter(self.Refresh)
+ return
+ if self.offDownRec.Contains(pos):
+ self.offset -= 12
+ if self.offset < 0:
+ self.offset = 0
+ wx.CallAfter(self.Refresh)
+ return
+
+ total = len(self.blackSelected) + len(self.whiteSelected)
+ scanWhite = True
+ note = None
+ if self.hold:
+ for i, rec in enumerate(self.blackKeys):
+ if rec.Contains(pos):
+ pit = self.black[i % 5] + i // 5 * 12 + self.offset
+ if i in self.blackSelected:
+ self.blackSelected.remove(i)
+ del self.blackVelocities[i]
+ vel = 0
+ else:
+ hb = h * 4 // 7
+ vel = (hb - pos[1]) * 127 // hb
+ if total < self.poly:
+ self.blackSelected.append(i)
+ self.blackVelocities[i] = int(127 - vel)
+ note = (pit, vel)
+ scanWhite = False
+ break
+ if scanWhite:
+ for i, rec in enumerate(self.whiteKeys):
+ if rec.Contains(pos):
+ pit = self.white[i % 7] + i // 7 * 12 + self.offset
+ if i in self.whiteSelected:
+ self.whiteSelected.remove(i)
+ del self.whiteVelocities[i]
+ vel = 0
+ else:
+ vel = (h - pos[1]) * 127 // h
+ if total < self.poly:
+ self.whiteSelected.append(i)
+ self.whiteVelocities[i] = int(127 - vel)
+ note = (pit, vel)
+ break
+ if note:
+ if note[1] == 0:
+ pass
+ elif total < self.poly:
+ pass
+ else:
+ self.keyPressed = None
+ for i, rec in enumerate(self.blackKeys):
+ if rec.Contains(pos):
+ pit = self.black[i % 5] + i // 5 * 12 + self.offset
+ if i not in self.blackSelected:
+ hb = h * 4 // 7
+ vel = (hb - pos[1]) * 127 // hb
+ if total < self.poly:
+ self.blackSelected.append(i)
+ self.blackVelocities[i] = int(127 - vel)
+ note = (pit, vel)
+ self.keyPressed = (i, pit)
+ scanWhite = False
+ break
+ if scanWhite:
+ for i, rec in enumerate(self.whiteKeys):
+ if rec.Contains(pos):
+ pit = self.white[i % 7] + i // 7 * 12 + self.offset
+ if i not in self.whiteSelected:
+ vel = (h - pos[1]) * 127 // h
+ if total < self.poly:
+ self.whiteSelected.append(i)
+ self.whiteVelocities[i] = int(127 - vel)
+ note = (pit, vel)
+ self.keyPressed = (i, pit)
+ break
+ if note:
+ if total < self.poly:
+ pass
+ wx.CallAfter(self.Refresh)
+
+ def OnPaint(self, evt):
+ w,h = self.GetSize()
+ dc = wx.AutoBufferedPaintDC(self)
+ dc.SetBrush(wx.Brush("#000000", wx.SOLID))
+ dc.Clear()
+ dc.SetPen(wx.Pen("#000000", width=1, style=wx.SOLID))
+ dc.DrawRectangle(0, 0, w, h)
+
+ if sys.platform == "darwin":
+ dc.SetFont(wx.Font(12, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL,
+ wx.FONTWEIGHT_BOLD))
+ else:
+ dc.SetFont(wx.Font(8, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL,
+ wx.FONTWEIGHT_BOLD))
+
+ for i, rec in enumerate(self.whiteKeys):
+ if i in self.whiteSelected:
+ amp = int(self.whiteVelocities[i] * 1.5)
+ dc.GradientFillLinear(rec, (250, 250, 250), (amp, amp, amp), wx.SOUTH)
+ dc.SetBrush(wx.Brush("#CCCCCC", wx.SOLID))
+ dc.SetPen(wx.Pen("#CCCCCC", width=1, style=wx.SOLID))
+ else:
+ dc.SetBrush(wx.Brush("#FFFFFF", wx.SOLID))
+ dc.SetPen(wx.Pen("#FFFFFF", width=1, style=wx.SOLID))
+ dc.DrawRectangle(rec)
+ if i == (35 - (7 * (self.offset // 12))):
+ if i in self.whiteSelected:
+ dc.SetTextForeground("#FFFFFF")
+ else:
+ dc.SetTextForeground("#000000")
+ dc.DrawText("C", rec[0] + 3, rec[3] - 15)
+
+ dc.SetPen(wx.Pen("#000000", width=1, style=wx.SOLID))
+ for i, rec in enumerate(self.blackKeys):
+ if i in self.blackSelected:
+ amp = int(self.blackVelocities[i] * 1.5)
+ dc.GradientFillLinear(rec, (250, 250, 250), (amp, amp, amp), wx.SOUTH)
+ dc.DrawLine(rec[0], 0, rec[0], rec[3])
+ dc.DrawLine(rec[0] + rec[2], 0, rec[0] + rec[2], rec[3])
+ dc.DrawLine(rec[0], rec[3], rec[0] + rec[2], rec[3])
+ dc.SetBrush(wx.Brush("#DDDDDD", wx.SOLID))
+ else:
+ dc.SetBrush(wx.Brush("#000000", wx.SOLID))
+ dc.SetPen(wx.Pen("#000000", width=1, style=wx.SOLID))
+ dc.DrawRectangle(rec)
+
+ dc.SetBrush(wx.Brush(KEYBOARD_BACKGROUND_COLOUR, wx.SOLID))
+ dc.SetPen(wx.Pen("#AAAAAA", width=1, style=wx.SOLID))
+ dc.DrawRectangle(self.offRec)
+ dc.DrawRectangle(self.holdRec)
+ dc.DrawRectangle(wx.Rect(w - 14, 0, 14, h))
+
+ dc.SetTextForeground("#000000")
+ dc.DrawText("oct", self.offRec[0] + 3, 15)
+ x1, y1 = self.offRec[0], self.offRec[1]
+ dc.SetBrush(wx.Brush("#000000", wx.SOLID))
+ if sys.platform == "darwin":
+ dc.DrawPolygon([wx.Point(x1 + 3, 36), wx.Point(x1 + 10, 29),
+ wx.Point(x1 + 17, 36)])
+ self.offUpRec = wx.Rect(x1, 28, x1 + 20, 10)
+ dc.DrawPolygon([wx.Point(x1 + 3, 55), wx.Point(x1 + 10, 62),
+ wx.Point(x1 + 17, 55)])
+ self.offDownRec = wx.Rect(x1, 54, x1 + 20, 10)
+ else:
+ dc.DrawPolygon([wx.Point(x1 + 3, 38), wx.Point(x1 + 10, 31),
+ wx.Point(x1 + 17, 38)])
+ self.offUpRec = wx.Rect(x1, 30, x1 + 20, 10)
+ dc.DrawPolygon([wx.Point(x1 + 3, 57), wx.Point(x1 + 10, 64),
+ wx.Point(x1 + 17, 57)])
+ self.offDownRec = wx.Rect(x1, 56, x1 + 20, 10)
+
+ dc.DrawText("%d" % (self.offset // 12), x1 + 7, 41)
+
+ if self.hold:
+ dc.SetTextForeground("#0000CC")
+ else:
+ dc.SetTextForeground("#000000")
+ for i, c in enumerate("HOLD"):
+ dc.DrawText(c, self.holdRec[0] + 6, self.holdRec[3] // 6 * i + 15)
+
+ dc.SetBrush(wx.Brush(KEYBOARD_BACKGROUND_COLOUR, wx.SOLID))
+ dc.SetPen(wx.Pen(KEYBOARD_BACKGROUND_COLOUR, width=1, style=wx.SOLID))
+ dc.DrawRectangle(w - self.gap, 0, self.gap, h)
+ dc.SetPen(wx.Pen("#000000", width=1, style=wx.SOLID))
+ dc.DrawLine(0, 3, w, 3)
+ dc.SetPen(wx.Pen("#444444", width=1, style=wx.SOLID))
+ dc.DrawLine(0, 2, w, 2)
+ dc.SetPen(wx.Pen("#888888", width=1, style=wx.SOLID))
+ dc.DrawLine(0, 1, w, 1)
+ dc.SetPen(wx.Pen("#CCCCCC", width=1, style=wx.SOLID))
+ dc.DrawLine(0, 0, w, 0)
+
+if __name__ == "__main__":
+ app = wx.App()
+ frame = wx.Frame(None, title="Piano keyboard test", size=(650, 110))
+ keyboard = Keyboard(frame)
+ frame.Show()
+ app.MainLoop()
diff --git a/work-in-progress/test_event_parser.py b/work-in-progress/test_event_parser.py
new file mode 100644
index 0000000..81703fa
--- /dev/null
+++ b/work-in-progress/test_event_parser.py
@@ -0,0 +1,69 @@
+import random
+from pyo import *
+from EventParser import EventParser
+
+### Orchestra ###
+class Instr1:
+ def __init__(self, duration, *args):
+ self.f = Fader(0.001, duration-0.005, duration, args[1]).play()
+ self.f.setExp(3)
+ self.osc = SineLoop([args[0], args[0]*1.01], feedback=0.12, mul=self.f)
+ self.filt = ButHP(self.osc, args[0]).out()
+
+class Rhythm:
+ def __init__(self, duration, *args):
+ self.env = CosTable([(0,0), (32,1), (1000,.25), (8191,0)])
+ rhythms = [[2,2,1,1,1,1,4], [1,2,1,2,2,1,2,1,2,1,1],[4,2,1,1,2,2,1.3,1.3,1.4]]
+ self.seq = Seq(.125, random.choice(rhythms), poly=1, onlyonce=True).play()
+ self.amp = TrigEnv(self.seq, self.env, .125, mul=args[1])
+ self.osc = Lorenz([args[0], args[0]*1.01], args[2], True, mul=self.amp)
+ self.disto = Disto(self.osc, drive=0.9, slope=0.9, mul=0.4)
+ self.bp = ButBP(self.disto, freq=1000, q=0.7).out()
+
+class Chord:
+ def __init__(self, duration, *args, **kwargs):
+ self.f = Fader(1, 1, duration, args[0]).play()
+ self.o1 = LFO(kwargs["f1"], sharp=0.95, type=2, mul=self.f).out()
+ self.o2 = LFO(kwargs["f2"], sharp=0.95, type=2, mul=self.f).out(1)
+ self.o3 = LFO(kwargs["f3"], sharp=0.95, type=2, mul=self.f).out()
+ self.o4 = LFO(kwargs["f4"], sharp=0.95, type=2, mul=self.f).out(1)
+
+### Little score generator ###
+sc = ""
+starttime = 8
+for i in range(300):
+ template = "Instr1 => %f %f %f %f\n"
+ dur = random.choice([.25, .75, 1])
+ freq = random.choice(midiToHz([67,70,72,75,79,84,86,87,91]))
+ amp = random.uniform(0.08, 0.15)
+ sc = sc + template % (starttime, dur, freq, amp)
+ starttime += random.choice([.125, .125, .25, .25])
+for i in range(65):
+ template = "Rhythm => %f %f %f %f %f\n"
+ pit = random.uniform(0.9, 1.0)
+ amp = random.uniform(0.1, 0.2)
+ chaos = random.uniform(0.8, 1.0)
+ sc = sc + template % (i, 1, pit, amp, chaos)
+for i in range(17):
+ template = "Chord => %f 5 0.03 %s\n"
+ notes = midiToHz([48.01,55.02,59.99,63.01,67,69.98,72.03,75.04])
+ cdict = {"f1": random.choice(notes), "f2": random.choice(notes),
+ "f3": random.choice(notes), "f4": random.choice(notes)}
+ sc = sc + template % (i * 4, str(cdict))
+
+### Rendering ###
+REALTIME = True
+
+if REALTIME:
+ s = Server().boot()
+else:
+ s = Server(buffersize=8, audio="offline").boot()
+ s.recordOptions(dur=70, filename="rendered_score.wav")
+
+reader = EventParser(s, sc, globals())
+reader.play()
+
+if REALTIME:
+ s.gui(locals())
+else:
+ s.start()
\ No newline at end of file
--
python-pyo packaging
More information about the pkg-multimedia-commits
mailing list