Distribute pyjack with freewheel-related functionality
authorNikita Zlobin <cook60020tmp@mail.ru>
Sun, 26 Dec 2010 23:17:48 +0000 (27 04:17 +0500)
committerNikita Zlobin <cook60020tmp@mail.ru>
Sun, 26 Dec 2010 23:17:48 +0000 (27 04:17 +0500)
28 files changed:
pyjack-0.5.2/Changelog [new file with mode: 0644]
pyjack-0.5.2/LICENSE [new file with mode: 0644]
pyjack-0.5.2/README [new file with mode: 0644]
pyjack-0.5.2/TODO [new file with mode: 0644]
pyjack-0.5.2/blender/.directory [new file with mode: 0644]
pyjack-0.5.2/blender/README [new file with mode: 0644]
pyjack-0.5.2/blender/blender-jacktrans.py [new file with mode: 0644]
pyjack-0.5.2/debian/.directory [new file with mode: 0644]
pyjack-0.5.2/debian/changelog [new file with mode: 0644]
pyjack-0.5.2/debian/compat [new file with mode: 0644]
pyjack-0.5.2/debian/control [new file with mode: 0644]
pyjack-0.5.2/debian/copyright [new file with mode: 0644]
pyjack-0.5.2/debian/pyjack-0.4.egg-info [new file with mode: 0644]
pyjack-0.5.2/debian/python-jack-demos.install [new file with mode: 0644]
pyjack-0.5.2/debian/python-jack.install [new file with mode: 0644]
pyjack-0.5.2/debian/rules [new file with mode: 0755]
pyjack-0.5.2/demos/.directory [new file with mode: 0644]
pyjack-0.5.2/demos/alsa_midi_busconnect.py [new file with mode: 0755]
pyjack-0.5.2/demos/capture.py [new file with mode: 0755]
pyjack-0.5.2/demos/just_capture.py [new file with mode: 0755]
pyjack-0.5.2/demos/qtransport.py [new file with mode: 0755]
pyjack-0.5.2/demos/qtransport_gui.ui [new file with mode: 0644]
pyjack-0.5.2/demos/testtone.py [new file with mode: 0755]
pyjack-0.5.2/demos/transporter.py [new file with mode: 0755]
pyjack-0.5.2/install.sh [new file with mode: 0755]
pyjack-0.5.2/patches/enable-jack2.diff [new file with mode: 0644]
pyjack-0.5.2/pyjack.c [new file with mode: 0644]
pyjack-0.5.2/setup.py [new file with mode: 0755]

