[SCM] python-pyo/master: New pyo release - new files.
tiago at users.alioth.debian.org
tiago at users.alioth.debian.org
Tue Dec 13 20:35:49 UTC 2016
The following commit has been merged in the master branch:
commit 83a2d72865bcb40c106d0b2599ea7ecc4a116cd3
Author: Tiago Bortoletto Vaz <tiago at debian.org>
Date: Tue Dec 13 13:15:33 2016 -0500
New pyo release - new files.
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..b213785
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,74 @@
+This is a list of features/fixes to implement for future releases
+=================================================================
+
+Internal
+--------
+
+- Replace malloc/realloc with a custom memory pool allocator.
+
+- Use inheritance (instead of a bunch of macros) at the C level.
+ PyoObject_base or Stream) should handle `mul`, `add` and
+ stream-related functions for every PyoObject. It should make the
+ code much simple and easier to maintain/extend, and also reduce
+ compiling time and binary size.
+
+
+Server
+------
+
+- A method to retrieve a graph of the internal state of the server
+ (active objects, connections, attribute values, ...).
+
+- Remove, if possible, PyGILState_Ensure/PyGILState_Release from
+ the process_buffers function.
+
+
+Examples
+--------
+
+- A section about building fx and synth classes.
+
+
+Objects
+-------
+
+- TrigMap(inputs, values, init=0, mul=1, add=0)
+
+ 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.
+
+MIDI
+----
+
+- Create a MidiLinseg object that act like MidiAdsr but with a breakpoints
+ function as the envelope. The sustain point should settable by the user.
+
+
+GUI
+---
+
+- Implement all GUI components with Tkinter and make it the default GUI
+ toolkit (instead of wxpython). WxPython classes could be removed from
+ pyo sources and built as an optional extra package (pyo-wxgui). The idea
+ is to remove an extra dependency, as tk is generally builtin with python.
+
+- MixerGUI, an interface to control the routing of a Mixer object.
+
+
+Tables
+------
+
+- Objects that can write to tables should accept any PyoTableObject,
+ not just a NewTable or a DataTable.
+
+
+E-Pyo
+-----
+
+- Window splitter to show more than one file at the time (multiple
+ views) ?
+
+- We need A way to let the user interact with the script via input()
+ and raw_input() functions.
diff --git a/doc-sphinx/source/_static/structure.png b/doc-sphinx/source/_static/structure.png
new file mode 100644
index 0000000..7f44901
Binary files /dev/null and b/doc-sphinx/source/_static/structure.png differ
diff --git a/doc-sphinx/source/perftips.rst b/doc-sphinx/source/perftips.rst
new file mode 100644
index 0000000..ed66221
--- /dev/null
+++ b/doc-sphinx/source/perftips.rst
@@ -0,0 +1,435 @@
+How to improve performance of your pyo programs
+===============================================
+
+This document lists various tips that help to improve the performance of your
+pyo programs.
+
+Python tips
+-----------
+
+There is not much you can do at the Python level because once the script has
+finished its execution run, almost all computations are done in the C level
+of pyo. Nevertheless, there is these two tricks to consider:
+
+Adjust the interpreter's "check interval"
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You can change how often the interpreter checks for periodic things with
+`sys.setcheckinterval(interval)`. The defaults is 100, which means the check
+is performed every 100 Python virtual instructions. Setting it to a larger
+value may increase performance for programs using threads.
+
+Use the subprocess or multiprocessing modules
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You can use the subprocess or multiprocessing modules to spawn your processes
+on multiple processors. From the python docs:
+
+ The multiprocessing package offers both local and remote concurrency,
+ effectively side-stepping the Global Interpreter Lock by using subprocesses
+ instead of threads. Due to this, the multiprocessing module allows the
+ programmer to fully leverage multiple processors on a given machine.
+ It runs on both Unix and Windows.
+
+Here is a little example of using the multiprocessing module to spawn a lot of
+sine wave computations to multiple processors.
+
+.. code-block:: python
+
+ #!/usr/bin/env python
+ # encoding: utf-8
+ """
+ Spawning lot of sine waves to multiple processes.
+ From the command line, run the script with -i flag.
+
+ """
+ from pyo import *
+ from random import uniform
+ import time, multiprocessing
+
+ class Group(multiprocessing.Process):
+ def __init__(self, n):
+ super(Group, self).__init__()
+ self.daemon = True
+
+ self.s = Server()
+ self.s.deactivateMidi()
+ self.s.boot().start()
+
+ freqs = [uniform(400,800) for i in range(n)]
+ self.a = Sine(freq=freqs, mul=.005).out()
+
+ def run(self):
+ while True:
+ time.sleep(0.001)
+
+ if __name__ == '__main__':
+ jobs = []
+ # Starts four processes playing 500 sines each.
+ for i in range(4):
+ jobs.append(Group(500))
+ for job in jobs:
+ job.start()
+
+Avoid memory allocation after initialization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Dynamic memory allocation (malloc/calloc/realloc) tends to be
+nondeterministic; the time taken to allocate memory may not be predictable,
+making it inappropriate for real time systems. To be sure that the audio
+callback will run smoothly all the time, it is better to create all audio
+objects at the program's initialization and call their `stop()`, `play()`,
+`out()` methods when needed.
+
+Be aware that a simple arithmetic operation involving an audio object will
+create a `Dummy` object (to hold the modified signal), thus will allocate
+memory for its audio stream AND add a processing task on the CPU. Run this
+simple example and watch the process's CPU growing:
+
+.. code-block:: python
+
+ from pyo import *
+ import random
+
+ s = Server().boot()
+
+ env = Fader(0.005, 0.09, 0.1, mul=0.2)
+ jit = Randi(min=1.0, max=1.02, freq=3)
+ sig = RCOsc(freq=[100,100], mul=env).out()
+
+ def change():
+ freq = midiToHz(random.randrange(60, 72, 2))
+ # Because `jit` is a PyoObject, both `freq+jit` and `freq-jit` will
+ # create a `Dummy` object, for which a reference will be created and
+ # saved in the `sig` object. The result is both memory and CPU
+ # increase until something bad happens!
+ sig.freq = [freq+jit, freq-jit]
+ env.play()
+
+ pat = Pattern(change, time=0.125).play()
+
+ s.gui(locals())
+
+An efficient version of this program should look like this:
+
+.. code-block:: python
+
+ from pyo import *
+ import random
+
+ s = Server().boot()
+
+ env = Fader(0.005, 0.09, 0.1, mul=0.2)
+ jit = Randi(min=1.0, max=1.02, freq=3)
+ # Create a `Sig` object to hold the frequency value.
+ frq = Sig(100)
+ # Create the `Dummy` objects only once at initialization.
+ sig = RCOsc(freq=[frq+jit, frq-jit], mul=env).out()
+
+ def change():
+ freq = midiToHz(random.randrange(60, 72, 2))
+ # Only change the `value` attribute of the Sig object.
+ frq.value = freq
+ env.play()
+
+ pat = Pattern(change, time=0.125).play()
+
+ s.gui(locals())
+
+Don't do anything that can trigger the garbage collector
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The garbage collector of python is another nondeterministic process. You
+should avoid doing anything that can trigger it. So, instead of deleting
+an audio object, which can turn out to delete many stream objects, you
+should just call its `stop()` method to remove it from the server's
+processing loop.
+
+Pyo tips
+--------
+
+Here is a list of tips specific to pyo that you should consider when trying to
+reduce the CPU consumption of your audio program.
+
+Mix down before applying effects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+It is very easy to over-saturate the CPU with pyo, especially if you use the
+multi-channel expansion feature. If your final output uses less channels than
+the number of audio streams in an object, don't forget to mix it down (call
+its `mix()` method) before applying effects on the sum of the signals.
+
+Consider the following snippet, which create a chorus of 50 oscillators and
+apply a phasing effect on the resulting sound:
+
+.. code-block:: python
+
+ src = SineLoop(freq=[random.uniform(190,210) for i in range(50)],
+ feedback=0.1, mul=0.01)
+ lfo = Sine(.25).range(200, 400)
+ phs = Phaser(src, freq=lfo, q=20, feedback=0.95).out()
+
+
+This version uses around 47% of the CPU on my Thinkpad T430, i5 3320M @ 2.6GHz.
+The problem is that the 50 oscillators given in input of the Phaser object
+creates 50 identical Phaser objects, one for each oscillator. That is a big
+waste of CPU. The next version mixes the oscillators into a stereo stream
+before applying the effect and the CPU consumption drops to ~7% !
+
+.. code-block:: python
+
+ src = SineLoop(freq=[random.uniform(190,210) for i in range(50)],
+ feedback=0.1, mul=0.01)
+ lfo = Sine(.25).range(200, 400)
+ phs = Phaser(src.mix(2), freq=lfo, q=20, feedback=0.95).out()
+
+
+When costly effects are involved, this can have a very drastic impact on the
+CPU usage.
+
+Stop your unused audio objects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Whenever you don't use an audio object (but you want to keep it for future
+uses), call its `stop()` method. This will inform the server to remove it from
+the computation loop. Setting the volume to 0 does not save CPU (everything is
+computed then multiplied by 0), the `stop()` method does. My own synth classes
+often looks like something like this:
+
+.. code-block:: python
+
+ class Glitchy:
+ def __init__(self):
+ self.feed = Lorenz(0.002, 0.8, True, 0.49, 0.5)
+ self.amp = Sine(0.2).range(0.01, 0.3)
+ self.src = SineLoop(1, self.feed, mul=self.amp)
+ self.filt = ButLP(self.src, 10000)
+
+ def play(self, chnl=0):
+ self.feed.play()
+ self.amp.play()
+ self.src.play()
+ self.filt.out(chnl)
+ return self
+
+ def stop(self):
+ self.feed.stop()
+ self.amp.stop()
+ self.src.stop()
+ self.filt.stop()
+ return self
+
+Control attribute with numbers instead of PyoObjects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Objects internal processing functions are optimized when plain numbers are
+given to their attributes. Unless you really need audio control over some
+parameters, don't waste CPU cycles and give fixed numbers to every attribute
+that don't need to change over time. See this comparison:
+
+.. code-block:: python
+
+ n = Noise(.2)
+
+ # ~5% CPU
+ p1 = Phaser(n, freq=[100,105], spread=1.2, q=10,
+ feedback=0.9, num=48).out()
+
+ # ~14% CPU
+ p2 = Phaser(n, freq=[100,105], spread=Sig(1.2), q=10,
+ feedback=0.9, num=48).out()
+
+Making the `spread` attribute of `p2` an audio signal causes the frequency of
+the 48 notches to be recalculated every sample, which can be a very costly
+process.
+
+Check for denormal numbers
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+From wikipedia:
+
+ In computer science, denormal numbers or denormalized numbers (now
+ often called subnormal numbers) fill the underflow gap around zero in
+ floating-point arithmetic. Any non-zero number with magnitude smaller
+ than the smallest normal number is 'subnormal'.
+
+The problem is that some processors compute denormal numbers very
+slowly, which makes grow the CPU consumption very quickly. The solution is to
+wrap the objects that are subject to denormals (any object with an internal
+recursive delay line, ie. filters, delays, reverbs, harmonizers, etc.) in a
+`Denorm` object. `Denorm` adds a little amount of noise, with a magnitude
+just above the smallest normal number, to its input. Of course, you can use
+the same noise for multiple denormalizations:
+
+.. code-block:: python
+
+ n = Noise(1e-24) # low-level noise for denormals
+
+ src = SfPlayer(SNDS_PATH+"/transparent.aif")
+ dly = Delay(src+n, delay=.1, feedback=0.8, mul=0.2).out()
+ rev = WGVerb(src+n).out()
+
+Use a PyoObject when available
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Always look first if a PyoObject does what you want, it will always more
+efficient than a the same process written from scratch.
+
+This construct, although pedagogically valid, will never be more efficient, in
+term of CPU and memory usage, than a native PyoObject (Phaser) written in C.
+
+.. code-block:: python
+
+ a = BrownNoise(.02).mix(2).out()
+
+ lfo = Sine(.25).range(.75, 1.25)
+ filters = []
+ for i in range(24):
+ freq = rescale(i, xmin=0, xmax=24, ymin=100, ymax=10000)
+ filter = Allpass2(a, freq=lfo*freq, bw=freq/2, mul=0.2).out()
+ filters.append(filter)
+
+It is also more efficient to use `Biquadx(stages=4)` than a cascade of four
+`Biquad` objects with identical arguments.
+
+Avoid trigonometric computation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Avoid trigonometric functions computed at audio rate (`Sin`, `Cos`, `Tan`,
+`Atan2`, etc.), use simple approximations instead. For example, you can
+replace a clean `Sin/Cos` panning function with a cheaper one based on `Sqrt`:
+
+.. code-block:: python
+
+ # Heavier
+ pan = Linseg([(0,0), (2, 1)]).play()
+ left = Cos(pan * math.pi * 0.5, mul=0.5)
+ right = Sin(pan * math.pi * 0.5, mul=0.5)
+ a = Noise([left, right]).out()
+
+ # Cheaper
+ pan2 = Linseg([(0,0), (2, 1)]).play()
+ left2 = Sqrt(1 - pan2, mul=0.5)
+ right2 = Sqrt(pan2, mul=0.5)
+ a2 = Noise([left2, right2]).out()
+
+Use approximations if absolute precision is not needed
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When absolute precision is not really important, you can save precious CPU
+cycles by using approximations instead of the real function. `FastSine` is an
+approximation of the `sin` function that can be almost twice cheaper than a
+lookup table (Sine). I plan to add more approximations like this one in the
+future.
+
+Re-use your generators
+^^^^^^^^^^^^^^^^^^^^^^
+
+Some times it possible to use the same signal for parallel purposes. Let's
+study the next process:
+
+.. code-block:: python
+
+ # single white noise
+ noise = Noise()
+
+ # denormal signal
+ denorm = noise * 1e-24
+ # little jitter around 1 used to modulate frequency
+ jitter = noise * 0.0007 + 1.0
+ # excitation signal of the waveguide
+ source = noise * 0.7
+
+ env = Fader(fadein=0.001, fadeout=0.01, dur=0.015).play()
+ src = ButLP(source, freq=1000, mul=env)
+ wg = Waveguide(src+denorm, freq=100*jitter, dur=30).out()
+
+Here the same white noise is used for three purposes at the same time. First,
+it is used to generate a denormal signal. Then, it is used to generate a
+little jitter applied to the frequency of the waveguide (that adds a little
+buzz to the string sound) and finally, we use it as the excitation of the
+waveguide. This is surely cheaper than generating three different white noises
+without noticeable difference in the sound.
+
+Leave 'mul' and 'add' attributes to their defaults when possible
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+There is an internal condition that bypass the object "post-processing"
+function when `mul=1` and `add=0`. It is a good practice to apply amplitude
+control in one place instead of messing with the `mul` attribute of each
+objects.
+
+.. code-block:: python
+
+ # wrong
+ n = Noise(mul=0.7)
+ bp1 = ButBP(n, freq=500, q=10, mul=0.5)
+ bp2 = ButBP(n, freq=1500, q=10, mul=0.5)
+ bp3 = ButBP(n, freq=2500, q=10, mul=0.5)
+ rev = Freeverb(bp1+bp2+bp3, size=0.9, bal=0.3, mul=0.7).out()
+
+ # good
+ n = Noise(mul=0.25)
+ bp1 = ButBP(n, freq=500, q=10)
+ bp2 = ButBP(n, freq=1500, q=10)
+ bp3 = ButBP(n, freq=2500, q=10)
+ rev = Freeverb(bp1+bp2+bp3, size=0.9, bal=0.3).out()
+
+Avoid graphical updates
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Even if they run in different threads, with different priorities, the audio
+callback and the graphical interface of a python program are parts of a unique
+process, sharing the same CPU. Don't use the Server's GUI if you don't need to
+see the meters or use the volume slider. Instead, you could start the script
+from command line with `-i` flag to leave the interpreter alive.
+
+.. code-block:: bash
+
+ $ python -i myscript.py
+
+List of CPU intensive objects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Here is a non-exhaustive list of the most CPU intensive objects of the library.
+
+- Analysis
+ - Yin
+ - Centroid
+ - Spectrum
+ - Scope
+- Arithmetic
+ - Sin
+ - Cos
+ - Tan
+ - Tanh
+ - Atan2
+- Dynamic
+ - Compress
+ - Gate
+- Special Effects
+ - Convolve
+- Prefix Expression Evaluator
+ - Expr
+- Filters
+ - Phaser
+ - Vocoder
+ - IRWinSinc
+ - IRAverage
+ - IRPulse
+ - IRFM
+- Fast Fourier Transform
+ - CvlVerb
+- Phase Vocoder
+ - Almost every objects!
+- Signal Generators
+ - LFO
+- Matrix Processing
+ - MatrixMorph
+- Table Processing
+ - Granulator
+ - Granule
+ - Particule
+ - OscBank
+- Utilities
+ - Resample
diff --git a/doc-sphinx/source/structure.rst b/doc-sphinx/source/structure.rst
new file mode 100644
index 0000000..84c8595
--- /dev/null
+++ b/doc-sphinx/source/structure.rst
@@ -0,0 +1,8 @@
+Structure of the library
+==========================
+
+This diagram shows the internal structure of the library.
+
+.. image:: _static/structure.png
+ :scale: 70
+ :align: center
diff --git a/embedded/openframeworks/PyoClass.cpp b/embedded/bela/PyoClass.cpp
similarity index 61%
copy from embedded/openframeworks/PyoClass.cpp
copy to embedded/bela/PyoClass.cpp
index bed1d65..7ffe0a6 100644
--- a/embedded/openframeworks/PyoClass.cpp
+++ b/embedded/bela/PyoClass.cpp
@@ -9,14 +9,17 @@
** nChannels : int, number of in/out channels.
** bufferSize : int, number of samples per buffer.
** sampleRate : int, sample rate frequency.
+** nAnalogChannels : int, number of analog channels.
**
** All arguments should be equal to the host audio settings.
*/
-void Pyo::setup(int _nChannels, int _bufferSize, int _sampleRate) {
+void Pyo::setup(int _nChannels, int _bufferSize, int _sampleRate, int _nAnalogChannels) {
nChannels = _nChannels;
bufferSize = _bufferSize;
sampleRate = _sampleRate;
- interpreter = pyo_new_interpreter(sampleRate, bufferSize, nChannels);
+ nAnalogChannels = _nAnalogChannels;
+ nTotalChannels = nChannels+nAnalogChannels;
+ interpreter = pyo_new_interpreter(sampleRate, bufferSize, nTotalChannels);
pyoInBuffer = reinterpret_cast<float*>(pyo_get_input_buffer_address(interpreter));
pyoOutBuffer = reinterpret_cast<float*>(pyo_get_output_buffer_address(interpreter));
pyoCallback = reinterpret_cast<callPtr*>(pyo_get_embedded_callback_address(interpreter));
@@ -32,27 +35,107 @@ Pyo::~Pyo() {
/*
** This function fills pyo's input buffers with new samples. Should be called
-** once per process block, inside the host's audioIn function.
+** once per process block, inside the host's render function.
**
** arguments:
** *buffer : float *, float pointer pointing to the host's input buffers.
*/
void Pyo::fillin(float *buffer) {
- for (int i=0; i<(bufferSize*nChannels); i++) pyoInBuffer[i] = buffer[i];
+ for (int i=0; i<bufferSize; i++) {
+ for (int j=0; j<nChannels; j++) {
+ pyoInBuffer[i*nTotalChannels+j] = buffer[i*nChannels+j];
+ }
+ }
}
+/*
+** This function fills pyo's reminaing input buffers (after audio voices)
+** with samples coming from analog inputs. Should be called once per
+** process block, inside the host's render function.
+**
+** arguments:
+** *buffer : float *, float pointer pointing to the host's analog buffers.
+*/
+void Pyo::analogin(float *buffer) {
+ switch (nAnalogChannels) {
+ case 2:
+ for (int i=0; i<bufferSize; i++) {
+ for (int j=0; j<nAnalogChannels; j++) {
+ pyoInBuffer[i*nTotalChannels+j+nChannels] = buffer[i*2*nAnalogChannels+j];
+ }
+ }
+ break;
+ case 4:
+ for (int i=0; i<bufferSize; i++) {
+ for (int j=0; j<nAnalogChannels; j++) {
+ pyoInBuffer[i*nTotalChannels+j+nChannels] = buffer[i*nAnalogChannels+j];
+ }
+ }
+ break;
+ case 8:
+ int ioff, joff;
+ for (int i=0; i<bufferSize/2; i++) {
+ ioff = i * 2 * nTotalChannels;
+ for (int j=0; j<nAnalogChannels; j++) {
+ joff = ioff + nChannels + j;
+ pyoInBuffer[joff] = pyoInBuffer[joff+nTotalChannels] = buffer[i*nAnalogChannels+j];
+ }
+ }
+ break;
+ }
+}
/*
** This function tells pyo to process a buffer of samples and fills the host's
** output buffer with new samples. Should be called once per process block,
-** inside the host's audioOut function.
+** inside the host's render function.
**
** arguments:
** *buffer : float *, float pointer pointing to the host's output buffers.
*/
void Pyo::process(float *buffer) {
pyoCallback(pyoId);
- for (int i=0; i<(bufferSize*nChannels); i++) buffer[i] = pyoOutBuffer[i];
+ for (int i=0; i<bufferSize; i++) {
+ for (int j=0; j<nChannels; j++) {
+ buffer[i*nChannels+j] = pyoOutBuffer[i*nTotalChannels+j];
+ }
+ }
+}
+
+/*
+** This function fills the host's analog output buffer with new samples.
+** Should be called once per process block, after a process() call, inside
+** the host's render function.
+**
+** arguments:
+** *buffer : float *, float pointer pointing to the host's analog output buffers.
+*/
+void Pyo::analogout(float *buffer) {
+ switch (nAnalogChannels) {
+ case 2:
+ int bufpos;
+ for (int i=0; i<bufferSize; i++) {
+ for (int j=0; j<nAnalogChannels; j++) {
+ bufpos = i * 2 * nAnalogChannels + j;
+ buffer[bufpos] = buffer[bufpos+nAnalogChannels] = pyoOutBuffer[i*nTotalChannels+j+nChannels];
+ }
+ }
+ break;
+ case 4:
+ for (int i=0; i<bufferSize; i++) {
+ for (int j=0; j<nAnalogChannels; j++) {
+ buffer[i*nAnalogChannels+j] = pyoOutBuffer[i*nTotalChannels+j+nChannels];
+ }
+ }
+ break;
+ case 8:
+ for (int i=0; i<bufferSize/2; i++) {
+ for (int j=0; j<nAnalogChannels; j++) {
+ buffer[i*nAnalogChannels+j] = pyoOutBuffer[i*2*nTotalChannels+j+nChannels];
+ }
+ }
+ break;
+ }
}
/*
@@ -85,7 +168,7 @@ int Pyo::loadfile(const char *file, int add) {
**
** freq = SigTo(value=440, time=0.1, init=440)
**
-** Inside OpenFrameworks (for a Pyo object named `pyo`):
+** Inside the host (for a Pyo object named `pyo`):
**
** pyo.value("freq", 880);
*/
@@ -108,7 +191,7 @@ int Pyo::value(const char *name, float value) {
**
** freq = SigTo(value=[100,200,300,400], time=0.1, init=[100,200,300,400])
**
-** Inside OpenFrameworks (for a Pyo object named `pyo`):
+** Inside the host (for a Pyo object named `pyo`):
**
** float frequencies[4] = {150, 250, 350, 450};
** pyo.value("freq", frequencies, 4);
@@ -137,7 +220,7 @@ int Pyo::value(const char *name, float *value, int len) {
**
** filter = Biquad(input=Noise(0.5), freq=1000, q=4, type=2)
**
-** Inside OpenFrameworks (for a Pyo object named `pyo`):
+** Inside the host (for a Pyo object named `pyo`):
**
** pyo.set("filter.freq", 2000);
*/
@@ -160,7 +243,7 @@ int Pyo::set(const char *name, float value) {
**
** filters = Biquad(input=Noise(0.5), freq=[250, 500, 1000, 2000], q=5, type=2)
**
-** Inside OpenFrameworks (for a Pyo object named `pyo`):
+** Inside the host (for a Pyo object named `pyo`):
**
** float frequencies[4] = {350, 700, 1400, 2800};
** pyo.set("filters.freq", frequencies, 4);
diff --git a/embedded/openframeworks/PyoClass.h b/embedded/bela/PyoClass.h
similarity index 83%
copy from embedded/openframeworks/PyoClass.h
copy to embedded/bela/PyoClass.h
index 2ca65b4..19b639c 100644
--- a/embedded/openframeworks/PyoClass.h
+++ b/embedded/bela/PyoClass.h
@@ -7,9 +7,11 @@ typedef int callPtr(int);
class Pyo {
public:
~Pyo();
- void setup(int nChannels, int bufferSize, int sampleRate);
+ void setup(int nChannels, int bufferSize, int sampleRate, int nAnalogChannels);
void process(float *buffer);
void fillin(float *buffer);
+ void analogin(float *buffer);
+ void analogout(float *buffer);
void clear();
int loadfile(const char *file, int add);
int exec(const char *msg);
@@ -22,6 +24,8 @@ class Pyo {
int nChannels;
int bufferSize;
int sampleRate;
+ int nAnalogChannels;
+ int nTotalChannels;
PyThreadState *interpreter;
float *pyoInBuffer;
float *pyoOutBuffer;
diff --git a/embedded/bela/README b/embedded/bela/README
new file mode 100644
index 0000000..b6057e0
--- /dev/null
+++ b/embedded/bela/README
@@ -0,0 +1,67 @@
+Introduction on how to use pyo on the BeagleBone Black with bela
+================================================================
+
+------------------------------------------------------------------------
+------------------------------------------------------------------------
+Step 1 - Changes made to the image bela_stable_2016.04.19.img
+
+1) Need the python-dev package
+
+ sudo apt-get install python-dev
+
+2) Compile a minimalistic pyo (libsndfile as only dependency)
+
+ git -c http.sslVerify=false clone https://github.com/belangeo/pyo.git
+ cd pyo
+ sudo python setup.py install --minimal
+
+3) Modify the Makefile to compile and link with python
+
+line 11:
+
+LIBS := -lrt -lnative -lxenomai -lsndfile `python-config --ldflags`
+
+line 20:
+
+CPP_FLAGS := -O3 -march=armv7-a -mtune=cortex-a8 -mfloat-abi=hard -mfpu=neon -ftree-vectorize `python-config --cflags`
+
+
+------------------------------------------------------------------------
+------------------------------------------------------------------------
+Step 2 - On the host computer, clone the beaglert repository:
+
+ hg clone https://code.soundsoftware.ac.uk/hg/beaglert
+
+------------------------------------------------------------------------
+Step 3 - Create a folder "pyo" in the beaglert/projects directory and copy:
+these files into it:
+
+- from the folder pyo/embedded:
+m_pyo.h
+
+- from the folder pyo/embedded/bela:
+main.cpp
+render.cpp
+main.py
+PyoClass.cpp
+PyoClass.h
+
+------------------------------------------------------------------------
+Step 3 - From the script folder, with the bbb plugged to the host computer,
+comple and run your project:
+
+ ./build_project.sh ../projects/pyo
+
+See the bela wiki for more options when building projects on the bbb board.
+
+https://code.soundsoftware.ac.uk/projects/beaglert/wiki/_Compiling_Bela_projects_on_the_board
+
+Documentation
+=============
+
+For a complete description of functions that can be used to communicate
+with the pyo embedded processes, see documentation comments in the file
+PyoClass.cpp.
+
+(c) 2016 - belangeo
+
diff --git a/embedded/bela/examples/analog-in-out.py b/embedded/bela/examples/analog-in-out.py
new file mode 100644
index 0000000..7174e84
--- /dev/null
+++ b/embedded/bela/examples/analog-in-out.py
@@ -0,0 +1,15 @@
+"""
+This example shows how to manage analog inputs and outputs.
+
+"""
+
+# Analog inputs comes right after the stereo audio channels.
+i1 = Tone(Input(2), 8) # analog in 0
+i2 = Tone(Input(3), 8) # analog in 1
+
+lfo = Sine([8,10], mul=0.2)
+
+# Analog outputs comes right after the stereo audio channels.
+o1 = Clip(i1+lfo[0], 0, 1).out(2) # analog out 0
+o2 = Clip(i2+lfo[1], 0, 1).out(3) # analog out 1
+
diff --git a/embedded/bela/examples/music-box.py b/embedded/bela/examples/music-box.py
new file mode 100644
index 0000000..02d2c90
--- /dev/null
+++ b/embedded/bela/examples/music-box.py
@@ -0,0 +1,22 @@
+"""
+Music box - Four voices randomly choosing frequencies
+over a common scale.
+
+"""
+# Set to True to control the global gain with analog input 0.
+WITH_ANALOG_INPUT = False
+
+if WITH_ANALOG_INPUT:
+ v = Tone(Input(2), 8) # knob 1 - global gain
+else:
+ v = 0.5
+
+mid_freqs = [midiToHz(m+7) for m in [60,62,63.93,65,67.01,69,71,72]]
+high_freqs = [midiToHz(m+7) for m in [72,74,75.93,77,79.01]]
+freqs = [mid_freqs,mid_freqs,high_freqs,high_freqs]
+
+chx = Choice(choice=freqs, freq=[2,3,3,4])
+port = Port(chx, risetime=.001, falltime=.001)
+sines = SineLoop(port, feedback=[.057,.033,.035,.016],
+ mul=[.1,.1,.05,.05]*v).out()
+
diff --git a/embedded/bela/examples/ring-mod.py b/embedded/bela/examples/ring-mod.py
new file mode 100644
index 0000000..ae2804d
--- /dev/null
+++ b/embedded/bela/examples/ring-mod.py
@@ -0,0 +1,58 @@
+"""
+01-Simple FX - Stereo ring modulator.
+
+This example shows how to build a ring modulation effect
+with modulator's frequency and brightness control with
+analog inputs (use audio inputs after the stereo audio
+channels, ie. Input(2) is analog-in 0, Input(3) is
+analog-in 1, etc.).
+
+It also show how to send signal to analog outputs. Again,
+use the outputs after the stereo audio channels, ie.
+.out(2) writes to analog-out 0, .out(3) to analog-out 1,
+etc.).
+
+"""
+# Set to True if you want to control the modulator
+# frequency and brightness with analog inputs.
+WITH_ANALOG_INPUT = True
+# If False, set frequency and brightness values.
+FREQUENCY = 500 # Hz
+BRIGHTNESS = 0.05 # 0 -> 0.2
+
+# If True, a positive value is sent on analog-out 0 and 1
+# whenever there is an output signal (can be used to build
+# a cheap vumeter with leds).
+WITH_ANALOG_OUTPUT = True
+
+# stereo input
+src = Input([0,1])
+
+# Don't know if the noise comes from my mic,
+# but it sounds better with a gate on the input!
+gate = Gate(src.mix(), thresh=-60, risetime=.005,
+ falltime=.02, lookahead=1, outputAmp=True)
+srcg = src * gate
+
+if WITH_ANALOG_INPUT:
+ # analog-in 0 (modulator's frequency)
+ i0 = Tone(Input(2), 8)
+ freq = Scale(i0, 0, 1, 1, 1000, 3)
+
+ # analog-in 1 (modulator's brightness)
+ i1 = Tone(Input(3), 8)
+ feed = i1 * 0.2
+else:
+ freq = FREQUENCY
+ feed = BRIGHTNESS
+
+# Modulation oscillator
+mod = SineLoop(freq, feed)
+
+# Ring modulation and stereo output
+out = (srcg * mod).out()
+
+if WITH_ANALOG_OUTPUT:
+ # analog out 0-1 (stereo vumeter)
+ fol = Sqrt(Clip(Follower(out, mul=4))).out(2)
+
diff --git a/embedded/bela/main.cpp b/embedded/bela/main.cpp
new file mode 100644
index 0000000..76d9c56
--- /dev/null
+++ b/embedded/bela/main.cpp
@@ -0,0 +1,95 @@
+/*
+ * main.cpp
+ *
+ * Created on: Oct 24, 2014
+ * Author: parallels
+ */
+#include <unistd.h>
+#include <iostream>
+#include <cstdlib>
+#include <libgen.h>
+#include <signal.h>
+#include <getopt.h>
+#include <BeagleRT.h>
+
+using namespace std;
+
+// Handle Ctrl-C by requesting that the audio rendering stop
+void interrupt_handler(int var)
+{
+ gShouldStop = true;
+}
+
+// Print usage information
+void usage(const char * processName)
+{
+ cerr << "Usage: " << processName << " [options]" << endl;
+
+ BeagleRT_usage();
+
+ cerr << " --help [-h]: Print this menu\n";
+}
+
+int main(int argc, char *argv[])
+{
+ BeagleRTInitSettings settings; // Standard audio settings
+
+ struct option customOptions[] =
+ {
+ {"help", 0, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+ };
+
+ // Set default settings
+ BeagleRT_defaultSettings(&settings);
+ // Set the buffer size
+ settings.periodSize = 64;
+ // Set the number of Analog channels (2, 4 or 8)
+ settings.numAnalogChannels = 8;
+
+ // Parse command-line arguments
+ while (1) {
+ int c;
+ if ((c = BeagleRT_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0)
+ break;
+ switch (c) {
+ case 'h':
+ usage(basename(argv[0]));
+ exit(0);
+ case '?':
+ default:
+ usage(basename(argv[0]));
+ exit(1);
+ }
+ }
+
+ // Initialise the PRU audio device
+ if(BeagleRT_initAudio(&settings, 0) != 0) {
+ cout << "Error: unable to initialise audio" << endl;
+ return -1;
+ }
+
+ // Start the audio device running
+ if(BeagleRT_startAudio()) {
+ cout << "Error: unable to start real-time audio" << endl;
+ return -1;
+ }
+
+ // Set up interrupt handler to catch Control-C and SIGTERM
+ signal(SIGINT, interrupt_handler);
+ signal(SIGTERM, interrupt_handler);
+
+ // Run until told to stop
+ while(!gShouldStop) {
+ usleep(100000);
+ }
+
+ // Stop the audio device
+ BeagleRT_stopAudio();
+
+ // Clean up any resources allocated for audio
+ BeagleRT_cleanupAudio();
+
+ // All done!
+ return 0;
+}
diff --git a/embedded/bela/main.py b/embedded/bela/main.py
new file mode 100644
index 0000000..02d2c90
--- /dev/null
+++ b/embedded/bela/main.py
@@ -0,0 +1,22 @@
+"""
+Music box - Four voices randomly choosing frequencies
+over a common scale.
+
+"""
+# Set to True to control the global gain with analog input 0.
+WITH_ANALOG_INPUT = False
+
+if WITH_ANALOG_INPUT:
+ v = Tone(Input(2), 8) # knob 1 - global gain
+else:
+ v = 0.5
+
+mid_freqs = [midiToHz(m+7) for m in [60,62,63.93,65,67.01,69,71,72]]
+high_freqs = [midiToHz(m+7) for m in [72,74,75.93,77,79.01]]
+freqs = [mid_freqs,mid_freqs,high_freqs,high_freqs]
+
+chx = Choice(choice=freqs, freq=[2,3,3,4])
+port = Port(chx, risetime=.001, falltime=.001)
+sines = SineLoop(port, feedback=[.057,.033,.035,.016],
+ mul=[.1,.1,.05,.05]*v).out()
+
diff --git a/embedded/bela/render.cpp b/embedded/bela/render.cpp
new file mode 100644
index 0000000..16b7f53
--- /dev/null
+++ b/embedded/bela/render.cpp
@@ -0,0 +1,35 @@
+#include <BeagleRT.h>
+#include <cmath>
+#include <iostream>
+#include <Utilities.h>
+#include "PyoClass.h"
+
+Pyo pyo;
+
+bool setup(BeagleRTContext *context, void *userData)
+{
+ // Initialize a pyo server.
+ pyo.setup(context->audioChannels, context->audioFrames,
+ context->audioSampleRate, context->analogChannels);
+ // Load a python file.
+ pyo.loadfile("/root/BeagleRT/source/main.py", 0);
+
+ return true;
+}
+
+void render(BeagleRTContext *context, void *userData)
+{
+ // Fill pyo input buffer (channels 0-1) with audio samples.
+ pyo.fillin(context->audioIn);
+ // Fill pyo input buffer (channels 2+) with analog inputs.
+ pyo.analogin(context->analogIn);
+ // Call pyo processing function and retrieve back stereo outputs.
+ pyo.process(context->audioOut);
+ // Get back pyo output channels 2+ as analog outputs.
+ pyo.analogout(context->analogOut);
+}
+
+void cleanup(BeagleRTContext *context, void *userData)
+{
+}
+
diff --git a/examples/01-intro/01-audio-server.py b/examples/01-intro/01-audio-server.py
new file mode 100644
index 0000000..dc354ea
--- /dev/null
+++ b/examples/01-intro/01-audio-server.py
@@ -0,0 +1,30 @@
+"""
+01-audio-server.py - Booting the audio server.
+
+A Server object needs to be created before any other audio object.
+It is the one that handles the communication with the audio and midi
+drivers and also the one that keeps track of the processing chain.
+
+"""
+from pyo import *
+
+# Creates a Server object with default arguments.
+# See the manual about how to change the sampling rate, the buffer
+# size, the number of channels or one of the other global settings.
+s = Server()
+
+# Boots the server. This step initializes audio and midi streams.
+# Audio and midi configurations (if any) must be done before that call.
+s.boot()
+
+# Starts the server. This step activates the server processing loop.
+s.start()
+
+# Here comes the processing chain...
+
+# The Server object provides a Graphical User Interface with the
+# gui() method. One of its purpose is to keep the program alive
+# while computing samples over time. If the locals dictionary is
+# given as argument, the user can continue to send commands to the
+# python interpreter from the GUI.
+s.gui(locals())
diff --git a/examples/01-intro/02-sine-tone.py b/examples/01-intro/02-sine-tone.py
new file mode 100644
index 0000000..1b441aa
--- /dev/null
+++ b/examples/01-intro/02-sine-tone.py
@@ -0,0 +1,21 @@
+"""
+02-sine-tone.py - The "hello world" of audio programming!
+
+This script simply plays a 1000 Hz sine tone.
+
+"""
+from pyo import *
+
+# Creates and boots the server.
+# The user should send the "start" command from the GUI.
+s = Server().boot()
+# Drops the gain by 20 dB.
+s.amp = 0.1
+
+# Creates a sine wave player.
+# The out() method starts the processing
+# and sends the signal to the output.
+a = Sine().out()
+
+# Opens the server graphical interface.
+s.gui(locals())
diff --git a/examples/01-intro/03-parallel-proc.py b/examples/01-intro/03-parallel-proc.py
new file mode 100644
index 0000000..f2e008a
--- /dev/null
+++ b/examples/01-intro/03-parallel-proc.py
@@ -0,0 +1,31 @@
+"""
+03-parallel-proc.py - Multiple processes on a single source.
+
+This example shows how to play different audio objects side-by-side.
+Every processing object (ie the ones that modify an audio source) have
+a first argument called "input". This argument takes the audio object
+to process.
+
+Note the input variable given to each processing object and the call
+to the out() method of each object that should send its samples to the
+output.
+
+"""
+from pyo import *
+
+s = Server().boot()
+s.amp = 0.1
+
+# Creates a sine wave as the source to process.
+a = Sine()
+
+# Passes the sine wave through an harmonizer.
+hr = Harmonizer(a).out()
+
+# Also through a chorus.
+ch = Chorus(a).out()
+
+# And through a frequency shifter.
+sh = FreqShift(a).out()
+
+s.gui(locals())
diff --git a/examples/01-intro/04-serial-proc.py b/examples/01-intro/04-serial-proc.py
new file mode 100644
index 0000000..53e32cf
--- /dev/null
+++ b/examples/01-intro/04-serial-proc.py
@@ -0,0 +1,32 @@
+"""
+04-serial-proc.py - Chaining processes on a single source.
+
+This example shows how to chain processes on a single source.
+Every processing object (ie the ones that modify an audio source) have
+a first argument called "input". This argument takes the audio object
+to process.
+
+Note the input variable given to each Harmonizer.
+
+"""
+from pyo import *
+
+s = Server().boot()
+s.amp = 0.1
+
+# Creates a sine wave as the source to process.
+a = Sine().out()
+
+# Passes the sine wave through an harmonizer.
+h1 = Harmonizer(a).out()
+
+# Then the harmonized sound through another harmonizer.
+h2 = Harmonizer(h1).out()
+
+# And again...
+h3 = Harmonizer(h2).out()
+
+# And again...
+h4 = Harmonizer(h3).out()
+
+s.gui(locals())
diff --git a/examples/01-intro/05-output-channels.py b/examples/01-intro/05-output-channels.py
new file mode 100644
index 0000000..f4b558a
--- /dev/null
+++ b/examples/01-intro/05-output-channels.py
@@ -0,0 +1,31 @@
+"""
+05-output-channels.py - Sending signals to different physical outputs.
+
+The simplest way to choose the output channel where to send the sound
+is to give it as the first argument of the out() method. In fact, the
+signature of the out() method reads as:
+
+.out(chnl=0, inc=1, dur=0, delay=0)
+
+`chnl` is the output where to send the first audio channel (stream) of
+the object. `inc` is the output increment for other audio channels.
+`dur` is the living duration, in seconds, of the process and `delay`
+is a delay, in seconds, before activating the process. A duration of
+0 means play forever.
+
+"""
+from pyo import *
+
+s = Server().boot()
+s.amp = 0.1
+
+# Creates a source (white noise)
+n = Noise()
+
+# Sends the bass frequencies (below 1000 Hz) to the left
+lp = ButLP(n).out()
+
+# Sends the high frequencies (above 1000 Hz) to the right
+hp = ButHP(n).out(1)
+
+s.gui(locals())
diff --git a/examples/02-controls/01-fixed-control.py b/examples/02-controls/01-fixed-control.py
new file mode 100644
index 0000000..72252ae
--- /dev/null
+++ b/examples/02-controls/01-fixed-control.py
@@ -0,0 +1,28 @@
+"""
+01-fixed-control.py - Number as argument.
+
+Audio objects behaviour can be controlled by passing
+value to their arguments at initialization time.
+
+"""
+from pyo import *
+
+s = Server().boot()
+s.amp = 0.1
+
+# Sets fundamental frequency
+freq = 200
+
+# Approximates a triangle waveform by adding odd harmonics with
+# amplitude proportional to the inverse square of the harmonic number.
+h1 = Sine(freq=freq, mul=1).out()
+h2 = Sine(freq=freq*3, phase=0.5, mul=1./pow(3,2)).out()
+h3 = Sine(freq=freq*5, mul=1./pow(5,2)).out()
+h4 = Sine(freq=freq*7, phase=0.5, mul=1./pow(7,2)).out()
+h5 = Sine(freq=freq*9, mul=1./pow(9,2)).out()
+h6 = Sine(freq=freq*11, phase=0.5, mul=1./pow(11,2)).out()
+
+# Displays the final waveform
+sp = Scope(h1+h2+h3+h4+h5+h6)
+
+s.gui(locals())
diff --git a/examples/02-controls/02-dynamic-control.py b/examples/02-controls/02-dynamic-control.py
new file mode 100644
index 0000000..09223aa
--- /dev/null
+++ b/examples/02-controls/02-dynamic-control.py
@@ -0,0 +1,23 @@
+"""
+02-dynamic-control.py - Graphical control for parameters.
+
+With pyo, it's easy to quickly try some parameter combination
+with the controller window already configured for each object.
+To open the controller window, just call the ctrl() method on
+the object you want to control.
+
+"""
+from pyo import *
+
+s = Server().boot()
+s.amp = 0.1
+
+# Creates two objects with cool parameters, one per channel.
+a = FM().out()
+b = FM().out(1)
+
+# Opens the controller windows.
+a.ctrl(title="Frequency modulation left channel")
+b.ctrl(title="Frequency modulation right channel")
+
+s.gui(locals())
diff --git a/examples/02-controls/03-output-range.py b/examples/02-controls/03-output-range.py
new file mode 100644
index 0000000..b26a8f1
--- /dev/null
+++ b/examples/02-controls/03-output-range.py
@@ -0,0 +1,41 @@
+"""
+03-output-range.py - The `mul` and `add` attributes.
+
+Almost all audio objects have a `mul` and `add` attributes.
+These are defined inside the PyoObject, which is the base
+class for all objects generating audio signal. The manual
+page of the PyoObject explains all behaviours common to
+audio objects.
+
+An audio signal outputs samples as floating-point numbers in
+the range -1 to 1. The `mul` and `add` attributes can be used
+to change the output range. Common uses are for modulating the
+amplitude of a sound or for building control signals like low
+frequency oscillators.
+
+A shortcut to automatically manipulate both `mul` and `add`
+attributes is to call the range(min, max) method of the
+PyoObject. This method sets `mul` and `add` attributes
+according to the desired `min` and `max` output values. It
+assumes that the generated signal is in the range -1 to 1.
+
+"""
+from pyo import *
+
+s = Server().boot().start()
+
+# The `mul` attribute multiplies each sample by its value.
+a = Sine(freq=100, mul=0.1)
+
+# The `add` attribute adds an offset to each sample.
+# The multiplication is applied before the addition.
+b = Sine(freq=100, mul=0.5, add=0.5)
+
+# Using the range(min, max) method allows to automatically
+# compute both `mul` and `add` attributes.
+c = Sine(freq=100).range(-0.25, 0.5)
+
+# Displays the waveforms
+sc = Scope([a, b, c])
+
+s.gui(locals())
diff --git a/examples/02-controls/04-building-lfo.py b/examples/02-controls/04-building-lfo.py
new file mode 100644
index 0000000..f2c4921
--- /dev/null
+++ b/examples/02-controls/04-building-lfo.py
@@ -0,0 +1,39 @@
+"""
+04-building-lfo.py - Audio control of parameters.
+
+One of the most important thing with computer music is the
+trajectories taken by parameters over time. This is what
+gives life to the synthesized sound.
+
+One way to create moving values is by connecting a low
+frequency oscillator to an object's attribute. This script
+shows that process.
+
+Other possibilities that will be covered later use random
+class objects or feature extraction from an audio signal.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# Creates a noise source
+n = Noise()
+
+# Creates an LFO oscillating +/- 500 around 1000 (filter's frequency)
+lfo1 = Sine(freq=.1, mul=500, add=1000)
+# Creates an LFO oscillating between 2 and 8 (filter's Q)
+lfo2 = Sine(freq=.4).range(2, 8)
+# Creates a dynamic bandpass filter applied to the noise source
+bp1 = ButBP(n, freq=lfo1, q=lfo2).out()
+
+# The LFO object provides more waveforms than just a sine wave
+
+# Creates a ramp oscillating +/- 1000 around 12000 (filter's frequency)
+lfo3 = LFO(freq=.25, type=1, mul=1000, add=1200)
+# Creates a square oscillating between 4 and 12 (filter's Q)
+lfo4 = LFO(freq=4, type=2).range(4, 12)
+# Creates a second dynamic bandpass filter applied to the noise source
+bp2 = ButBP(n, freq=lfo3, q=lfo4).out(1)
+
+s.gui(locals())
diff --git a/examples/02-controls/05-math-ops.py b/examples/02-controls/05-math-ops.py
new file mode 100644
index 0000000..9a1a2dc
--- /dev/null
+++ b/examples/02-controls/05-math-ops.py
@@ -0,0 +1,49 @@
+"""
+05-math-ops.py - Audio objects and arithmetic expresssions.
+
+This script shows how a PyoObject reacts when used inside an
+arithmetic expression.
+
+Multiplication, addition, division and substraction can be applied
+between pyo objects or between pyo objects and numbers. Doing so
+returns a Dummy object that outputs the result of the operation.
+
+A Dummy object is only a place holder to keep track of arithmetic
+operations on audio objects.
+
+PyoObject can also be used in expression with the exponent (**),
+modulo (%) and unary negative (-) operators.
+
+"""
+from __future__ import print_function
+from pyo import *
+
+s = Server().boot()
+s.amp = 0.1
+
+# Full scale sine wave
+a = Sine()
+
+# Creates a Dummy object `b` with `mul` attribute
+# set to 0.5 and leaves `a` unchanged.
+b = a * 0.5
+b.out()
+
+# Instance of Dummy class
+print(b)
+
+# Computes a ring modulation between two PyoObjects
+# and scales the amplitude of the resulting signal.
+c = Sine(300)
+d = a * c * 0.3
+d.out()
+
+# PyoObject can be used with Exponent operator.
+e = c ** 10 * 0.4
+e.out(1)
+
+# Displays the ringmod and the rectified signals.
+sp = Spectrum([d, e])
+sc = Scope([d, e])
+
+s.gui(locals())
diff --git a/examples/02-controls/06-multichannel-expansion.py b/examples/02-controls/06-multichannel-expansion.py
new file mode 100644
index 0000000..b59f0ce
--- /dev/null
+++ b/examples/02-controls/06-multichannel-expansion.py
@@ -0,0 +1,55 @@
+"""
+06-multichannel-expansion.py - What is a `Stream`? Polyphonic objects.
+
+List expansion is a powerful technique for generating many audio
+streams at once.
+
+What is a "stream"? A "stream" is a monophonic channel of samples.
+It is the basic structure over which all the library is built. Any
+PyoObject can handle as many streams as necessary to represent the
+defined process. When a polyphonic (ie more than one stream) object
+is asked to send its signals to the output, the server will use the
+arguments (`chnl` and `inc`) of the out() method to distribute the
+streams over the available output channels.
+
+Almost all attributes of all objects of the library accept list of
+values instead of a single value. The object will create internally
+the same number of streams than the length of the largest list
+given to an attribute at the initialization time. Each value of the
+list is used to generate one stream. Shorter lists will wrap around
+when reaching the end of the list.
+
+A PyoObject is considered by other object as a list. The function
+`len(obj)` returns the number of streams managed by the object. This
+feature is useful to create a polyphonic dsp chain.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+### Using multichannel-expansion to create a square wave ###
+
+# Sets fundamental frequency.
+freq = 100
+# Sets the highest harmonic.
+high = 20
+
+# Generates the list of harmonic frequencies (odd only).
+harms = [freq * i for i in range(1, high) if i%2 == 1]
+# Generates the list of harmonic amplitudes (1 / n).
+amps = [0.33 / i for i in range(1, high) if i%2 == 1]
+
+# Creates all sine waves at once.
+a = Sine(freq=harms, mul=amps)
+# Prints the number of streams managed by "a".
+print(len(a))
+
+# The mix(voices) method (defined in PyoObject) mixes
+# the object streams into `voices` streams.
+b = a.mix(voices=1).out()
+
+# Displays the waveform.
+sc = Scope(b)
+
+s.gui(locals())
diff --git a/examples/02-controls/07-multichannel-expansion-2.py b/examples/02-controls/07-multichannel-expansion-2.py
new file mode 100644
index 0000000..eb65c7b
--- /dev/null
+++ b/examples/02-controls/07-multichannel-expansion-2.py
@@ -0,0 +1,24 @@
+"""
+07-multichannel-expansion-2.py - Extended multichannel expansion.
+
+When using multichannel expansion with lists of different lengths,
+the longer list is used to set the number of streams and smaller
+lists will be wrap-around to fill the holes.
+
+This feature is very useful to create complex sonorities.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# 12 streams with different combinations of `freq` and `ratio`.
+a = SumOsc(freq=[100, 150.2, 200.5, 250.7],
+ ratio=[0.501, 0.753, 1.255],
+ index=[.3, .4, .5, .6, .7, .4, .5, .3, .6, .7, .3, .5],
+ mul=.05)
+
+# Adds a stereo reverberation to the signal
+rev = Freeverb(a.mix(2), size=0.80, damp=0.70, bal=0.30).out()
+
+s.gui(locals())
diff --git a/examples/02-controls/08-handling-channels.py b/examples/02-controls/08-handling-channels.py
new file mode 100644
index 0000000..f5b8c50
--- /dev/null
+++ b/examples/02-controls/08-handling-channels.py
@@ -0,0 +1,41 @@
+"""
+08-handling-channels.py - Managing object's internal audio streams.
+
+Because audio objects expand their number of streams according to lists
+given to their arguments and the fact that an audio object is considered
+as a list, if a multi-streams object is given as an argument to another
+audio object, the later will also be expanded in order to process all
+given streams. This is really powerful to create polyphonic processes
+without copying long chunks of code but it can be very CPU expensive.
+
+In this example, we create a square from a sum of sine waves. After that,
+a chorus is applied to the resulting waveform. If we don't mix down the
+square wave, we got tens of Chorus objects in the processing chain (one
+per sine). This can easily overrun the CPU. The exact same result can
+be obtained with only one Chorus applied to the sum of the sine waves.
+The `mix(voices)` method of the PyoObject helps the handling of channels
+in order to save CPU cycles. Here, we down mix all streams to only two
+streams (to maintain the stereo) before processing the Chorus arguments.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# Sets fundamental frequency and highest harmonic.
+freq = 100
+high = 20
+
+# Generates lists for frequencies and amplitudes
+harms = [freq * i for i in range(1, high) if i%2 == 1]
+amps = [0.33 / i for i in range(1, high) if i%2 == 1]
+
+# Creates a square wave by additive synthesis.
+a = Sine(freq=harms, mul=amps)
+print("Number of Sine streams: %d" % len(a))
+
+# Mix down the number of streams of "a" before computing the Chorus.
+b = Chorus(a.mix(2), feedback=0.5).out()
+print("Number of Chorus streams: %d" % len(b))
+
+s.gui(locals())
diff --git a/examples/02-controls/09-handling-channels-2.py b/examples/02-controls/09-handling-channels-2.py
new file mode 100644
index 0000000..b50b96e
--- /dev/null
+++ b/examples/02-controls/09-handling-channels-2.py
@@ -0,0 +1,26 @@
+"""
+09-handling-channels-2.py - The `out` method and the physical outputs.
+
+In a multichannel environment, we can carefully choose which stream
+goes to which output channel. To achieve this, we use the `chnl` and
+`inc` arguments of the out method.
+
+chnl : Physical output assigned to the first audio stream of the object.
+inc : Output channel increment value.
+
+"""
+from pyo import *
+
+# Creates a Server with 8 channels
+s = Server(nchnls=8).boot()
+
+# Generates a sine wave
+a = Sine(freq=500, mul=0.3)
+
+# Mixes it up to four streams
+b = a.mix(4)
+
+# Outputs to channels 0, 2, 4 and 6
+b.out(chnl=0, inc=2)
+
+s.gui(locals())
diff --git a/examples/02-controls/10-handling-channels-3.py b/examples/02-controls/10-handling-channels-3.py
new file mode 100644
index 0000000..7362f36
--- /dev/null
+++ b/examples/02-controls/10-handling-channels-3.py
@@ -0,0 +1,23 @@
+"""
+10-handling-channels-3.py - Random multichannel outputs.
+
+If `chnl` is negative, streams begin at 0, increment the output
+number by inc and wrap around the global number of channels.
+Then, the list of streams is scrambled.
+
+"""
+from pyo import *
+
+# Creates a Server with 8 channels
+s = Server(nchnls=8).boot()
+
+amps = [.05,.1,.15,.2,.25,.3,.35,.4]
+
+# Generates 8 sine waves with
+# increasing amplitudes
+a = Sine(freq=500, mul=amps)
+
+# Shuffles physical output channels
+a.out(chnl=-1)
+
+s.gui(locals())
diff --git a/examples/02-controls/11-handling-channels-4.py b/examples/02-controls/11-handling-channels-4.py
new file mode 100644
index 0000000..f9f9a50
--- /dev/null
+++ b/examples/02-controls/11-handling-channels-4.py
@@ -0,0 +1,22 @@
+"""
+11-handling-channels-4.py - Explicit control of the physical outputs.
+
+If `chnl` is a list, successive values in the list will be assigned
+to successive streams.
+
+"""
+from pyo import *
+
+# Creates a Server with 8 channels
+s = Server(nchnls=8).boot()
+
+amps = [.05,.1,.15,.2,.25,.3,.35,.4]
+
+# Generates 8 sine waves with
+# increasing amplitudes
+a = Sine(freq=500, mul=amps)
+
+# Sets the output channels ordering
+a.out(chnl=[3,4,2,5,1,6,0,7])
+
+s.gui(locals())
diff --git a/examples/03-generators/01-complex-oscs.py b/examples/03-generators/01-complex-oscs.py
new file mode 100644
index 0000000..447094d
--- /dev/null
+++ b/examples/03-generators/01-complex-oscs.py
@@ -0,0 +1,57 @@
+"""
+01-complex-oscs.py - Complex spectrum oscillators.
+
+This tutorial presents four objects of the library which are
+useful to generate complex spectrums by means of synthesis.
+
+Blit:
+Impulse train generator with control over the number of harmonics.
+
+RCOsc:
+Aproximation of a RC circuit (a capacitor and a resistor in series).
+
+SineLoop:
+Sine wave oscillator with feedback.
+
+SuperSaw:
+Roland JP-8000 Supersaw emulator.
+
+Use the "voice" slider of the window "Input interpolator" to
+interpolate between the four waveforms. Each one have an LFO
+applied to the argument that change the tone of the sound.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# Sets fundamental frequency.
+freq = 200
+
+# Impulse train generator.
+lfo1 = Sine(.1).range(1, 50)
+osc1 = Blit(freq=freq, harms=lfo1, mul=0.3)
+
+# RC circuit.
+lfo2 = Sine(.1, mul=0.5, add=0.5)
+osc2 = RCOsc(freq=freq, sharp=lfo2, mul=0.3)
+
+# Sine wave oscillator with feedback.
+lfo3 = Sine(.1).range(0, .18)
+osc3 = SineLoop(freq=freq, feedback=lfo3, mul=0.3)
+
+# Roland JP-8000 Supersaw emulator.
+lfo4 = Sine(.1).range(0.1, 0.75)
+osc4 = SuperSaw(freq=freq, detune=lfo4, mul=0.3)
+
+# Interpolates between input objects to produce a single output
+sel = Selector([osc1, osc2, osc3, osc4]).out()
+sel.ctrl(title="Input interpolator (0=Blit, 1=RCOsc, 2=SineLoop, 3=SuperSaw)")
+
+# Displays the waveform of the chosen source
+sc = Scope(sel)
+
+# Displays the spectrum contents of the chosen source
+sp = Spectrum(sel)
+
+s.gui(locals())
diff --git a/examples/03-generators/02-band-limited-oscs.py b/examples/03-generators/02-band-limited-oscs.py
new file mode 100644
index 0000000..bbd41db
--- /dev/null
+++ b/examples/03-generators/02-band-limited-oscs.py
@@ -0,0 +1,46 @@
+"""
+02-band-limited-oscs.py - Oscillators whose spectrum is kept under the Nyquist frequency.
+
+This tutorial presents an object (misnamed LFO but it's too late
+to change its name!) that implements various band-limited waveforms.
+A band-limited signal is a signal that none of its partials exceeds
+the nyquist frequency (sr/2).
+
+The LFO object, despite its name, can be use as a standard oscillator,
+with very high fundamental frequencies. At lower frequencies (below 20 Hz)
+this object will give a true LFO with various shapes.
+
+The "type" slider in the controller window lets choose between these
+particular waveforms:
+
+0. Saw up (default)
+1. Saw down
+2. Square
+3. Triangle
+4. Pulse
+5. Bipolar pulse
+6. Sample and hold
+7. Modulated Sine
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# Sets fundamental frequency.
+freq = 200
+
+# LFO applied to the `sharp` attribute
+lfo = Sine(.2, mul=0.5, add=0.5)
+
+# Various band-limited waveforms
+osc = LFO(freq=freq, sharp=lfo, mul=0.4).out()
+osc.ctrl()
+
+# Displays the waveform
+sc = Scope(osc)
+
+# Displays the spectrum contents
+sp = Spectrum(osc)
+
+s.gui(locals())
diff --git a/examples/03-generators/03-fm-generators.py b/examples/03-generators/03-fm-generators.py
new file mode 100644
index 0000000..b15d932
--- /dev/null
+++ b/examples/03-generators/03-fm-generators.py
@@ -0,0 +1,38 @@
+"""
+03-fm-generators.py - Frequency modulation synthesis.
+
+There two objects in the library that implement frequency
+modulation algorithms. These objects are very simple, although
+powerful. It is also relatively simple to build a custom FM
+algorithm, this will be covered in the tutorials on custom
+synthesis algorithms.
+
+Use the "voice" slider of the window "Input interpolator" to
+interpolate between the two sources. Use the controller windows
+to change the parameters of the FM algorithms.
+
+Note what happened in the controller window when we give a
+list of floats to an object's argument.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# FM implements the basic Chowning algorithm
+fm1 = FM(carrier=250, ratio=[1.5,1.49], index=10, mul=0.3)
+fm1.ctrl()
+
+# CrossFM implements a frequency modulation synthesis where the
+# output of both oscillators modulates the frequency of the other one.
+fm2 = CrossFM(carrier=250, ratio=[1.5,1.49], ind1=10, ind2=2, mul=0.3)
+fm2.ctrl()
+
+# Interpolates between input objects to produce a single output
+sel = Selector([fm1, fm2]).out()
+sel.ctrl(title="Input interpolator (0=FM, 1=CrossFM)")
+
+# Displays the spectrum contents of the chosen source
+sp = Spectrum(sel)
+
+s.gui(locals())
diff --git a/examples/03-generators/04-noise-generators.py b/examples/03-generators/04-noise-generators.py
new file mode 100644
index 0000000..b78f379
--- /dev/null
+++ b/examples/03-generators/04-noise-generators.py
@@ -0,0 +1,41 @@
+"""
+04-noise-generators.py - Different pseudo-random noise generators.
+
+There are three noise generators (beside random generators that
+will be covered later) in the library. These are the classic
+white noise, pink noise and brown noise.
+
+Noise:
+White noise generator, flat spectrum.
+
+PinkNoise:
+Pink noise generator, 3dB rolloff per octave.
+
+BrownNoise:
+Brown noise generator, 6dB rolloff per octave.
+
+Use the "voice" slider of the window "Input interpolator" to
+interpolate between the three sources.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# White noise
+n1 = Noise(0.3)
+
+# Pink noise
+n2 = PinkNoise(0.3)
+
+# Brown noise
+n3 = BrownNoise(0.3)
+
+# Interpolates between input objects to produce a single output
+sel = Selector([n1, n2, n3]).out()
+sel.ctrl(title="Input interpolator (0=White, 1=Pink, 2=Brown)")
+
+# Displays the spectrum contents of the chosen source
+sp = Spectrum(sel)
+
+s.gui(locals())
diff --git a/examples/03-generators/05-strange-attractors.py b/examples/03-generators/05-strange-attractors.py
new file mode 100644
index 0000000..4241df1
--- /dev/null
+++ b/examples/03-generators/05-strange-attractors.py
@@ -0,0 +1,58 @@
+"""
+05-strange-attractors.py - Non-linear ordinary differential equations.
+
+Oscilloscope part of the tutorial
+---------------------------------
+
+A strange attractor is a system of three non-linear ordinary
+differential equations. These differential equations define a
+continuous-time dynamical system that exhibits chaotic dynamics
+associated with the fractal properties of the attractor.
+
+There is three strange attractors in the library, the Rossler,
+the Lorenz and the ChenLee objects. Each one can output stereo
+signal if the `stereo` argument is set to True.
+
+Use the "voice" slider of the window "Input interpolator" to
+interpolate between the three sources.
+
+Audio part of the tutorial
+--------------------------
+
+It's possible to create very interesting LFO with strange
+attractors. The last part of this tutorial shows the use of
+Lorenz's output to drive the frequency of two sine wave oscillators.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+### Oscilloscope ###
+
+# LFO applied to the `chaos` attribute
+lfo = Sine(0.2).range(0, 1)
+
+# Rossler attractor
+n1 = Rossler(pitch=0.5, chaos=lfo, stereo=True)
+
+# Lorenz attractor
+n2 = Lorenz(pitch=0.5, chaos=lfo, stereo=True)
+
+# ChenLee attractor
+n3 = ChenLee(pitch=0.5, chaos=lfo, stereo=True)
+
+# Interpolates between input objects to produce a single output
+sel = Selector([n1, n2, n3])
+sel.ctrl(title="Input interpolator (0=Rossler, 1=Lorenz, 2=ChenLee)")
+
+# Displays the waveform of the chosen attractor
+sc = Scope(sel)
+
+### Audio ###
+
+# Lorenz with very low pitch value that acts as a LFO
+freq = Lorenz(0.005, chaos=0.7, stereo=True, mul=250, add=500)
+a = Sine(freq, mul=0.3).out()
+
+s.gui(locals())
diff --git a/examples/03-generators/06-random-generators.py b/examples/03-generators/06-random-generators.py
new file mode 100644
index 0000000..e822131
--- /dev/null
+++ b/examples/03-generators/06-random-generators.py
@@ -0,0 +1,44 @@
+"""
+06-random-generators.py - Overview of some random generators of pyo.
+
+The pyo's random category contains many objects that can be used
+for different purposes. This category really deserves to be studied.
+
+In this tutorial, we use three random objects (Choice, Randi, RandInt)
+to control the pitches, the amplitude and the tone of a simple synth.
+
+We will come back to random generators when we will talk about musical
+algorithms.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# Two streams of midi pitches chosen randomly in a predefined list.
+# The argument `choice` of Choice object can be a list of lists to
+# list-expansion.
+mid = Choice(choice=[60,62,63,65,67,69,71,72], freq=[2,3])
+
+# Two small jitters applied on frequency streams.
+# Randi interpolates between old and new values.
+jit = Randi(min=0.993, max=1.007, freq=[4.3,3.5])
+
+# Converts midi pitches to frequencies and applies the jitters.
+fr = MToF(mid, mul=jit)
+
+# Chooses a new feedback value, between 0 and 0.15, every 4 seconds.
+fd = Randi(min=0, max=0.15, freq=0.25)
+
+# RandInt generates a pseudo-random integer number between 0 and `max`
+# values at a frequency specified by `freq` parameter. It holds the
+# value until the next generation.
+# Generates an new LFO frequency once per second.
+sp = RandInt(max=6, freq=1, add=8)
+# Creates an LFO oscillating between 0 and 0.4.
+amp = Sine(sp, mul=0.2, add=0.2)
+
+# A simple synth...
+a = SineLoop(freq=fr, feedback=fd, mul=amp).out()
+
+s.gui(locals())
diff --git a/examples/04-soundfiles/01-read-from-disk.py b/examples/04-soundfiles/01-read-from-disk.py
new file mode 100644
index 0000000..5948579
--- /dev/null
+++ b/examples/04-soundfiles/01-read-from-disk.py
@@ -0,0 +1,26 @@
+"""
+01-read-from-disk.py - Soundfile playback from disk.
+
+SfPlayer and friends read samples from a file on disk with control
+over playback speed and looping mode.
+
+Player family:
+ - **SfPlayer** : Reads many soundfile formats from disk.
+ - **SfMarkerLooper** : AIFF with markers soundfile looper.
+ - **SfMarkerShuffler** : AIFF with markers soundfile shuffler.
+
+Reading sound file from disk can save a lot of RAM, especially if
+the soundfile is big, but it is more CPU expensive than loading
+the sound file in memory in a first pass.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+path = SNDS_PATH + "/transparent.aif"
+
+# stereo playback with a slight shift between the two channels.
+sf = SfPlayer(path, speed=[1, 0.995], loop=True, mul=0.4).out()
+
+s.gui(locals())
diff --git a/examples/04-soundfiles/02-read-from-disk-2.py b/examples/04-soundfiles/02-read-from-disk-2.py
new file mode 100644
index 0000000..ba5a9b8
--- /dev/null
+++ b/examples/04-soundfiles/02-read-from-disk-2.py
@@ -0,0 +1,46 @@
+"""
+02-read-from-disk-2.py - Catching the `end-of-file` signal from the SfPlayer object.
+
+This example demonstrates how to use the `end-of-file` signal
+of the SfPlayer object to trigger another playback (possibly
+with another sound, another speed, etc.).
+
+When a SfPlayer reaches the end of the file, it sends a trigger
+(more on trigger later) that the user can retrieve with the
+syntax :
+
+variable_name["trig"]
+
+"""
+from pyo import *
+import random
+
+s = Server().boot()
+
+# Sound bank
+folder = "../snds/"
+sounds = ["alum1.wav", "alum2.wav", "alum3.wav", "alum4.wav"]
+
+# Creates the left and right players
+sfL = SfPlayer(folder+sounds[0], speed=1, mul=0.5).out()
+sfR = SfPlayer(folder+sounds[0], speed=1, mul=0.5).out(1)
+
+# Function to choose a new sound and a new speed for the left player
+def newL():
+ sfL.path = folder + sounds[random.randint(0, 3)]
+ sfL.speed = random.uniform(0.75, 1.5)
+ sfL.out()
+
+# The "end-of-file" signal triggers the function "newL"
+tfL = TrigFunc(sfL["trig"], newL)
+
+# Function to choose a new sound and a new speed for the right player
+def newR():
+ sfR.path = folder + sounds[random.randint(0, 3)]
+ sfR.speed = random.uniform(0.75, 1.5)
+ sfR.out(1)
+
+# The "end-of-file" signal triggers the function "newR"
+tfR = TrigFunc(sfR["trig"], newR)
+
+s.gui(locals())
diff --git a/examples/04-soundfiles/03-read-from-ram.py b/examples/04-soundfiles/03-read-from-ram.py
new file mode 100644
index 0000000..bc693e0
--- /dev/null
+++ b/examples/04-soundfiles/03-read-from-ram.py
@@ -0,0 +1,30 @@
+"""
+03-read-from-ram.py - Soundfile playback from RAM.
+
+Reading a sound file from the RAM gives the advantage of a very
+fast access to every loaded samples. This is very useful for a
+lot of processes, such as granulation, looping, creating envelopes
+and waveforms and many others.
+
+The simplest way of loading a sound in RAM is to use the SndTable
+object. This example loads a sound file and reads it in loop.
+We will see some more evolved processes later...
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+path = SNDS_PATH + "/transparent.aif"
+
+# Loads the sound file in RAM. Beginning and ending points
+# can be controlled with "start" and "stop" arguments.
+t = SndTable(path)
+
+# Gets the frequency relative to the table length.
+freq = t.getRate()
+
+# Simple stereo looping playback (right channel is 180 degrees out-of-phase).
+osc = Osc(table=t, freq=freq, phase=[0, 0.5], mul=0.4).out()
+
+s.gui(locals())
diff --git a/examples/04-soundfiles/04-record-perf.py b/examples/04-soundfiles/04-record-perf.py
new file mode 100644
index 0000000..c22a487
--- /dev/null
+++ b/examples/04-soundfiles/04-record-perf.py
@@ -0,0 +1,48 @@
+"""
+04-record-perf.py - Recording the performance on disk.
+
+The Server object allow the recording of the overall playback
+(that is exactly what your hear). The "Rec Start" button of the
+Server's window is doing that with default parameters. It'll
+record a file called "pyo_rec.wav" (16-bit, 44100 Hz) on the
+user's desktop.
+
+You can control the recording with the Server's method called
+`recordOptions`, the arguments are:
+
+- dur : The duration of the recording, a value of -1 means
+ record forever (recstop() must be called by the user).
+- filename : Indicates the location of the recorded file.
+- fileformat : The format of the audio file (see documentation
+ for available formats).
+- sampletype : The sample type of the audio file (see documentation
+ for available types).
+
+The recording can be triggered programmatically with the Server's
+methods `recstart()` and `recstop()`. In order to record multiple files
+from a unique performance, it is possible to set the filename
+with an argument to `recstart()`.
+
+
+"""
+from pyo import *
+import os
+
+s = Server().boot()
+
+# Path of the recorded sound file.
+path = os.path.join(os.path.expanduser("~"), "Desktop", "synth.wav")
+# Record for 10 seconds a 24-bit wav file.
+s.recordOptions(dur=10, filename=path, fileformat=0, sampletype=1)
+
+# Creates an amplitude envelope
+amp = Fader(fadein=1, fadeout=1, dur=10, mul=0.3).play()
+
+# A Simple synth
+lfo = Sine(freq=[0.15, 0.16]).range(1.25, 1.5)
+fm2 = CrossFM(carrier=200, ratio=lfo, ind1=10, ind2=2, mul=amp).out()
+
+# Starts the recording for 10 seconds...
+s.recstart()
+
+s.gui(locals())
diff --git a/examples/04-soundfiles/05-record-streams.py b/examples/04-soundfiles/05-record-streams.py
new file mode 100644
index 0000000..9c552ea
--- /dev/null
+++ b/examples/04-soundfiles/05-record-streams.py
@@ -0,0 +1,55 @@
+"""
+05-record-streams.py - Recording individual audio streams on disk.
+
+The Record object can be used to record specific audio streams
+from a performance. It can be useful to record a sound in mutiple
+tracks to make post-processing on individual part easier. This
+example record the bass, the mid and the higher part in three
+separated files on the user's desktop.
+
+The `fileformat` and `sampletype` arguments are the same as in
+the Server's `recordOptions` method.
+
+"""
+from pyo import *
+import os
+
+s = Server().boot()
+
+# Defines sound file paths.
+path = os.path.join(os.path.expanduser("~"), "Desktop")
+bname = os.path.join(path, "bass.wav")
+mname = os.path.join(path, "mid.wav")
+hname = os.path.join(path, "high.wav")
+
+# Creates an amplitude envelope
+amp = Fader(fadein=1, fadeout=1, dur=10, mul=0.3).play()
+
+# Bass voice
+blfo = Sine(freq=[0.15, 0.16]).range(78, 82)
+bass = RCOsc(freq=blfo, mul=amp).out()
+
+# Mid voice
+mlfo = Sine(freq=[0.18, 0.19]).range(0.24, 0.26)
+mid = FM(carrier=1600, ratio=mlfo, index=5, mul=amp*0.3).out()
+
+# High voice
+hlfo = Sine(freq=[0.1, 0.11, 0.12, 0.13]).range(7000, 8000)
+high = Sine(freq=hlfo, mul=amp*0.1).out()
+
+# Creates the recorders
+brec = Record(bass, filename=bname, chnls=2, fileformat=0, sampletype=1)
+mrec = Record(mid, filename=mname, chnls=2, fileformat=0, sampletype=1)
+hrec = Record(high, filename=hname, chnls=2, fileformat=0, sampletype=1)
+
+# After 10.1 seconds, recorder objects will be automatically deleted.
+# This will trigger their stop method and properly close the sound files.
+clean = Clean_objects(10.1, brec, mrec, hrec)
+
+# Starts the internal timer of Clean_objects. Use its own thread.
+clean.start()
+
+# Starts the Server, in order to be sync with the cleanup process.
+s.start()
+
+s.gui(locals())
diff --git a/examples/04-soundfiles/06-record-table.py b/examples/04-soundfiles/06-record-table.py
new file mode 100644
index 0000000..9f8a9e8
--- /dev/null
+++ b/examples/04-soundfiles/06-record-table.py
@@ -0,0 +1,37 @@
+"""
+06-record-table.py - Recording live sound in RAM.
+
+By recording a stream of sound in RAM, one can quickly re-use the
+samples in the current process. A combination NewTable - TableRec
+is all what one need to record any stream in a table.
+
+The NewTable object has a `feedback` argument, allowing overdub.
+
+The TableRec object starts a new recording (records until the table
+is full) every time its method `play()` is called.
+
+"""
+from pyo import *
+import os
+
+# Audio inputs must be available.
+s = Server(duplex=1).boot()
+
+# Path of the recorded sound file.
+path = os.path.join(os.path.expanduser("~"), "Desktop", "synth.wav")
+
+# Creates a two seconds stereo empty table. The "feedback" argument
+# is the amount of old data to mix with a new recording (overdub).
+t = NewTable(length=2, chnls=2, feedback=0.5)
+
+# Retrieves the stereo input
+inp = Input([0,1])
+
+# Table recorder. Call rec.play() to start a recording, it stops
+# when the table is full. Call it multiple times to overdub.
+rec = TableRec(inp, table=t, fadetime=0.05)
+
+# Reads the content of the table in loop.
+osc = Osc(table=t, freq=t.getRate(), mul=0.5).out()
+
+s.gui(locals())
diff --git a/examples/05-envelopes/01-data-signal-conversion.py b/examples/05-envelopes/01-data-signal-conversion.py
new file mode 100644
index 0000000..f7ec208
--- /dev/null
+++ b/examples/05-envelopes/01-data-signal-conversion.py
@@ -0,0 +1,31 @@
+"""
+01-data-signal-conversion.py - Conversion from number to audio stream.
+
+The Stream object is a new type introduced by pyo to represent an
+audio signal as a vector of floats. It is sometimes useful to be
+able to convert simple numbers (python's floats or integers) to
+audio signal or to extract numbers from an audio stream.
+
+The Sig object converts a number to an audio stream.
+
+The PyoObject.get() method extracts a float from an audio stream.
+
+"""
+from __future__ import print_function
+from pyo import *
+
+s = Server().boot()
+
+# A python integer (or float).
+anumber = 100
+
+# Conversion from number to an audio stream (vector of floats).
+astream = Sig(anumber)
+
+# Use a Print (capital "P") object to print an audio stream.
+pp = Print(astream, interval=0.1, message="Audio stream value")
+
+# Use the get() method to extract a float from an audio stream.
+print("Float from audio stream : ", astream.get())
+
+s.gui(locals())
diff --git a/examples/05-envelopes/02-linear-ramp.py b/examples/05-envelopes/02-linear-ramp.py
new file mode 100644
index 0000000..98aa3a5
--- /dev/null
+++ b/examples/05-envelopes/02-linear-ramp.py
@@ -0,0 +1,41 @@
+"""
+02-linear-ramp.py - Portamento, glissando, ramping.
+
+The SigTo object allows to create audio glissando between the
+current value and the target value, within a user-defined time.
+The target value can be a float or another PyoObject. A new ramp
+is created everytime the target value changes.
+
+Also:
+
+The VarPort object acts similarly but works only with float and
+can call a user-defined callback when the ramp reaches the target
+value.
+
+The PyoObject.set() method is another way create a ramp for any
+given parameter that accept audio signal but is not already
+controlled with a PyoObject.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# 2 seconds linear ramp starting at 0.0 and ending at 0.3.
+amp = SigTo(value=0.3, time=2.0, init=0.0)
+
+# Pick a new value four times per second.
+pick = Choice([200,250,300,350,400], freq=4)
+
+# Print the chosen frequency
+pp = Print(pick, method=1, message="Frequency")
+
+# Add a little portamento on an audio target and detune a second frequency.
+freq = SigTo(pick, time=0.01, mul=[1, 1.005])
+# Play with portamento time.
+freq.ctrl([SLMap(0, 0.25, "lin", "time", 0.01, dataOnly=True)])
+
+# Play a simple wave.
+sig = RCOsc(freq, sharp=0.7, mul=amp).out()
+
+s.gui(locals())
diff --git a/examples/05-envelopes/03-exponential-ramp.py b/examples/05-envelopes/03-exponential-ramp.py
new file mode 100644
index 0000000..a0b18ee
--- /dev/null
+++ b/examples/05-envelopes/03-exponential-ramp.py
@@ -0,0 +1,33 @@
+"""
+03-exponential-ramp.py - Exponential portamento with rising and falling times.
+
+The Port object is designed to lowpass filter an audio signal with
+different coefficients for rising and falling signals. A lowpass
+filter is a good and efficient way of creating an exponential ramp
+from a signal containing abrupt changes. The rising and falling
+coefficients are controlled in seconds.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# 2 seconds linear ramp starting at 0.0 and ending at 0.3.
+amp = SigTo(value=0.3, time=2.0, init=0.0)
+
+# Pick a new value four times per second.
+pick = Choice([200,250,300,350,400], freq=4)
+
+# Print the chosen frequency
+pp = Print(pick, method=1, message="Frequency")
+
+# Add an exponential portamento on an audio target and detune a second frequency.
+# Sharp attack for rising notes and long release for falling notes.
+freq = Port(pick, risetime=0.001, falltime=0.25, mul=[1, 1.005])
+# Play with portamento times.
+freq.ctrl()
+
+# Play a simple wave.
+sig = RCOsc(freq, sharp=0.7, mul=amp).out()
+
+s.gui(locals())
diff --git a/examples/05-envelopes/04-simple-envelopes.py b/examples/05-envelopes/04-simple-envelopes.py
new file mode 100644
index 0000000..c16b1f0
--- /dev/null
+++ b/examples/05-envelopes/04-simple-envelopes.py
@@ -0,0 +1,46 @@
+"""
+04-simple-envelopes.py - ASR and ADSR envelopes.
+
+The Fader object is a simple way to setup an Attack/Sustain/Release envelope.
+This envelope allows to apply fadein and fadeout on audio streams.
+
+If the `dur` argument of the Fader object is set to 0 (the default), the
+object waits for a stop() command before activating the release part of
+the envelope. Otherwise, the sum of `fadein` and `fadeout` must be less
+than or egal to `dur` and the envelope runs to the end on a play() command.
+
+The Adsr object (Attack/Decay/Sustain/Release) acts exactly like the Fader
+object, with a more flexible (and so common) kind of envelope.
+
+"""
+from pyo import *
+import random
+
+s = Server().boot()
+
+# Infinite sustain for the global envelope.
+globalamp = Fader(fadein=2, fadeout=2, dur=0).play()
+
+# Envelope for discrete events, sharp attack, long release.
+env = Adsr(attack=0.01, decay=0.1, sustain=0.5, release=1.5, dur=2, mul=0.5)
+# setExp method can be used to create exponential or logarithmic envelope.
+env.setExp(0.75)
+
+# Initialize a simple wave player and apply both envelopes.
+sig = SuperSaw(freq=[100,101], detune=0.6, bal=0.8, mul=globalamp*env).out()
+
+def play_note():
+ "Play a new note with random frequency and jitterized envelope."
+ freq = random.choice(midiToHz([36, 38, 41, 43, 45]))
+ sig.freq = [freq, freq*1.005]
+ env.attack = random.uniform(0.002, 0.01)
+ env.decay = random.uniform(0.1, 0.5)
+ env.sustain = random.uniform(0.3, 0.6)
+ env.release = random.uniform(0.8, 1.4)
+ # Start the envelope for the event.
+ env.play()
+
+# Periodically call a function.
+pat = Pattern(play_note, time=2).play()
+
+s.gui(locals())
diff --git a/examples/05-envelopes/05-breakpoints-functions.py b/examples/05-envelopes/05-breakpoints-functions.py
new file mode 100644
index 0000000..8ddc614
--- /dev/null
+++ b/examples/05-envelopes/05-breakpoints-functions.py
@@ -0,0 +1,53 @@
+"""
+05-breakpoints-functions.py - Multi-segments envelopes.
+
+Linseg and Expseg objects draw a series of line segments between
+specified break-points, either linear or exponential.
+
+These objects wait for play() call to start reading the envelope.
+
+They have methods to set loop mode, call pause/play without reset,
+and replace the breakpoints.
+
+One can use the graph() method to open a graphical display of the current
+envelope, edit it, and copy the points (in the list format) to the
+clipboard (Menu "File" of the graph display => "Copy all Points ...").
+This makes it easier to explore and paste the result into the python
+script when happy with the envelope!
+
+"""
+from pyo import *
+import random
+
+s = Server().boot()
+
+# Randomly built 10-points amplitude envelope.
+t = 0
+points = [(0.0, 0.0), (2.0, 0.0)]
+for i in range(8):
+ t += random.uniform(.1, .2)
+ v = random.uniform(.1, .9)
+ points.insert(-1, (t, v))
+
+amp = Expseg(points, exp=3, mul=0.3)
+amp.graph(title="Amplitude envelope")
+
+sig = RCOsc(freq=[150,151], sharp=0.85, mul=amp)
+
+# A simple linear function to vary the amount of frequency shifting.
+sft = Linseg([(0.0, 0.0), (0.5, 20.0), (2, 0.0)])
+sft.graph(yrange=(0.0, 20.0), title="Frequency shift")
+
+fsg = FreqShift(sig, shift=sft).out()
+
+rev = WGVerb(sig+fsg, feedback=0.9, cutoff=3500, bal=0.3).out()
+
+def playnote():
+ "Start the envelopes to play an event."
+ amp.play()
+ sft.play()
+
+# Periodically call a function.
+pat = Pattern(playnote, 2).play()
+
+s.gui(locals())
diff --git a/examples/06-filters/01-lowpass-filters.py b/examples/06-filters/01-lowpass-filters.py
new file mode 100644
index 0000000..87857dc
--- /dev/null
+++ b/examples/06-filters/01-lowpass-filters.py
@@ -0,0 +1,41 @@
+"""
+01-lowpass-filters.py - The effect of the order of a filter.
+
+For this first example about filtering, we compare the frequency
+spectrum of three common lowpass filters.
+
+- Tone : IIR first-order lowpass
+- ButLP : IIR second-order lowpass (Butterworth)
+- MoogLP : IIR fourth-order lowpass (+ resonance as an extra parameter)
+
+Complementary highpass filters for the Tone and ButLP objects are Atone
+and ButHP. Another common highpass filter is the DCBlock object, which
+can be used to remove DC component from an audio signal.
+
+The next example will present bandpass filters.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# White noise generator
+n = Noise(.5)
+
+# Common cutoff frequency control
+freq = Sig(1000)
+freq.ctrl([SLMap(50, 5000, "lin", "value", 1000)], title="Cutoff Frequency")
+
+# Three different lowpass filters
+tone = Tone(n, freq)
+butlp = ButLP(n, freq)
+mooglp = MoogLP(n, freq)
+
+# Interpolates between input objects to produce a single output
+sel = Selector([tone, butlp, mooglp]).out()
+sel.ctrl(title="Filter selector (0=Tone, 1=ButLP, 2=MoogLP)")
+
+# Displays the spectrum contents of the chosen source
+sp = Spectrum(sel)
+
+s.gui(locals())
diff --git a/examples/06-filters/02-bandpass-filters.py b/examples/06-filters/02-bandpass-filters.py
new file mode 100644
index 0000000..dbc3705
--- /dev/null
+++ b/examples/06-filters/02-bandpass-filters.py
@@ -0,0 +1,37 @@
+"""
+02-bandpass-filters.py - Narrowing a bandpass filter bandwidth.
+
+This example illustrates the difference between a simple IIR second-order
+bandpass filter and a cascade of second-order bandpass filters. A cascade
+of four bandpass filters with a high Q can be used as a efficient resonator
+on the signal.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# White noise generator
+n = Noise(.5)
+
+# Common cutoff frequency control
+freq = Sig(1000)
+freq.ctrl([SLMap(50, 5000, "lin", "value", 1000)], title="Cutoff Frequency")
+
+# Common filter's Q control
+q = Sig(5)
+q.ctrl([SLMap(0.7, 20, "log", "value", 5)], title="Filter's Q")
+
+# Second-order bandpass filter
+bp1 = Reson(n, freq, q=q)
+# Cascade of second-order bandpass filters
+bp2 = Resonx(n, freq, q=q, stages=4)
+
+# Interpolates between input objects to produce a single output
+sel = Selector([bp1, bp2]).out()
+sel.ctrl(title="Filter selector (0=Reson, 1=Resonx)")
+
+# Displays the spectrum contents of the chosen source
+sp = Spectrum(sel)
+
+s.gui(locals())
diff --git a/examples/06-filters/03-complex-resonator.py b/examples/06-filters/03-complex-resonator.py
new file mode 100644
index 0000000..cdbbc32
--- /dev/null
+++ b/examples/06-filters/03-complex-resonator.py
@@ -0,0 +1,33 @@
+"""
+03-complex-resonator.py - Filtering by mean of a complex multiplication.
+
+ComplexRes implements a resonator derived from a complex
+multiplication, which is very similar to a digital filter.
+
+It is used here to create a rhythmic chime with varying resonance.
+
+"""
+from pyo import *
+import random
+
+s = Server().boot()
+
+# Six random frequencies.
+freqs = [random.uniform(1000, 3000) for i in range(6)]
+
+# Six different plucking speeds.
+pluck = Metro([.9,.8,.6,.4,.3,.2]).play()
+
+# LFO applied to the decay of the resonator.
+decay = Sine(.1).range(.01, .15)
+
+# Six ComplexRes filters.
+rezos = ComplexRes(pluck, freqs, decay, mul=5).out()
+
+# Change chime frequencies every 7.2 seconds
+def new():
+ freqs = [random.uniform(1000, 3000) for i in range(6)]
+ rezos.freq = freqs
+pat = Pattern(new, 7.2).play()
+
+s.gui(locals())
diff --git a/examples/06-filters/04-phasing.py b/examples/06-filters/04-phasing.py
new file mode 100644
index 0000000..ca42ace
--- /dev/null
+++ b/examples/06-filters/04-phasing.py
@@ -0,0 +1,39 @@
+"""
+04-phasing.py - The phasing effect.
+
+The Phaser object implements a variable number of second-order
+allpass filters, allowing to quickly build complex phasing effects.
+
+ A phaser is an electronic sound processor used to filter a signal
+ by creating a series of peaks and troughs in the frequency spectrum.
+ The position of the peaks and troughs of the waveform being affected
+ is typically modulated so that they vary over time, creating a sweeping
+ effect. For this purpose, phasers usually include a low-frequency
+ oscillator. - https://en.wikipedia.org/wiki/Phaser_(effect)
+
+A phase shifter unit can be built from scratch with the Allpass2 object,
+which implement a second-order allpass filter that create, when added to
+the original source, one notch in the spectrum.
+
+"""
+from pyo import *
+
+s = Server().boot()
+
+# Simple fadein.
+fade = Fader(fadein=.5, mul=.2).play()
+
+# Noisy source.
+a = PinkNoise(fade)
+
+# These LFOs modulate the `freq`, `spread` and `q` arguments of
+# the Phaser object. We give a list of two frequencies in order
+# to create two-streams LFOs, therefore a stereo phasing effect.
+lf1 = Sine(freq=[.1, .15], mul=100, add=250)
+lf2 = Sine(freq=[.18, .13], mul=.4, add=1.5)
+lf3 = Sine(freq=[.07, .09], mul=5, add=6)
+
+# Apply the phasing effect with 20 notches.
+b = Phaser(a, freq=lf1, spread=lf2, q=lf3, num=20, mul=.5).out()
+
+s.gui(locals())
diff --git a/examples/06-filters/05-convolution-filters.py b/examples/06-filters/05-convolution-filters.py
new file mode 100644
index 0000000..0c57ac1
--- /dev/null
+++ b/examples/06-filters/05-convolution-filters.py
@@ -0,0 +1,76 @@
+"""
+05-convolution-filters.py - Circular convolution.
+
+A circular convolution is defined as the integral of the
+product of two functions after one is reversed and shifted.
+
+Circular convolution allows to implement very complex FIR
+filters, at a CPU cost that is related to the filter impulse
+response (kernel) length.
+
+Within pyo, there is a family of IR* filter objects using
+circular convolution with predefined kernel:
+
+- IRAverage : moving average filter
+- IRFM : FM-like filter
+- IRPulse : comb-like filter
+- RWinSinc : break wall filters (lp, hp, hp, br)
+
+For general circular convolution, use the Convolve object
+with a PyoTableObject as the kernel, as in this example:
+
+A white noise is filtered by four impulses taken from the input mic.
+
+Call r1.play(), r2.play(), r3.play() or r4.play() in the Interpreter
+field while making some noise in the mic to fill the impulse response
+tables. The slider handles the morphing between the four kernels.
+
+Call t1.view(), t2.view(), t3.view() or t4.view() to view impulse
+response tables.
+
+Because circular convolution is very expensive, TLEN (in samples)
+should be keep small.
+
+"""
+from pyo import *
+
+# duplex=1 to tell the Server we need both input and output sounds.
+s = Server(duplex=1).boot()
+
+# Length of the impulse response in samples.
+TLEN = 512
+
+# Conversion to seconds for NewTable objects.
+DUR = sampsToSec(TLEN)
+
+# Excitation signal for the filters.
+sf = Noise(.5)
+
+# Signal from the mic to record the kernels.
+inmic = Input()
+
+# Four tables and recorders.
+t1 = NewTable(length=DUR, chnls=1)
+r1 = TableRec(inmic, table=t1, fadetime=.001)
+
+t2 = NewTable(length=DUR, chnls=1)
+r2 = TableRec(inmic, table=t2, fadetime=.001)
+
+t3 = NewTable(length=DUR, chnls=1)
+r3 = TableRec(inmic, table=t3, fadetime=.001)
+
+t4 = NewTable(length=DUR, chnls=1)
+r4 = TableRec(inmic, table=t4, fadetime=.001)
+
+# Interpolation control between the tables.
+pha = Sig(0)
+pha.ctrl(title="Impulse responses morphing")
+
+# Morphing between the four impulse responses.
+res = NewTable(length=DUR, chnls=1)
+morp = TableMorph(pha, res, [t1,t2,t3,t4])
+
+# Circular convolution between the excitation and the morphed kernel.
+a = Convolve(sf, table=res, size=res.getSize(), mul=.1).mix(2).out()
+
+s.gui(locals())
diff --git a/examples/06-filters/06-vocoder.py b/examples/06-filters/06-vocoder.py
new file mode 100644
index 0000000..542f893
--- /dev/null
+++ b/examples/06-filters/06-vocoder.py
@@ -0,0 +1,35 @@
+"""
+06-vocoder.py - Analysis/resynthesis vocoder effect.
+
+A vocoder is an analysis/resynthesis process that
+uses the spectral envelope of a first sound to shape
+the spectrum of a second sound. Usually (for the best
+results) the first sound should present a dynamic
+spectrum (for both frequencies and amplitudes) and the
+second sound should contain a rich and stable spectrum.
+
+In this example, LFOs are applied to every dynamic argument
+of the Vocoder object to show the range of sound effects
+the user can get with a vocoder.
+
+"""
+from pyo import *
+from random import random
+
+s = Server().boot()
+
+# First sound - dynamic spectrum.
+spktrm = SfPlayer("../snds/baseballmajeur_m.aif", speed=[1,1.001], loop=True)
+
+# Second sound - rich and stable spectrum.
+excite = Noise(0.2)
+
+# LFOs to modulated every parameters of the Vocoder object.
+lf1 = Sine(freq=0.1, phase=random()).range(60, 100)
+lf2 = Sine(freq=0.11, phase=random()).range(1.05, 1.5)
+lf3 = Sine(freq=0.07, phase=random()).range(1, 20)
+lf4 = Sine(freq=0.06, phase=random()).range(0.01, 0.99)
+
+voc = Vocoder(spktrm, excite, freq=lf1, spread=lf2, q=lf3, slope=lf4, stages=32).out()
+
+s.gui(locals())
diff --git a/examples/06-filters/07-hilbert-transform.py b/examples/06-filters/07-hilbert-transform.py
new file mode 100644
index 0000000..b084319
--- /dev/null
+++ b/examples/06-filters/07-hilbert-transform.py
@@ -0,0 +1,51 @@
+"""
+07-hilbert-transform.py - Barberpole-like phasing effect.
+
+This example uses two frequency shifters (based on complex
+modulation) linearly shifting the frequency content of a sound.
+
+Frequency shifting is similar to ring modulation, except the
+upper and lower sidebands are separated into individual outputs.
+
+"""
+from pyo import *
+
+class ComplexMod:
+ """
+ Complex modulation used to shift the frequency
+ spectrum of the input sound.
+ """
+ def __init__(self, hilb, freq):
+ # Quadrature oscillator (sine, cosine).
+ self._quad = Sine(freq, [0, 0.25])
+ # real * cosine.
+ self._mod1 = hilb['real'] * self._quad[1]
+ # imaginary * sine.
+ self._mod2 = hilb['imag'] * self._quad[0]
+ # Up shift corresponds to the sum frequencies.
+ self._up = (self._mod1 + self._mod2) * 0.7
+
+ def out(self, chnl=0):
+ self._up.out(chnl)
+ return self
+
+s = Server().boot()
+
+# Large spectrum source.
+src = PinkNoise(.2)
+
+# Apply the Hilbert transform.
+hilb = Hilbert(src)
+
+# LFOs controlling the amount of frequency shifting.
+lf1 = Sine(.03, mul=6)
+lf2 = Sine(.05, mul=6)
+
+# Stereo Single-Sideband Modulation.
+wetl = ComplexMod(hilb, lf1).out()
+wetr = ComplexMod(hilb, lf2).out(1)
+
+# Mixed with the dry sound.
+dry = src.mix(2).out()
+
+s.gui(locals())
diff --git a/examples/utilities/buffer_interface.py b/examples/utilities/buffer_interface.py
new file mode 100644
index 0000000..0b7c5ce
--- /dev/null
+++ b/examples/utilities/buffer_interface.py
@@ -0,0 +1,33 @@
+"""
+This example shows two things:
+
+1) How to share memory from a PyoTableObject to a numpy array. Numpy
+ functions can be used to modify the table's content without copying
+ every samples.
+
+2) How to register a `callback` function that the server will call at
+ the beginning of every processing loop (each `buffersize` samples).
+
+"""
+from pyo import *
+import numpy as np
+
+s = Server().boot()
+bs = s.getBufferSize()
+
+# Create a table of length `buffer size` and read it in loop.
+t = DataTable(size=bs)
+osc = TableRead(t, freq=t.getRate(), loop=True, mul=0.1).out()
+
+# Share the table's memory with a numpy array.
+arr = np.asarray(t.getBuffer())
+
+def process():
+ "Fill the array (so the table) with white noise."
+ arr[:] = np.random.normal(0.0, 0.5, size=bs)
+
+# Register the `process` function to be called at the beginning
+# of every processing loop.
+s.setCallback(process)
+
+s.gui(locals())
diff --git a/include/dummymodule.h b/include/ad_coreaudio.h
similarity index 52%
copy from include/dummymodule.h
copy to include/ad_coreaudio.h
index 8ce3436..d157fb0 100644
--- a/include/dummymodule.h
+++ b/include/ad_coreaudio.h
@@ -1,5 +1,5 @@
/**************************************************************************
- * Copyright 2009-2015 Olivier Belanger *
+ * Copyright 2009-2016 Olivier Belanger *
* *
* This file is part of pyo, a python module to help digital signal *
* processing script creation. *
@@ -18,18 +18,29 @@
* License along with pyo. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#include <Python.h>
-#include "pyomodule.h"
+#ifndef _AD_COREAUDIO_H
+#define _AD_COREAUDIO_H
-typedef struct {
- pyo_audio_HEAD
- PyObject *input;
- Stream *input_stream;
- int modebuffer[2]; // need at least 2 slots for mul & add
-} Dummy;
+#include <CoreAudio/AudioHardware.h>
+#include "servermodule.h"
-extern PyObject * Dummy_initialize(Dummy *self);
+OSStatus coreaudio_input_callback(AudioDeviceID device, const AudioTimeStamp* inNow,
+ const AudioBufferList* inInputData,
+ const AudioTimeStamp* inInputTime,
+ AudioBufferList* outOutputData,
+ const AudioTimeStamp* inOutputTime,
+ void* defptr);
+OSStatus coreaudio_output_callback(AudioDeviceID device, const AudioTimeStamp* inNow,
+ const AudioBufferList* inInputData,
+ const AudioTimeStamp* inInputTime,
+ AudioBufferList* outOutputData,
+ const AudioTimeStamp* inOutputTime,
+ void* defptr);
+int coreaudio_stop_callback(Server *self);
+int Server_coreaudio_init(Server *self);
+int Server_coreaudio_deinit(Server *self);
+int Server_coreaudio_start(Server *self);
+int Server_coreaudio_stop(Server *self);
-#define MAKE_NEW_DUMMY(self, type, rt_error) \
-(self) = (Dummy *)(type)->tp_alloc((type), 0); \
-if ((self) == rt_error) { return rt_error; }
+#endif
+/* _AD_COREAUDIO_H */
diff --git a/include/matrixmodule.h b/include/ad_jack.h
similarity index 65%
copy from include/matrixmodule.h
copy to include/ad_jack.h
index 72f5593..afac2de 100644
--- a/include/matrixmodule.h
+++ b/include/ad_jack.h
@@ -1,5 +1,5 @@
/**************************************************************************
- * Copyright 2009-2015 Olivier Belanger *
+ * Copyright 2009-2016 Olivier Belanger *
* *
* This file is part of pyo, a python module to help digital signal *
* processing script creation. *
@@ -18,31 +18,28 @@
* License along with pyo. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#include "Python.h"
-#include "pyomodule.h"
+#ifndef _AD_JACK_H
+#define _AD_JACK_H
-#ifdef __MATRIX_MODULE
+#include <jack/jack.h>
+#include "servermodule.h"
typedef struct {
- PyObject_HEAD
- int width;
- int height;
- MYFLT **data;
-} MatrixStream;
-
-
-#define MAKE_NEW_MATRIXSTREAM(self, type, rt_error) \
-(self) = (MatrixStream *)(type)->tp_alloc((type), 0); \
-if ((self) == rt_error) { return rt_error; } \
-\
-(self)->width = (self)->height = 0
-
-#else
-
-int MatrixStream_getWidth(PyObject *self);
-int MatrixStream_getHeight(PyObject *self);
-MYFLT MatrixStream_getPointFromPos(PyObject *self, long x, long y);
-MYFLT MatrixStream_getInterpPointFromPos(PyObject *self, MYFLT x, MYFLT y);
-extern PyTypeObject MatrixStreamType;
-
-#endif
\ No newline at end of file
+ jack_client_t *jack_client;
+ jack_port_t **jack_in_ports;
+ jack_port_t **jack_out_ports;
+} PyoJackBackendData;
+
+int jack_callback(jack_nframes_t nframes, void *arg);
+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);
+void Server_jack_autoconnect(Server *self);
+int Server_jack_init(Server *self);
+int Server_jack_deinit(Server *self);
+int Server_jack_start(Server *self);
+int Server_jack_stop(Server *self);
+
+#endif
+/* _AD_JACK_H */
diff --git a/include/ad_portaudio.h b/include/ad_portaudio.h
new file mode 100644
index 0000000..1c338c0
--- /dev/null
+++ b/include/ad_portaudio.h
@@ -0,0 +1,64 @@
+/**************************************************************************
+ * Copyright 2009-2016 Olivier Belanger *
+ * *
+ * This file is part of pyo, a python module to help digital signal *
+ * processing script creation. *
+ * *
+ * pyo is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * pyo is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with pyo. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#ifndef _AD_PORTAUDIO_H
+#define _AD_PORTAUDIO_H
+
+#include <Python.h>
+#include "portaudio.h"
+#include "servermodule.h"
+
+typedef struct {
+ PaStream *stream;
+} PyoPaBackendData;
+
+int pa_callback_interleaved(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *arg);
+
+int pa_callback_nonInterleaved(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *arg);
+int Server_pa_init(Server *self);
+int Server_pa_deinit(Server *self);
+int Server_pa_start(Server *self);
+int Server_pa_stop(Server *self);
+
+/* Queries. */
+PyObject * portaudio_get_version();
+PyObject * portaudio_get_version_text();
+PyObject * portaudio_count_host_apis();
+PyObject * portaudio_list_host_apis();
+PyObject * portaudio_get_default_host_api();
+PyObject * portaudio_count_devices();
+PyObject * portaudio_list_devices();
+PyObject * portaudio_get_devices_infos();
+PyObject * portaudio_get_output_devices();
+PyObject * portaudio_get_output_max_channels(PyObject *self, PyObject *arg);
+PyObject * portaudio_get_input_max_channels(PyObject *self, PyObject *arg);
+PyObject * portaudio_get_input_devices();
+PyObject * portaudio_get_default_input();
+PyObject * portaudio_get_default_output();
+
+#endif /* _AD_PORTAUDIO_H */
diff --git a/include/dummymodule.h b/include/md_portmidi.h
similarity index 55%
copy from include/dummymodule.h
copy to include/md_portmidi.h
index 8ce3436..0248a14 100644
--- a/include/dummymodule.h
+++ b/include/md_portmidi.h
@@ -1,5 +1,5 @@
/**************************************************************************
- * Copyright 2009-2015 Olivier Belanger *
+ * Copyright 2009-2016 Olivier Belanger *
* *
* This file is part of pyo, a python module to help digital signal *
* processing script creation. *
@@ -18,18 +18,36 @@
* License along with pyo. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
+#ifndef _MD_PORTMIDI_H
+#define _MD_PORTMIDI_H
+
#include <Python.h>
-#include "pyomodule.h"
+#include "portmidi.h"
+#include "porttime.h"
+#include "servermodule.h"
typedef struct {
- pyo_audio_HEAD
- PyObject *input;
- Stream *input_stream;
- int modebuffer[2]; // need at least 2 slots for mul & add
-} Dummy;
+ PmStream *midiin[64];
+ PmStream *midiout[64];
+} PyoPmBackendData;
+
+void portmidiGetEvents(Server *self);
+int Server_pm_init(Server *self);
+int Server_pm_deinit(Server *self);
+void pm_noteout(Server *self, int pit, int vel, int chan, long timestamp);
+void pm_afterout(Server *self, int pit, int vel, int chan, long timestamp);
+void pm_ctlout(Server *self, int ctlnum, int value, int chan, long timestamp);
+void pm_programout(Server *self, int value, int chan, long timestamp);
+void pm_pressout(Server *self, int value, int chan, long timestamp);
+void pm_bendout(Server *self, int value, int chan, long timestamp);
+void pm_sysexout(Server *self, unsigned char *msg, long timestamp);
-extern PyObject * Dummy_initialize(Dummy *self);
+/* Queries. */
+PyObject * portmidi_count_devices();
+PyObject * portmidi_list_devices();
+PyObject * portmidi_get_input_devices();
+PyObject * portmidi_get_output_devices();
+PyObject * portmidi_get_default_input();
+PyObject * portmidi_get_default_output();
-#define MAKE_NEW_DUMMY(self, type, rt_error) \
-(self) = (Dummy *)(type)->tp_alloc((type), 0); \
-if ((self) == rt_error) { return rt_error; }
+#endif /* _MD_PORTMIDI_H */
diff --git a/include/py2to3.h b/include/py2to3.h
new file mode 100644
index 0000000..d0227d4
--- /dev/null
+++ b/include/py2to3.h
@@ -0,0 +1,87 @@
+/**************************************************************************
+ * Copyright 2009-2015 Olivier Belanger *
+ * *
+ * This file is part of pyo, a python module to help digital signal *
+ * processing script creation. *
+ * *
+ * pyo is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * pyo is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with pyo. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+// This header includes some compatibility code between python 2 and python 3
+
+#include "Python.h"
+
+#ifndef _PY_2TO3_H
+#define _PY_2TO3_H
+
+
+#if PY_MAJOR_VERSION >= 3
+/* This is the default on Python3 and constant has been removed. */
+#define Py_TPFLAGS_CHECKTYPES 0
+/* This seems to be a Python 2 thing only for compatibility with even older versions of Python.
+ * It has been removed in Python 3. */
+#define Py_TPFLAGS_HAVE_NEWBUFFER 0
+#define PyFloat_FromString(a,removed_parameter) PyFloat_FromString(a)
+
+/* PyInt -> PyLong remapping */
+#define PyInt_AsLong PyLong_AsLong
+#define PyInt_Check PyLong_Check
+#define PyInt_FromString PyLong_FromString
+#define PyInt_FromUnicode PyLong_FromUnicode
+#define PyInt_FromLong PyLong_FromLong
+#define PyInt_FromSize_t PyLong_FromSize_t
+#define PyInt_FromSsize_t PyLong_FromSsize_t
+#define PyInt_AsLong PyLong_AsLong
+// Note: Slightly different semantics, the macro does not do any error checking
+#define PyInt_AS_LONG PyLong_AsLong
+#define PyInt_AsSsize_t PyLong_AsSsize_t
+#define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask
+#define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask
+
+#define PyNumber_Int PyNumber_Long
+#define PyInt_Type PyLong_Type
+
+#endif /* PY_MAJOR_VERSION >= 3 */
+
+#endif
+
+// See PEP 238
+#define PyNumber_Divide PyNumber_TrueDivide
+#define PyNumber_InPlaceDivide PyNumber_InPlaceTrueDivide
+
+#if PY_MAJOR_VERSION >= 3
+// nb_coerce, nb_oct and nb_hex fields have been removed in Python 3
+#define INITIALIZE_NB_COERCE_ZERO
+#define INITIALIZE_NB_OCT_ZERO
+#define INITIALIZE_NB_HEX_ZERO
+#define INITIALIZE_NB_IN_PLACE_DIVIDE_ZERO
+#define INITIALIZE_NB_DIVIDE_ZERO
+#else
+#define INITIALIZE_NB_COERCE_ZERO 0,
+#define INITIALIZE_NB_OCT_ZERO 0,
+#define INITIALIZE_NB_HEX_ZERO 0,
+#define INITIALIZE_NB_IN_PLACE_DIVIDE_ZERO 0,
+#define INITIALIZE_NB_DIVIDE_ZERO 0,
+#endif
+
+/* Unicode/string handling. */
+#if PY_MAJOR_VERSION >= 3
+#define PY_STRING_CHECK(a) PyUnicode_Check(a)
+#define PY_STRING_AS_STRING(a) PyUnicode_AsUTF8(a)
+#define PY_UNICODE_AS_UNICODE(a) PyUnicode_AsUTF8(a)
+#else
+#define PY_STRING_CHECK(a) (PyUnicode_Check(a) || PyBytes_Check(a))
+#define PY_STRING_AS_STRING(a) PyBytes_AsString(a)
+#define PY_UNICODE_AS_UNICODE(a) PyBytes_AsString(PyUnicode_AsASCIIString(a))
+#endif
diff --git a/installers/osx/PkgResources_x86_64_py2/License.rtf b/installers/osx/PkgResources_x86_64_py2/License.rtf
new file mode 100755
index 0000000..50a49ab
--- /dev/null
+++ b/installers/osx/PkgResources_x86_64_py2/License.rtf
@@ -0,0 +1,423 @@
+{\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 Droid Sans Fallback;}{\f7\fnil\fprq2\fcharset0 FreeSans;}{\f8\fswiss\fprq0\fcharset128 FreeSans;}}
+{\colortbl;\red0\green0\blue0;\red128\green128\blue128;}
+{\stylesheet{\s0\snext0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084 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;}
+}{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\author olivier }{\revtim\yr2015\mo3\dy5\hr14\min36}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern67306242}}\deftab720
+\viewscale100
+{\*\pgdsctbl
+{\pgdsc0\pgdscuse451\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Default Style;}}
+\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
+{\*\ftnsep}\pgndec\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+GNU LESSER GENERAL PUBLIC LICENSE}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Version 3, 29 June 2007}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Everyone is permitted to copy and distribute verbatim copies}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+of this license document, but changing it is not allowed.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+This version of the GNU Lesser General Public License incorporates}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+the terms and conditions of version 3 of the GNU General Public}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+License, supplemented by the additional permissions listed below.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+0. Additional Definitions.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+As used herein, "this License" refers to version 3 of the GNU Lesser}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+General Public License, and the "GNU GPL" refers to version 3 of the GNU}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+General Public License.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+"The Library" refers to a covered work governed by this License,}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+other than an Application or a Combined Work as defined below.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+An "Application" is any work that makes use of an interface provided}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+by the Library, but which is not otherwise based on the Library.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Defining a subclass of a class defined by the Library is deemed a mode}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+of using an interface provided by the Library.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+A "Combined Work" is a work produced by combining or linking an}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Application with the Library. The particular version of the Library}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+with which the Combined Work was made is also called the "Linked}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Version".}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+The "Minimal Corresponding Source" for a Combined Work means the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Corresponding Source for the Combined Work, excluding any source code}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+for portions of the Combined Work that, considered in isolation, are}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+based on the Application, and not on the Linked Version.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+The "Corresponding Application Code" for a Combined Work means the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+object code and/or source code for the Application, including any data}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+and utility programs needed for reproducing the Combined Work from the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Application, but excluding the System Libraries of the Combined Work.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+1. Exception to Section 3 of the GNU GPL.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+You may convey a covered work under sections 3 and 4 of this License}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+without being bound by section 3 of the GNU GPL.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+2. Conveying Modified Versions.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+If you modify a copy of the Library, and, in your modifications, a}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+facility refers to a function or data to be supplied by an Application}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+that uses the facility (other than as an argument passed when the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+facility is invoked), then you may convey a copy of the modified}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+version:}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+a) under this License, provided that you make a good faith effort to}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+ensure that, in the event an Application does not supply the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+function or data, the facility still operates, and performs}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+whatever part of its purpose remains meaningful, or}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+b) under the GNU GPL, with none of the additional permissions of}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+this License applicable to that copy.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+3. Object Code Incorporating Material from Library Header Files.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+The object code form of an Application may incorporate material from}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+a header file that is part of the Library. You may convey such object}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+code under terms of your choice, provided that, if the incorporated}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+material is not limited to numerical parameters, data structure}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+layouts and accessors, or small macros, inline functions and templates}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+(ten or fewer lines in length), you do both of the following:}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+a) Give prominent notice with each copy of the object code that the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Library is used in it and that the Library and its use are}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+covered by this License.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+b) Accompany the object code with a copy of the GNU GPL and this license}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+document.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+4. Combined Works.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+You may convey a Combined Work under terms of your choice that,}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+taken together, effectively do not restrict modification of the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+portions of the Library contained in the Combined Work and reverse}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+engineering for debugging such modifications, if you also do each of}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+the following:}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+a) Give prominent notice with each copy of the Combined Work that}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+the Library is used in it and that the Library and its use are}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+covered by this License.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+b) Accompany the Combined Work with a copy of the GNU GPL and this license}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+document.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+c) For a Combined Work that displays copyright notices during}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+execution, include the copyright notice for the Library among}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+these notices, as well as a reference directing the user to the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+copies of the GNU GPL and this license document.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+d) Do one of the following:}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+0) Convey the Minimal Corresponding Source under the terms of this}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+License, and the Corresponding Application Code in a form}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+suitable for, and under terms that permit, the user to}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+recombine or relink the Application with a modified version of}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+the Linked Version to produce a modified Combined Work, in the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+manner specified by section 6 of the GNU GPL for conveying}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Corresponding Source.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+1) Use a suitable shared library mechanism for linking with the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Library. A suitable mechanism is one that (a) uses at run time}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+a copy of the Library already present on the user's computer}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+system, and (b) will operate properly with a modified version}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+of the Library that is interface-compatible with the Linked}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Version.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+e) Provide Installation Information, but only if you would otherwise}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+be required to provide such information under section 6 of the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+GNU GPL, and only to the extent that such information is}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+necessary to install and execute a modified version of the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Combined Work produced by recombining or relinking the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Application with a modified version of the Linked Version. (If}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+you use option 4d0, the Installation Information must accompany}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+the Minimal Corresponding Source and Corresponding Application}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Code. If you use option 4d1, you must provide the Installation}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Information in the manner specified by section 6 of the GNU GPL}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+for conveying Corresponding Source.)}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+5. Combined Libraries.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+You may place library facilities that are a work based on the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Library side by side in a single library together with other library}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+facilities that are not Applications and are not covered by this}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+License, and convey such a combined library under terms of your}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+choice, if you do both of the following:}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+a) Accompany the combined library with a copy of the same work based}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+on the Library, uncombined with any other library facilities,}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+conveyed under the terms of this License.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+b) Give prominent notice with the combined library that part of it}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+is a work based on the Library, and explaining where to find the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+accompanying uncombined form of the same work.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+6. Revised Versions of the GNU Lesser General Public License.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+The Free Software Foundation may publish revised and/or new versions}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+of the GNU Lesser General Public License from time to time. Such new}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+versions will be similar in spirit to the present version, but may}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+differ in detail to address new problems or concerns.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Each version is given a distinguishing version number. If the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Library as you received it specifies that a certain numbered version}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+of the GNU Lesser General Public License "or any later version"}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+applies to it, you have the option of following the terms and}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+conditions either of that published version or of any later version}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+published by the Free Software Foundation. If the Library as you}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+received it does not specify a version number of the GNU Lesser}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+General Public License, you may choose any version of the GNU Lesser}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+General Public License ever published by the Free Software Foundation.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+If the Library as you received it specifies that a proxy can decide}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+whether future versions of the GNU Lesser General Public License shall}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+apply, that proxy's public statement of acceptance of any version is}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+permanent authorization for you to choose that version for the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Library.}
+\par }
\ No newline at end of file
diff --git a/installers/osx/PkgResources_x86_64_py2/ReadMe.rtf b/installers/osx/PkgResources_x86_64_py2/ReadMe.rtf
new file mode 100755
index 0000000..daa1aed
--- /dev/null
+++ b/installers/osx/PkgResources_x86_64_py2/ReadMe.rtf
@@ -0,0 +1,84 @@
+{\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.3.3$Linux_X86_64 LibreOffice_project/20m0$Build-3}{\info{\author Olivier }{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr2016\mo12\dy8\hr11\min16}{\printim\yr0\mo0\dy0\hr0\min0}}{\*\userprops}\deftab720
+\viewscale100
+{\*\pgdsctbl
+{\pgdsc0\pgdscuse451\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Default Style;}}
+\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
+{\*\ftnsep}\pgndec\pard\plain \s0\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
+1}{\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 : }{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+macOS}{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+ 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 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_py2/Welcome.rtf b/installers/osx/PkgResources_x86_64_py2/Welcome.rtf
new file mode 100755
index 0000000..b8b9917
--- /dev/null
+++ b/installers/osx/PkgResources_x86_64_py2/Welcome.rtf
@@ -0,0 +1,7 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
+{\colortbl;\red255\green255\blue255;}
+\margl1440\margr1440\vieww10100\viewh11340\viewkind0
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
+
+\f0\fs26 \cf0 You are about to install pyo in your computer. This includes the pyo Python module and support libs.}
\ No newline at end of file
diff --git a/installers/osx/PkgResources_x86_64_py2/postinstall b/installers/osx/PkgResources_x86_64_py2/postinstall
new file mode 100755
index 0000000..8a86d60
--- /dev/null
+++ b/installers/osx/PkgResources_x86_64_py2/postinstall
@@ -0,0 +1,74 @@
+#! /bin/sh
+
+# Removed older versions in the python site-packages builtin and in the python site-packages from python.org directories
+PATHS=/Library/Python/2.6/site-packages/:/Library/Python/2.7/site-packages/:/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/:/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
+for path in ${PATHS//:/ }; do
+ if cd $path; then
+ if [ -f pyo.py ]; then
+ sudo rm pyo.py;
+ fi
+ if [ -f pyo64.py ]; then
+ sudo rm pyo64.py;
+ fi
+ if [ -f pyo.pyc ]; then
+ sudo rm pyo.pyc;
+ fi
+ if [ -f pyo64.pyc ]; then
+ sudo rm pyo64.pyc;
+ fi
+ if [ -f _pyo.so ]; then
+ sudo rm _pyo.so;
+ fi
+ if [ -f _pyo64.so ]; then
+ sudo rm _pyo64.so;
+ fi
+ if [ -d pyolib ]; then
+ sudo rm -rf pyolib/;
+ fi
+ ls -1 pyo*-info > /dev/null 2>&1
+ if [ "$?" = "0" ]; then
+ sudo rm pyo*-info;
+ fi
+ fi
+done
+
+# Install pyo in the python site-packages builtin directories
+if cd /Library/Python/2.7/site-packages/; then
+ sudo cp -r /tmp/python27/* .
+else
+ sudo mkdir -p /Library/Python/2.7/site-packages/
+ cd /Library/Python/2.7/site-packages/
+ sudo cp -r /tmp/python27/* .
+fi
+
+# Install pyo in the python.org site-packages directories
+if cd /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/; then
+ sudo cp -r /tmp/python27/* .
+else
+ sudo mkdir -p /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
+ cd /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
+ sudo cp -r /tmp/python27/* .
+fi
+
+# Check if anaconda is already installed and copy files to site-packages directory
+if cd ~/anaconda/lib/python2.7/site-packages/; then
+ sudo cp -r /tmp/python27/* .
+fi
+
+# Clean up.
+sudo rm -rf /tmp/python27
+
+# Add /usr/local/lib in .bash_profile if not already done
+searchString="/usr/local/lib"
+
+if [ -f ~/.bash_profile ]; then
+ if `cat ~/.bash_profile | grep "${searchString}" 1>/dev/null 2>&1`; then
+ echo "path already in PATH variable";
+ else
+ echo "adding path to .bash_profile..."
+ echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" >> ~/.bash_profile;
+ fi
+else
+ echo "creating .bash_profile and adding path to it..."
+ echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" > ~/.bash_profile;
+fi
diff --git a/installers/osx/PkgResources_x86_64_py2/postupgrade b/installers/osx/PkgResources_x86_64_py2/postupgrade
new file mode 100755
index 0000000..8a86d60
--- /dev/null
+++ b/installers/osx/PkgResources_x86_64_py2/postupgrade
@@ -0,0 +1,74 @@
+#! /bin/sh
+
+# Removed older versions in the python site-packages builtin and in the python site-packages from python.org directories
+PATHS=/Library/Python/2.6/site-packages/:/Library/Python/2.7/site-packages/:/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/:/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
+for path in ${PATHS//:/ }; do
+ if cd $path; then
+ if [ -f pyo.py ]; then
+ sudo rm pyo.py;
+ fi
+ if [ -f pyo64.py ]; then
+ sudo rm pyo64.py;
+ fi
+ if [ -f pyo.pyc ]; then
+ sudo rm pyo.pyc;
+ fi
+ if [ -f pyo64.pyc ]; then
+ sudo rm pyo64.pyc;
+ fi
+ if [ -f _pyo.so ]; then
+ sudo rm _pyo.so;
+ fi
+ if [ -f _pyo64.so ]; then
+ sudo rm _pyo64.so;
+ fi
+ if [ -d pyolib ]; then
+ sudo rm -rf pyolib/;
+ fi
+ ls -1 pyo*-info > /dev/null 2>&1
+ if [ "$?" = "0" ]; then
+ sudo rm pyo*-info;
+ fi
+ fi
+done
+
+# Install pyo in the python site-packages builtin directories
+if cd /Library/Python/2.7/site-packages/; then
+ sudo cp -r /tmp/python27/* .
+else
+ sudo mkdir -p /Library/Python/2.7/site-packages/
+ cd /Library/Python/2.7/site-packages/
+ sudo cp -r /tmp/python27/* .
+fi
+
+# Install pyo in the python.org site-packages directories
+if cd /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/; then
+ sudo cp -r /tmp/python27/* .
+else
+ sudo mkdir -p /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
+ cd /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
+ sudo cp -r /tmp/python27/* .
+fi
+
+# Check if anaconda is already installed and copy files to site-packages directory
+if cd ~/anaconda/lib/python2.7/site-packages/; then
+ sudo cp -r /tmp/python27/* .
+fi
+
+# Clean up.
+sudo rm -rf /tmp/python27
+
+# Add /usr/local/lib in .bash_profile if not already done
+searchString="/usr/local/lib"
+
+if [ -f ~/.bash_profile ]; then
+ if `cat ~/.bash_profile | grep "${searchString}" 1>/dev/null 2>&1`; then
+ echo "path already in PATH variable";
+ else
+ echo "adding path to .bash_profile..."
+ echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" >> ~/.bash_profile;
+ fi
+else
+ echo "creating .bash_profile and adding path to it..."
+ echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" > ~/.bash_profile;
+fi
diff --git a/installers/osx/PkgResources_x86_64_py3/License.rtf b/installers/osx/PkgResources_x86_64_py3/License.rtf
new file mode 100755
index 0000000..50a49ab
--- /dev/null
+++ b/installers/osx/PkgResources_x86_64_py3/License.rtf
@@ -0,0 +1,423 @@
+{\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 Droid Sans Fallback;}{\f7\fnil\fprq2\fcharset0 FreeSans;}{\f8\fswiss\fprq0\fcharset128 FreeSans;}}
+{\colortbl;\red0\green0\blue0;\red128\green128\blue128;}
+{\stylesheet{\s0\snext0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084 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;}
+}{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\author olivier }{\revtim\yr2015\mo3\dy5\hr14\min36}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern67306242}}\deftab720
+\viewscale100
+{\*\pgdsctbl
+{\pgdsc0\pgdscuse451\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Default Style;}}
+\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
+{\*\ftnsep}\pgndec\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+GNU LESSER GENERAL PUBLIC LICENSE}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Version 3, 29 June 2007}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Everyone is permitted to copy and distribute verbatim copies}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+of this license document, but changing it is not allowed.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+This version of the GNU Lesser General Public License incorporates}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+the terms and conditions of version 3 of the GNU General Public}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+License, supplemented by the additional permissions listed below.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+0. Additional Definitions.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+As used herein, "this License" refers to version 3 of the GNU Lesser}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+General Public License, and the "GNU GPL" refers to version 3 of the GNU}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+General Public License.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+"The Library" refers to a covered work governed by this License,}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+other than an Application or a Combined Work as defined below.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+An "Application" is any work that makes use of an interface provided}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+by the Library, but which is not otherwise based on the Library.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Defining a subclass of a class defined by the Library is deemed a mode}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+of using an interface provided by the Library.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+A "Combined Work" is a work produced by combining or linking an}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Application with the Library. The particular version of the Library}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+with which the Combined Work was made is also called the "Linked}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Version".}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+The "Minimal Corresponding Source" for a Combined Work means the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Corresponding Source for the Combined Work, excluding any source code}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+for portions of the Combined Work that, considered in isolation, are}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+based on the Application, and not on the Linked Version.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+The "Corresponding Application Code" for a Combined Work means the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+object code and/or source code for the Application, including any data}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+and utility programs needed for reproducing the Combined Work from the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Application, but excluding the System Libraries of the Combined Work.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+1. Exception to Section 3 of the GNU GPL.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+You may convey a covered work under sections 3 and 4 of this License}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+without being bound by section 3 of the GNU GPL.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+2. Conveying Modified Versions.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+If you modify a copy of the Library, and, in your modifications, a}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+facility refers to a function or data to be supplied by an Application}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+that uses the facility (other than as an argument passed when the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+facility is invoked), then you may convey a copy of the modified}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+version:}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+a) under this License, provided that you make a good faith effort to}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+ensure that, in the event an Application does not supply the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+function or data, the facility still operates, and performs}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+whatever part of its purpose remains meaningful, or}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+b) under the GNU GPL, with none of the additional permissions of}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+this License applicable to that copy.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+3. Object Code Incorporating Material from Library Header Files.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+The object code form of an Application may incorporate material from}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+a header file that is part of the Library. You may convey such object}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+code under terms of your choice, provided that, if the incorporated}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+material is not limited to numerical parameters, data structure}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+layouts and accessors, or small macros, inline functions and templates}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+(ten or fewer lines in length), you do both of the following:}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+a) Give prominent notice with each copy of the object code that the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Library is used in it and that the Library and its use are}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+covered by this License.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+b) Accompany the object code with a copy of the GNU GPL and this license}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+document.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+4. Combined Works.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+You may convey a Combined Work under terms of your choice that,}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+taken together, effectively do not restrict modification of the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+portions of the Library contained in the Combined Work and reverse}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+engineering for debugging such modifications, if you also do each of}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+the following:}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+a) Give prominent notice with each copy of the Combined Work that}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+the Library is used in it and that the Library and its use are}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+covered by this License.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+b) Accompany the Combined Work with a copy of the GNU GPL and this license}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+document.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+c) For a Combined Work that displays copyright notices during}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+execution, include the copyright notice for the Library among}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+these notices, as well as a reference directing the user to the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+copies of the GNU GPL and this license document.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+d) Do one of the following:}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+0) Convey the Minimal Corresponding Source under the terms of this}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+License, and the Corresponding Application Code in a form}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+suitable for, and under terms that permit, the user to}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+recombine or relink the Application with a modified version of}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+the Linked Version to produce a modified Combined Work, in the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+manner specified by section 6 of the GNU GPL for conveying}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Corresponding Source.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+1) Use a suitable shared library mechanism for linking with the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Library. A suitable mechanism is one that (a) uses at run time}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+a copy of the Library already present on the user's computer}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+system, and (b) will operate properly with a modified version}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+of the Library that is interface-compatible with the Linked}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Version.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+e) Provide Installation Information, but only if you would otherwise}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+be required to provide such information under section 6 of the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+GNU GPL, and only to the extent that such information is}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+necessary to install and execute a modified version of the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Combined Work produced by recombining or relinking the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Application with a modified version of the Linked Version. (If}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+you use option 4d0, the Installation Information must accompany}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+the Minimal Corresponding Source and Corresponding Application}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Code. If you use option 4d1, you must provide the Installation}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Information in the manner specified by section 6 of the GNU GPL}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+for conveying Corresponding Source.)}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+5. Combined Libraries.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+You may place library facilities that are a work based on the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Library side by side in a single library together with other library}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+facilities that are not Applications and are not covered by this}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+License, and convey such a combined library under terms of your}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+choice, if you do both of the following:}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+a) Accompany the combined library with a copy of the same work based}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+on the Library, uncombined with any other library facilities,}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+conveyed under the terms of this License.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+b) Give prominent notice with the combined library that part of it}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+is a work based on the Library, and explaining where to find the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+accompanying uncombined form of the same work.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+6. Revised Versions of the GNU Lesser General Public License.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+The Free Software Foundation may publish revised and/or new versions}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+of the GNU Lesser General Public License from time to time. Such new}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+versions will be similar in spirit to the present version, but may}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+differ in detail to address new problems or concerns.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Each version is given a distinguishing version number. If the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Library as you received it specifies that a certain numbered version}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+of the GNU Lesser General Public License "or any later version"}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+applies to it, you have the option of following the terms and}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+conditions either of that published version or of any later version}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+published by the Free Software Foundation. If the Library as you}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+received it does not specify a version number of the GNU Lesser}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+General Public License, you may choose any version of the GNU Lesser}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+General Public License ever published by the Free Software Foundation.}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\rtlch \ltrch\loch
+
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\fs26\loch\f5
+ }{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+If the Library as you received it specifies that a proxy can decide}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+whether future versions of the GNU Lesser General Public License shall}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+apply, that proxy's public statement of acceptance of any version is}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+permanent authorization for you to choose that version for the}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af6\langfe2052\dbch\af7\afs24\alang1081\loch\f3\fs24\lang3084\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f5
+Library.}
+\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
new file mode 100755
index 0000000..1afd5e1
--- /dev/null
+++ b/installers/osx/PkgResources_x86_64_py3/ReadMe.rtf
@@ -0,0 +1,84 @@
+{\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.3.3$Linux_X86_64 LibreOffice_project/20m0$Build-3}{\info{\author Olivier }{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr2016\mo12\dy8\hr11\min17}{\printim\yr0\mo0\dy0\hr0\min0}}{\*\userprops}\deftab720
+\viewscale100
+{\*\pgdsctbl
+{\pgdsc0\pgdscuse451\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Default Style;}}
+\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
+{\*\ftnsep}\pgndec\pard\plain \s0\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
+1}{\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 : }{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+macOS}{\cf1\rtlch \ltrch\loch\fs26\loch\f5\hich\af5
+ 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/PkgResources_x86_64_py3/Welcome.rtf b/installers/osx/PkgResources_x86_64_py3/Welcome.rtf
new file mode 100755
index 0000000..b8b9917
--- /dev/null
+++ b/installers/osx/PkgResources_x86_64_py3/Welcome.rtf
@@ -0,0 +1,7 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
+{\colortbl;\red255\green255\blue255;}
+\margl1440\margr1440\vieww10100\viewh11340\viewkind0
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
+
+\f0\fs26 \cf0 You are about to install pyo in your computer. This includes the pyo Python module and support libs.}
\ No newline at end of file
diff --git a/installers/osx/PkgResources_x86_64_py3/postinstall b/installers/osx/PkgResources_x86_64_py3/postinstall
new file mode 100755
index 0000000..d3b0e5a
--- /dev/null
+++ b/installers/osx/PkgResources_x86_64_py3/postinstall
@@ -0,0 +1,74 @@
+#! /bin/sh
+
+# Removed older versions in the python site-packages builtin and in the python site-packages from python.org directories
+PATHS=/Library/Python/3.5/site-packages/:/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/
+for path in ${PATHS//:/ }; do
+ if cd $path; then
+ if [ -f pyo.py ]; then
+ sudo rm pyo.py;
+ fi
+ if [ -f pyo64.py ]; then
+ sudo rm pyo64.py;
+ fi
+ if [ -f pyo.pyc ]; then
+ sudo rm pyo.pyc;
+ fi
+ if [ -f pyo64.pyc ]; then
+ sudo rm pyo64.pyc;
+ fi
+ if [ -f _pyo.cpython-35m-darwin.so ]; then
+ sudo rm _pyo.so;
+ fi
+ if [ -f _pyo64.cpython-35m-darwin.so ]; then
+ sudo rm _pyo64.so;
+ fi
+ if [ -d pyolib ]; then
+ sudo rm -rf pyolib/;
+ fi
+ ls -1 pyo*-info > /dev/null 2>&1
+ if [ "$?" = "0" ]; then
+ sudo rm pyo*-info;
+ fi
+ fi
+done
+
+# Install pyo in the python site-packages builtin directories
+if cd /Library/Python/3.5/site-packages/; then
+ sudo cp -r /tmp/python35/* .
+else
+ sudo mkdir -p /Library/Python/3.5/site-packages/
+ cd /Library/Python/3.5/site-packages/
+ sudo cp -r /tmp/python35/* .
+fi
+
+# Install pyo in the python.org site-packages directories
+if cd /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/; then
+ sudo cp -r /tmp/python35/* .
+else
+ sudo mkdir -p /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/
+ cd /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/
+ sudo cp -r /tmp/python35/* .
+fi
+
+# Check if anaconda is already installed and copy files to site-packages directory
+if cd ~/anaconda/lib/python3.5/site-packages/; then
+ sudo cp -r /tmp/python35/* .
+fi
+
+# Clean up.
+sudo rm -rf /tmp/python35
+
+# Add /usr/local/lib in .bash_profile if not already done
+searchString="/usr/local/lib"
+
+if [ -f ~/.bash_profile ]; then
+ if `cat ~/.bash_profile | grep "${searchString}" 1>/dev/null 2>&1`; then
+ echo "path already in PATH variable";
+ else
+ echo "adding path to .bash_profile..."
+ echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" >> ~/.bash_profile;
+ fi
+else
+ echo "creating .bash_profile and adding path to it..."
+ echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" > ~/.bash_profile;
+fi
diff --git a/installers/osx/PkgResources_x86_64_py3/postupgrade b/installers/osx/PkgResources_x86_64_py3/postupgrade
new file mode 100755
index 0000000..d3b0e5a
--- /dev/null
+++ b/installers/osx/PkgResources_x86_64_py3/postupgrade
@@ -0,0 +1,74 @@
+#! /bin/sh
+
+# Removed older versions in the python site-packages builtin and in the python site-packages from python.org directories
+PATHS=/Library/Python/3.5/site-packages/:/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/
+for path in ${PATHS//:/ }; do
+ if cd $path; then
+ if [ -f pyo.py ]; then
+ sudo rm pyo.py;
+ fi
+ if [ -f pyo64.py ]; then
+ sudo rm pyo64.py;
+ fi
+ if [ -f pyo.pyc ]; then
+ sudo rm pyo.pyc;
+ fi
+ if [ -f pyo64.pyc ]; then
+ sudo rm pyo64.pyc;
+ fi
+ if [ -f _pyo.cpython-35m-darwin.so ]; then
+ sudo rm _pyo.so;
+ fi
+ if [ -f _pyo64.cpython-35m-darwin.so ]; then
+ sudo rm _pyo64.so;
+ fi
+ if [ -d pyolib ]; then
+ sudo rm -rf pyolib/;
+ fi
+ ls -1 pyo*-info > /dev/null 2>&1
+ if [ "$?" = "0" ]; then
+ sudo rm pyo*-info;
+ fi
+ fi
+done
+
+# Install pyo in the python site-packages builtin directories
+if cd /Library/Python/3.5/site-packages/; then
+ sudo cp -r /tmp/python35/* .
+else
+ sudo mkdir -p /Library/Python/3.5/site-packages/
+ cd /Library/Python/3.5/site-packages/
+ sudo cp -r /tmp/python35/* .
+fi
+
+# Install pyo in the python.org site-packages directories
+if cd /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/; then
+ sudo cp -r /tmp/python35/* .
+else
+ sudo mkdir -p /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/
+ cd /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/
+ sudo cp -r /tmp/python35/* .
+fi
+
+# Check if anaconda is already installed and copy files to site-packages directory
+if cd ~/anaconda/lib/python3.5/site-packages/; then
+ sudo cp -r /tmp/python35/* .
+fi
+
+# Clean up.
+sudo rm -rf /tmp/python35
+
+# Add /usr/local/lib in .bash_profile if not already done
+searchString="/usr/local/lib"
+
+if [ -f ~/.bash_profile ]; then
+ if `cat ~/.bash_profile | grep "${searchString}" 1>/dev/null 2>&1`; then
+ echo "path already in PATH variable";
+ else
+ echo "adding path to .bash_profile..."
+ echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" >> ~/.bash_profile;
+ fi
+else
+ echo "creating .bash_profile and adding path to it..."
+ echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" > ~/.bash_profile;
+fi
diff --git a/installers/osx/release_x86_64_py2.sh b/installers/osx/release_x86_64_py2.sh
new file mode 100755
index 0000000..0fec069
--- /dev/null
+++ b/installers/osx/release_x86_64_py2.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+
+# Need Xcode 3.2.6 or later (pkgbuild and productbuild)
+# with python 2.7.12 (32/64-bit) and wxpython 3.0.2.0 (classic) installed
+
+# 1. update pyo sources
+# 2. compile and install pyo float and double for python2
+# 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.1_x86_64_py2.pkg
+export DMG_DIR="pyo 0.8.1 py2 Universal"
+export DMG_NAME="pyo_0.8.1_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
+export BUILD_RESOURCES=$INSTALLER_DIR/PkgResources/English.lproj
+export PKG_RESOURCES=$INSTALLER_DIR/../PkgResources_x86_64_py2
+
+mkdir -p $PYO_MODULE_DIR
+mkdir -p $SUPPORT_LIBS_DIR
+mkdir -p $BUILD_RESOURCES
+
+cp $PKG_RESOURCES/License.rtf $BUILD_RESOURCES/License.rtf
+cp $PKG_RESOURCES/Welcome.rtf $BUILD_RESOURCES/Welcome.rtf
+cp $PKG_RESOURCES/ReadMe.rtf $BUILD_RESOURCES/ReadMe.rtf
+
+cd ../..
+git checkout-index -a -f --prefix=installers/osx/installer/pyo-build/
+cd installers/osx/installer/pyo-build
+
+echo "building pyo for python 2.7 (64-bit)..."
+sudo /usr/local/bin/python2.7 setup.py install --use-coreaudio --use-double
+
+sudo cp -R build/lib.macosx-10.6-intel-2.7 $PYO_MODULE_DIR/python27
+
+sudo install_name_tool -change /usr/local/opt/portmidi/lib/libportmidi.dylib /usr/local/lib/libportmidi.dylib $PYO_MODULE_DIR/python27/_pyo.so
+sudo install_name_tool -change /usr/local/opt/portmidi/lib/libportmidi.dylib /usr/local/lib/libportmidi.dylib $PYO_MODULE_DIR/python27/_pyo64.so
+sudo install_name_tool -change /usr/local/opt/portaudio/lib/libportaudio.2.dylib /usr/local/lib/libportaudio.2.dylib $PYO_MODULE_DIR/python27/_pyo.so
+sudo install_name_tool -change /usr/local/opt/portaudio/lib/libportaudio.2.dylib /usr/local/lib/libportaudio.2.dylib $PYO_MODULE_DIR/python27/_pyo64.so
+sudo install_name_tool -change /usr/local/opt/liblo/lib/liblo.7.dylib /usr/local/lib/liblo.7.dylib $PYO_MODULE_DIR/python27/_pyo.so
+sudo install_name_tool -change /usr/local/opt/liblo/lib/liblo.7.dylib /usr/local/lib/liblo.7.dylib $PYO_MODULE_DIR/python27/_pyo64.so
+sudo install_name_tool -change /usr/local/opt/libsndfile/lib/libsndfile.1.dylib /usr/local/lib/libsndfile.1.dylib $PYO_MODULE_DIR/python27/_pyo.so
+sudo install_name_tool -change /usr/local/opt/libsndfile/lib/libsndfile.1.dylib /usr/local/lib/libsndfile.1.dylib $PYO_MODULE_DIR/python27/_pyo64.so
+
+cd ..
+
+echo "copying support libs..."
+sudo cp /usr/local/lib/liblo.7.dylib $SUPPORT_LIBS_DIR/liblo.7.dylib
+sudo cp /usr/local/lib/libportaudio.2.dylib $SUPPORT_LIBS_DIR/libportaudio.2.dylib
+sudo cp /usr/local/lib/libportmidi.dylib $SUPPORT_LIBS_DIR/libportmidi.dylib
+sudo cp /usr/local/lib/libsndfile.1.dylib $SUPPORT_LIBS_DIR/libsndfile.1.dylib
+sudo cp /usr/local/lib/libFLAC.8.dylib $SUPPORT_LIBS_DIR/libFLAC.8.dylib
+sudo cp /usr/local/lib/libvorbisenc.2.dylib $SUPPORT_LIBS_DIR/libvorbisenc.2.dylib
+sudo cp /usr/local/lib/libvorbis.0.dylib $SUPPORT_LIBS_DIR/libvorbis.0.dylib
+sudo cp /usr/local/lib/libogg.0.dylib $SUPPORT_LIBS_DIR/libogg.0.dylib
+
+echo "setting permissions..."
+sudo chgrp -R admin PyoModule/Package_Contents/tmp
+sudo chown -R root PyoModule/Package_Contents/tmp
+sudo chmod -R 755 PyoModule/Package_Contents/tmp
+
+sudo chgrp -R wheel SupportLibs/Package_Contents/usr
+sudo chown -R root SupportLibs/Package_Contents/usr
+sudo chmod -R 755 SupportLibs/Package_Contents/usr
+
+echo "building packages..."
+
+pkgbuild --identifier com.iact.umontreal.ca.pyo.py2.tmp.pkg \
+ --root PyoModule/Package_Contents/ \
+ --version 1.0 \
+ --scripts $PKG_RESOURCES \
+ PyoModule.pkg
+
+pkgbuild --identifier com.iact.umontreal.ca.pyo.py2.usr.pkg \
+ --root SupportLibs/Package_Contents/ \
+ --version 1.0 \
+ SupportLibs.pkg
+
+echo "building product..."
+productbuild --distribution ../Distribution.dist --resources $BUILD_RESOURCES $PACKAGE_NAME
+
+echo "assembling DMG..."
+mkdir "$DMG_DIR"
+cd "$DMG_DIR"
+cp ../$PACKAGE_NAME .
+cp -R ../../../../utils/E-Pyo_OSX_py2/E-Pyo.app .
+ln -s /Applications .
+cd ..
+
+hdiutil create "$DMG_NAME" -srcfolder "$DMG_DIR"
+
+cd ..
+mv installer/$DMG_NAME .
+
+echo "clean up resources..."
+sudo rm -rf installer
diff --git a/installers/osx/release_x86_64_py3.sh b/installers/osx/release_x86_64_py3.sh
new file mode 100755
index 0000000..a7401a8
--- /dev/null
+++ b/installers/osx/release_x86_64_py3.sh
@@ -0,0 +1,99 @@
+#!/bin/sh
+
+# Need Xcode 3.2.6 or later (pkgbuild and productbuild)
+# with python 3.5.2 (32/64-bit) and wxpython 3.0.3.0 (phoenix) installed
+
+# 1. update pyo sources
+# 2. compile and install pyo float and double for python3
+# 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.1_x86_64_py3.pkg
+export DMG_DIR="pyo 0.8.1 py3 Universal"
+export DMG_NAME="pyo_0.8.1_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
+export BUILD_RESOURCES=$INSTALLER_DIR/PkgResources/English.lproj
+export PKG_RESOURCES=$INSTALLER_DIR/../PkgResources_x86_64_py3
+
+mkdir -p $PYO_MODULE_DIR
+mkdir -p $SUPPORT_LIBS_DIR
+mkdir -p $BUILD_RESOURCES
+
+cp $PKG_RESOURCES/License.rtf $BUILD_RESOURCES/License.rtf
+cp $PKG_RESOURCES/Welcome.rtf $BUILD_RESOURCES/Welcome.rtf
+cp $PKG_RESOURCES/ReadMe.rtf $BUILD_RESOURCES/ReadMe.rtf
+
+cd ../..
+git checkout-index -a -f --prefix=installers/osx/installer/pyo-build/
+cd installers/osx/installer/pyo-build
+
+echo "building pyo for python 3.5 (64-bit)..."
+sudo /usr/local/bin/python3.5 setup.py install --use-coreaudio --use-double
+
+sudo cp -R build/lib.macosx-10.6-intel-3.5 $PYO_MODULE_DIR/python35
+
+sudo install_name_tool -change /usr/local/opt/portmidi/lib/libportmidi.dylib /usr/local/lib/libportmidi.dylib $PYO_MODULE_DIR/python35/_pyo.cpython-35m-darwin.so
+sudo install_name_tool -change /usr/local/opt/portmidi/lib/libportmidi.dylib /usr/local/lib/libportmidi.dylib $PYO_MODULE_DIR/python35/_pyo64.cpython-35m-darwin.so
+sudo install_name_tool -change /usr/local/opt/portaudio/lib/libportaudio.2.dylib /usr/local/lib/libportaudio.2.dylib $PYO_MODULE_DIR/python35/_pyo.cpython-35m-darwin.so
+sudo install_name_tool -change /usr/local/opt/portaudio/lib/libportaudio.2.dylib /usr/local/lib/libportaudio.2.dylib $PYO_MODULE_DIR/python35/_pyo64.cpython-35m-darwin.so
+sudo install_name_tool -change /usr/local/opt/liblo/lib/liblo.7.dylib /usr/local/lib/liblo.7.dylib $PYO_MODULE_DIR/python35/_pyo.cpython-35m-darwin.so
+sudo install_name_tool -change /usr/local/opt/liblo/lib/liblo.7.dylib /usr/local/lib/liblo.7.dylib $PYO_MODULE_DIR/python35/_pyo64.cpython-35m-darwin.so
+sudo install_name_tool -change /usr/local/opt/libsndfile/lib/libsndfile.1.dylib /usr/local/lib/libsndfile.1.dylib $PYO_MODULE_DIR/python35/_pyo.cpython-35m-darwin.so
+sudo install_name_tool -change /usr/local/opt/libsndfile/lib/libsndfile.1.dylib /usr/local/lib/libsndfile.1.dylib $PYO_MODULE_DIR/python35/_pyo64.cpython-35m-darwin.so
+
+cd ..
+
+echo "copying support libs..."
+sudo cp /usr/local/lib/liblo.7.dylib $SUPPORT_LIBS_DIR/liblo.7.dylib
+sudo cp /usr/local/lib/libportaudio.2.dylib $SUPPORT_LIBS_DIR/libportaudio.2.dylib
+sudo cp /usr/local/lib/libportmidi.dylib $SUPPORT_LIBS_DIR/libportmidi.dylib
+sudo cp /usr/local/lib/libsndfile.1.dylib $SUPPORT_LIBS_DIR/libsndfile.1.dylib
+sudo cp /usr/local/lib/libFLAC.8.dylib $SUPPORT_LIBS_DIR/libFLAC.8.dylib
+sudo cp /usr/local/lib/libvorbisenc.2.dylib $SUPPORT_LIBS_DIR/libvorbisenc.2.dylib
+sudo cp /usr/local/lib/libvorbis.0.dylib $SUPPORT_LIBS_DIR/libvorbis.0.dylib
+sudo cp /usr/local/lib/libogg.0.dylib $SUPPORT_LIBS_DIR/libogg.0.dylib
+
+echo "setting permissions..."
+sudo chgrp -R admin PyoModule/Package_Contents/tmp
+sudo chown -R root PyoModule/Package_Contents/tmp
+sudo chmod -R 755 PyoModule/Package_Contents/tmp
+
+sudo chgrp -R wheel SupportLibs/Package_Contents/usr
+sudo chown -R root SupportLibs/Package_Contents/usr
+sudo chmod -R 755 SupportLibs/Package_Contents/usr
+
+echo "building packages..."
+
+pkgbuild --identifier com.iact.umontreal.ca.pyo.py3.tmp.pkg \
+ --root PyoModule/Package_Contents/ \
+ --version 1.0 \
+ --scripts $PKG_RESOURCES \
+ PyoModule.pkg
+
+pkgbuild --identifier com.iact.umontreal.ca.pyo.py3.usr.pkg \
+ --root SupportLibs/Package_Contents/ \
+ --version 1.0 \
+ SupportLibs.pkg
+
+echo "building product..."
+productbuild --distribution ../Distribution.dist --resources $BUILD_RESOURCES $PACKAGE_NAME
+
+echo "assembling DMG..."
+mkdir "$DMG_DIR"
+cd "$DMG_DIR"
+cp ../$PACKAGE_NAME .
+cp -R ../../../../utils/E-Pyo_OSX_py3/E-Pyo.app .
+ln -s /Applications .
+cd ..
+
+hdiutil create "$DMG_NAME" -srcfolder "$DMG_DIR"
+
+cd ..
+mv installer/$DMG_NAME .
+
+echo "clean up resources..."
+sudo rm -rf installer
+
+
diff --git a/installers/win/README-win32-py27.txt b/installers/win/README-win32-py35.txt
similarity index 82%
copy from installers/win/README-win32-py27.txt
copy to installers/win/README-win32-py35.txt
index eddb84d..a1cd9e3 100644
--- a/installers/win/README-win32-py27.txt
+++ b/installers/win/README-win32-py35.txt
@@ -1,21 +1,21 @@
-Pyo is a Python module written in C to help digital signal processing script creation.
-
-* Python 2.7 must be installed on your system before running this installer. *
-
-http://www.python.org/download/
-
-To use the WxPython toolkit for widgets, you need to install wxPython 3.0 for python 2.7:
-
-http://www.wxpython.org/download.php#stable
-
-This installer will leave a folder called pyo_examples on the Desktop,
-it's a good starting point to explore the library!
-
-In a Command Prompt:
-
-cd Desktop\pyo_examples\algorithmic
-python 01_music_box.py
-
-Please, send comments and bugs to:
-
-belangeo at gmail.com
+Pyo is a Python module written in C to help digital signal processing script creation.
+
+* Python 3.5 must be installed on your system before running this installer. *
+
+http://www.python.org/download/
+
+To use the WxPython toolkit for widgets, you need to install wxPython Phoenix (3.0.3+) for python 3.5:
+
+http://www.wxpython.org/download.php#stable
+
+This installer will leave a folder called pyo_examples on the Desktop,
+it's a good starting point to explore the library!
+
+In a Command Prompt:
+
+cd Desktop\pyo_examples\algorithmic
+python 01_music_box.py
+
+Please, send comments and bugs to:
+
+belangeo at gmail.com
diff --git a/installers/win/win_installer_py27.iss b/installers/win/win_installer_py35.iss
similarity index 57%
copy from installers/win/win_installer_py27.iss
copy to installers/win/win_installer_py35.iss
index d34ab8a..8962ee9 100644
--- a/installers/win/win_installer_py27.iss
+++ b/installers/win/win_installer_py35.iss
@@ -1,99 +1,101 @@
-; Script generated by the Inno Setup Script Wizard.
-; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
+; Script generated by the Inno Setup Script Wizard.
+; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define appName "pyo"
-#define pyVer "2.7"
+#define pyVer "3.5"
#define appVer "0.8.1"
-
-[Setup]
-; NOTE: The value of AppId uniquely identifies this application.
-; Do not use the same AppId value in installers for other applications.
-; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
-AppId={{59447873-F994-4BC7-8B1D-0DDCA5B6AFFD}
-AppName={#appName}
-AppVersion={#appVer}
-AppPublisher=ajaxsoundstudio.com
-AppPublisherURL=https://github.com/belangeo/pyo
-AppSupportURL=https://github.com/belangeo/pyo
-AppUpdatesURL=https://github.com/belangeo/pyo
-DefaultDirName={code:GetDirName}
+
+[Setup]
+; NOTE: The value of AppId uniquely identifies this application.
+; Do not use the same AppId value in installers for other applications.
+; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
+AppId={{D9B062A3-AFAE-4FC0-9603-CE4FCA106382}
+AppName={#appName}
+AppVersion={#appVer}
+AppPublisher=ajaxsoundstudio.com
+AppPublisherURL=https://github.com/belangeo/pyo
+AppSupportURL=https://github.com/belangeo/pyo
+AppUpdatesURL=https://github.com/belangeo/pyo
+DefaultDirName={code:GetDirName}
DisableDirPage=no
-AlwaysShowDirOnReadyPage=yes
-DefaultGroupName={#appName}
-AllowNoIcons=yes
-InfoBeforeFile=C:\Users\olivier\git\pyo\installers\win\\README-win32-py27.txt
-LicenseFile=C:\Users\olivier\git\pyo\COPYING.txt
-OutputBaseFilename={#appName}_{#appVer}_py{#pyVer}_setup
-Compression=lzma
-SolidCompression=yes
-ChangesAssociations=yes
+AlwaysShowDirOnReadyPage=yes
+DefaultGroupName={#appName}
+AllowNoIcons=yes
+InfoBeforeFile=C:\Users\olivier\git\pyo\installers\win\\README-win32-py35.txt
+LicenseFile=C:\Users\olivier\git\pyo\COPYING.txt
+OutputBaseFilename={#appName}_{#appVer}_py{#pyVer}_setup
+Compression=lzma
+SolidCompression=yes
+ChangesAssociations=yes
ChangesEnvironment=yes
-DirExistsWarning=no
-SetupIconFile=C:\Users\olivier\git\pyo\utils\E-PyoIcon.ico
-
-[Languages]
-Name: "english"; MessagesFile: "compiler:Default.isl"
-
-[Files]
-Source: "C:\Python27\Lib\site-packages\pyo.py"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\pyo64.py"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\pyolib\*"; DestDir: "{app}\Lib\site-packages\pyolib"; Flags: ignoreversion recursesubdirs createallsubdirs
-Source: "C:\Python27\Lib\site-packages\_pyo.pyd"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\_pyo64.pyd"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\libsndfile-1.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\lo.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\portaudio.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\portmidi.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\porttime.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\pthreadVC2.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\msvcr90.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\MinGW\bin\libgcc_s_dw2-1.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\MinGW\bin\libstdc++-6.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\pyo-{#appVer}-py{#pyVer}.egg-info"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Users\olivier\git\pyo\examples\*"; DestDir: "{userdesktop}\pyo_examples\"; Flags: ignoreversion recursesubdirs createallsubdirs
-; NOTE: Don't use "Flags: ignoreversion" on any shared system files
-
-; E-Pyo stuff
-Source: "C:\Users\olivier\git\pyo\utils\E-Pyo_py27\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
-Source: "C:\Users\olivier\git\pyo\utils\E-Pyo_py27\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
-
-[Tasks]
-Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
-
-[Icons]
-Name: "{group}\E-Pyo"; Filename: "{pf}\E-Pyo\E-Pyo.exe"; WorkingDir: "{pf}\E-Pyo"
-Name: "{commondesktop}\E-Pyo"; Filename: "{pf}\E-Pyo\E-Pyo.exe"; Tasks: desktopicon
-
-[Run]
-Filename: "{pf}\E-Pyo\E-Pyo.exe"; Description: "{cm:LaunchProgram,E-Pyo}"; Flags: nowait postinstall skipifsilent
-
-[InstallDelete]
-Type: filesandordirs; Name: "{userdesktop}\pyo_examples";
-Type: filesandordirs; Name: "{userdocs}\.epyo";
-;;;;;;;;;;;;;
-
-[Registry]
-Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{app};{olddata}"; Check: NeedsAddPath('{app}')
-
-[Code]
+DirExistsWarning=no
+SetupIconFile=C:\Users\olivier\git\pyo\utils\E-PyoIcon.ico
+
+[Languages]
+Name: "english"; MessagesFile: "compiler:Default.isl"
+
+[Files]
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\pyo.py"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\pyo64.py"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\pyolib\*"; DestDir: "{app}\Lib\site-packages\pyolib"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\_pyo.cp35-win32.pyd"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\_pyo64.cp35-win32.pyd"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\libsndfile-1.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\lo.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\portaudio.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\portmidi.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\porttime.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\pthreadVC2.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\dcomp.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\gpsvc.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\sysntfy.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\MinGW\bin\libgcc_s_dw2-1.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\MinGW\bin\libstdc++-6.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\pyo-{#appVer}-py{#pyVer}.egg-info"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olivier\git\pyo\examples\*"; DestDir: "{userdesktop}\pyo_examples\"; Flags: ignoreversion recursesubdirs createallsubdirs
+; NOTE: Don't use "Flags: ignoreversion" on any shared system files
+
+; E-Pyo stuff
+Source: "C:\Users\olivier\git\pyo\utils\E-Pyo_py35\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
+Source: "C:\Users\olivier\git\pyo\utils\E-Pyo_py35\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
+
+[Tasks]
+Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
+
+[Icons]
+Name: "{group}\E-Pyo"; Filename: "{pf}\E-Pyo\E-Pyo.exe"; WorkingDir: "{pf}\E-Pyo"
+Name: "{commondesktop}\E-Pyo"; Filename: "{pf}\E-Pyo\E-Pyo.exe"; Tasks: desktopicon
+
+[Run]
+Filename: "{pf}\E-Pyo\E-Pyo.exe"; Description: "{cm:LaunchProgram,E-Pyo}"; Flags: nowait postinstall skipifsilent
+
+[InstallDelete]
+Type: filesandordirs; Name: "{userdesktop}\pyo_examples";
+Type: filesandordirs; Name: "{userdocs}\.epyo";
+;;;;;;;;;;;;;
+
+[Registry]
+Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{app};{olddata}"; Check: NeedsAddPath('{app}')
+
+[Code]
procedure ExitProcess(exitCode:integer);
external 'ExitProcess at kernel32.dll stdcall';
-function NeedsAddPath(Param: string): boolean;
-var
- OrigPath: string;
-begin
- if not RegQueryStringValue(HKEY_LOCAL_MACHINE,
- 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
- 'Path', OrigPath)
- then begin
- Result := True;
- exit;
- end;
- // look for the path with leading and trailing semicolon
- // Pos() returns 0 if not found
- Result := Pos(';' + Param + ';', ';' + OrigPath + ';') = 0;
-end;
+function NeedsAddPath(Param: string): boolean;
+var
+ OrigPath: string;
+begin
+ if not RegQueryStringValue(HKEY_LOCAL_MACHINE,
+ 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
+ 'Path', OrigPath)
+ then begin
+ Result := True;
+ exit;
+ end;
+ // look for the path with leading and trailing semicolon
+ // Pos() returns 0 if not found
+ Result := Pos(';' + Param + ';', ';' + OrigPath + ';') = 0;
+end;
function GetDirName(Value: string): string;
var
@@ -103,10 +105,10 @@ var
reg3 : string;
reg4 : string;
begin
- reg1 := 'SOFTWARE\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
- reg2 := 'SOFTWARE\Wow6432Node\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
- reg3 := 'Software\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
- reg4 := 'Software\Wow6432Node\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+ reg1 := 'SOFTWARE\Python\PythonCore\' + '{#PyVer}' + '-32\InstallPath';
+ reg2 := 'SOFTWARE\Wow6432Node\Python\PythonCore\' + '{#PyVer}' + '-32\InstallPath';
+ reg3 := 'Software\Python\PythonCore\' + '{#PyVer}' + '-32\InstallPath';
+ reg4 := 'Software\Wow6432Node\Python\PythonCore\' + '{#PyVer}' + '-32\InstallPath';
if RegQueryStringValue(HKLM, reg1, '', InstallPath) then
BEGIN
Result := InstallPath;
@@ -124,6 +126,6 @@ begin
Result := InstallPath;
END else
BEGIN
- Result := 'C:\Python27';
+ Result := 'C:\Python35-32';
END
end;
\ No newline at end of file
diff --git a/scripts/release_builder_OSX.sh b/scripts/release_builder_OSX.sh
new file mode 100755
index 0000000..5e27998
--- /dev/null
+++ b/scripts/release_builder_OSX.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+# macOS release builder.
+
+# Update sources
+git pull
+
+# Build float and double for both python2 and python3
+if [ -d build ]; then
+ sudo rm -rf build/;
+fi
+
+sudo python setup.py install --use-coreaudio --use-double
+sudo python3 setup.py install --use-coreaudio --use-double
+
+# Compile E-Pyo for both python2 and python3
+cd utils
+
+if [ -d E-Pyo_OSX_py2 ]; then
+ sudo rm -rf E-Pyo_OSX_py2/;
+fi
+
+if [ -d E-Pyo_OSX_py3 ]; then
+ sudo rm -rf E-Pyo_OSX_py3/;
+fi
+
+sh epyo_builder_OSX_py2.sh
+sh epyo_builder_OSX_py3.sh
+
+# Build the packages
+cd ../installers/osx
+
+sudo rm -rf *.dmg
+
+sudo sh release_x86_64_py2.sh
+sudo sh release_x86_64_py3.sh
diff --git a/src/engine/ad_coreaudio.c b/src/engine/ad_coreaudio.c
new file mode 100644
index 0000000..d9fff78
--- /dev/null
+++ b/src/engine/ad_coreaudio.c
@@ -0,0 +1,444 @@
+/**************************************************************************
+ * Copyright 2009-2016 Olivier Belanger *
+ * *
+ * This file is part of pyo, a python module to help digital signal *
+ * processing script creation. *
+ * *
+ * pyo is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * pyo is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with pyo. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#include "ad_coreaudio.h"
+
+OSStatus coreaudio_input_callback(AudioDeviceID device, const AudioTimeStamp* inNow,
+ const AudioBufferList* inInputData,
+ const AudioTimeStamp* inInputTime,
+ AudioBufferList* outOutputData,
+ const AudioTimeStamp* inOutputTime,
+ void* defptr)
+{
+ int i, j, bufchnls, servchnls, off1chnls, off2chnls;
+ Server *server = (Server *) defptr;
+ (void) outOutputData;
+ const AudioBuffer* inputBuf = inInputData->mBuffers;
+ float *bufdata = (float*)inputBuf->mData;
+ bufchnls = inputBuf->mNumberChannels;
+ servchnls = server->ichnls < bufchnls ? server->ichnls : bufchnls;
+ for (i=0; i<server->bufferSize; i++) {
+ off1chnls = i*bufchnls+server->input_offset;
+ off2chnls = i*servchnls;
+ for (j=0; j<servchnls; j++) {
+ server->input_buffer[off2chnls+j] = (MYFLT)bufdata[off1chnls+j];
+ }
+ }
+ return kAudioHardwareNoError;
+}
+
+OSStatus coreaudio_output_callback(AudioDeviceID device, const AudioTimeStamp* inNow,
+ const AudioBufferList* inInputData,
+ const AudioTimeStamp* inInputTime,
+ AudioBufferList* outOutputData,
+ const AudioTimeStamp* inOutputTime,
+ void* defptr)
+{
+ int i, j, bufchnls, servchnls, off1chnls, off2chnls;
+ Server *server = (Server *) defptr;
+
+ (void) inInputData;
+
+ if (server->withPortMidi == 1) {
+ pyoGetMidiEvents(server);
+ }
+
+ Server_process_buffers(server);
+ AudioBuffer* outputBuf = outOutputData->mBuffers;
+ bufchnls = outputBuf->mNumberChannels;
+ servchnls = server->nchnls < bufchnls ? server->nchnls : bufchnls;
+ float *bufdata = (float*)outputBuf->mData;
+ for (i=0; i<server->bufferSize; i++) {
+ off1chnls = i*bufchnls+server->output_offset;
+ off2chnls = i*servchnls;
+ for(j=0; j<servchnls; j++) {
+ bufdata[off1chnls+j] = server->output_buffer[off2chnls+j];
+ }
+ }
+ server->midi_count = 0;
+
+ return kAudioHardwareNoError;
+}
+
+int
+coreaudio_stop_callback(Server *self)
+{
+ OSStatus err = kAudioHardwareNoError;
+
+ if (self->duplex == 1) {
+ err = AudioDeviceStop(self->input, coreaudio_input_callback);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Input AudioDeviceStop failed %d\n", (int)err);
+ return -1;
+ }
+ }
+
+ err = AudioDeviceStop(self->output, coreaudio_output_callback);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Output AudioDeviceStop failed %d\n", (int)err);
+ return -1;
+ }
+ self->server_started = 0;
+ return 0;
+}
+
+int
+Server_coreaudio_init(Server *self)
+{
+ OSStatus err = kAudioHardwareNoError;
+ UInt32 count, namelen, propertySize;
+ int i, numdevices;
+ char *name;
+ AudioDeviceID mOutputDevice = kAudioDeviceUnknown;
+ AudioDeviceID mInputDevice = kAudioDeviceUnknown;
+ Boolean writable;
+ AudioTimeStamp now;
+
+ now.mFlags = kAudioTimeStampHostTimeValid;
+ now.mHostTime = AudioGetCurrentHostTime();
+
+ /************************************/
+ /* List Coreaudio available devices */
+ /************************************/
+ err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &count, 0);
+ AudioDeviceID *devices = (AudioDeviceID*) malloc(count);
+ err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Get kAudioHardwarePropertyDevices error %s\n", (char*)&err);
+ free(devices);
+ }
+
+ numdevices = count / sizeof(AudioDeviceID);
+ Server_debug(self, "Coreaudio : Number of devices: %i\n", numdevices);
+
+ for (i=0; i<numdevices; ++i) {
+ err = AudioDeviceGetPropertyInfo(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, 0);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Info kAudioDevicePropertyDeviceName error %s A %d %08X\n", (char*)&err, i, devices[i]);
+ break;
+ }
+
+ char *name = (char*)malloc(count);
+ err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, name);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Get kAudioDevicePropertyDeviceName error %s A %d %08X\n", (char*)&err, i, devices[i]);
+ free(name);
+ break;
+ }
+ Server_debug(self, " %d : \"%s\"\n", i, name);
+ free(name);
+ }
+
+ /************************************/
+ /* Acquire input and output devices */
+ /************************************/
+ /* Acquire input audio device */
+ if (self->duplex == 1) {
+ if (self->input != -1)
+ mInputDevice = devices[self->input];
+
+ if (mInputDevice==kAudioDeviceUnknown) {
+ count = sizeof(mInputDevice);
+ err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &count, (void *) &mInputDevice);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Get kAudioHardwarePropertyDefaultInputDevice error %s\n", (char*)&err);
+ return -1;
+ }
+ }
+
+ err = AudioDeviceGetPropertyInfo(mInputDevice, 0, false, kAudioDevicePropertyDeviceName, &namelen, 0);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Info kAudioDevicePropertyDeviceName error %s A %08X\n", (char*)&err, mInputDevice);
+ }
+ name = (char*)malloc(namelen);
+ err = AudioDeviceGetProperty(mInputDevice, 0, false, kAudioDevicePropertyDeviceName, &namelen, name);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Get kAudioDevicePropertyDeviceName error %s A %08X\n", (char*)&err, mInputDevice);
+ }
+ Server_debug(self, "Coreaudio : Uses input device : \"%s\"\n", name);
+ self->input = mInputDevice;
+ free(name);
+ }
+
+ /* Acquire output audio device */
+ if (self->output != -1)
+ mOutputDevice = devices[self->output];
+
+ if (mOutputDevice==kAudioDeviceUnknown) {
+ count = sizeof(mOutputDevice);
+ err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) &mOutputDevice);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Get kAudioHardwarePropertyDefaultOutputDevice error %s\n", (char*)&err);
+ return -1;
+ }
+ }
+
+ err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &namelen, 0);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Info kAudioDevicePropertyDeviceName error %s A %08X\n", (char*)&err, mOutputDevice);
+ }
+ name = (char*)malloc(namelen);
+ err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &namelen, name);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Get kAudioDevicePropertyDeviceName error %s A %08X\n", (char*)&err, mOutputDevice);
+ }
+ Server_debug(self, "Coreaudio : Uses output device : \"%s\"\n", name);
+ self->output = mOutputDevice;
+ free(name);
+
+ /*************************************************/
+ /* Get in/out buffer frame and buffer frame size */
+ /*************************************************/
+ UInt32 bufferSize;
+ AudioValueRange range;
+ Float64 sampleRate;
+
+ /* Get input device buffer frame size and buffer frame size range */
+ if (self->duplex == 1) {
+ count = sizeof(UInt32);
+ err = AudioDeviceGetProperty(mInputDevice, 0, false, kAudioDevicePropertyBufferFrameSize, &count, &bufferSize);
+ if (err != kAudioHardwareNoError)
+ Server_error(self, "Get kAudioDevicePropertyBufferFrameSize error %s\n", (char*)&err);
+ Server_debug(self, "Coreaudio : Coreaudio input device buffer size = %ld\n", bufferSize);
+
+ count = sizeof(AudioValueRange);
+ err = AudioDeviceGetProperty(mInputDevice, 0, false, kAudioDevicePropertyBufferSizeRange, &count, &range);
+ if (err != kAudioHardwareNoError)
+ Server_error(self, "Get kAudioDevicePropertyBufferSizeRange error %s\n", (char*)&err);
+ Server_debug(self, "Coreaudio : Coreaudio input device buffer size range = %f -> %f\n", range.mMinimum, range.mMaximum);
+
+ /* Get input device sampling rate */
+ count = sizeof(Float64);
+ err = AudioDeviceGetProperty(mInputDevice, 0, false, kAudioDevicePropertyNominalSampleRate, &count, &sampleRate);
+ if (err != kAudioHardwareNoError)
+ Server_debug(self, "Get kAudioDevicePropertyNominalSampleRate error %s\n", (char*)&err);
+ Server_debug(self, "Coreaudio : Coreaudio input device sampling rate = %.2f\n", sampleRate);
+ }
+
+ /* Get output device buffer frame size and buffer frame size range */
+ count = sizeof(UInt32);
+ err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyBufferFrameSize, &count, &bufferSize);
+ if (err != kAudioHardwareNoError)
+ Server_error(self, "Get kAudioDevicePropertyBufferFrameSize error %s\n", (char*)&err);
+ Server_debug(self, "Coreaudio : Coreaudio output device buffer size = %ld\n", bufferSize);
+
+ count = sizeof(AudioValueRange);
+ err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyBufferSizeRange, &count, &range);
+ if (err != kAudioHardwareNoError)
+ Server_error(self, "Get kAudioDevicePropertyBufferSizeRange error %s\n", (char*)&err);
+ Server_debug(self, "Coreaudio : Coreaudio output device buffer size range = %.2f -> %.2f\n", range.mMinimum, range.mMaximum);
+
+ /* Get output device sampling rate */
+ count = sizeof(Float64);
+ err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyNominalSampleRate, &count, &sampleRate);
+ if (err != kAudioHardwareNoError)
+ Server_debug(self, "Get kAudioDevicePropertyNominalSampleRate error %s\n", (char*)&err);
+ Server_debug(self, "Coreaudio : Coreaudio output device sampling rate = %.2f\n", sampleRate);
+
+
+ /****************************************/
+ /********* Set audio properties *********/
+ /****************************************/
+ /* set/get the buffersize for the devices */
+ count = sizeof(UInt32);
+ err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &self->bufferSize);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "set kAudioDevicePropertyBufferFrameSize error %4.4s\n", (char*)&err);
+ self->bufferSize = bufferSize;
+ err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &self->bufferSize);
+ if (err != kAudioHardwareNoError)
+ Server_error(self, "set kAudioDevicePropertyBufferFrameSize error %4.4s\n", (char*)&err);
+ else
+ Server_debug(self, "pyo buffer size set to output device buffer size : %i\n", self->bufferSize);
+ }
+ else
+ Server_debug(self, "Coreaudio : Changed output device buffer size successfully: %i\n", self->bufferSize);
+
+ if (self->duplex == 1) {
+ err = AudioDeviceSetProperty(mInputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &self->bufferSize);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "set kAudioDevicePropertyBufferFrameSize error %4.4s\n", (char*)&err);
+ }
+ }
+
+ /* set/get the sampling rate for the devices */
+ count = sizeof(double);
+ double pyoSamplingRate = self->samplingRate;
+ err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyNominalSampleRate, count, &pyoSamplingRate);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "set kAudioDevicePropertyNominalSampleRate error %s\n", (char*)&err);
+ self->samplingRate = (double)sampleRate;
+ err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyNominalSampleRate, count, &sampleRate);
+ if (err != kAudioHardwareNoError)
+ Server_error(self, "set kAudioDevicePropertyNominalSampleRate error %s\n", (char*)&err);
+ else
+ Server_debug(self, "pyo sampling rate set to output device sampling rate : %i\n", self->samplingRate);
+ }
+ else
+ Server_debug(self, "Coreaudio : Changed output device sampling rate successfully: %.2f\n", self->samplingRate);
+
+ if (self->duplex ==1) {
+ pyoSamplingRate = self->samplingRate;
+ err = AudioDeviceSetProperty(mInputDevice, &now, 0, false, kAudioDevicePropertyNominalSampleRate, count, &pyoSamplingRate);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "set kAudioDevicePropertyNominalSampleRate error %s\n", (char*)&err);
+ }
+ }
+
+
+ /****************************************/
+ /* Input and output stream descriptions */
+ /****************************************/
+ AudioStreamBasicDescription outputStreamDescription;
+ AudioStreamBasicDescription inputStreamDescription;
+
+ // Get input device stream configuration
+ if (self->duplex == 1) {
+ count = sizeof(AudioStreamBasicDescription);
+ err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyStreamFormat, &count, &inputStreamDescription);
+ if (err != kAudioHardwareNoError)
+ Server_debug(self, "Get kAudioDevicePropertyStreamFormat error %s\n", (char*)&err);
+
+ /*
+ inputStreamDescription.mSampleRate = (Float64)self->samplingRate;
+
+ err = AudioDeviceSetProperty(mInputDevice, &now, 0, false, kAudioDevicePropertyStreamFormat, count, &inputStreamDescription);
+ if (err != kAudioHardwareNoError)
+ Server_debug(self, "-- Set kAudioDevicePropertyStreamFormat error %s\n", (char*)&err);
+
+ // Print new input stream description
+ err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyStreamFormat, &count, &inputStreamDescription);
+ if (err != kAudioHardwareNoError)
+ Server_debug(self, "Get kAudioDevicePropertyNominalSampleRate error %s\n", (char*)&err);
+ */
+ Server_debug(self, "Coreaudio : Coreaudio driver input stream sampling rate = %.2f\n", inputStreamDescription.mSampleRate);
+ Server_debug(self, "Coreaudio : Coreaudio driver input stream bytes per frame = %i\n", inputStreamDescription.mBytesPerFrame);
+ Server_debug(self, "Coreaudio : Coreaudio driver input stream number of channels = %i\n", inputStreamDescription.mChannelsPerFrame);
+ }
+
+ /* Get output device stream configuration */
+ count = sizeof(AudioStreamBasicDescription);
+ err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDescription);
+ if (err != kAudioHardwareNoError)
+ Server_debug(self, "Get kAudioDevicePropertyStreamFormat error %s\n", (char*)&err);
+
+ /*
+ outputStreamDescription.mSampleRate = (Float64)self->samplingRate;
+
+ err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyStreamFormat, count, &outputStreamDescription);
+ if (err != kAudioHardwareNoError)
+ Server_debug(self, "Set kAudioDevicePropertyStreamFormat error %s\n", (char*)&err);
+
+ // Print new output stream description
+ err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDescription);
+ if (err != kAudioHardwareNoError)
+ Server_debug(self, "Get kAudioDevicePropertyStreamFormat error %s\n", (char*)&err);
+ */
+ Server_debug(self, "Coreaudio : Coreaudio driver output stream sampling rate = %.2f\n", outputStreamDescription.mSampleRate);
+ Server_debug(self, "Coreaudio : Coreaudio driver output stream bytes per frame = %i\n", outputStreamDescription.mBytesPerFrame);
+ Server_debug(self, "Coreaudio : Coreaudio driver output stream number of channels = %i\n", outputStreamDescription.mChannelsPerFrame);
+
+
+ /**************************************************/
+ /********* Set input and output callbacks *********/
+ /**************************************************/
+ if (self->duplex == 1) {
+ err = AudioDeviceAddIOProc(self->input, coreaudio_input_callback, (void *) self); // setup our device with an IO proc
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Input AudioDeviceAddIOProc failed %d\n", (int)err);
+ return -1;
+ }
+ err = AudioDeviceGetPropertyInfo(self->input, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
+ AudioHardwareIOProcStreamUsage *input_su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
+ input_su->mIOProc = (void*)coreaudio_input_callback;
+ err = AudioDeviceGetProperty(self->input, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, input_su);
+ for (i=0; i<inputStreamDescription.mChannelsPerFrame; ++i) {
+ input_su->mStreamIsOn[i] = 1;
+ }
+ err = AudioDeviceSetProperty(self->input, &now, 0, true, kAudioDevicePropertyIOProcStreamUsage, propertySize, input_su);
+ }
+
+ err = AudioDeviceAddIOProc(self->output, coreaudio_output_callback, (void *) self); // setup our device with an IO proc
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Output AudioDeviceAddIOProc failed %d\n", (int)err);
+ return -1;
+ }
+ err = AudioDeviceGetPropertyInfo(self->output, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
+ AudioHardwareIOProcStreamUsage *output_su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
+ output_su->mIOProc = (void*)coreaudio_output_callback;
+ err = AudioDeviceGetProperty(self->output, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, output_su);
+ for (i=0; i<outputStreamDescription.mChannelsPerFrame; ++i) {
+ output_su->mStreamIsOn[i] = 1;
+ }
+ err = AudioDeviceSetProperty(self->output, &now, 0, false, kAudioDevicePropertyIOProcStreamUsage, propertySize, output_su);
+
+ return 0;
+}
+
+int
+Server_coreaudio_deinit(Server *self)
+{
+ OSStatus err = kAudioHardwareNoError;
+
+ if (self->duplex == 1) {
+ err = AudioDeviceRemoveIOProc(self->input, coreaudio_input_callback);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Input AudioDeviceRemoveIOProc failed %d\n", (int)err);
+ return -1;
+ }
+ }
+
+ err = AudioDeviceRemoveIOProc(self->output, coreaudio_output_callback);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Output AudioDeviceRemoveIOProc failed %d\n", (int)err);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+Server_coreaudio_start(Server *self)
+{
+ OSStatus err = kAudioHardwareNoError;
+
+ if (self->duplex == 1) {
+ err = AudioDeviceStart(self->input, coreaudio_input_callback);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Input AudioDeviceStart failed %d\n", (int)err);
+ return -1;
+ }
+ }
+
+ err = AudioDeviceStart(self->output, coreaudio_output_callback);
+ if (err != kAudioHardwareNoError) {
+ Server_error(self, "Output AudioDeviceStart failed %d\n", (int)err);
+ return -1;
+ }
+ return 0;
+}
+
+int
+Server_coreaudio_stop(Server *self)
+{
+ coreaudio_stop_callback(self);
+ self->server_stopped = 1;
+ return 0;
+}
diff --git a/src/engine/ad_jack.c b/src/engine/ad_jack.c
new file mode 100644
index 0000000..1e8996e
--- /dev/null
+++ b/src/engine/ad_jack.c
@@ -0,0 +1,300 @@
+/**************************************************************************
+ * Copyright 2009-2016 Olivier Belanger *
+ * *
+ * This file is part of pyo, a python module to help digital signal *
+ * processing script creation. *
+ * *
+ * pyo is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * pyo is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with pyo. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#include "ad_jack.h"
+#include "py2to3.h"
+
+int
+jack_callback(jack_nframes_t nframes, void *arg) {
+ int i, j;
+ Server *server = (Server *) arg;
+ assert(nframes == server->bufferSize);
+ jack_default_audio_sample_t *in_buffers[server->ichnls], *out_buffers[server->nchnls];
+
+ if (server->withPortMidi == 1) {
+ pyoGetMidiEvents(server);
+ }
+ PyoJackBackendData *be_data = (PyoJackBackendData *) server->audio_be_data;
+ for (i = 0; i < server->ichnls; i++) {
+ in_buffers[i] = jack_port_get_buffer(be_data->jack_in_ports[i+server->input_offset], server->bufferSize);
+ }
+ for (i = 0; i < server->nchnls; i++) {
+ out_buffers[i] = jack_port_get_buffer(be_data->jack_out_ports[i+server->output_offset], server->bufferSize);
+
+ }
+ /* jack audio data is not interleaved */
+ if (server->duplex == 1) {
+ for (i=0; i<server->bufferSize; i++) {
+ for (j=0; j<server->ichnls; j++) {
+ server->input_buffer[(i*server->ichnls)+j] = (MYFLT) in_buffers[j][i];
+ }
+ }
+ }
+ Server_process_buffers(server);
+ for (i=0; i<server->bufferSize; i++) {
+ for (j=0; j<server->nchnls; j++) {
+ out_buffers[j][i] = (jack_default_audio_sample_t) server->output_buffer[(i*server->nchnls)+j];
+ }
+ }
+ server->midi_count = 0;
+ 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);
+ 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);
+ return 0;
+}
+
+void
+jack_error_cb(const char *desc) {
+ PySys_WriteStdout("JACK error: %s\n", desc);
+}
+
+void
+jack_shutdown_cb(void *arg) {
+ Server *s = (Server *) arg;
+ Server_shut_down(s);
+ Server_warning(s, "JACK server shutdown. Pyo Server shut down.\n");
+}
+
+void
+Server_jack_autoconnect(Server *self) {
+ const char **ports;
+ char *portname;
+ int i, j, num;
+ PyoJackBackendData *be_data = (PyoJackBackendData *) self->audio_be_data;
+
+ if (self->jackautoin) {
+ if ((ports = jack_get_ports(be_data->jack_client, "system", NULL, JackPortIsOutput)) == NULL) {
+ Server_error(self, "Jack: Cannot find any physical capture ports called 'system'\n");
+ }
+
+ i=0;
+ while(ports[i] != NULL && be_data->jack_in_ports[i] != NULL){
+ if (jack_connect(be_data->jack_client, ports[i], jack_port_name(be_data->jack_in_ports[i]))) {
+ Server_error(self, "Jack: cannot connect 'system' to input ports\n");
+ }
+ i++;
+ }
+ free(ports);
+ }
+
+ if (self->jackautoout) {
+ if ((ports = jack_get_ports(be_data->jack_client, "system", NULL, JackPortIsInput)) == NULL) {
+ Server_error(self, "Jack: Cannot find any physical playback ports called 'system'\n");
+ }
+
+ i=0;
+ while(ports[i] != NULL && be_data->jack_out_ports[i] != NULL){
+ if (jack_connect(be_data->jack_client, jack_port_name (be_data->jack_out_ports[i]), ports[i])) {
+ Server_error(self, "Jack: cannot connect output ports to 'system'\n");
+ }
+ i++;
+ }
+ free(ports);
+ }
+
+ num = PyList_Size(self->jackAutoConnectInputPorts);
+ if (num > 0) {
+ if (num != self->ichnls || !PyList_Check(PyList_GetItem(self->jackAutoConnectInputPorts, 0))) {
+ Server_error(self, "Jack: auto-connect input ports list size does not match server.ichnls.\n");
+ }
+ else {
+ for (j=0; j<self->ichnls; j++) {
+ 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]))) {
+ Server_error(self, "Jack: cannot connect '%s' to input port %d\n", portname, j);
+ }
+ }
+ else {
+ Server_error(self, "Jack: cannot find port '%s'\n", portname);
+ }
+ }
+ }
+ }
+ }
+
+ num = PyList_Size(self->jackAutoConnectOutputPorts);
+ if (num > 0) {
+ if (num != self->nchnls || !PyList_Check(PyList_GetItem(self->jackAutoConnectOutputPorts, 0))) {
+ Server_error(self, "Jack: auto-connect output ports list size does not match server.nchnls.\n");
+ } else {
+ for (j=0; j<self->nchnls; j++) {
+ num = PyList_Size(PyList_GetItem(self->jackAutoConnectOutputPorts, j));
+ 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)) {
+ Server_error(self, "Jack: cannot connect output port %d to '%s'\n", j, portname);
+ }
+ }
+ else {
+ Server_error(self, "Jack: cannot find port '%s'\n", portname);
+ }
+ }
+ }
+ }
+ }
+}
+
+int
+Server_jack_init(Server *self) {
+ char client_name[32];
+ char name[16];
+ const char *server_name = "server";
+ jack_options_t options = JackNullOption;
+ jack_status_t status;
+ int sampleRate = 0;
+ int bufferSize = 0;
+ int nchnls = 0;
+ int total_nchnls = 0;
+ int index = 0;
+ int ret = 0;
+ assert(self->audio_be_data == NULL);
+ PyoJackBackendData *be_data = (PyoJackBackendData *) malloc(sizeof(PyoJackBackendData *));
+ self->audio_be_data = (void *) be_data;
+ 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);
+ if (be_data->jack_client == NULL) {
+ Server_error(self, "Jack error: Unable to create JACK client\n");
+ if (status & JackServerFailed) {
+ Server_debug(self, "Jack error: jack_client_open() failed, "
+ "status = 0x%2.0x\n", status);
+ }
+ return -1;
+ }
+ if (status & JackServerStarted) {
+ Server_warning(self, "JACK server started.\n");
+ }
+ if (strcmp(self->serverName, jack_get_client_name(be_data->jack_client)) ) {
+ strcpy(self->serverName, jack_get_client_name(be_data->jack_client));
+ Server_warning(self, "Jack name `%s' assigned\n", self->serverName);
+ }
+
+ 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);
+ }
+ else {
+ Server_debug(self, "Jack engine sample rate: %" PRIu32 "\n", sampleRate);
+ }
+ if (sampleRate <= 0) {
+ Server_error(self, "Invalid Jack engine sample rate.");
+ jack_client_close(be_data->jack_client);
+ return -1;
+ }
+ bufferSize = jack_get_buffer_size(be_data->jack_client);
+ if (bufferSize != self->bufferSize) {
+ self->bufferSize = bufferSize;
+ Server_warning(self, "Buffer size set to Jack engine buffer size: %" PRIu32 "\n", bufferSize);
+ }
+ else {
+ Server_debug(self, "Jack engine buffer size: %" PRIu32 "\n", bufferSize);
+ }
+
+ nchnls = total_nchnls = self->ichnls + self->input_offset;
+ while (nchnls-- > 0) {
+ 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);
+ }
+
+ if ((be_data->jack_in_ports[index] == NULL)) {
+ Server_error(self, "Jack: no more JACK input ports available\n");
+ return -1;
+ }
+ }
+
+ nchnls = total_nchnls = self->nchnls + self->output_offset;
+ while (nchnls-- > 0) {
+ 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);
+ }
+ if ((be_data->jack_out_ports[index] == NULL)) {
+ Server_error(self, "Jack: no more JACK output ports available\n");
+ return -1;
+ }
+ }
+ jack_set_error_function(jack_error_cb);
+ jack_set_sample_rate_callback(be_data->jack_client, jack_srate_cb, (void *) self);
+ jack_on_shutdown(be_data->jack_client, jack_shutdown_cb, (void *) self);
+ jack_set_buffer_size_callback(be_data->jack_client, jack_bufsize_cb, (void *) self);
+ return 0;
+}
+
+int
+Server_jack_deinit(Server *self) {
+ PyoJackBackendData *be_data = (PyoJackBackendData *) self->audio_be_data;
+ int ret = jack_client_close(be_data->jack_client);
+ 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
+Server_jack_start(Server *self) {
+ PyoJackBackendData *be_data = (PyoJackBackendData *) self->audio_be_data;
+ jack_set_process_callback(be_data->jack_client, jack_callback, (void *) self);
+ if (jack_activate(be_data->jack_client)) {
+ Server_error(self, "Jack error: cannot activate jack client.\n");
+ jack_client_close(be_data->jack_client);
+ Server_shut_down(self);
+ return -1;
+ }
+ Server_jack_autoconnect(self);
+ return 0;
+}
+
+int
+Server_jack_stop(Server *self) {
+ PyoJackBackendData *be_data = (PyoJackBackendData *) self->audio_be_data;
+ int ret = jack_deactivate(be_data->jack_client);
+ if (ret)
+ Server_error(self, "Jack error: cannot deactivate jack client.\n");
+ self->server_started = 0;
+ return ret;
+}
diff --git a/src/engine/ad_portaudio.c b/src/engine/ad_portaudio.c
new file mode 100644
index 0000000..20e714c
--- /dev/null
+++ b/src/engine/ad_portaudio.c
@@ -0,0 +1,635 @@
+/**************************************************************************
+ * Copyright 2009-2016 Olivier Belanger *
+ * *
+ * This file is part of pyo, a python module to help digital signal *
+ * processing script creation. *
+ * *
+ * pyo is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * pyo is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with pyo. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#include "ad_portaudio.h"
+#include "py2to3.h"
+
+/* Audio server's functions. */
+
+static void portaudio_assert(PaError ecode, const char* cmdName) {
+ if (ecode != paNoError) {
+ const char* eText = Pa_GetErrorText(ecode);
+ if (!eText) {
+ eText = "???";
+ }
+ PySys_WriteStdout("portaudio error in %s: %s\n", cmdName, eText);
+ Pa_Terminate();
+ }
+}
+
+int
+pa_callback_interleaved( const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *arg )
+{
+ float *out = (float *)outputBuffer;
+ Server *server = (Server *) arg;
+
+ assert(framesPerBuffer == server->bufferSize);
+ int i, j, bufchnls, index1, index2;
+
+ /* avoid unused variable warnings */
+ (void) timeInfo;
+ (void) statusFlags;
+
+ if (server->withPortMidi == 1) {
+ pyoGetMidiEvents(server);
+ }
+
+ if (server->duplex == 1) {
+ float *in = (float *)inputBuffer;
+ bufchnls = server->ichnls + server->input_offset;
+ for (i=0; i<server->bufferSize; i++) {
+ index1 = i * server->ichnls;
+ index2 = i * bufchnls + server->input_offset;
+ for (j=0; j<server->ichnls; j++) {
+ server->input_buffer[index1+j] = (MYFLT)in[index2+j];
+ }
+ }
+ }
+
+ Server_process_buffers(server);
+ bufchnls = server->nchnls + server->output_offset;
+ for (i=0; i<server->bufferSize; i++) {
+ index1 = i * server->nchnls;
+ index2 = i * bufchnls + server->output_offset;
+ for (j=0; j<server->nchnls; j++) {
+ out[index2+j] = (float) server->output_buffer[index1+j];
+ }
+ }
+ server->midi_count = 0;
+
+#ifdef _OSX_
+ if (server->server_stopped == 1)
+ return paComplete;
+ else
+#endif
+ return paContinue;
+}
+
+int
+pa_callback_nonInterleaved( const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *arg )
+{
+ float **out = (float **)outputBuffer;
+ Server *server = (Server *) arg;
+
+ assert(framesPerBuffer == server->bufferSize);
+ int i, j;
+
+ /* avoid unused variable warnings */
+ (void) timeInfo;
+ (void) statusFlags;
+
+ if (server->withPortMidi == 1) {
+ pyoGetMidiEvents(server);
+ }
+
+ if (server->duplex == 1) {
+ float **in = (float **)inputBuffer;
+ for (i=0; i<server->bufferSize; i++) {
+ for (j=0; j<server->ichnls; j++) {
+ server->input_buffer[(i*server->ichnls)+j] = (MYFLT)in[j+server->input_offset][i];
+ }
+ }
+ }
+
+ Server_process_buffers(server);
+ for (i=0; i<server->bufferSize; i++) {
+ for (j=0; j<server->nchnls; j++) {
+ out[j+server->output_offset][i] = (float) server->output_buffer[(i*server->nchnls)+j];
+ }
+ }
+ server->midi_count = 0;
+
+#ifdef _OSX_
+ if (server->server_stopped == 1)
+ return paComplete;
+ else
+#endif
+ return paContinue;
+}
+
+int
+Server_pa_init(Server *self)
+{
+ PaError err;
+ PaStreamParameters outputParameters;
+ PaStreamParameters inputParameters;
+ PaDeviceIndex n, inDevice, outDevice;
+ const PaDeviceInfo *deviceInfo;
+ PaHostApiIndex hostIndex;
+ const PaHostApiInfo *hostInfo;
+ PaHostApiTypeId hostId;
+ PaSampleFormat sampleFormat;
+ PaStreamCallback *streamCallback;
+
+ err = Pa_Initialize();
+ portaudio_assert(err, "Pa_Initialize");
+
+ n = Pa_GetDeviceCount();
+ if (n < 0) {
+ portaudio_assert(n, "Pa_GetDeviceCount");
+ }
+
+ PyoPaBackendData *be_data = (PyoPaBackendData *) malloc(sizeof(PyoPaBackendData *));
+ self->audio_be_data = (void *) be_data;
+
+ if (self->output == -1)
+ outDevice = Pa_GetDefaultOutputDevice(); /* default output device */
+ else
+ outDevice = (PaDeviceIndex) self->output; /* selected output device */
+ if (self->input == -1)
+ inDevice = Pa_GetDefaultInputDevice(); /* default input device */
+ else
+ inDevice = (PaDeviceIndex) self->input; /* selected input device */
+
+ /* Retrieve host api id and define sample and callback format*/
+ deviceInfo = Pa_GetDeviceInfo(outDevice);
+ hostIndex = deviceInfo->hostApi;
+ hostInfo = Pa_GetHostApiInfo(hostIndex);
+ hostId = hostInfo->type;
+ if (hostId == paASIO) {
+ Server_debug(self, "Portaudio uses non-interleaved callback.\n");
+ sampleFormat = paFloat32 | paNonInterleaved;
+ streamCallback = pa_callback_nonInterleaved;
+ }
+ else if (hostId == paALSA) {
+ Server_debug(self, "Portaudio uses interleaved callback.\n");
+ Server_debug(self, "Using ALSA, if no input/output devices are specified, force to devices 0.\n");
+ if (self->input == -1 && self->output == -1) {
+ self->input = self->output = 0;
+ inDevice = outDevice = (PaDeviceIndex) 0;
+ }
+ sampleFormat = paFloat32;
+ streamCallback = pa_callback_interleaved;
+ }
+ else {
+ Server_debug(self, "Portaudio uses interleaved callback.\n");
+ sampleFormat = paFloat32;
+ streamCallback = pa_callback_interleaved;
+ }
+
+
+ /* setup output and input streams */
+ memset(&outputParameters, 0, sizeof(outputParameters));
+ outputParameters.device = outDevice;
+ outputParameters.channelCount = self->nchnls + self->output_offset;
+ outputParameters.sampleFormat = sampleFormat;
+ outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ if (self->duplex == 1) {
+ memset(&inputParameters, 0, sizeof(inputParameters));
+ inputParameters.device = inDevice;
+ inputParameters.channelCount = self->ichnls + self->input_offset;
+ inputParameters.sampleFormat = sampleFormat;
+ inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ;
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+ }
+
+ if (self->input == -1 && self->output == -1) {
+ if (self->duplex == 1)
+ err = Pa_OpenDefaultStream(&be_data->stream,
+ self->ichnls + self->input_offset,
+ self->nchnls + self->output_offset,
+ sampleFormat,
+ self->samplingRate,
+ self->bufferSize,
+ streamCallback,
+ (void *) self);
+ else
+ err = Pa_OpenDefaultStream(&be_data->stream,
+ 0,
+ self->nchnls + self->output_offset,
+ sampleFormat,
+ self->samplingRate,
+ self->bufferSize,
+ streamCallback,
+ (void *) self);
+ }
+ else {
+ if (self->duplex == 1)
+ err = Pa_OpenStream(&be_data->stream,
+ &inputParameters,
+ &outputParameters,
+ self->samplingRate,
+ self->bufferSize,
+ paNoFlag,
+ streamCallback,
+ (void *) self);
+ else
+ err = Pa_OpenStream(&be_data->stream,
+ (PaStreamParameters *) NULL,
+ &outputParameters,
+ self->samplingRate,
+ self->bufferSize,
+ paNoFlag,
+ streamCallback,
+ (void *) self);
+ }
+ portaudio_assert(err, "Pa_OpenStream");
+ if (err < 0) {
+ Server_error(self, "Portaudio error: %s", Pa_GetErrorText(err));
+ return -1;
+ }
+ return 0;
+}
+
+int
+Server_pa_deinit(Server *self)
+{
+ PaError err;
+ PyoPaBackendData *be_data = (PyoPaBackendData *) self->audio_be_data;
+
+ if (Pa_IsStreamActive(be_data->stream) || ! Pa_IsStreamStopped(be_data->stream)) {
+ self->server_started = 0;
+ err = Pa_AbortStream(be_data->stream);
+ portaudio_assert(err, "Pa_AbortStream");
+ }
+
+ err = Pa_CloseStream(be_data->stream);
+ portaudio_assert(err, "Pa_CloseStream");
+
+ err = Pa_Terminate();
+ portaudio_assert(err, "Pa_Terminate");
+
+ free(self->audio_be_data);
+ return err;
+}
+
+int
+Server_pa_start(Server *self)
+{
+ PaError err;
+ PyoPaBackendData *be_data = (PyoPaBackendData *) self->audio_be_data;
+
+ if (Pa_IsStreamActive(be_data->stream) || ! Pa_IsStreamStopped(be_data->stream)) {
+ err = Pa_AbortStream(be_data->stream);
+ portaudio_assert(err, "Pa_AbortStream");
+ }
+ err = Pa_StartStream(be_data->stream);
+ portaudio_assert(err, "Pa_StartStream");
+ return err;
+}
+
+int
+Server_pa_stop(Server *self)
+{
+ PyoPaBackendData *be_data = (PyoPaBackendData *) self->audio_be_data;
+
+ if (Pa_IsStreamActive(be_data->stream) || ! Pa_IsStreamStopped(be_data->stream)) {
+#ifndef _OSX_
+ PaError err = Pa_AbortStream(be_data->stream);
+ portaudio_assert(err, "Pa_AbortStream");
+#endif
+ }
+ self->server_started = 0;
+ self->server_stopped = 1;
+ return 0;
+}
+
+/* Query functions. */
+
+PyObject *
+portaudio_get_version() {
+ return PyInt_FromLong(Pa_GetVersion());
+}
+
+PyObject *
+portaudio_get_version_text() {
+ return PyUnicode_FromString(Pa_GetVersionText());
+}
+
+PyObject *
+portaudio_count_host_apis(){
+ PaError err;
+ PaHostApiIndex numApis;
+
+ err = Pa_Initialize();
+ if (err != paNoError) {
+ portaudio_assert(err, "Pa_Initialize");
+ Py_RETURN_NONE;
+ }
+ else {
+ numApis = Pa_GetHostApiCount();
+ if( numApis < 0 )
+ portaudio_assert(numApis, "Pa_GetHostApiCount");
+ return PyInt_FromLong(numApis);
+ }
+}
+
+PyObject *
+portaudio_list_host_apis(){
+ PaError err;
+ PaHostApiIndex n, i;
+
+ err = Pa_Initialize();
+ if (err != paNoError) {
+ portaudio_assert(err, "Pa_Initialize");
+ }
+ else {
+ n = Pa_GetHostApiCount();
+ if (n < 0){
+ portaudio_assert(n, "Pa_GetHostApiCount");
+ }
+ else {
+ for (i=0; i < n; ++i){
+ const PaHostApiInfo *info = Pa_GetHostApiInfo(i);
+ assert(info);
+ PySys_WriteStdout("index: %i, id: %i, name: %s, num devices: %i, default in: %i, default out: %i\n",
+ i, (int)info->type, info->name, (int)info->deviceCount, (int)info->defaultInputDevice,
+ (int)info->defaultOutputDevice);
+ }
+ }
+ }
+ Py_RETURN_NONE;
+}
+
+PyObject *
+portaudio_get_default_host_api(){
+ PaError err;
+ PaHostApiIndex i;
+
+ err = Pa_Initialize();
+ if (err != paNoError) {
+ portaudio_assert(err, "Pa_Initialize");
+ Py_RETURN_NONE;
+ }
+ else {
+ i = Pa_GetDefaultHostApi();
+ return PyInt_FromLong(i);
+ }
+}
+
+PyObject *
+portaudio_count_devices(){
+ PaError err;
+ PaDeviceIndex numDevices;
+
+ err = Pa_Initialize();
+ if (err != paNoError) {
+ portaudio_assert(err, "Pa_Initialize");
+ Py_RETURN_NONE;
+ }
+ else {
+ numDevices = Pa_GetDeviceCount();
+ if( numDevices < 0 )
+ portaudio_assert(numDevices, "Pa_GetDeviceCount");
+ return PyInt_FromLong(numDevices);
+ }
+
+}
+
+PyObject *
+portaudio_list_devices(){
+ PaError err;
+ PaDeviceIndex n, i;
+
+ err = Pa_Initialize();
+ if (err != paNoError) {
+ portaudio_assert(err, "Pa_Initialize");
+ Py_RETURN_NONE;
+ }
+ else {
+ n = Pa_GetDeviceCount();
+ if (n < 0){
+ portaudio_assert(n, "Pa_GetDeviceCount");
+ }
+ else {
+ PySys_WriteStdout("AUDIO devices:\n");
+ for (i=0; i < n; ++i){
+ const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
+ assert(info);
+
+ if (info->maxInputChannels > 0)
+ PySys_WriteStdout("%i: IN, name: %s, host api index: %i, default sr: %i Hz, latency: %f s\n",
+ i, info->name, (int)info->hostApi, (int)info->defaultSampleRate,
+ (float)info->defaultLowInputLatency);
+
+ if (info->maxOutputChannels > 0)
+ PySys_WriteStdout("%i: OUT, name: %s, host api index: %i, default sr: %i Hz, latency: %f s\n",
+ i, info->name, (int)info->hostApi, (int)info->defaultSampleRate,
+ (float)info->defaultLowOutputLatency);
+ }
+ PySys_WriteStdout("\n");
+ }
+ }
+ Py_RETURN_NONE;
+}
+
+PyObject *
+portaudio_get_devices_infos(){
+ PaError err;
+ PaDeviceIndex n, i;
+ PyObject *inDict, *outDict, *tmpDict;
+ inDict = PyDict_New();
+ outDict = PyDict_New();
+
+ err = Pa_Initialize();
+ 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);
+ tmpDict = PyDict_New();
+ if (info->maxInputChannels > 0) {
+ 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));
+ 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);
+ }
+ }
+}
+
+PyObject *
+portaudio_get_output_devices(){
+ PaError err;
+ PaDeviceIndex n, i;
+
+ PyObject *list, *list_index;
+ list = PyList_New(0);
+ list_index = PyList_New(0);
+
+ err = Pa_Initialize();
+ 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));
+ PyList_Append(list_index, PyInt_FromLong(i));
+ }
+ }
+ return Py_BuildValue("OO", list, list_index);
+ }
+ }
+}
+
+PyObject *
+portaudio_get_output_max_channels(PyObject *self, PyObject *arg){
+ PaError err;
+ PaDeviceIndex n, i = PyInt_AsLong(arg);
+
+ err = Pa_Initialize();
+ 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 {
+ const PaDeviceInfo *info=Pa_GetDeviceInfo(i);
+ assert(info);
+ return PyInt_FromLong(info->maxOutputChannels);
+ }
+ }
+}
+
+PyObject *
+portaudio_get_input_max_channels(PyObject *self, PyObject *arg){
+ PaError err;
+ PaDeviceIndex n, i = PyInt_AsLong(arg);
+
+ err = Pa_Initialize();
+ 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 {
+ const PaDeviceInfo *info=Pa_GetDeviceInfo(i);
+ assert(info);
+ return PyInt_FromLong(info->maxInputChannels);
+ }
+ }
+}
+
+PyObject *
+portaudio_get_input_devices(){
+ PaError err;
+ PaDeviceIndex n, i;
+
+ PyObject *list, *list_index;
+ list = PyList_New(0);
+ list_index = PyList_New(0);
+
+ err = Pa_Initialize();
+ 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));
+ PyList_Append(list_index, PyInt_FromLong(i));
+ }
+ }
+ return Py_BuildValue("OO", list, list_index);
+ }
+ }
+}
+
+PyObject *
+portaudio_get_default_input(){
+ PaError err;
+ PaDeviceIndex i;
+
+ err = Pa_Initialize();
+ if (err != paNoError) {
+ portaudio_assert(err, "Pa_Initialize");
+ Py_RETURN_NONE;
+ }
+ else {
+ i = Pa_GetDefaultInputDevice();
+ return PyInt_FromLong(i);
+ }
+
+}
+
+PyObject *
+portaudio_get_default_output(){
+ PaError err;
+ PaDeviceIndex i;
+
+ err = Pa_Initialize();
+ if (err != paNoError) {
+ portaudio_assert(err, "Pa_Initialize");
+ Py_RETURN_NONE;
+ }
+ else {
+ i = Pa_GetDefaultOutputDevice();
+ return PyInt_FromLong(i);
+
+ }
+}
diff --git a/src/engine/md_portmidi.c b/src/engine/md_portmidi.c
new file mode 100644
index 0000000..0c65f55
--- /dev/null
+++ b/src/engine/md_portmidi.c
@@ -0,0 +1,484 @@
+/**************************************************************************
+ * Copyright 2009-2016 Olivier Belanger *
+ * *
+ * This file is part of pyo, a python module to help digital signal *
+ * processing script creation. *
+ * *
+ * pyo is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * pyo is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with pyo. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#include "md_portmidi.h"
+#include "py2to3.h"
+
+static PyoMidiEvent PmEventToPyoMidiEvent(PmEvent buffer)
+{
+ PyoMidiEvent newbuf;
+ newbuf.message = buffer.message;
+ newbuf.timestamp = buffer.timestamp;
+ return newbuf;
+}
+
+void portmidiGetEvents(Server *self)
+{
+ int i;
+ PmError result;
+ PmEvent buffer;
+
+ PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data;
+
+ for (i=0; i<self->midiin_count; i++) {
+ do {
+ result = Pm_Poll(be_data->midiin[i]);
+ if (result) {
+ if (Pm_Read(be_data->midiin[i], &buffer, 1) == pmBufferOverflow)
+ continue;
+ self->midiEvents[self->midi_count++] = PmEventToPyoMidiEvent(buffer);
+ }
+ } while (result);
+ }
+}
+
+int
+Server_pm_init(Server *self)
+{
+ int i = 0, ret = 0;
+ PmError pmerr;
+
+ if (self->midiActive == 0) {
+ self->withPortMidi = 0;
+ self->withPortMidiOut = 0;
+ return 0;
+ }
+
+ pmerr = Pm_Initialize();
+ if (pmerr) {
+ Server_warning(self, "Portmidi warning: could not initialize Portmidi: %s\n", Pm_GetErrorText(pmerr));
+ self->withPortMidi = 0;
+ self->withPortMidiOut = 0;
+ return -1;
+ }
+ else {
+ Server_debug(self, "Portmidi initialized.\n");
+ self->withPortMidi = 1;
+ self->withPortMidiOut = 1;
+ }
+
+ PyoPmBackendData *be_data = (PyoPmBackendData *) malloc(sizeof(PyoPmBackendData *));
+ self->midi_be_data = (void *) be_data;
+
+ if (self->withPortMidi == 1) {
+ self->midiin_count = self->midiout_count = 0;
+ int num_devices = Pm_CountDevices();
+ Server_debug(self, "Portmidi number of devices: %d.\n", num_devices);
+ if (num_devices > 0) {
+ if (self->midi_input < num_devices) {
+ if (self->midi_input == -1)
+ self->midi_input = Pm_GetDefaultInputDeviceID();
+ Server_debug(self, "Midi input device : %d.\n", self->midi_input);
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(self->midi_input);
+ if (info != NULL) {
+ if (info->input) {
+ pmerr = Pm_OpenInput(&be_data->midiin[0], self->midi_input, NULL, 100, NULL, NULL);
+ if (pmerr) {
+ Server_warning(self,
+ "Portmidi warning: could not open midi input %d (%s): %s\n",
+ self->midi_input, info->name, Pm_GetErrorText(pmerr));
+ self->withPortMidi = 0;
+ }
+ else {
+ Server_debug(self, "Midi input (%s) opened.\n", info->name);
+ self->midiin_count = 1;
+ }
+ }
+ else {
+ Server_warning(self, "Portmidi warning: Midi Device (%s), not an input device!\n", info->name);
+ self->withPortMidi = 0;
+ }
+ }
+ else {
+ Server_debug(self, "Can't get midi input device info : %d.\n", self->midi_input);
+ self->withPortMidi = 0;
+ }
+ }
+ else if (self->midi_input >= num_devices) {
+ Server_debug(self, "Midi input device : all!\n");
+ self->midiin_count = 0;
+ for (i=0; i<num_devices; i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ if (info != NULL) {
+ if (info->input) {
+ pmerr = Pm_OpenInput(&be_data->midiin[self->midiin_count], i, NULL, 100, NULL, NULL);
+ if (pmerr) {
+ Server_warning(self,
+ "Portmidi warning: could not open midi input %d (%s): %s\n",
+ 0, info->name, Pm_GetErrorText(pmerr));
+ }
+ else {
+ Server_debug(self, "Midi input (%s) opened.\n", info->name);
+ self->midiin_count++;
+ }
+ }
+ }
+ }
+ if (self->midiin_count == 0)
+ self->withPortMidi = 0;
+ }
+ else {
+ Server_warning(self, "Portmidi warning: no input device!\n");
+ self->withPortMidi = 0;
+ }
+
+ if (self->midi_output < num_devices) {
+ if (self->midi_output == -1)
+ self->midi_output = Pm_GetDefaultOutputDeviceID();
+ Server_debug(self, "Midi output device : %d.\n", self->midi_output);
+ const PmDeviceInfo *outinfo = Pm_GetDeviceInfo(self->midi_output);
+ if (outinfo != NULL) {
+ if (outinfo->output) {
+ Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+ pmerr = Pm_OpenOutput(&be_data->midiout[0], self->midi_output, NULL, 0, NULL, NULL, 1);
+ if (pmerr) {
+ Server_warning(self,
+ "Portmidi warning: could not open midi output %d (%s): %s\n",
+ self->midi_output, outinfo->name, Pm_GetErrorText(pmerr));
+ self->withPortMidiOut = 0;
+ if (Pt_Started())
+ Pt_Stop();
+ }
+ else {
+ Server_debug(self, "Midi output (%s) opened.\n", outinfo->name);
+ self->midiout_count = 1;
+ }
+ }
+ else {
+ Server_warning(self, "Portmidi warning: Midi Device (%s), not an output device!\n", outinfo->name);
+ self->withPortMidiOut = 0;
+ }
+ }
+ else {
+ Server_debug(self, "Can't get midi output device info : %d.\n", self->midi_output);
+ self->withPortMidiOut = 0;
+ }
+ }
+ else if (self->midi_output >= num_devices) {
+ Server_debug(self, "Midi output device : all!\n");
+ self->midiout_count = 0;
+ Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+ for (i=0; i<num_devices; i++) {
+ const PmDeviceInfo *outinfo = Pm_GetDeviceInfo(i);
+ if (outinfo != NULL) {
+ if (outinfo->output) {
+ pmerr = Pm_OpenOutput(&be_data->midiout[self->midiout_count], i, NULL, 100, NULL, NULL, 1);
+ if (pmerr) {
+ Server_warning(self,
+ "Portmidi warning: could not open midi output %d (%s): %s\n",
+ 0, outinfo->name, Pm_GetErrorText(pmerr));
+ }
+ else {
+ Server_debug(self, "Midi output (%s) opened.\n", outinfo->name);
+ self->midiout_count++;
+ }
+ }
+ }
+ }
+ if (self->midiout_count == 0) {
+ if (Pt_Started())
+ Pt_Stop();
+ self->withPortMidiOut = 0;
+ }
+ }
+ else {
+ Server_warning(self, "Portmidi warning: no output device!\n");
+ self->withPortMidiOut = 0;
+ }
+
+ if (self->withPortMidi == 0 && self->withPortMidiOut == 0) {
+ Pm_Terminate();
+ Server_warning(self, "Portmidi closed.\n");
+ ret = -1;
+ }
+ }
+ else {
+ Server_warning(self, "Portmidi warning: no midi device found!\nPortmidi closed.\n");
+ self->withPortMidi = 0;
+ self->withPortMidiOut = 0;
+ Pm_Terminate();
+ ret = -1;
+ }
+ }
+ if (self->withPortMidi == 1) {
+ self->midi_count = 0;
+ for (i=0; i<self->midiin_count; i++) {
+ Pm_SetFilter(be_data->midiin[i], PM_FILT_ACTIVE | PM_FILT_CLOCK);
+ }
+ }
+ return ret;
+}
+
+int
+Server_pm_deinit(Server *self)
+{
+ int i = 0;
+
+ //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. */
+
+ 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 (self->withPortMidiOut == 1) {
+ for (i=0; i<self->midiout_count; i++) {
+ //if (be_data->midiout[i] != NULL)
+ //Pm_Close(be_data->midiout[i]);
+ }
+ }
+ if (self->withPortMidi == 1 || self->withPortMidiOut == 1) {
+ if (Pt_Started())
+ Pt_Stop();
+ Pm_Terminate();
+ }
+ self->withPortMidi = 0;
+ self->withPortMidiOut = 0;
+
+ free(self->midi_be_data);
+
+ return 0;
+}
+
+void
+pm_noteout(Server *self, int pit, int vel, int chan, long timestamp)
+{
+ int i, curtime;
+ PmEvent buffer[1];
+
+ PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data;
+
+ curtime = Pt_Time();
+ buffer[0].timestamp = curtime + timestamp;
+ if (chan == 0)
+ buffer[0].message = Pm_Message(0x90, pit, vel);
+ else
+ buffer[0].message = Pm_Message(0x90 | (chan - 1), pit, vel);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Write(be_data->midiout[i], buffer, 1);
+ }
+}
+
+void
+pm_afterout(Server *self, int pit, int vel, int chan, long timestamp)
+{
+ int i, curtime;
+ PmEvent buffer[1];
+
+ PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data;
+
+ curtime = Pt_Time();
+ buffer[0].timestamp = curtime + timestamp;
+ if (chan == 0)
+ buffer[0].message = Pm_Message(0xA0, pit, vel);
+ else
+ buffer[0].message = Pm_Message(0xA0 | (chan - 1), pit, vel);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Write(be_data->midiout[i], buffer, 1);
+ }
+}
+
+void
+pm_ctlout(Server *self, int ctlnum, int value, int chan, long timestamp)
+{
+ int i, curtime;
+ PmEvent buffer[1];
+
+ PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data;
+
+ curtime = Pt_Time();
+ buffer[0].timestamp = curtime + timestamp;
+ if (chan == 0)
+ buffer[0].message = Pm_Message(0xB0, ctlnum, value);
+ else
+ buffer[0].message = Pm_Message(0xB0 | (chan - 1), ctlnum, value);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Write(be_data->midiout[i], buffer, 1);
+ }
+}
+
+void
+pm_programout(Server *self, int value, int chan, long timestamp)
+{
+ int i, curtime;
+ PmEvent buffer[1];
+
+ PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data;
+
+ curtime = Pt_Time();
+ buffer[0].timestamp = curtime + timestamp;
+ if (chan == 0)
+ buffer[0].message = Pm_Message(0xC0, value, 0);
+ else
+ buffer[0].message = Pm_Message(0xC0 | (chan - 1), value, 0);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Write(be_data->midiout[i], buffer, 1);
+ }
+}
+
+void
+pm_pressout(Server *self, int value, int chan, long timestamp)
+{
+ int i, curtime;
+ PmEvent buffer[1];
+
+ PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data;
+
+ curtime = Pt_Time();
+ buffer[0].timestamp = curtime + timestamp;
+ if (chan == 0)
+ buffer[0].message = Pm_Message(0xD0, value, 0);
+ else
+ buffer[0].message = Pm_Message(0xD0 | (chan - 1), value, 0);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Write(be_data->midiout[i], buffer, 1);
+ }
+}
+
+void
+pm_bendout(Server *self, int value, int chan, long timestamp)
+{
+ int i, lsb, msb, curtime;
+ PmEvent buffer[1];
+
+ PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data;
+
+ curtime = Pt_Time();
+ buffer[0].timestamp = curtime + timestamp;
+ lsb = value & 0x007F;
+ msb = (value & (0x007F << 7)) >> 7;
+ if (chan == 0)
+ buffer[0].message = Pm_Message(0xE0, lsb, msb);
+ else
+ buffer[0].message = Pm_Message(0xE0 | (chan - 1), lsb, msb);
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_Write(be_data->midiout[i], buffer, 1);
+ }
+}
+
+void
+pm_sysexout(Server *self, unsigned char *msg, long timestamp)
+{
+ int i, curtime;
+
+ PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data;
+
+ curtime = Pt_Time();
+ for (i=0; i<self->midiout_count; i++) {
+ Pm_WriteSysEx(be_data->midiout[i], curtime + timestamp, msg);
+ }
+}
+
+/* Query functions. */
+
+PyObject *
+portmidi_count_devices() {
+ int numDevices;
+ numDevices = Pm_CountDevices();
+ return PyInt_FromLong(numDevices);
+}
+
+PyObject *
+portmidi_list_devices() {
+ int i;
+ PySys_WriteStdout("MIDI devices:\n");
+ for (i = 0; i < Pm_CountDevices(); i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ if (info->input && info->output)
+ PySys_WriteStdout("%d: IN/OUT, name: %s, interface: %s\n", i, info->name, info->interf);
+ else if (info->input)
+ PySys_WriteStdout("%d: IN, name: %s, interface: %s\n", i, info->name, info->interf);
+ else if (info->output)
+ PySys_WriteStdout("%d: OUT, name: %s, interface: %s\n", i, info->name, info->interf);
+ }
+ PySys_WriteStdout("\n");
+ Py_RETURN_NONE;
+}
+
+PyObject *
+portmidi_get_input_devices() {
+ int n, i;
+ PyObject *list, *list_index;
+ list = PyList_New(0);
+ list_index = PyList_New(0);
+ n = Pm_CountDevices();
+ if (n < 0){
+ PySys_WriteStdout("Portmidi warning: No Midi interface found\n\n");
+ }
+ else {
+ for (i=0; i < n; i++){
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ if (info->input){
+ PyList_Append(list, PyUnicode_FromString(info->name));
+ PyList_Append(list_index, PyInt_FromLong(i));
+ }
+ }
+ PySys_WriteStdout("\n");
+ }
+ return Py_BuildValue("OO", list, list_index);
+}
+
+PyObject *
+portmidi_get_output_devices() {
+ int n, i;
+ PyObject *list, *list_index;
+ list = PyList_New(0);
+ list_index = PyList_New(0);
+ n = Pm_CountDevices();
+ if (n < 0){
+ PySys_WriteStdout("Portmidi warning: No Midi interface found\n\n");
+ }
+ else {
+ for (i=0; i < n; i++){
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ if (info->output){
+ PyList_Append(list, PyUnicode_FromString(info->name));
+ PyList_Append(list_index, PyInt_FromLong(i));
+ }
+ }
+ PySys_WriteStdout("\n");
+ }
+ return Py_BuildValue("OO", list, list_index);
+}
+
+PyObject *
+portmidi_get_default_input() {
+ PmDeviceID i;
+
+ i = Pm_GetDefaultInputDeviceID();
+ if (i < 0)
+ PySys_WriteStdout("pm_get_default_input: no midi input device found.\n");
+ return PyInt_FromLong(i);
+}
+
+
+PyObject *
+portmidi_get_default_output() {
+ PmDeviceID i;
+ i = Pm_GetDefaultOutputDeviceID();
+ if (i < 0)
+ PySys_WriteStdout("pm_get_default_output: no midi output device found.\n");
+ return PyInt_FromLong(i);
+}
diff --git a/src/engine/midilistenermodule.c b/src/engine/midilistenermodule.c
new file mode 100644
index 0000000..7039c3b
--- /dev/null
+++ b/src/engine/midilistenermodule.c
@@ -0,0 +1,261 @@
+/**************************************************************************
+ * Copyright 2009-2015 Olivier Belanger *
+ * *
+ * This file is part of pyo, a python module to help digital signal *
+ * processing script creation. *
+ * *
+ * pyo is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * pyo is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with pyo. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#include <Python.h>
+#include "py2to3.h"
+#include "structmember.h"
+#include <math.h>
+#include "pyomodule.h"
+#include "portmidi.h"
+#include "porttime.h"
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *midicallable;
+ PmStream *midiin[64];
+ int mididev;
+ int midicount;
+ int active;
+} MidiListener;
+
+void process_midi(PtTimestamp timestamp, void *userData)
+{
+ PmError result;
+ PmEvent buffer; /* just one message at a time */
+ int i, status, data1, data2;
+ PyObject *tup = NULL;
+ MidiListener *server = (MidiListener *)userData;
+
+ if (server->active == 0) return;
+
+ PyGILState_STATE s = PyGILState_Ensure();
+ do {
+ for (i=0; i<server->midicount; i++) {
+ result = Pm_Poll(server->midiin[i]);
+ if (result) {
+ if (Pm_Read(server->midiin[i], &buffer, 1) == pmBufferOverflow)
+ continue;
+ status = Pm_MessageStatus(buffer.message);
+ data1 = Pm_MessageData1(buffer.message);
+ data2 = Pm_MessageData2(buffer.message);
+ tup = PyTuple_New(3);
+ PyTuple_SetItem(tup, 0, PyInt_FromLong(status));
+ PyTuple_SetItem(tup, 1, PyInt_FromLong(data1));
+ PyTuple_SetItem(tup, 2, PyInt_FromLong(data2));
+ PyObject_Call((PyObject *)server->midicallable, tup, NULL);
+ }
+ }
+ } while (result);
+
+ PyGILState_Release(s);
+ Py_XDECREF(tup);
+}
+
+static int
+MidiListener_traverse(MidiListener *self, visitproc visit, void *arg)
+{
+ Py_VISIT(self->midicallable);
+ return 0;
+}
+
+static int
+MidiListener_clear(MidiListener *self)
+{
+ Py_CLEAR(self->midicallable);
+ return 0;
+}
+
+static void
+MidiListener_dealloc(MidiListener* self)
+{
+ if (self->active == 1)
+ PyObject_CallMethod((PyObject *)self, "stop", NULL);
+ MidiListener_clear(self);
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject *
+MidiListener_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *midicalltmp=NULL;
+ MidiListener *self;
+
+ self = (MidiListener *)type->tp_alloc(type, 0);
+
+ self->active = self->midicount = 0;
+ self->mididev = -1;
+
+ static char *kwlist[] = {"midicallable", "mididevice", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, &midicalltmp, &self->mididev))
+ Py_RETURN_NONE;
+
+ if (midicalltmp) {
+ PyObject_CallMethod((PyObject *)self, "setMidiFunction", "O", midicalltmp);
+ }
+
+ return (PyObject *)self;
+}
+
+static PyObject * MidiListener_play(MidiListener *self) {
+ int i, num_devices;
+ PmError pmerr;
+
+ /* always start the timer before you start midi */
+ Pt_Start(1, &process_midi, (void *)self);
+
+ pmerr = Pm_Initialize();
+ if (pmerr) {
+ PySys_WriteStdout("Portmidi warning: could not initialize Portmidi: %s\n", Pm_GetErrorText(pmerr));
+ }
+
+ num_devices = Pm_CountDevices();
+ if (num_devices > 0) {
+ if (self->mididev < num_devices) {
+ if (self->mididev == -1)
+ self->mididev = Pm_GetDefaultInputDeviceID();
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(self->mididev);
+ if (info != NULL) {
+ if (info->input) {
+ pmerr = Pm_OpenInput(&self->midiin[0], self->mididev, NULL, 100, NULL, NULL);
+ if (pmerr) {
+ PySys_WriteStdout("Portmidi warning: could not open midi input %d (%s): %s\n",
+ self->mididev, info->name, Pm_GetErrorText(pmerr));
+ }
+ else {
+ self->midicount = 1;
+ }
+ }
+ }
+ }
+ else if (self->mididev >= num_devices) {
+ self->midicount = 0;
+ for (i=0; i<num_devices; i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ if (info != NULL) {
+ if (info->input) {
+ pmerr = Pm_OpenInput(&self->midiin[self->midicount], i, NULL, 100, NULL, NULL);
+ if (pmerr) {
+ PySys_WriteStdout("Portmidi warning: could not open midi input %d (%s): %s\n",
+ i, info->name, Pm_GetErrorText(pmerr));
+ }
+ else {
+ self->midicount++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (i=0; i<self->midicount; i++) {
+ Pm_SetFilter(self->midiin[i], PM_FILT_ACTIVE | PM_FILT_CLOCK);
+ }
+
+ if (self->midicount > 0)
+ self->active = 1;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+};
+
+static PyObject * MidiListener_stop(MidiListener *self) {
+ int i;
+ Pt_Stop();
+ for (i=0; i<self->midicount; i++) {
+ Pm_Close(self->midiin[i]);
+ }
+ Pm_Terminate();
+ self->active = 0;
+ Py_INCREF(Py_None);
+ return Py_None;
+};
+
+static PyObject *
+MidiListener_setMidiFunction(MidiListener *self, PyObject *arg)
+{
+ PyObject *tmp;
+
+ if (! PyCallable_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, "The callable attribute must be a valid Python function.");
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ tmp = arg;
+ Py_XDECREF(self->midicallable);
+ Py_INCREF(tmp);
+ self->midicallable = tmp;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMemberDef MidiListener_members[] = {
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef MidiListener_methods[] = {
+ {"play", (PyCFunction)MidiListener_play, METH_NOARGS, "Starts computing without sending sound to soundcard."},
+ {"stop", (PyCFunction)MidiListener_stop, METH_NOARGS, "Stops computing."},
+ {"setMidiFunction", (PyCFunction)MidiListener_setMidiFunction, METH_O, "Sets the function to be called."},
+ {NULL} /* Sentinel */
+};
+
+PyTypeObject MidiListenerType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_pyo.MidiListener_base", /*tp_name*/
+ sizeof(MidiListener), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)MidiListener_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_as_async (tp_compare in Python 2)*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "MidiListener objects. Calls a function with midi data as arguments.", /* tp_doc */
+ (traverseproc)MidiListener_traverse, /* tp_traverse */
+ (inquiry)MidiListener_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ MidiListener_methods, /* tp_methods */
+ MidiListener_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ MidiListener_new, /* tp_new */
+};
diff --git a/src/engine/osclistenermodule.c b/src/engine/osclistenermodule.c
new file mode 100644
index 0000000..050ef2a
--- /dev/null
+++ b/src/engine/osclistenermodule.c
@@ -0,0 +1,244 @@
+/**************************************************************************
+ * Copyright 2009-2015 Olivier Belanger *
+ * *
+ * This file is part of pyo, a python module to help digital signal *
+ * processing script creation. *
+ * *
+ * pyo is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * pyo is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with pyo. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#include <Python.h>
+#include "py2to3.h"
+#include "structmember.h"
+#include <math.h>
+#include "pyomodule.h"
+#include "lo/lo.h"
+
+static void error(int num, const char *msg, const char *path)
+{
+ PySys_WriteStdout("liblo server error %d in path %s: %s\n", num, path, msg);
+}
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *osccallable;
+ lo_server osc_server;
+ int oscport;
+} OscListener;
+
+static PyObject *
+OscListener_get(OscListener *self)
+{
+ while (lo_server_recv_noblock(self->osc_server, 0) != 0) {};
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+int process_osc(const char *path, const char *types, lo_arg **argv, int argc,
+ void *data, void *user_data)
+{
+ OscListener *server = (OscListener *)user_data;
+ PyObject *tup;
+ lo_blob *blob = NULL;
+ char *blobdata = NULL;
+ uint32_t blobsize = 0;
+ PyObject *charlist = NULL;
+ tup = PyTuple_New(argc+1);
+ int i = 0;
+ unsigned int j = 0;
+
+ PyGILState_STATE s = PyGILState_Ensure();
+ PyTuple_SET_ITEM(tup, 0, PyUnicode_FromString(path));
+ for (i=0; i<argc; i++) {
+ switch (types[i]) {
+ case LO_INT32:
+ PyTuple_SET_ITEM(tup, i+1, PyInt_FromLong(argv[i]->i));
+ break;
+ case LO_INT64:
+ PyTuple_SET_ITEM(tup, i+1, PyLong_FromLong(argv[i]->h));
+ break;
+ case LO_FLOAT:
+ PyTuple_SET_ITEM(tup, i+1, PyFloat_FromDouble(argv[i]->f));
+ break;
+ case LO_DOUBLE:
+ PyTuple_SET_ITEM(tup, i+1, PyFloat_FromDouble(argv[i]->d));
+ break;
+ case LO_STRING:
+ PyTuple_SET_ITEM(tup, i+1, PyUnicode_FromString(&argv[i]->s));
+ break;
+ case LO_CHAR:
+ PyTuple_SET_ITEM(tup, i+1, PyUnicode_FromFormat("%c", argv[i]->c));
+ break;
+ case LO_BLOB:
+ blob = (lo_blob)argv[i];
+ blobsize = lo_blob_datasize(blob);
+ blobdata = lo_blob_dataptr(blob);
+ charlist = PyList_New(blobsize);
+ for (j=0; j<blobsize; j++) {
+ PyList_SET_ITEM(charlist, j, PyUnicode_FromFormat("%c", blobdata[j]));
+ }
+ PyTuple_SET_ITEM(tup, i+1, charlist);
+ break;
+ case LO_MIDI:
+ charlist = PyList_New(4);
+ for (j=0; j<4; j++) {
+ PyList_SET_ITEM(charlist, j, PyInt_FromLong(argv[i]->m[j]));
+ }
+ PyTuple_SET_ITEM(tup, i+1, charlist);
+ break;
+ case LO_NIL:
+ Py_INCREF(Py_None);
+ PyTuple_SET_ITEM(tup, i+1, Py_None);
+ break;
+ case LO_TRUE:
+ Py_INCREF(Py_True);
+ PyTuple_SET_ITEM(tup, i+1, Py_True);
+ break;
+ case LO_FALSE:
+ Py_INCREF(Py_False);
+ PyTuple_SET_ITEM(tup, i+1, Py_False);
+ break;
+ default:
+ break;
+ }
+ }
+ PyObject_Call((PyObject *)server->osccallable, tup, NULL);
+ PyGILState_Release(s);
+ Py_XDECREF(tup);
+
+ return 0;
+}
+
+static int
+OscListener_traverse(OscListener *self, visitproc visit, void *arg)
+{
+ Py_VISIT(self->osccallable);
+ return 0;
+}
+
+static int
+OscListener_clear(OscListener *self)
+{
+ Py_CLEAR(self->osccallable);
+ return 0;
+}
+
+static void
+OscListener_dealloc(OscListener* self)
+{
+ lo_server_free(self->osc_server);
+ OscListener_clear(self);
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject *
+OscListener_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ char buf[20];
+ PyObject *osccalltmp=NULL;
+ OscListener *self;
+
+ self = (OscListener *)type->tp_alloc(type, 0);
+
+ static char *kwlist[] = {"osccallable", "port", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, &osccalltmp, &self->oscport))
+ Py_RETURN_NONE;
+
+ if (osccalltmp) {
+ PyObject_CallMethod((PyObject *)self, "setOscFunction", "O", osccalltmp);
+ }
+
+ sprintf(buf, "%i", self->oscport);
+ self->osc_server = lo_server_new(buf, error);
+ lo_server_add_method(self->osc_server, NULL, NULL, process_osc, (void *)self);
+
+ return (PyObject *)self;
+}
+
+static PyObject *
+OscListener_setOscFunction(OscListener *self, PyObject *arg)
+{
+ PyObject *tmp;
+
+ if (arg == Py_None) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ if (! PyCallable_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, "The callable attribute must be a valid Python function.");
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ tmp = arg;
+ Py_XDECREF(self->osccallable);
+ Py_INCREF(tmp);
+ self->osccallable = tmp;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMemberDef OscListener_members[] = {
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef OscListener_methods[] = {
+ {"get", (PyCFunction)OscListener_get, METH_NOARGS, "Check for new osc messages."},
+ {"setOscFunction", (PyCFunction)OscListener_setOscFunction, METH_O, "Sets the function to be called."},
+ {NULL} /* Sentinel */
+};
+
+PyTypeObject OscListenerType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_pyo.OscListener_base", /*tp_name*/
+ sizeof(OscListener), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)OscListener_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_as_async (tp_compare in Python 2)*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "OscListener objects. Calls a function with OSC data as arguments.", /* tp_doc */
+ (traverseproc)OscListener_traverse, /* tp_traverse */
+ (inquiry)OscListener_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ OscListener_methods, /* tp_methods */
+ OscListener_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ OscListener_new, /* tp_new */
+};
diff --git a/utils/epyo_builder_OSX_py2.sh b/utils/epyo_builder_OSX_py2.sh
new file mode 100755
index 0000000..5f1b5ab
--- /dev/null
+++ b/utils/epyo_builder_OSX_py2.sh
@@ -0,0 +1,39 @@
+mkdir Resources
+cp PyoDoc.py Resources/
+cp Tutorial_01_RingMod.py Resources/
+cp Tutorial_02_Flanger.py Resources/
+cp Tutorial_03_TriTable.py Resources/
+cp *.icns Resources/
+cp -R ../examples Resources/
+cp -R snippets Resources/
+cp -R styles Resources/
+
+rm -rf build dist
+
+python2 setup.py py2app
+
+rm -rf build
+mv dist E-Pyo_OSX_py2
+
+if cd E-Pyo_OSX_py2;
+then
+ find . -name .git -depth -exec rm -rf {} \
+ find . -name *.pyc -depth -exec rm -f {} \
+ find . -name .* -depth -exec rm -f {} \;
+else
+ echo "Something wrong. E-Pyo_OSX not created"
+ exit;
+fi
+
+# keep only 64-bit arch
+ditto --rsrc --arch x86_64 E-Pyo.app E-Pyo-x86_64.app
+rm -rf E-Pyo.app
+mv E-Pyo-x86_64.app E-Pyo.app
+
+# Fixed wrong path in Info.plist
+cd E-Pyo.app/Contents
+awk '{gsub("Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python", "@executable_path/../Frameworks/Python.framework/Versions/2.7/Python")}1' Info.plist > Info.plist_tmp && mv Info.plist_tmp Info.plist
+
+cd ../../..
+
+rm -rf Resources
diff --git a/utils/epyo_builder_OSX_py3.sh b/utils/epyo_builder_OSX_py3.sh
new file mode 100755
index 0000000..ce39d6d
--- /dev/null
+++ b/utils/epyo_builder_OSX_py3.sh
@@ -0,0 +1,42 @@
+mkdir Resources
+cp PyoDoc.py Resources/
+cp Tutorial_01_RingMod.py Resources/
+cp Tutorial_02_Flanger.py Resources/
+cp Tutorial_03_TriTable.py Resources/
+cp *.icns Resources/
+cp -R ../examples Resources/
+cp -R snippets Resources/
+cp -R styles Resources/
+
+rm -rf build dist
+
+python3 setup.py py2app
+
+rm -rf build
+mv dist E-Pyo_OSX_py3
+
+if cd E-Pyo_OSX_py3;
+then
+ find . -name .git -depth -exec rm -rf {} \
+ find . -name *.pyc -depth -exec rm -f {} \
+ find . -name .* -depth -exec rm -f {} \;
+else
+ echo "Something wrong. E-Pyo_OSX not created"
+ exit;
+fi
+
+# keep only 64-bit arch
+ditto --rsrc --arch x86_64 E-Pyo.app E-Pyo-x86_64.app
+rm -rf E-Pyo.app
+mv E-Pyo-x86_64.app E-Pyo.app
+
+# py2app does not handle correctly wxpython phoenix dylib imports, add them manually.
+cp /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/wx/*.dylib E-Pyo.app/Contents/Resources/lib/python3.5/lib-dynload/wx/
+
+# Fixed wrong path in Info.plist
+cd E-Pyo.app/Contents
+awk '{gsub("/Library/Frameworks/Python.framework/Versions/3.5/bin/python3", "@executable_path/../Frameworks/Python.framework/Versions/3.5/Python")}1' Info.plist > Info.plist_tmp && mv Info.plist_tmp Info.plist
+
+cd ../../..
+
+rm -rf Resources
diff --git a/utils/setup.py b/utils/setup.py
new file mode 100644
index 0000000..165595d
--- /dev/null
+++ b/utils/setup.py
@@ -0,0 +1,38 @@
+"""
+This is a setup.py script generated by py2applet
+
+Usage:
+ python setup.py py2app
+"""
+from setuptools import setup
+
+APP = ['E-Pyo.py']
+APP_NAME = 'E-Pyo'
+DATA_FILES = ['Resources/']
+OPTIONS = {'argv_emulation': False,
+ 'iconfile': 'E-PyoIcon.icns',
+ 'plist': {
+ 'CFBundleDisplayName': 'E-Pyo',
+ 'CFBundleExecutable': 'E-Pyo',
+ 'CFBundleIconFile': 'E-PyoIcon.icns',
+ 'CFBundleIdentifier': 'com.ajaxsoundstudio.E-Pyo',
+ 'CFBundleInfoDictionaryVersion': '0.8.1',
+ 'CFBundleName': 'E-Pyo',
+ 'CFBundlePackageType': 'APPL',
+ 'CFBundleShortVersionString': '0.8.1',
+ 'CFBundleVersion': '0.8.1',
+ 'CFBundleDocumentTypes': [{'CFBundleTypeOSTypes': ['TEXT'],
+ 'CFBundleTypeExtensions': ['py'],
+ 'CFBundleTypeRole': 'Editor',
+ 'CFBundleTypeIconFile': 'E-PyoIconDoc.icns',
+ 'LSIsAppleDefaultForType': False}]
+ }
+ }
+
+setup(
+ name=APP_NAME,
+ app=APP,
+ data_files=DATA_FILES,
+ options={'py2app': OPTIONS},
+ setup_requires=['py2app'],
+)
--
python-pyo packaging
More information about the pkg-multimedia-commits
mailing list