diff --git a/pyjack-0.5.2/Changelog b/pyjack-0.5.2/Changelog
new file mode 100644 (file)
index 0000000..d68d279
--- /dev/null
@@ -0,0 +1,43 @@
+PyJack Changelog
+
+version 0.5.2:
+ * PyJack never raises JackInputSyncError
+ * Get "numpy/arrayobject.h" path from numpy
+
+version 0.5.1:
+ * Added check for Jack2 (disable some functions if not)
+    (fixes compilation on older Jack versions)
+
+version 0.5:
+ * Implemented "get_version" (not working ?)
+ * Implemented "get_port_short_name"
+ * Implemented "port_is_mine"
+ * Implemented "set_buffer_size"
+ * Implemented "set_sync_timeout"
+ * Implemented "buffer_size_callback"
+ * Implemented "xrun_callback"
+ * Fixed auto-selecting 1st available port when port name is empty
+ * Disabled "get_version_string" for now (requires a very recent Jack version)
+ * Other very small fixes
+
+version 0.4:
+ * Implemented "get_version_string"
+ * Implemented "get_cpu_load"
+ * Implemented "get_port_type"
+ * Implemented "get_port_type_id"
+ * Implemented "is_realtime"
+
+version 0.3:
+* Implemented changes from the clam team branch:  (many thanks!)
+  - Added a get_client_name function
+  - Fixed SEGFAULT when connecting unexisting ports in deactivated state
+  - Fixed memory corruption (free of not owned memory) when connecting ports in deactivated state
+  - Fix: output_pipe[0] was not initialized
+  - Connecting already connected or disconnecting already disconnected do not throw
+  - Using numpy package instead of the deprecated Numeric
+  - Capture.py: use scipy to save the captured audio
+  - Disconnecting non existing ports gives a more informative message
+* Updated the demos (and kicked "jack_bus_connect.py")
+* Added a simple GUI demo for controlling Transport
+* Allow add/remove ports while client is still active (otherwise it won't work)
+* Added this Changelog
diff --git a/pyjack-0.5.2/LICENSE b/pyjack-0.5.2/LICENSE
new file mode 100644 (file)
index 0000000..d60c31a
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/pyjack-0.5.2/README b/pyjack-0.5.2/README
new file mode 100644 (file)
index 0000000..399bdc4
--- /dev/null
@@ -0,0 +1,339 @@
+PyJack version 0.x
+Original code by Andrew W. Schmeder <andy@a2hd.com>, in2003
+Transport support by Il'dar Akhmetgaleev <akhilman at gmail dot com>, in Jan 14 2008
+Revision and packaging by falkTX <falktx@gmail.com>, in Feb 2010
+Implemented changes by the Clam Team <falktx@gmail.com>, in Mar 2010
+More Jack implementations by falkTX <falktx@gmail.com>, in Apr 2010
+
+
+This is open source software released under the GPL license.
+The full text of this license is found in the file 'LICENSE',
+included with this source code package.
+
+This software is presently distributed from http://www.a2hd.com.
+Please check that site for the latest version.
+
+------------------------------------------------------------------------
+------------------------------------------------------------------------
+Description:
+
+  PyJack is a module written in C which exposes the Jack API to Python.
+For information about Jack see http://jackit.sourceforge.net.  This
+enables a Python program to connect to and interact with pro-audio
+applications which use the Jack Audio Server.
+
+------------------------------------------------------------------------
+Purpose:
+
+- To show that it can be done.
+
+- For programmers who want to prototype DSP and sound synthesis
+algorithms using Numeric Python and similar tools.  PyJack provides the
+means to capture and playback audio.
+
+-  For patchbay applications; A powerful Jack patchbay can be written
+in Python using this module.  This is planned for the future.
+
+------------------------------------------------------------------------
+Installation:
+
+  This package uses the excellent and simple Python distutils.
+  Installation is very simple.  It works something like this;
+  
+# tar -xzvf pyjack-0.*.tar.gz           (unpack archive)
+# cd pyjack-0.*                         (cd to source dir)
+# (sudo) python setup.py install        (install...)
+
+------------------------------------------------------------------------
+Demos:
+
+  Demos can be found in the "demos" directory
+  
+------------------------------------------------------------------------
+Realtime Issues:
+
+  Python is known to be relatively slow (compared to C/C++),
+and non-realtime due to memory management details.  Because of this,
+Python is -NOT- a suitable language for realtime audio processing!
+This means that it is unacceptable to place the Python intepreter 
+"inside" of a Jack client.  
+  PyJack therefore uses a "semi-detached" method.  The PyJack 
+client consists of two threads; a Jack client thread and a Python
+thread.  The Jack client thread is run in realtime context; it never
+blocks, it is entirely deterministic, and does not touch any Python
+data structures nor the interpreter.  The Jack client thread merely
+copies audio data in/out of socket buffers.  On the Python side,
+calls to jack.process() copy audio data in/out of the other end of
+those sockets providing the connection to Python via Numeric arrays
+of floats.  In any case, use of a large buffer size (e.g. 1024 samples)
+is recommended.
+  In order to capture or playback audio without missing a block,
+Python must call jack.process() at least once every 500*(N/Sr)
+milliseconds.  (N = jack.get_buffer_size(), Sr = jack.get_sample_rate()).
+If this rate is not kept up, you may get jack.InputSyncError or 
+jack.OutputSyncError exceptions thrown by jack.process().
+  Typically you will want to use the following design for a DSP
+prototyping program:
+
+  1.  Attach to the jack server (jack.attach)
+      Create input and output ports (jack.register_port)
+      Connect inputs and outputs to jack graph (jack.connect)
+      Activate client (jack.activate)
+  2.  Preallocate matricies for input and output audio data
+  3.  Capture X seconds of audio (jack.process)
+  4.  Process audio using your algorithm
+      It does not matter how long this takes...
+  5.  Playback X seconds of audio (jack.process)
+  6.  Detach from jack server (jack.detach)
+
+  See the example code to get started; testtone.py and capture.py.
+
+------------------------------------------------------------------------
+------------------------------------------------------------------------
+------------------------------------------------------------------------
+Module Documentation and Usage Examples:
+
+Example: Importing the module:
+>>> import jack
+>>> dir(jack)
+['CanMonitor', ... ]
+>>> print jack.attach.__doc__
+Attach client to the Jack server
+
+------------------------------------------------------------------------
+Exceptions Thrown by the Jack module:
+
+  These are called jack.Error, jack.InputSyncError, etc.
+  
+jack.Error:
+  A general exception thrown when things go wrong.  Usually something 
+  bad, like "can't connect to server", or "failed to connect ports"
+
+jack.NotConnectedError:
+  Thrown when you try to access a jack API function before the client 
+  has been attached.   
+
+jack.UsageError:
+  Thrown when you are misusing the PyJack API.  For example, trying to 
+  call jack.activate() when the client has already been activated.
+
+jack.InputSyncError:
+jack.OutputSyncError:
+  Often the low level jack client thread is not synchronized with the 
+  Python side.  This exception will be thrown to warn you that there a 
+  potential synchronization problem.  jack.OutputSyncError is extremely 
+  uncommon, you should not ever see that error.  jack.InputSyncError is 
+  very common, for example if you have activated the client but do not 
+  start calling jack.process() immediately.
+
+>>> import jack
+>>> import time
+>>> jack.attach("test")
+... etc
+>>> jack.activate()
+>>> time.sleep(1)
+>>> jack.process(output, input)
+
+  Here you will get a InputSyncError, because you have been sleeping 
+  for 1 second, the data in the audio buffer is about 1 second old.  
+  In other words, the input stream has been stopped for 1 second, 
+  holding old data. In spite of getting this error, you _will_ get 
+  the old audio data in your input array.
+
+  Say that you want to write a monitoring application in Python; Now, 
+  having a toolkit running along with audio processing in realtime is 
+  nearly impossible (I've tried it; there is just not enough time to 
+  redraw the screen without getting an InputSyncError). Basically what 
+  you will want to do is only call jack.process() a few times per 
+  second (say 5 times per second).  Each time you call jack.process() 
+  it will throw an InputSyncError, but you know that the audio data is 
+  at most 1/5th of a second old; that is probably good enough for a 
+  very simple metering of the input without making the GUI requirements 
+  too extreme.
+
+------------------------------------------------------------------------
+Jack Port Flags:
+
+jack.IsInput
+jack.IsOutput
+jack.CanMonitor
+jack.IsPhysical
+jack.IsTerminal
+
+  These are bit flags which indicate the properties of Jack ports.  Use 
+  the bitwise operators (| and &) with them; 
+  
+Example:
+>>> print jack.get_port_flags('alsa_pcm:capture_1')
+22
+>>> print (jack.get_port_flags('alsa_pcm:capture_1') & jack.IsInput) > 0
+0
+>>> print (jack.get_port_flags('alsa_pcm:capture_1') & jack.IsOutput) > 0
+1
+>>> print (jack.get_port_flags('alsa_pcm:capture_1') & jack.IsPhysical) > 0
+1
+>>> print (jack.get_port_flags('alsa_pcm:capture_1') & jack.IsTerminal) > 0
+1
+>>> print (jack.get_port_flags('alsa_pcm:capture_1') & jack.CanMonitor) > 0
+0
+
+  When creating ports, you will want to use a bitwise | of the flags;
+  
+>>> jack.register_port("input_1", jack.IsInput | jack.CanMonitor)
+>>> jack.register_port("input_1", jack.IsOutput | jack.CanMonitor)
+
+------------------------------------------------------------------------
+Function calls in the jack module:
+
+---
+jack.attach(name)
+  Attach to the jack server using the given client name.
+  All other function calls in the jack module require that you call
+  this function first.  (otherwise you will get a NotConnectedError).
+
+>>> jack.attach("foo_client")
+
+---
+jack.detach()
+  Detach from the jack server
+  
+>>> jack.detach()
+>>> jack.get_sample_rate()
+Traceback (most recent call last):
+  File "<stdin>", line 1, in ?
+jack.NotConnectedError: Jack connection has not yet been established.
+
+---
+jack.register_port(name, flags)
+  Create a new port for this client with the given flags.
+  Once a port is created it cannot be 'unregistered'.
+  (The Jack API does permit this, but the PyJack module does not support it.)
+
+---
+jack.activate()
+  Enables callbacks to the realtime jack thread.
+  This must be called before jack.process() is used.
+  Enabling the realtime thread has minimal CPU overhead.
+  
+---
+jack.deactivate()
+  Disables Jack callbacks to the realtime thread.
+  Opposite of jack.activate()
+  jack.process() cannot be used after jack.deactivate() is called,
+  until jack.activate() is called again.
+
+---
+jack.process()
+  This function exchanges audio between Python and the realtime jack thread.
+  
+  It requires two arguments, which are both 2D Numeric Python arrays.
+  The arrays -must- be of type 'Float'.  The size in the first dimenision
+  must match the number of inputs or outputs, and the size of the second
+  dimension must match the buffer size.  See capture.py and testtone.py
+  for examples of how this works.  Following is a part of the code from
+  testtone.py.  In this example there is only one input port and one output
+  port.  input.shape = (1, 1024), output.shape = (1, 144000).
+  Notice that process will modify entries in the input array.
+
+input = Numeric.zeros((1,N), 'f')    # note the float type here...
+output = Numeric.reshape(
+    Numeric.sin(
+        2*Numeric.pi*440.0 * (Numeric.arange(0, sec, 1.0/(Sr), 'f')[0:int(Sr*sec)])
+    ), (1, Sr*sec)).astype('f')
+
+i = 0
+while i < output.shape[1] - N:
+    try:
+        jack.process(output[:,i:i+N], input)
+        i += N
+    except jack.InputSyncError:
+        pass
+    except jack.OutputSyncError:
+        pass
+
+---
+jack.get_ports()
+  Returns a list of all registered ports in the Jack graph.
+  The name of a port looks like: "client_name:port_name"
+
+>>> jack.get_ports()
+['alsa_pcm:capture_1', 'alsa_pcm:capture_2', 'alsa_pcm:capture_3', ... ]
+
+---
+jack.get_port_flags()
+  Returns an integer which is the bitwise-or of all flags for a given port.
+
+>>> jack.get_port_flags('alsa_pcm:playback_6')
+21
+
+---
+jack.get_connections()
+  Returns a list of ports connected to the given port.
+  If nothing is connected, returns a list of length zero.
+  
+>>> jack.get_connections('alsa_pcm:capture_1')
+['foo_client:input_1']
+
+---
+jack.connect(source, destination)
+  Connect two ports on the Jack graph.
+  Note that source must have the IsOutput flag, and
+  destination must have the IsInput flag.
+  If you want to recieve or send audio, you must
+  connect your client's inputs/outputs (those
+  ports registered via jack.register_port()) to
+  something else which is generating or recieving
+  audio, e.g. the alsa_pcm ports.
+  You can connect ports which belong to other clients
+  as well, e.g. for a patchbay application.
+  
+  At the time of writing, there is a bug in the Jack
+  API which causes audio data to be missing from
+  input buffers if ports are connected before 
+  jack.activate() is called.  Until this is fixed,
+  please make sure that you call jack.activate() 
+  prior to using jack.connect().
+  
+---
+jack.disconnect(source, destination)
+  Break a connection established by jack.connect().
+---
+jack.get_buffer_size()
+  Returns the current buffer size used by the Jack server.
+  If this number is small you may have a lot of synchronization problems.
+  
+---
+jack.get_sample_rate()
+  Returns the current sample rate used by the Jack server.
+  
+---
+jack.check_events()
+  Check if any asynchronous event callbacks have been raised since
+  the last call to jack.check_events().
+  Use of this function does -NOT- require that you be presently attached
+  to the Jack server; however the values will not change unless you are!
+
+>>> jack.check_events()
+{'graph_ordering': 0, 'shutdown': 0, 'port_registration': 0, 'hangup': 0}
+
+If graph_ordering == 1:
+  Then a pair of ports somewhere in the jack graph has been connected or 
+disconnected.
+
+If port_registration == 1:
+  Then a port has been added or removed from the jack graph.
+  
+If shutdown == 1:
+  Then the Jack server has shutdown; your client is no longer attached.
+  
+If hangup == 1:
+  Then the Jack server decided to kill the PyJack client for some reason;
+  the client is no longer attached.
+  
+  Any flag which is raised is immediatly reset to zero when this 
+  function is called.
+  
+------------------------------------------------------------------------
+
+
diff --git a/pyjack-0.5.2/TODO b/pyjack-0.5.2/TODO
new file mode 100644 (file)
index 0000000..0b171e3
--- /dev/null
@@ -0,0 +1,24 @@
+PyJack
+TODO Items
+---------------------------------------------
+
+- Make variable buffering within the PyJack client independent of the
+  Jack server's buffer size; this would enable the PyJack client to run
+  jack.process with larger buffers while still working with apps which 
+  require small buffers.
+
+- May need a select call with timeout in jack.process()
+  Otherwise, if the jack server shutsdown or SIGHUPS this call might
+  wait forever on the socket read.
+
+- Monitoring?
+  I don't really understand how monitoring is supposed to work.
+  
+- Do we need sample rate events?
+  Will the sample rate ever change in the middle of a process,
+  or is it a fixed value like buffer size?
+  
+- Peak/Power monitoring
+   
+Contributions are welcome!
+
diff --git a/pyjack-0.5.2/blender/.directory b/pyjack-0.5.2/blender/.directory
new file mode 100644 (file)
index 0000000..a54bcb7
--- /dev/null
@@ -0,0 +1,3 @@
+[Dolphin]
+Timestamp=2010,1,5,2,36,25
+ViewMode=1
diff --git a/pyjack-0.5.2/blender/README b/pyjack-0.5.2/blender/README
new file mode 100644 (file)
index 0000000..b42b061
--- /dev/null
@@ -0,0 +1,29 @@
+-------------------
+ HOW TO USE THIS SCRIPT
+--------------------------
+
+
+First, make sure you have sucessufully installed:
+ - Blender (2.49)
+ - PyJack
+ - Jack
+
+
+To enable this script in blender:
+ - copy the script to ~/.blender/scripts
+ - start blender
+ - open a script window, and "update menus"
+ - Select Misc -> "Jack Transport"
+
+
+A new, small widget will appear:
+
+s | < | > |   play   | x
+
+ "s" will make transport to go 00:00;
+ "<" and ">" will fast backwards forward;
+ "play"/"pause" is obvious;
+ "x" will stop the script
+
+
+Enjoy!
diff --git a/pyjack-0.5.2/blender/blender-jacktrans.py b/pyjack-0.5.2/blender/blender-jacktrans.py
new file mode 100644 (file)
index 0000000..55cea07
--- /dev/null
@@ -0,0 +1,157 @@
+#!BPY
+# -*- coding: utf-8 -*-
+"""
+Name: 'Jack Transport'
+Blender: 249
+Group: 'Misc'
+Tooltip: 'Makes jack and blender synced'
+"""
+__script__ = "Jack Transport"
+__author__ = "falkTX"
+__version__ = "0.1"
+__url__ = ["Communicate problems and errors, BlenderArtists.org, Python forum"]
+__email__= ["falktx@gmail.com", "blender-pyjack script"]
+__bpydoc__ = """\
+blender-jacktransport.py v0.1
+
+Version History:
+ 0.1: Initial release
+"""
+
+# Depends from PyJack-0.2
+# Uses code from bpyjack.py by IL'dar AKHmetgaleev (aka AkhIL)
+
+# Tried to get this as fast (and simple) as possible
+
+import bpy
+import jack, time, sys
+import Blender
+from Blender import *
+
+play_button = Draw.Create(False)
+BEV_PLAY = 1
+BEV_EXIT = 2
+BEV_PREV = 3
+BEV_NEXT = 4
+BEV_START = 5
+ret_blender_curr = 0
+ret_blender_next = 0
+ret_jack_current = 0
+prev_blen = 0
+prev_jack = 0
+
+try:
+    jack.attach("/var/run/jack-blender")
+except jack.UsageError:
+    pass # continue using exist jack if script crashed but jack still online 
+
+def getFrames():
+    global ret_blender_curr
+    global ret_blender_next
+    global ret_jack_current
+
+    currblenframe = Get("curframe")
+    currjackframe = jack.get_current_transport_frame()
+
+    rate = jack.get_sample_rate()
+
+    fps = Scene.GetCurrent().getRenderingContext().fps
+    fpsBase = Scene.GetCurrent().getRenderingContext().fpsBase
+    factor = int(rate/(fps/fpsBase))
+
+    ret_blender_curr = currblenframe*factor
+    ret_blender_next = currjackframe/factor
+    ret_jack_current = currjackframe
+
+
+def refresh():
+    global ret_blender_curr
+    global ret_blender_next
+    global ret_jack_current
+    global prev_blen
+    global prev_jack
+
+    getFrames()
+
+    #print "blender old", prev_blen
+    #print "blender frame is", ret_blender_curr
+    #print "jack old", prev_jack
+    #print "jack frame is", ret_jack_current
+
+    if (prev_jack != ret_jack_current): #Jack changed, externally
+        Set("curframe", ret_blender_next)
+        #Window.Redraw(Window.Types.ACTION)
+        Window.Redraw(Window.Types.BUTS)
+        #Window.Redraw(Window.Types.IMAGE)
+        #Window.Redraw(Window.Types.IMASEL)
+        #Window.Redraw(Window.Types.INFO)
+        Window.Redraw(Window.Types.SEQ)
+        #Window.Redraw(Window.Types.TEXT)
+        Window.Redraw(Window.Types.VIEW3D)
+    elif (prev_blen != ret_blender_curr): #Blender changed, internally
+        jack.transport_locate(ret_blender_curr)
+        while jack.get_current_transport_frame() != ret_blender_curr:
+            time.sleep(0.01) # waiting till pyjack applyed transport
+
+    id = Window.GetAreaID()
+    Window.QAdd(id, Draw.TIMER3, 0, 1)
+
+    prev_blen = ret_blender_curr
+    prev_jack = ret_jack_current
+
+def event (evt, dummy):
+    if evt == Draw.TIMER3:
+        refresh()
+        time.sleep(0.001)
+
+def button_event (evt):
+    global play_button
+
+    currentJackFrame = jack.get_current_transport_frame()
+
+    if evt == BEV_PLAY: #play/pause
+        if play_button.val == 1:
+            jack.transport_start()
+        else:
+            jack.transport_stop()
+
+    elif evt == BEV_START: #back to 0
+        jack.transport_locate(0)
+
+    elif evt == BEV_PREV: #go back
+        nextJackFrame = currentJackFrame - 200000
+        if (nextJackFrame < 0): nextJackFrame = 0
+        jack.transport_locate(nextJackFrame)
+
+    elif evt == BEV_NEXT: #go forward
+        nextJackFrame = currentJackFrame + 200000
+        jack.transport_locate(nextJackFrame)
+
+    elif evt == BEV_EXIT: #quit script
+        jack.detach()
+        Draw.Exit()
+
+def gui ():
+    global play_button
+    BGL.glClearColor(*map(lambda x: x/255.0, Window.Theme.Get()[0].get('buts').back))
+    BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
+    Draw.BeginAlign()
+
+    if jack.get_transport_state() == jack.TransportStopped:
+        play_button.val = 0
+        button_text = "play"
+    else:
+        play_button.val = 1
+        button_text = "pause"
+
+    Draw.PushButton("s", BEV_START, 1, 1, 20, 20, "Go to 0")
+    Draw.PushButton("<", BEV_PREV, 20, 1, 20, 20, "Go back")
+    Draw.PushButton(">", BEV_NEXT, 40, 1, 20, 20, "Go forward")
+    play_button = Draw.Toggle(button_text, BEV_PLAY, 60, 1, 75, 20, play_button.val, "Play / Pause")
+    Draw.PushButton("x", BEV_EXIT, 135, 1, 25, 20, "Exit from script")
+    Draw.EndAlign()
+
+
+Draw.Register(gui, event, button_event)
+
+refresh()
diff --git a/pyjack-0.5.2/debian/.directory b/pyjack-0.5.2/debian/.directory
new file mode 100644 (file)
index 0000000..0561bbd
--- /dev/null
@@ -0,0 +1,4 @@
+[Dolphin]
+AdditionalInfo=3
+Timestamp=2010,3,26,1,42,43
+ViewMode=1
diff --git a/pyjack-0.5.2/debian/changelog b/pyjack-0.5.2/debian/changelog
new file mode 100644 (file)
index 0000000..d8017eb
--- /dev/null
@@ -0,0 +1,35 @@
+pyjack (0.5.2-1~build1) lucid; urgency=low
+
+  * New upstream release
+
+ -- falkTX <falktx@gmail.com>  Mon, 12 Jul 2010 09:33:35 +0100
+
+pyjack (0.5.1-1~build1) lucid; urgency=low
+
+  * New upstream release
+
+ -- falkTX <falktx@gmail.com>  Wed, 21 Apr 2010 13:50:40 +0100
+
+pyjack (0.5-1~build1) lucid; urgency=low
+
+  * New upstream release
+
+ -- falkTX <falktx@gmail.com>  Tue, 20 Apr 2010 17:27:28 +0100
+
+pyjack (0.4-1~build1) lucid; urgency=low
+
+  * New upstream release
+
+ -- falkTX <falktx@gmail.com>  Wed, 07 Apr 2010 14:44:32 +0100
+
+pyjack (0.3-1~build1) lucid; urgency=low
+
+  * New upstream release
+
+ -- falkTX <falktx@gmail.com>  Fri, 26 Mar 2010 01:41:28 +0000
+
+pyjack (0.2-1~build1) lucid; urgency=low
+
+  * Initial release
+
+ -- falkTX <falktx@gmail.com>  Wed, 10 Feb 2010 10:47:31 +0000
diff --git a/pyjack-0.5.2/debian/compat b/pyjack-0.5.2/debian/compat
new file mode 100644 (file)
index 0000000..7f8f011
--- /dev/null
@@ -0,0 +1 @@
+7
diff --git a/pyjack-0.5.2/debian/control b/pyjack-0.5.2/debian/control
new file mode 100644 (file)
index 0000000..b47b871
--- /dev/null
@@ -0,0 +1,31 @@
+Source: pyjack
+Section: python
+Priority: optional
+Maintainer: falkTX <falktx@gmail.com>
+Build-Depends: cdbs, debhelper (>= 7), libjack-dev,
+ python2.6, python-numpy, python-dev
+Standards-Version: 3.8.4
+
+Package: python-jack
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, jackd, python-numpy
+Recommends: python-jack-examples
+Description: Jack modules for python
+ PyJack2 is a module written in C which exposes the Jack API to Python.
+ For information about Jack see http://jackit.sourceforge.net.
+ This enables a Python program to connect to and interact with pro-audio
+ applications which use the Jack Audio Server.
+ .
+ This package contains the python modules
+
+Package: python-jack-demos
+Architecture: all
+Depends: ${python:Depends}, ${misc:Depends}, python-jack
+Suggests: python-scipy, python-qt4
+Description: Jack modules for python
+ PyJack2 is a module written in C which exposes the Jack API to Python.
+ For information about Jack see http://jackit.sourceforge.net.
+ This enables a Python program to connect to and interact with pro-audio
+ applications which use the Jack Audio Server.
+ .
+ This package provides a set of demos/examples of python-jack usage
diff --git a/pyjack-0.5.2/debian/copyright b/pyjack-0.5.2/debian/copyright
new file mode 100644 (file)
index 0000000..32ab3d6
--- /dev/null
@@ -0,0 +1,27 @@
+This package was debianized by:
+
+    falkTX <falktx@gmail.com> on Wed, 09 Sep 2009 04:17:22 +0200
+
+License:
+
+    This package is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as
+    published by the Free Software Foundation.
+
+    This package is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this package; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL'.
+
+The Debian packaging is:
+
+    Copyright C) 2010, falkTX <falktx@gmail.com>
+
+and is licensed under the GPL, see above.
diff --git a/pyjack-0.5.2/debian/pyjack-0.4.egg-info b/pyjack-0.5.2/debian/pyjack-0.4.egg-info
new file mode 100644 (file)
index 0000000..f969c53
--- /dev/null
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: pyjack
+Version: 0.5
+Summary: Python binding for the Jack Audio Server
+Home-page: http://www.a2hd.com/software
+Author: Andrew W. Schmeder, falkTX
+Author-email: andy@a2hd.com
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
diff --git a/pyjack-0.5.2/debian/python-jack-demos.install b/pyjack-0.5.2/debian/python-jack-demos.install
new file mode 100644 (file)
index 0000000..a8a3c0b
--- /dev/null
@@ -0,0 +1,2 @@
+blender/*.py usr/share/doc/python-jack-demos/demos/
+demos/*.py usr/share/doc/python-jack-demos/demos/
diff --git a/pyjack-0.5.2/debian/python-jack.install b/pyjack-0.5.2/debian/python-jack.install
new file mode 100644 (file)
index 0000000..0c3ecfc
--- /dev/null
@@ -0,0 +1 @@
+debian/pyjack-*.egg-info usr/lib/python2.6/dist-packages/
diff --git a/pyjack-0.5.2/debian/rules b/pyjack-0.5.2/debian/rules
new file mode 100755 (executable)
index 0000000..f700e94
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+
+clean::
+       rm -rf build
+
+install/python-jack::
+       python setup.py build
+       mkdir -p debian/python-jack/usr/lib/python2.6/dist-packages/
+       cp build/lib.linux-*/* debian/python-jack/usr/lib/python2.6/dist-packages/
diff --git a/pyjack-0.5.2/demos/.directory b/pyjack-0.5.2/demos/.directory
new file mode 100644 (file)
index 0000000..bf0b297
--- /dev/null
@@ -0,0 +1,3 @@
+[Dolphin]
+Timestamp=2010,3,26,2,24,40
+ViewMode=1
diff --git a/pyjack-0.5.2/demos/alsa_midi_busconnect.py b/pyjack-0.5.2/demos/alsa_midi_busconnect.py
new file mode 100755 (executable)
index 0000000..2471c0c
--- /dev/null
@@ -0,0 +1,77 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import re
+import os
+
+def _getClients(typeOfClient):
+       lines=[line.strip() for line in os.popen("LANG=C aconnect -%s" % typeOfClient).readlines()]
+       listOfClients=[]
+       temporalList=[]
+       for line in lines:
+               if line.find("client ")==0:
+                       listOfClients.append(dict())
+                       listOfClients[-1]["clientName"]=re.search("'(.*)'",line).group(1)
+                       listOfClients[-1]["clientNumber"]=int(re.search("client (.*):",line).group(1))
+                       if len(temporalList)>0:
+                               listOfClients[-2]["ports"]=temporalList
+                       temporalList=[]
+               else:
+                       line=re.search("'(.*)'",line).group(1)
+                       temporalList.append(line)
+       listOfClients[-1]["ports"]=temporalList
+       return listOfClients
+
+def _getClientPorts(name,typeOfClient):
+       listOfClients=_getClients(typeOfClient)
+       try:
+               index=[client['clientName'] for client in listOfClients].index(name)
+       except:
+               print "WARNING: trying to get ports of client %s, which doesn't exist. Returning an empty list." % name
+               return []
+       if index == -1:
+               return None
+       client=listOfClients[index]
+       return [ "%s:%i" % (client["clientNumber"],client["ports"].index(port)) for port in client["ports"] ]
+
+def getInputClients():
+       return _getClients("o")
+       
+def getOutputClients():
+       return _getClients("i")
+
+def getClientInputPorts(name):
+       return _getClientPorts(name,"o")
+
+def getClientOutputPorts(name):
+       return _getClientPorts(name,"i")
+
+def connect(source,target):
+       os.system("aconnect %s %s" % (source,target))
+
+def bus_connect(source, target):
+       """
+       Connects two lists of ports. The arguments can be a list or a string. If the latter, all the available ports of the client will be used.
+       """
+       sources = source if type(source) == type([]) else getClientOutputPorts(source)
+       targets = target if type(target) == type([]) else getClientInputPorts(target)
+       num_connections = min(len(sources), len(targets))
+       print 'Doing %i connections. Client has %i out ports and target has %i in ports' % (num_connections, len(sources), len(targets))
+       for i in xrange(num_connections) :
+               print 'connect', sources[i], targets[i]
+               connect(sources[i], targets[i])
+       return num_connections != 0
+
+def main():
+       print "input clients: "
+       print getInputClients()
+       print "output ones: "
+       print getOutputClients()
+       print "Midi Through:"
+       print getClientInputPorts("Midi Through")
+       print "Midi Through outputs:"
+       print getClientOutputPorts("Midi Through")
+       bus_connect("Midi Through","Midi Through")
+
+if __name__ == '__main__':
+       main()
diff --git a/pyjack-0.5.2/demos/capture.py b/pyjack-0.5.2/demos/capture.py
new file mode 100755 (executable)
index 0000000..f791d80
--- /dev/null
@@ -0,0 +1,81 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Capture 3 seconds of stereo audio from alsa_pcm:capture_1/2; then play it back.
+#
+# Copyright 2003, Andrew W. Schmeder
+# This source code is released under the terms of the GNU Public License.
+# See LICENSE for the full text of these terms.
+
+import numpy
+import jack
+import time
+
+jack.attach("captest")
+
+print jack.get_ports()
+
+jack.register_port("in_1", jack.IsInput)
+jack.register_port("in_2", jack.IsInput)
+jack.register_port("out_1", jack.IsOutput)
+jack.register_port("out_2", jack.IsOutput)
+
+jack.activate()
+
+print jack.get_ports()
+
+jack.connect("system:capture_1", "captest:in_1")
+jack.connect("system:capture_2", "captest:in_2")
+jack.connect("captest:out_1", "system:playback_1")
+jack.connect("captest:out_2", "system:playback_2")
+
+print jack.get_connections("captest:in_1")
+
+N = jack.get_buffer_size()
+Sr = float(jack.get_sample_rate())
+print "Buffer Size:", N, "Sample Rate:", Sr
+sec = 3.0
+
+capture = numpy.zeros((2,int(Sr*sec)), 'f')
+input = numpy.zeros((2,N), 'f')
+output = numpy.zeros((2,N), 'f')
+
+#time.sleep(1)
+
+print "Capturing audio..."
+
+i = 0
+while i < capture.shape[1] - N:
+    try:
+        jack.process(output, capture[:,i:i+N])
+        i += N
+    except jack.InputSyncError:
+        print "Input Sync"
+        pass
+    except jack.OutputSyncError:
+        print "Output Sync"
+        pass
+    print ".",
+
+print "\nPlaying back..."
+
+i = 0
+iS = 0
+oS = 0
+while i < capture.shape[1] - N:
+    try:
+        jack.process(capture[:,i:i+N], input)
+        i += N
+    except jack.InputSyncError:
+        iS += 1
+        pass
+    except jack.OutputSyncError:
+        iO += 1
+        pass
+print "Finished with", iS, "input-off-sync &", oS, "output-off-sync"
+
+jack.deactivate()
+jack.detach()
+
+import numpy, scipy.io.wavfile
+toSave = numpy.array((2**15-1)*capture.transpose(),dtype="int16")
+scipy.io.wavfile.write("output.wav", int(Sr), toSave)
diff --git a/pyjack-0.5.2/demos/just_capture.py b/pyjack-0.5.2/demos/just_capture.py
new file mode 100755 (executable)
index 0000000..9f8b5d6
--- /dev/null
@@ -0,0 +1,91 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Capture 3 seconds of stereo audio from alsa_pcm:capture_1/2; then play it back.
+#
+# Copyright 2003, Andrew W. Schmeder
+# This source code is released under the terms of the GNU Public License.
+# See LICENSE for the full text of these terms.
+
+import numpy
+import jack
+import time
+
+jack.attach("captest")
+
+myname = jack.get_client_name()
+print "Client:", myname
+print "Jack ports (before):", jack.get_ports()
+
+jack.register_port("in_1", jack.IsInput)
+jack.register_port("in_2", jack.IsInput)
+
+jack.activate()
+
+print "Jack ports (after):", jack.get_ports()
+
+jack.connect("system:capture_1", myname+":in_1")
+jack.connect("system:capture_2", myname+":in_2")
+
+print jack.get_connections(myname+":in_1")
+
+N = jack.get_buffer_size()
+Sr = float(jack.get_sample_rate())
+print "Buffer Size:", N, "Sample Rate:", Sr
+sec = 3.0
+
+capture = numpy.zeros((2,int(Sr*sec)), 'f')
+dummy = numpy.zeros((2,0), 'f')
+
+#time.sleep(1)
+
+print "Capturing audio..."
+
+i = 0
+while i < capture.shape[1] - N:
+    try:
+        jack.process(dummy, capture[:,i:i+N])
+        i += N
+    except jack.InputSyncError:
+        print "Input Sync"
+        pass
+    except jack.OutputSyncError:
+        print "Output Sync"
+        pass
+    print ".",
+
+print "\nPlaying back..."
+
+jack.unregister_port("in_1")
+jack.unregister_port("in_2")
+
+jack.deactivate()
+
+jack.register_port("out_1", jack.IsOutput)
+jack.register_port("out_2", jack.IsOutput)
+
+jack.activate()
+
+jack.connect(myname+":out_1", "system:playback_1")
+jack.connect(myname+":out_2", "system:playback_2")
+
+i = 0
+iS = 0
+oS = 0
+while i < capture.shape[1] - N:
+    try:
+        jack.process(capture[:,i:i+N], dummy)
+        i += N
+    except jack.InputSyncError:
+        iS += 1
+        pass
+    except jack.OutputSyncError:
+        oS += 1
+        pass
+print "Finished with", iS, "input-off-sync &", oS, "output-off-sync"
+
+jack.deactivate()
+jack.detach()
+
+import numpy, scipy.io.wavfile
+toSave = numpy.array((2**15-1)*capture.transpose(),dtype="int16")
+scipy.io.wavfile.write("output.wav", int(Sr), toSave)
diff --git a/pyjack-0.5.2/demos/qtransport.py b/pyjack-0.5.2/demos/qtransport.py
new file mode 100755 (executable)
index 0000000..1e9991f
--- /dev/null
@@ -0,0 +1,82 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import jack, os, sys
+from PyQt4.QtGui import QApplication, QDialog
+from PyQt4.QtCore import QTimer, SIGNAL, SLOT
+from PyQt4.uic import loadUi
+
+jack.attach("qtransport")
+
+class MainW(QDialog):
+    def __init__(self, *args):
+        QDialog.__init__(self, *args)
+        loadUi(sys.path[0]+"/qtransport_gui.ui", self)
+        
+        self.timer = QTimer()
+        self.timer.start(100)
+        
+        self.connect(self.b_back, SIGNAL("clicked()"), self.goBack)
+        self.connect(self.b_play, SIGNAL("clicked()"), self.play)
+        self.connect(self.b_stop, SIGNAL("clicked()"), self.stop)
+        self.connect(self.b_forward, SIGNAL("clicked()"), self.goForward)
+        self.connect(self.timer, SIGNAL("timeout()"), self.refreshUi)
+        
+    def goBack(self):
+       pos = int(jack.get_current_transport_frame()) - 100000
+       if pos < 0:
+         jack.transport_locate(0)
+       else:
+         jack.transport_locate(pos)
+
+    def goForward(self):
+       jack.transport_locate(jack.get_current_transport_frame()+100000)
+
+    def play(self):
+       if (self.b_play.isChecked()):
+         jack.transport_start()
+       else:
+         jack.transport_stop()
+
+    def stop(self):
+       jack.transport_stop()
+       jack.transport_locate(0)
+       self.b_play.setChecked(False)
+
+    def refreshUi(self):
+       state = jack.get_transport_state()
+       frame = jack.get_current_transport_frame()
+       rate  = jack.get_sample_rate()
+       
+       # Jack State
+       if (state == 0):
+         self.l_state.setText("Stopped")
+         self.b_play.setChecked(False)
+       elif (state == 1):
+         self.l_state.setText("Rolling")
+         self.b_play.setChecked(True)
+       elif (state == 3): self.l_state.setText("Starting")
+       else: self.l_state.setText("Unknown (%i)" % state)
+
+       # Current Time
+       time = frame / rate
+       secs = time % 60
+       mins = (time / 60) % 60
+       hrs  = (time / 3600) % 60
+       secH = minH = hrsH = ""
+       if secs < 10: secH = "0"
+       if mins < 10: minH = "0"
+       if hrs  < 10: hrsH = "0"
+       self.l_time.setText(hrsH+str(hrs)+":"+minH+str(mins)+":"+secH+str(secs))
+       
+       # Current Frame
+       self.l_frame.setText(str(frame))
+
+#--------------- main ------------------
+if __name__ == '__main__':
+
+    app = QApplication(sys.argv)
+    gui = MainW()
+    gui.show()
+    app.exec_()
+    jack.detach()
diff --git a/pyjack-0.5.2/demos/qtransport_gui.ui b/pyjack-0.5.2/demos/qtransport_gui.ui
new file mode 100644 (file)
index 0000000..1523bbd
--- /dev/null
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>376</width>
+    <height>115</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>QTransport Example</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Transport Frame:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="l_frame">
+       <property name="text">
+        <string>00000000</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <item>
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>Transport Time:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="l_time">
+       <property name="text">
+        <string>0:00:00</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_4">
+     <item>
+      <widget class="QLabel" name="label_3">
+       <property name="text">
+        <string>Transport State:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="l_state">
+       <property name="text">
+        <string>Unkown</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer_2">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="b_back">
+       <property name="text">
+        <string>&lt;&lt;</string>
+       </property>
+       <property name="autoRepeat">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="b_play">
+       <property name="text">
+        <string>|&gt;</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="b_stop">
+       <property name="text">
+        <string>[]</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="b_forward">
+       <property name="text">
+        <string>&gt;&gt;</string>
+       </property>
+       <property name="autoRepeat">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/pyjack-0.5.2/demos/testtone.py b/pyjack-0.5.2/demos/testtone.py
new file mode 100755 (executable)
index 0000000..5b61858
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Plays a 440.0 Hz test tone for 3 seconds to alsa_pcm:playback_1.
+#
+# Copyright 2003, Andrew W. Schmeder
+# This source code is released under the terms of the GNU Public License.
+# See LICENSE for the full text of these terms.
+
+import numpy
+import jack
+
+jack.attach("testtone")
+jack.register_port("in_1", jack.IsInput)
+jack.register_port("out_1", jack.IsOutput)
+jack.activate()
+jack.connect("testtone:out_1", "alsa_pcm:playback_1")
+
+N = jack.get_buffer_size()
+Sr = float(jack.get_sample_rate())
+print "Buffer Size:", N, "Sample Rate:", Sr
+sec = 3.0
+
+input = numpy.zeros((1,N), 'f')
+output = numpy.reshape(
+    numpy.sin(
+        2*numpy.pi*440.0 * (numpy.arange(0, sec, 1.0/(Sr), 'f')[0:int(Sr*sec)])
+    ), (1, Sr*sec)).astype('f')
+
+i = 0
+while i < output.shape[1] - N:
+    try:
+        jack.process(output[:,i:i+N], input)
+        i += N
+    except jack.InputSyncError:
+        pass
+    except jack.OutputSyncError:
+        pass
+        
+jack.deactivate()
+
+jack.detach()
diff --git a/pyjack-0.5.2/demos/transporter.py b/pyjack-0.5.2/demos/transporter.py
new file mode 100755 (executable)
index 0000000..f117dd1
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import jack
+
+#print current time
+def print_time ():
+    time = float(jack.get_current_transport_frame()) / jack.get_sample_rate()
+    print "current time: %f s" % time
+
+#testing state set/get
+def print_state():
+    state = jack.get_transport_state()
+    statename = {
+            jack.TransportStopped:"stopped",
+            jack.TransportRolling:"rolling",
+            jack.TransportStarting:"starting"
+        } [state]
+    print("current state is %i (%s)"% (state, statename))
+
+#testing position set/get
+from time import sleep
+jack.attach("transporter.py")
+print ("getting current time")
+print_time()
+print ("going to frame 0")
+jack.transport_locate(0)
+sleep (2)
+
+print ("getting current time")
+print_time()
+
+sleep (0.5)
+print ("going to 6 sec")
+jack.transport_locate(jack.get_sample_rate()*6)
+sleep (2)
+
+print ("getting current time")
+print_time()
+
+print ("TransportStopped: %i" % jack.TransportStopped)
+print ("TransportRolling: %i" % jack.TransportRolling)
+print ("TransportStarting: %i" % jack.TransportStarting)
+print_state()
+
+print ("playing")
+jack.transport_start()
+sleep(5)
+print ("stopping")
+jack.transport_stop()
+
+print_time()
diff --git a/pyjack-0.5.2/install.sh b/pyjack-0.5.2/install.sh
new file mode 100755 (executable)
index 0000000..28c3450
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+sudo python ./setup.py install
+
diff --git a/pyjack-0.5.2/patches/enable-jack2.diff b/pyjack-0.5.2/patches/enable-jack2.diff
new file mode 100644 (file)
index 0000000..baa1bb7
--- /dev/null
@@ -0,0 +1,11 @@
+--- pyjack.c.old       2010-04-21 13:37:01.000000000 +0100
++++ pyjack.c   2010-04-21 13:37:16.202977932 +0100
+@@ -40,7 +40,7 @@
+ // Global shared data for jack
+ /* Uncomment the next line if you have Jack2 */
+-// #define JACK2 1
++#define JACK2 1
+ #define PYJACK_MAX_PORTS 256
diff --git a/pyjack-0.5.2/pyjack.c b/pyjack-0.5.2/pyjack.c
new file mode 100644 (file)
index 0000000..711a8a8
--- /dev/null
@@ -0,0 +1,1360 @@
+/**
+  * pyjackc - C module implementation for pyjack
+  *
+  * Copyright 2003 Andrew W. Schmeder <andy@a2hd.com>
+  * Copyright 2010 Filipe Coelho (aka 'falkTX') <falktx@gmail.com>
+  *
+  * This source code is released under the terms of the GNU GPL v2.
+  * See LICENSE for the full text of these terms.
+  */
+
+// Python includes
+#include "Python.h"
+#include "numpy/arrayobject.h"
+
+// Jack
+#include <jack/jack.h>
+#include <jack/transport.h>
+
+// C standard
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+/*
+TODO's:
+- dettach on client on __del__
+- free buffers
+- close sockets
+- hangup callback
+- user python callbacks for non-rt events
+- make global client a python object
+- eventually deprecate the global client api
+- remove the attach and detach methods
+*/
+
+// Global shared data for jack
+
+/* Uncomment the next line if you have Jack2 */
+// #define JACK2 1
+
+
+#define PYJACK_MAX_PORTS 256
+#define W 0
+#define R 1
+typedef struct {
+    PyObject_HEAD
+    jack_client_t* pjc;                             // Client handle
+    int            buffer_size;                     // Buffer size
+    int            num_inputs;                      // Number of input ports registered
+    int            num_outputs;                     // Number of output ports registered
+    jack_port_t*   input_ports[PYJACK_MAX_PORTS];   // Input ports
+    jack_port_t*   output_ports[PYJACK_MAX_PORTS];  // Output ports
+    fd_set         input_rfd;                       // fdlist for select
+    fd_set         output_rfd;                      // fdlist for select
+    int            input_pipe[2];                   // socket pair for input port data
+    int            output_pipe[2];                  // socket pair for output port data
+    float*         input_buffer_0;                  // buffer used to transmit audio via slink...
+    float*         output_buffer_0;                 // buffer used to send audio via slink...
+    float*         input_buffer_1;                  // buffer used to transmit audio via slink...
+    float*         output_buffer_1;                 // buffer used to send audio via slink...
+    int            input_buffer_size;               // buffer_size * num_inputs * sizeof(sample_t)
+    int            output_buffer_size;              // buffer_size * num_outputs * sizeof(sample_t)
+    int            iosync;                          // true when the python side synchronizing properly...
+    int            event_graph_ordering;            // true when a graph ordering event has occured
+    int            event_port_registration;         // true when a port registration event has occured
+    int            event_freewheel;                 // true when a freewheel mode toggle event has occured
+    int            event_buffer_size;               // true when a buffer size change has occured
+    int            event_sample_rate;               // true when a sample rate change has occured
+    int            event_xrun;                      // true when a xrun occurs
+    int            event_shutdown;                  // true when the jack server is shutdown
+    int            event_hangup;                    // true when client got hangup signal
+    int            freewheel;                       // indicates if freewheel mode active
+    int            active;                          // indicates if the client is currently process-enabled
+} pyjack_client_t;
+
+pyjack_client_t global_client;
+
+pyjack_client_t * self_or_global_client(PyObject * self) {
+    if (!self) return & global_client;
+    return (pyjack_client_t*) self;
+}
+
+// Initialize global data
+void pyjack_init(pyjack_client_t * client) {
+    client->pjc = NULL;
+    client->active = 0;
+    client->iosync = 0;
+    client->num_inputs = 0;
+    client->num_outputs = 0;
+    client->input_pipe[R] = 0;
+    client->input_pipe[W] = 0;
+    client->output_pipe[R] = 0;
+    client->output_pipe[W] = 0;
+
+    // Initialize unamed, raw datagram-type sockets...
+    if (socketpair(PF_UNIX, SOCK_DGRAM, 0, client->input_pipe) == -1) {
+        printf("ERROR: Failed to create socketpair input_pipe!!\n");
+    }
+    if (socketpair(PF_UNIX, SOCK_DGRAM, 0, client->output_pipe) == -1) {
+        printf("ERROR: Failed to create socketpair output_pipe!!\n");
+    }
+
+    // Convention is that pipe[W=1] is the "write" end of the pipe, which is always non-blocking.
+    fcntl(client->input_pipe[W], F_SETFL, O_NONBLOCK);
+    fcntl(client->output_pipe[W], F_SETFL, O_NONBLOCK);
+    fcntl(client->output_pipe[R], F_SETFL, O_NONBLOCK);
+
+    // The read end, pipe[R=0], is blocking, but we use a select() call to make sure that data is really there.
+    FD_ZERO(&client->input_rfd);
+    FD_ZERO(&client->output_rfd);
+    FD_SET(client->input_pipe[R], &client->input_rfd);
+    FD_SET(client->output_pipe[R], &client->output_rfd);
+
+    // Init buffers to null...
+    client->input_buffer_size = 0;
+    client->output_buffer_size = 0;
+    client->input_buffer_0 = NULL;
+    client->output_buffer_0 = NULL;
+    client->input_buffer_1 = NULL;
+    client->output_buffer_1 = NULL;
+}
+
+static void free_and_reset(float ** pointer)
+{
+    if (!*pointer) return;
+    free(*pointer);
+    *pointer=0;
+}
+
+static void close_and_reset(int * fd)
+{
+    if (!*fd) return;
+    close(*fd);
+    *fd=0;
+}
+
+// Finalize global data
+void pyjack_final(pyjack_client_t * client) {
+    client->pjc = NULL;
+    // Free buffers...
+    client->num_inputs = 0;
+    client->num_outputs = 0;
+    client->buffer_size = 0;
+    free_and_reset(&client->input_buffer_0);
+    free_and_reset(&client->input_buffer_1);
+    free_and_reset(&client->output_buffer_0);
+    free_and_reset(&client->output_buffer_1);
+    // Close socket...
+    close_and_reset(&client->input_pipe[R]);
+    close_and_reset(&client->input_pipe[W]);
+    close_and_reset(&client->output_pipe[R]);
+    close_and_reset(&client->output_pipe[W]);
+}
+
+// (Re)initialize socketpair buffers
+void init_pipe_buffers(pyjack_client_t  * client) {
+    // allocate buffers for send and recv
+    unsigned new_input_size = client->num_inputs * client->buffer_size * sizeof(float);
+    if(client->input_buffer_size != new_input_size) {
+        client->input_buffer_size = new_input_size;
+        client->input_buffer_0 = realloc(client->input_buffer_0, new_input_size);
+        client->input_buffer_1 = realloc(client->input_buffer_1, new_input_size);
+        //printf("Input buffer size %d bytes\n", input_buffer_size);
+    }
+    unsigned new_output_size = client->num_outputs * client->buffer_size * sizeof(float);
+    if(client->output_buffer_size != new_output_size) {
+        client->output_buffer_size = new_output_size;
+        client->output_buffer_0 = realloc(client->output_buffer_0, new_output_size);
+        client->output_buffer_1 = realloc(client->output_buffer_1, new_output_size);
+        //printf("Output buffer size %d bytes\n", output_buffer_size);
+    }
+
+    // set socket buffers to same size as snd/rcv buffers
+    setsockopt(client->input_pipe[R], SOL_SOCKET, SO_RCVBUF, &client->input_buffer_size, sizeof(int));
+    setsockopt(client->input_pipe[R], SOL_SOCKET, SO_SNDBUF, &client->input_buffer_size, sizeof(int));
+    setsockopt(client->input_pipe[W], SOL_SOCKET, SO_RCVBUF, &client->input_buffer_size, sizeof(int));
+    setsockopt(client->input_pipe[W], SOL_SOCKET, SO_SNDBUF, &client->input_buffer_size, sizeof(int));
+
+    setsockopt(client->output_pipe[R], SOL_SOCKET, SO_RCVBUF, &client->output_buffer_size, sizeof(int));
+    setsockopt(client->output_pipe[R], SOL_SOCKET, SO_SNDBUF, &client->output_buffer_size, sizeof(int));
+    setsockopt(client->output_pipe[W], SOL_SOCKET, SO_RCVBUF, &client->output_buffer_size, sizeof(int));
+    setsockopt(client->output_pipe[W], SOL_SOCKET, SO_SNDBUF, &client->output_buffer_size, sizeof(int));
+}
+
+// RT function called by jack
+int pyjack_process(jack_nframes_t n, void* arg) {
+
+    pyjack_client_t * client = (pyjack_client_t*) arg;
+    int i, r;
+
+    // Send input data to python side (non-blocking!)
+    if (client->num_inputs) { 
+        for(i = 0; i < client->num_inputs; i++) {
+            memcpy(
+                &client->input_buffer_0[client->buffer_size * i], 
+                jack_port_get_buffer(client->input_ports[i], n), 
+                (client->buffer_size * sizeof(float))
+            );
+        }
+
+        r = write(client->input_pipe[W], client->input_buffer_0, client->input_buffer_size);
+
+        if(r < 0) {
+            client->iosync = 0;
+        } else if(r == client->input_buffer_size) {
+            client->iosync = 1;
+        }
+    }
+
+    // Read data from python side (non-blocking!)
+    if (client->num_outputs) {
+        r = read(client->output_pipe[R], client->output_buffer_0, client->output_buffer_size);
+        if(r != client->buffer_size * sizeof(float) * client->num_outputs) {
+            //printf("not enough data; skipping output\n");
+            return 0;
+        }
+        for(i = 0; i < client->num_outputs; i++) {
+            memcpy(
+                jack_port_get_buffer(client->output_ports[i], client->buffer_size), 
+                client->output_buffer_0 + (client->buffer_size * i),
+                client->buffer_size * sizeof(float)
+            );
+        }
+    }
+
+    return 0;
+}
+
+// Event notification of buffer size change
+int pyjack_buffer_size_changed(jack_nframes_t n, void* arg) {
+    pyjack_client_t * client = (pyjack_client_t*) arg;
+    client->event_buffer_size = 1;
+    return 0;
+}
+
+// Event notification of sample rate change
+int pyjack_sample_rate_changed(jack_nframes_t n, void* arg) {
+    pyjack_client_t * client = (pyjack_client_t*) arg;
+    client->event_sample_rate = 1;
+    return 0;
+}
+
+// Event notification of freewheel mode toggle
+void pyjack_freewheel_changed(int starting, void* arg) {
+    pyjack_client_t * client = (pyjack_client_t*) arg;
+    client->event_freewheel = 1;
+    client->freewheel = starting;
+}
+
+// Event notification of graph connect/disconnection
+int pyjack_graph_order(void* arg) {
+    pyjack_client_t * client = (pyjack_client_t*) arg;
+    client->event_graph_ordering = 1;
+    return 0;
+}
+
+// Event notification of xrun
+int pyjack_xrun(void* arg) {
+    pyjack_client_t * client = (pyjack_client_t*) arg;
+    client->event_xrun = 1;
+    return 0;
+}
+
+// Event notification of port registration or drop
+void pyjack_port_registration(jack_port_id_t pid, int action, void* arg) {
+    pyjack_client_t * client = (pyjack_client_t*) arg;
+    client->event_port_registration = 1;
+}
+
+// Shutdown handler
+void pyjack_shutdown(void * arg) {
+    pyjack_client_t * client = (pyjack_client_t*) arg;
+    client->event_shutdown = 1;
+    client->pjc = NULL;    
+}
+
+// SIGHUP handler
+void pyjack_hangup(int signal) {
+    // TODO: what to do with non global clients
+    global_client.event_hangup = 1;
+    global_client.pjc = NULL;
+}
+
+// ------------- Python module stuff ---------------------
+
+// Module exception object
+static PyObject* JackError;
+static PyObject* JackNotConnectedError;
+static PyObject* JackUsageError;
+static PyObject* JackInputSyncError;
+static PyObject* JackOutputSyncError;
+
+// Attempt to connect to the Jack server
+static PyObject* attach(PyObject* self, PyObject* args)
+{
+    char* cname;
+    if (! PyArg_ParseTuple(args, "s", &cname))
+        return NULL;
+
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc != NULL) {
+        PyErr_SetString(JackUsageError, "A connection is already established.");
+        return NULL;
+    }
+
+    jack_status_t status;
+    client->pjc = jack_client_open(cname, JackNoStartServer, &status);
+    if(client->pjc == NULL) {
+        //TODO check status
+        PyErr_SetString(JackNotConnectedError, "Failed to connect to Jack audio server.");
+        return NULL;
+    }
+
+    jack_on_shutdown(client->pjc, pyjack_shutdown, client);
+    signal(SIGHUP, pyjack_hangup); // TODO: This just works with global clients
+
+    if(jack_set_process_callback(client->pjc, pyjack_process, client) != 0) {
+        PyErr_SetString(JackError, "Failed to set jack process callback.");
+        return NULL;
+    }
+
+    if(jack_set_buffer_size_callback(client->pjc, pyjack_buffer_size_changed, client) != 0) {
+        PyErr_SetString(JackError, "Failed to set jack buffer size callback.");
+        return NULL;
+    }
+
+    if(jack_set_sample_rate_callback(client->pjc, pyjack_sample_rate_changed, client) != 0) {
+        PyErr_SetString(JackError, "Failed to set jack sample rate callback.");
+        return NULL;
+    }
+
+    if(jack_set_freewheel_callback(client->pjc, pyjack_freewheel_changed, client) != 0) {
+      PyErr_SetString(JackError, "Failed to set jack sample rate callback.");
+      return NULL;
+    }
+
+    if(jack_set_port_registration_callback(client->pjc, pyjack_port_registration, client) != 0) {
+        PyErr_SetString(JackError, "Failed to set jack port registration callback.");
+        return NULL;
+    }
+
+    if(jack_set_graph_order_callback(client->pjc, pyjack_graph_order, client) != 0) {
+        PyErr_SetString(JackError, "Failed to set jack graph order callback.");
+        return NULL;
+    }
+
+    if(jack_set_xrun_callback(client->pjc, pyjack_xrun, client) != 0) {
+        PyErr_SetString(JackError, "Failed to set jack xrun callback.");
+        return NULL;
+    }
+
+    // Get buffer size
+    client->buffer_size = jack_get_buffer_size(client->pjc);
+
+    // Success!
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+// Detach client from the jack server (also destroys all connections)
+static PyObject* detach(PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+
+    if(client->pjc != NULL) {
+        jack_client_close(client->pjc);
+        pyjack_final(client);
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject* unregister_port(PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+    char* port_name;
+    if (! PyArg_ParseTuple(args, "s", &port_name))
+        return NULL;
+
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+//     if(client->active) {
+//         PyErr_SetString(JackUsageError, "Cannot unregister ports while client is active.");
+//         return NULL;
+//     }
+
+    int i = 0;
+    for (i=0;i<client->num_inputs;i++) {
+        if (strcmp(port_name, jack_port_short_name(client->input_ports[i]))) continue;
+        int error = jack_port_unregister(client->pjc, client->input_ports[i]);
+        if (error) {
+            PyErr_SetString(JackError, "Unable to unregister input port.");
+            return NULL;
+        }
+        client->num_inputs--;
+        for (;i<client->num_inputs;i++) {
+            client->input_ports[i] = client->input_ports[i+1];
+        }
+        init_pipe_buffers(client);
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+
+    for (i=0;i<client->num_outputs;i++) {
+        if (strcmp(port_name, jack_port_short_name(client->output_ports[i]))) continue;
+        int error = jack_port_unregister(client->pjc, client->output_ports[i]);
+        if (error) {
+            PyErr_SetString(JackError, "Unable to unregister output port.");
+            return NULL;
+        }
+        client->num_outputs--;
+        for (;i<client->num_outputs;i++) {
+            client->output_ports[i] = client->output_ports[i+1];
+        }
+        init_pipe_buffers(client);
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+    PyErr_SetString(JackUsageError, "Port not found.");
+    return NULL;
+}
+
+
+// Create a new port for this client
+// Unregistration of ports is not supported; you must disconnect, reconnect, re-reg all ports instead.
+static PyObject* register_port(PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+
+    int flags;
+    char* pname;
+    if (! PyArg_ParseTuple(args, "si", &pname, &flags))
+        return NULL;
+
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+//     if(client->active) {
+//         PyErr_SetString(JackUsageError, "Cannot register ports while client is active.");
+//         return NULL;
+//     }
+
+    if(client->num_inputs >= PYJACK_MAX_PORTS) {
+        PyErr_SetString(JackUsageError, "Cannot create more than 256 ports. Sorry.");
+        return NULL;
+    }
+
+    jack_port_t* jp = jack_port_register(client->pjc, pname, JACK_DEFAULT_AUDIO_TYPE, flags, 0);
+    if(jp == NULL) {
+        PyErr_SetString(JackError, "Failed to create port.");
+        return NULL;
+    }
+
+    // Store pointer to this port and increment counter
+    if(flags & JackPortIsInput) {
+        client->input_ports[client->num_inputs] = jp;
+        client->num_inputs++;
+    }
+    if(flags & JackPortIsOutput) {
+        client->output_ports[client->num_outputs] = jp;
+        client->num_outputs++;
+    }
+
+    init_pipe_buffers(client);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+// Returns a list of all port names registered in the Jack system
+static PyObject* get_ports(PyObject* self, PyObject* args)
+{
+    PyObject* plist;
+    const char** jplist;
+    int i;
+
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    jplist = jack_get_ports(client->pjc, NULL, NULL, 0);
+
+    i = 0;
+    plist = PyList_New(0);
+    if(jplist != NULL) {
+        while(jplist[i] != NULL) {
+            PyList_Append(plist, Py_BuildValue("s", jplist[i]));
+            //free(jplist[i]);  // Memory leak or not??
+            i++;
+        }
+    }
+
+    Py_INCREF(plist);
+    return plist;
+}
+
+// Return port flags (an integer)
+static PyObject* get_port_flags(PyObject* self, PyObject* args)
+{
+    char* pname;
+    jack_port_t* jp;
+    int i;
+
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    if (! PyArg_ParseTuple(args, "s", &pname))
+        return NULL;
+
+    jp = jack_port_by_name(client->pjc, pname);
+    if(jp == NULL) {
+        PyErr_SetString(JackError, "Bad port name.");
+        return NULL;
+    }
+
+    i = jack_port_flags(jp);
+    if(i < 0) {
+        PyErr_SetString(JackError, "Error getting port flags.");
+        return NULL;
+    }
+
+    return Py_BuildValue("i", i);
+}
+
+// Return a list of full port names connected to the named port
+// Port does not need to be owned by this client.
+static PyObject* get_connections(PyObject* self, PyObject* args)
+{
+    char* pname;
+    const char** jplist;
+    jack_port_t* jp;
+    PyObject* plist;
+    int i;
+
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    if (! PyArg_ParseTuple(args, "s", &pname))
+        return NULL;
+
+    jp = jack_port_by_name(client->pjc, pname);
+    if(jp == NULL) {
+        PyErr_SetString(JackError, "Bad port name.");
+        return NULL;
+    }
+
+    jplist = jack_port_get_all_connections(client->pjc, jp);
+
+    i = 0;
+    plist = PyList_New(0);
+    if(jplist != NULL) {
+        while(jplist[i] != NULL) {
+            PyList_Append(plist, Py_BuildValue("s", jplist[i]));
+            //free(jplist[i]);  // memory leak or not?
+            i++;
+        }
+    }
+
+    Py_INCREF(plist);
+    return plist;
+}
+
+// connect_port
+static PyObject* port_connect(PyObject* self, PyObject* args)
+{
+    char* src_name;
+    char* dst_name;
+
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    if (! PyArg_ParseTuple(args, "ss", &src_name, &dst_name))
+        return NULL;
+
+    jack_port_t * src = jack_port_by_name(client->pjc, src_name);
+    if (!src) {
+        PyErr_SetString(JackUsageError, "Non existing source port.");
+        return NULL;
+        }
+    jack_port_t * dst = jack_port_by_name(client->pjc, dst_name);
+    if (!dst) {
+        PyErr_SetString(JackUsageError, "Non existing destination port.");
+        return NULL;
+        }
+    if(! client->active) {
+        if(jack_port_is_mine(client->pjc, src) || jack_port_is_mine(client->pjc, dst)) {
+            PyErr_SetString(JackUsageError, "Jack client must be activated to connect own ports.");
+            return NULL;
+        }
+    }
+    int error = jack_connect(client->pjc, src_name, dst_name);
+    if (error !=0 && error != EEXIST) {
+        PyErr_SetString(JackError, "Failed to connect ports.");
+        return NULL;
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static int jack_port_connected_to_extern(const pyjack_client_t * client, 
+                                         const jack_port_t * src, 
+                                         const char* dst_name)
+{
+    // finds connections of src, then checks if dst is in there
+    const char ** existing_connections = jack_port_get_all_connections(client->pjc, src);
+    if (existing_connections) {
+        int i; // non C99 nonsense
+        for (i = 0; existing_connections[i]; i++) {
+            return strcmp(existing_connections[i], dst_name) == 0;
+        }
+    }
+    return 0;
+}
+
+// disconnect_port
+static PyObject* port_disconnect(PyObject* self, PyObject* args)
+{
+    char* src_name;
+    char* dst_name;
+    pyjack_client_t * client = self_or_global_client(self);
+
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    if (! PyArg_ParseTuple(args, "ss", &src_name, &dst_name))
+        return NULL;
+
+    jack_port_t * src = jack_port_by_name(client->pjc, src_name);
+    if (!src) {
+        PyErr_SetString(JackUsageError, "Non existing source port.");
+        return NULL;
+    }
+
+    jack_port_t * dst = jack_port_by_name(client->pjc, dst_name);
+    if (!dst) {
+        PyErr_SetString(JackUsageError, "Non existing destination port.");
+        return NULL;
+    }
+
+    if(jack_port_connected_to_extern(client, src, dst_name)) {
+        if (jack_disconnect(client->pjc, src_name, dst_name))  {
+            PyErr_SetString(JackError, "Failed to disconnect ports.");
+            return NULL;
+        }
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+// get_buffer_size
+static PyObject* get_buffer_size(PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    int bs = jack_get_buffer_size(client->pjc);
+    return Py_BuildValue("i", bs);
+}
+
+// get_sample_rate
+static PyObject* get_sample_rate(PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    int sr = jack_get_sample_rate(client->pjc);
+    return Py_BuildValue("i", sr);
+}
+
+// activate
+static PyObject* activate(PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    if(client->active) {
+        PyErr_SetString(JackUsageError, "Client is already active.");
+        return NULL;
+    }
+
+    if(jack_activate(client->pjc) != 0) {
+        PyErr_SetString(JackUsageError, "Could not activate client.");
+        return NULL;
+    }
+
+    client->active = 1;
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+// deactivate
+static PyObject* deactivate(PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    if(! client->active) {
+        PyErr_SetString(JackUsageError, "Client is not active.");
+        return NULL;
+    }
+
+    if(jack_deactivate(client->pjc) != 0) {
+        PyErr_SetString(JackError, "Could not deactivate client.");
+        return NULL;
+    }
+
+    client->active = 0;
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+// get_buffer_size
+static PyObject* get_freewheel(PyObject* self, PyObject* args)
+{
+  pyjack_client_t * client = self_or_global_client(self);
+
+  if(client->pjc == NULL) {
+    PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+    return NULL;
+  }
+
+  return Py_BuildValue("i", client->freewheel);
+}
+
+static PyObject * get_client_name(PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+    return Py_BuildValue("s", jack_get_client_name(client->pjc));
+}
+
+/** Commit a chunk of audio for the outgoing stream, if any.
+  * Return the next chunk of audio from the incoming stream, if any
+  */
+static PyObject* process(PyObject* self, PyObject *args)
+{
+    int j, c, r;
+    PyArrayObject *input_array;
+    PyArrayObject *output_array;
+
+    pyjack_client_t * client = self_or_global_client(self);
+    if(! client->active) {
+        PyErr_SetString(JackUsageError, "Client is not active.");
+        return NULL;
+    }
+
+    // Import the first and only arg...
+    if (! PyArg_ParseTuple(args, "O!O!", &PyArray_Type, &output_array, &PyArray_Type, &input_array))
+        return NULL;
+
+    if(input_array->descr->type_num != PyArray_FLOAT || output_array->descr->type_num != PyArray_FLOAT) {
+        PyErr_SetString(PyExc_ValueError, "arrays must be of type float");
+        return NULL;
+    }
+    if(input_array->nd != 2 || output_array->nd != 2) {
+        printf("%d, %d\n", input_array->nd, output_array->nd);
+        PyErr_SetString(PyExc_ValueError, "arrays must be two dimensional");
+        return NULL;
+    }
+    if((client->num_inputs > 0 && input_array->dimensions[1] != client->buffer_size) || 
+       (client->num_outputs > 0 && output_array->dimensions[1] != client->buffer_size)) {
+        PyErr_SetString(PyExc_ValueError, "columns of arrays must match buffer size.");
+        return NULL;
+    }
+    if(client->num_inputs > 0 && input_array->dimensions[0] != client->num_inputs) {
+        PyErr_SetString(PyExc_ValueError, "rows for input array must match number of input ports");
+        return NULL;
+    }
+    if(client->num_outputs > 0 && output_array->dimensions[0] != client->num_outputs) {
+        PyErr_SetString(PyExc_ValueError, "rows for output array must match number of output ports");
+        return NULL;
+    }
+
+    // Get input data
+    // If we are out of sync, there might be bad data in the buffer
+    // So we have to throw that away first...
+    if (client->input_buffer_size) {
+        r = read(client->input_pipe[R], client->input_buffer_1, client->input_buffer_size);
+
+        // Copy data into array...
+        for(c = 0; c < client->num_inputs; c++) {
+            for(j = 0; j < client->buffer_size; j++) {
+                memcpy(
+                    input_array->data + (c*input_array->strides[0] + j*input_array->strides[1]), 
+                    client->input_buffer_1 + j + (c*client->buffer_size), 
+                    sizeof(float)
+                );
+            }
+        }
+
+        if(!client->iosync) {
+            PyErr_SetString(JackInputSyncError, "Input data stream is not synchronized.");
+            return NULL;
+        }
+    }
+
+    if (client->output_buffer_size) {
+        // Copy output data into output buffer...
+        for(c = 0; c < client->num_outputs; c++) {
+            for(j = 0; j < client->buffer_size; j++) {
+                memcpy(&client->output_buffer_1[j + (c*client->buffer_size)],
+                       output_array->data + c*output_array->strides[0] + j*output_array->strides[1],
+                       sizeof(float)
+                );
+            }
+        }
+
+        // Send... raise an exception if the output data stream is full.
+        r = write(client->output_pipe[W], client->output_buffer_1, client->output_buffer_size);
+
+        if(r != client->output_buffer_size) {
+            PyErr_SetString(JackOutputSyncError, "Failed to write output data.");
+            return NULL;
+        }
+    }
+
+    // Okay...    
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+// Return event status numbers...
+static PyObject* check_events(PyObject* self, PyObject *args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+
+    PyObject* d;
+    d = PyDict_New();
+    if(d == NULL) return NULL;
+
+    PyDict_SetItemString(d, "graph_ordering", Py_BuildValue("i", client->event_graph_ordering));
+    PyDict_SetItemString(d, "port_registration", Py_BuildValue("i", client->event_port_registration));
+    PyDict_SetItemString(d, "xrun", Py_BuildValue("i", client->event_xrun));
+    PyDict_SetItemString(d, "shutdown", Py_BuildValue("i", client->event_shutdown));
+    PyDict_SetItemString(d, "hangup", Py_BuildValue("i", client->event_hangup));
+
+    // Reset all
+    client->event_graph_ordering = 0;
+    client->event_port_registration = 0;
+    client->event_xrun = 0;
+    client->event_shutdown = 0;
+    client->event_hangup = 0;
+
+    return d;
+}
+
+static PyObject* get_frame_time(PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    int frt = jack_frame_time(client->pjc);
+    return Py_BuildValue("i", frt);
+}
+
+static PyObject* get_current_transport_frame(PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    int ftr = jack_get_current_transport_frame(client->pjc);
+    return Py_BuildValue("i", ftr);
+}
+
+static PyObject* transport_locate (PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+    jack_nframes_t newfr;
+
+    if (! PyArg_ParseTuple(args, "i", &newfr))
+        return NULL;
+
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    jack_transport_locate (client->pjc,newfr);
+    return Py_None;
+}
+
+static PyObject* get_transport_state (PyObject* self, PyObject* args)
+{
+    //int state;
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    jack_transport_state_t transport_state;
+    transport_state = jack_transport_query (client->pjc, NULL);
+
+    return Py_BuildValue("i", transport_state);
+}
+
+#ifdef JACK2
+static PyObject* get_version(PyObject* self, PyObject* args)
+{
+    int major, minor, micro, proto;
+    jack_get_version(&major, &minor, &micro, &proto);
+    return Py_BuildValue("iiii", major, minor, micro, proto);
+}
+#endif
+
+#ifdef JACK2
+static PyObject* get_version_string(PyObject* self, PyObject* args)
+{
+    const char* version;
+    version = jack_get_version_string();
+    return Py_BuildValue("s", version);
+}
+#endif
+
+static PyObject* get_cpu_load(PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    float cpu_load = jack_cpu_load(client->pjc);
+
+    return Py_BuildValue("f", cpu_load);
+}
+
+static PyObject* get_port_short_name(PyObject* self, PyObject* args)
+{
+    char * port_name;
+
+    if (! PyArg_ParseTuple(args, "s", &port_name))
+        return NULL;
+
+    if (port_name == NULL) {
+        PyErr_SetString(JackError, "Port name cannot be empty.");
+        return NULL;
+    }
+
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    jack_port_t * port = jack_port_by_name(client->pjc, port_name);
+    if (!port) {
+        PyErr_SetString(JackError, "Port name cannot be empty.");
+        return NULL;
+    }
+    const char * port_short_name = jack_port_short_name(port);
+
+    return Py_BuildValue("s", port_short_name);
+}
+
+static PyObject* get_port_type(PyObject* self, PyObject* args)
+{
+    char * port_name;
+
+    if (! PyArg_ParseTuple(args, "s", &port_name))
+        return NULL;
+
+    if (port_name == NULL) {
+        PyErr_SetString(JackError, "Port name cannot be empty.");
+        return NULL;
+    }
+
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    jack_port_t * port = jack_port_by_name(client->pjc, port_name);
+    if (!port) {
+        PyErr_SetString(JackError, "Port name cannot be empty.");
+        return NULL;
+    }
+    const char * port_type = jack_port_type(port);
+
+    return Py_BuildValue("s", port_type);
+}
+
+#ifdef JACK2
+static PyObject* get_port_type_id(PyObject* self, PyObject* args)
+{
+    char * port_name;
+
+    if (! PyArg_ParseTuple(args, "s", &port_name))
+        return NULL;
+
+    if (port_name == NULL) {
+        PyErr_SetString(JackError, "Port name cannot be empty.");
+        return NULL;
+    }
+
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    jack_port_t * port = jack_port_by_name(client->pjc, port_name);
+    if (!port) {
+        PyErr_SetString(JackError, "Port name cannot be empty.");
+        return NULL;
+    }
+
+    jack_port_type_id_t port_type_id = jack_port_type_id(port);
+
+    int ret = port_type_id;
+    return Py_BuildValue("i", ret);
+}
+#endif
+
+static PyObject* is_realtime(PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    int realtime = jack_is_realtime(client->pjc);
+    return Py_BuildValue("i", realtime);
+}
+
+static PyObject* port_is_mine(PyObject* self, PyObject* args)
+{
+    char * port_name;
+
+    if (! PyArg_ParseTuple(args, "s", &port_name))
+        return NULL;
+
+    if (port_name == NULL) {
+        PyErr_SetString(JackError, "Port name cannot be empty.");
+        return NULL;
+    }
+
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    jack_port_t * port = jack_port_by_name(client->pjc, port_name);
+    if (!port) {
+        PyErr_SetString(JackError, "Port name cannot be empty.");
+        return NULL;
+    }
+
+    int port_mine = jack_port_is_mine(client->pjc, port);
+    return Py_BuildValue("i", port_mine);
+}
+
+
+static PyObject* transport_stop (PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    jack_transport_stop (client->pjc);
+
+    return Py_None;
+}
+
+static PyObject* transport_start (PyObject* self, PyObject* args)
+{
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    jack_transport_start (client->pjc);
+
+    return Py_None;
+}
+
+static PyObject* set_buffer_size(PyObject* self, PyObject* args)
+{
+    int size;
+
+    if (! PyArg_ParseTuple(args, "i", &size))
+        return NULL;
+
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    jack_nframes_t nsize = size;
+    jack_set_buffer_size(client->pjc, nsize);
+
+    return Py_None;
+}
+
+// set_buffer_size
+static PyObject* set_freewheel(PyObject* self, PyObject* args)
+{
+  int onoff;
+
+  if (! PyArg_ParseTuple(args, "i", &onoff))
+    return NULL;
+
+  pyjack_client_t * client = self_or_global_client(self);
+  if(client->pjc == NULL) {
+    PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+    return NULL;
+  }
+
+  int ret = jack_set_freewheel(client->pjc, onoff);
+  return Py_BuildValue("i", ret);
+}
+
+static PyObject* set_sync_timeout(PyObject* self, PyObject* args)
+{
+    int time;
+
+    if (! PyArg_ParseTuple(args, "i", &time))
+        return NULL;
+
+    pyjack_client_t * client = self_or_global_client(self);
+    if(client->pjc == NULL) {
+        PyErr_SetString(JackNotConnectedError, "Jack connection has not yet been established.");
+        return NULL;
+    }
+
+    jack_time_t timeout = time;
+    jack_set_sync_timeout(client->pjc, timeout);
+
+    return Py_None;
+}
+
+
+// Python Module definition ---------------------------------------------------
+
+static PyMethodDef pyjack_methods[] = {
+  {"attach",             attach,                  METH_VARARGS, "attach(name):\n  Attach client to the Jack server"},
+  {"detach",             detach,                  METH_VARARGS, "detach():\n  Detach client from the Jack server"},
+  {"activate",           activate,                METH_VARARGS, "activate():\n  Activate audio processing"},
+  {"deactivate",         deactivate,              METH_VARARGS, "deactivate():\n  Deactivate audio processing"},
+  {"connect",            port_connect,            METH_VARARGS, "connect(source, destination):\n  Connect two ports, given by name"},
+  {"disconnect",         port_disconnect,         METH_VARARGS, "disconnect(source, destination):\n  Disconnect two ports, given by name"},
+  {"process",            process,                 METH_VARARGS, "process(output_array, input_array):\n  Exchange I/O data with RT Jack thread"},
+  {"get_client_name",    get_client_name,         METH_VARARGS, "client_name():\n  Returns the actual name of the client"},
+  {"register_port",      register_port,           METH_VARARGS, "register_port(name, flags):\n  Register a new port for this client"},
+  {"unregister_port",    unregister_port,         METH_VARARGS, "unregister_port(name):\n  Unregister an existing port for this client"},
+  {"get_ports",          get_ports,               METH_VARARGS, "get_ports():\n  Get a list of all ports in the Jack graph"},
+  {"get_port_flags",     get_port_flags,          METH_VARARGS, "get_port_flags(port):\n  Return flags of a port (flags are bits in an integer)"},
+  {"get_connections",    get_connections,         METH_VARARGS, "get_connections():\n  Get a list of all ports connected to a port"},
+  {"get_buffer_size",    get_buffer_size,         METH_VARARGS, "get_buffer_size():\n  Get the buffer size currently in use"},
+  {"get_sample_rate",    get_sample_rate,         METH_VARARGS, "get_sample_rate():\n  Get the sample rate currently in use"},
+  {"get_freewheel",      get_freewheel,           METH_VARARGS, "get_freewheel():\n  Returns 1 if the JACK freewheel mode is started"},
+  {"check_events",       check_events,            METH_VARARGS, "check_events():\n  Check for event notifications"},
+  {"get_frame_time",     get_frame_time,          METH_VARARGS, "get_frame_time():\n  Returns the current frame time"},
+  {"get_current_transport_frame", get_current_transport_frame,  METH_VARARGS, "get_current_transport_frame():\n  Returns the current transport frame"},
+  {"transport_locate",   transport_locate,        METH_VARARGS, "transport_locate(frame):\n  Sets the current transport frame"},
+  {"get_transport_state",get_transport_state,     METH_VARARGS, "get_transport_state():\n  Returns the current transport state"},
+  {"transport_stop",     transport_stop,          METH_VARARGS, "transport_stop():\n  Stopping transport"},
+  {"transport_start",    transport_start,         METH_VARARGS, "transport_start():\n  Starting transport"},
+#ifdef JACK2
+  {"get_version",        get_version,             METH_VARARGS, "get_version():\n  Returns the version of JACK, in form of several numbers"},
+  {"get_version_string", get_version_string,      METH_VARARGS, "get_version_string():\n  Returns the version of JACK, in form of a string"},
+#endif
+  {"get_cpu_load",       get_cpu_load,            METH_VARARGS, "get_cpu_load():\n  Returns the current CPU load estimated by JACK"},
+  {"get_port_short_name",get_port_short_name,     METH_VARARGS, "get_port_short_name(port):\n  Returns the short name of the port (not including the \"client_name:\" prefix)"},
+  {"get_port_type",      get_port_type,           METH_VARARGS, "get_port_type(port):\n  Returns the port type (in a string)"},
+#ifdef JACK2
+  {"get_port_type_id",   get_port_type_id,        METH_VARARGS, "get_port_type_id(port):\n  Returns the port type id"},
+#endif
+  {"is_realtime",        is_realtime,             METH_VARARGS, "is_realtime():\n  Returns 1 if the JACK subsystem is running with -R (--realtime)"},
+  {"port_is_mine",       port_is_mine,            METH_VARARGS, "port_is_mine(port):\n  Returns 1 if port belongs to the running client"},
+  {"set_buffer_size",    set_buffer_size,         METH_VARARGS, "set_buffer_size(size):\n  Sets Jack Buffer Size (minimum appears to be 16)."},
+  {"set_freewheel",      set_freewheel,           METH_VARARGS, "set_freewheel(onoff):\n  Start/Stop JACK freewheel mode."},
+  {"set_sync_timeout",   set_sync_timeout,        METH_VARARGS, "set_sync_timeout(time):\n  Sets the delay (in microseconds) before the timeout expires."},
+  {NULL, NULL}
+};
+
+static PyObject *
+Client_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    pyjack_client_t *self = (pyjack_client_t *)type->tp_alloc(type, 0);
+    if (self == NULL) return NULL;
+
+    pyjack_init(self);
+
+    return (PyObject *)self;
+}
+
+static int
+Client_init(PyObject *self, PyObject *args, PyObject *kwds)
+{      
+    int status = 0;
+    if (!attach(self, args)) status = -1;
+    return status;
+}
+
+static void
+Client_dealloc(PyObject* self)
+{
+puts("pyjack: dealloc");
+    detach(self, Py_None);
+    self->ob_type->tp_free(self);
+}
+
+
+static PyTypeObject pyjack_ClientType = {
+    PyObject_HEAD_INIT(NULL)
+    /*ob_size*/             0, 
+    /*tp_name*/             "jack.Client",
+    /*tp_basicsize*/        sizeof(pyjack_client_t),
+    /*tp_itemsize*/         0,
+    /*tp_dealloc*/          Client_dealloc,
+    /*tp_print*/            0,
+    /*tp_getattr*/          0,
+    /*tp_setattr*/          0,
+    /*tp_compare*/          0,
+    /*tp_repr*/             0,
+    /*tp_as_number*/        0,
+    /*tp_as_sequence*/      0,
+    /*tp_as_mapping*/       0,
+    /*tp_hash */            0,
+    /*tp_call*/             0,
+    /*tp_str*/              0,
+    /*tp_getattro*/         0,
+    /*tp_setattro*/         0,
+    /*tp_as_buffer*/        0,
+    /*tp_flags*/            Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    /* tp_doc */            "JACK client object.\n"
+                            "Instatiate a jack.Client to interact with a jack server.\n"
+                            ,
+    /* tp_traverse */       0,
+    /* tp_clear */          0,
+    /* tp_richcompare */    0,
+    /* tp_weaklistoffset */ 0,
+    /* tp_iter */           0,
+    /* tp_iternext */       0,
+    /* tp_methods */        pyjack_methods,
+    /* 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 */           Client_init,
+    /* tp_alloc */          0,
+    /* tp_new */            Client_new,
+};
+
+
+
+#ifndef PyMODINIT_FUNC  /* declarations for DLL import/export */
+#define PyMODINIT_FUNC void
+#endif
+PyMODINIT_FUNC
+initjack(void)
+{
+  PyObject *m, *d;
+
+  if (PyType_Ready(&pyjack_ClientType) < 0)
+    return;
+  m = Py_InitModule3("jack", pyjack_methods,
+       "This module provides bindings to manage clients for the Jack Audio Connection Kit architecture");
+  if (m == NULL)
+    goto fail;
+  d = PyModule_GetDict(m);
+  if (d == NULL)
+    goto fail;
+
+  Py_INCREF(&pyjack_ClientType);
+  PyModule_AddObject(m, "Client", (PyObject *)&pyjack_ClientType);
+
+// Jack errors 
+  JackError = PyErr_NewException("jack.Error", NULL, NULL);
+  JackNotConnectedError = PyErr_NewException("jack.NotConnectedError", NULL, NULL);
+  JackUsageError = PyErr_NewException("jack.UsageError", NULL, NULL);
+  JackInputSyncError = PyErr_NewException("jack.InputSyncError", NULL, NULL);
+  JackOutputSyncError = PyErr_NewException("jack.OutputSyncError", NULL, NULL);
+
+  PyDict_SetItemString(d, "Error", JackError);
+  PyDict_SetItemString(d, "NotConnectedError", JackNotConnectedError);
+  PyDict_SetItemString(d, "UsageError", JackUsageError);
+  PyDict_SetItemString(d, "InputSyncError", JackInputSyncError);
+  PyDict_SetItemString(d, "OutputSyncError", JackOutputSyncError);
+// Jack flags
+  PyDict_SetItemString(d, "IsInput", Py_BuildValue("i", JackPortIsInput));
+  PyDict_SetItemString(d, "IsOutput", Py_BuildValue("i", JackPortIsOutput));
+  PyDict_SetItemString(d, "IsTerminal", Py_BuildValue("i", JackPortIsTerminal));
+  PyDict_SetItemString(d, "IsPhysical", Py_BuildValue("i", JackPortIsPhysical));
+  PyDict_SetItemString(d, "CanMonitor", Py_BuildValue("i", JackPortCanMonitor));
+  PyDict_SetItemString(d, "TransportStopped", Py_BuildValue("i", JackTransportStopped));
+  PyDict_SetItemString(d, "TransportRolling", Py_BuildValue("i", JackTransportRolling));
+  PyDict_SetItemString(d, "TransportStarting", Py_BuildValue("i", JackTransportStarting));
+
+  // Enable Numeric module
+  import_array();
+
+  if (PyErr_Occurred())
+    goto fail;
+
+  // Init jack data structures
+  pyjack_init(&global_client);
+
+  return;
+
+fail:
+  Py_FatalError("Failed to initialize module pyjack");
+}
diff --git a/pyjack-0.5.2/setup.py b/pyjack-0.5.2/setup.py
new file mode 100755 (executable)
index 0000000..f59459d
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Distutils installer for PyJack
+
+# Test for Jack2
+#---------------------------------------------------#
+import os
+if os.path.exists("/usr/local/include/jack/jack.h"):
+  path = "/usr/local/include/jack/jack.h"
+elif os.path.exists("/usr/include/jack/jack.h"):
+  path = "/usr/include/jack/jack.h"
+else:
+  print "You don't seem to have the jack headers installed.\nPlease install them first"
+  exit(-1)
+
+test = open(path).read()
+
+if ("jack_get_version_string" in test):
+  os.system("patch -f -s -p0 -r build/jack2.rej < ./patches/enable-jack2.diff > /dev/null")
+else:
+  os.system("patch -R -f -s -p0 -r build/jack2.rej < ./patches/enable-jack2.diff > /dev/null")
+#----------------------------------------------------#
+
+
+from distutils.core import setup, Extension
+import numpy.distutils
+
+numpy_include_dirs = numpy.distutils.misc_util.get_numpy_include_dirs()
+
+setup(
+    name = "pyjack",
+    version = "0.5.1",
+    description = "Python bindings for the Jack Audio Server",
+    author = "Andrew W. Schmeder, falkTX",
+    author_email = "andy@a2hd.com",
+    url = "http://www.a2hd.com/software",
+
+    ext_modules = [Extension("jack", ["pyjack.c"], libraries=["jack", "dl"], include_dirs=numpy_include_dirs)],
+    )
+