From 233bc020ffd37317b478fdab3e55b3233f2019b6 Mon Sep 17 00:00:00 2001 From: Nikita Zlobin Date: Mon, 27 Dec 2010 04:17:48 +0500 Subject: [PATCH] Distribute pyjack with freewheel-related functionality --- pyjack-0.5.2/Changelog | 43 + pyjack-0.5.2/LICENSE | 340 +++++++ pyjack-0.5.2/README | 339 ++++++ pyjack-0.5.2/TODO | 24 + pyjack-0.5.2/blender/.directory | 3 + pyjack-0.5.2/blender/README | 29 + pyjack-0.5.2/blender/blender-jacktrans.py | 157 +++ pyjack-0.5.2/debian/.directory | 4 + pyjack-0.5.2/debian/changelog | 35 + pyjack-0.5.2/debian/compat | 1 + pyjack-0.5.2/debian/control | 31 + pyjack-0.5.2/debian/copyright | 27 + pyjack-0.5.2/debian/pyjack-0.4.egg-info | 10 + pyjack-0.5.2/debian/python-jack-demos.install | 2 + pyjack-0.5.2/debian/python-jack.install | 1 + pyjack-0.5.2/debian/rules | 11 + pyjack-0.5.2/demos/.directory | 3 + pyjack-0.5.2/demos/alsa_midi_busconnect.py | 77 ++ pyjack-0.5.2/demos/capture.py | 81 ++ pyjack-0.5.2/demos/just_capture.py | 91 ++ pyjack-0.5.2/demos/qtransport.py | 82 ++ pyjack-0.5.2/demos/qtransport_gui.ui | 151 +++ pyjack-0.5.2/demos/testtone.py | 41 + pyjack-0.5.2/demos/transporter.py | 52 + pyjack-0.5.2/install.sh | 4 + pyjack-0.5.2/patches/enable-jack2.diff | 11 + pyjack-0.5.2/pyjack.c | 1360 +++++++++++++++++++++++++ pyjack-0.5.2/setup.py | 40 + 28 files changed, 3050 insertions(+) create mode 100644 pyjack-0.5.2/Changelog create mode 100644 pyjack-0.5.2/LICENSE create mode 100644 pyjack-0.5.2/README create mode 100644 pyjack-0.5.2/TODO create mode 100644 pyjack-0.5.2/blender/.directory create mode 100644 pyjack-0.5.2/blender/README create mode 100644 pyjack-0.5.2/blender/blender-jacktrans.py create mode 100644 pyjack-0.5.2/debian/.directory create mode 100644 pyjack-0.5.2/debian/changelog create mode 100644 pyjack-0.5.2/debian/compat create mode 100644 pyjack-0.5.2/debian/control create mode 100644 pyjack-0.5.2/debian/copyright create mode 100644 pyjack-0.5.2/debian/pyjack-0.4.egg-info create mode 100644 pyjack-0.5.2/debian/python-jack-demos.install create mode 100644 pyjack-0.5.2/debian/python-jack.install create mode 100755 pyjack-0.5.2/debian/rules create mode 100644 pyjack-0.5.2/demos/.directory create mode 100755 pyjack-0.5.2/demos/alsa_midi_busconnect.py create mode 100755 pyjack-0.5.2/demos/capture.py create mode 100755 pyjack-0.5.2/demos/just_capture.py create mode 100755 pyjack-0.5.2/demos/qtransport.py create mode 100644 pyjack-0.5.2/demos/qtransport_gui.ui create mode 100755 pyjack-0.5.2/demos/testtone.py create mode 100755 pyjack-0.5.2/demos/transporter.py create mode 100755 pyjack-0.5.2/install.sh create mode 100644 pyjack-0.5.2/patches/enable-jack2.diff create mode 100644 pyjack-0.5.2/pyjack.c create mode 100755 pyjack-0.5.2/setup.py diff --git a/pyjack-0.5.2/Changelog b/pyjack-0.5.2/Changelog new file mode 100644 index 0000000..d68d279 --- /dev/null +++ b/pyjack-0.5.2/Changelog @@ -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 index 0000000..d60c31a --- /dev/null +++ b/pyjack-0.5.2/LICENSE @@ -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. + + 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.) + +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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 0000000..399bdc4 --- /dev/null +++ b/pyjack-0.5.2/README @@ -0,0 +1,339 @@ +PyJack version 0.x +Original code by Andrew W. Schmeder , in2003 +Transport support by Il'dar Akhmetgaleev , in Jan 14 2008 +Revision and packaging by falkTX , in Feb 2010 +Implemented changes by the Clam Team , in Mar 2010 +More Jack implementations by falkTX , 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 "", 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 index 0000000..0b171e3 --- /dev/null +++ b/pyjack-0.5.2/TODO @@ -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 index 0000000..a54bcb7 --- /dev/null +++ b/pyjack-0.5.2/blender/.directory @@ -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 index 0000000..b42b061 --- /dev/null +++ b/pyjack-0.5.2/blender/README @@ -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 index 0000000..55cea07 --- /dev/null +++ b/pyjack-0.5.2/blender/blender-jacktrans.py @@ -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 index 0000000..0561bbd --- /dev/null +++ b/pyjack-0.5.2/debian/.directory @@ -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 index 0000000..d8017eb --- /dev/null +++ b/pyjack-0.5.2/debian/changelog @@ -0,0 +1,35 @@ +pyjack (0.5.2-1~build1) lucid; urgency=low + + * New upstream release + + -- falkTX Mon, 12 Jul 2010 09:33:35 +0100 + +pyjack (0.5.1-1~build1) lucid; urgency=low + + * New upstream release + + -- falkTX Wed, 21 Apr 2010 13:50:40 +0100 + +pyjack (0.5-1~build1) lucid; urgency=low + + * New upstream release + + -- falkTX Tue, 20 Apr 2010 17:27:28 +0100 + +pyjack (0.4-1~build1) lucid; urgency=low + + * New upstream release + + -- falkTX Wed, 07 Apr 2010 14:44:32 +0100 + +pyjack (0.3-1~build1) lucid; urgency=low + + * New upstream release + + -- falkTX Fri, 26 Mar 2010 01:41:28 +0000 + +pyjack (0.2-1~build1) lucid; urgency=low + + * Initial release + + -- falkTX 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 index 0000000..7f8f011 --- /dev/null +++ b/pyjack-0.5.2/debian/compat @@ -0,0 +1 @@ +7 diff --git a/pyjack-0.5.2/debian/control b/pyjack-0.5.2/debian/control new file mode 100644 index 0000000..b47b871 --- /dev/null +++ b/pyjack-0.5.2/debian/control @@ -0,0 +1,31 @@ +Source: pyjack +Section: python +Priority: optional +Maintainer: falkTX +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 index 0000000..32ab3d6 --- /dev/null +++ b/pyjack-0.5.2/debian/copyright @@ -0,0 +1,27 @@ +This package was debianized by: + + falkTX 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 + +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 index 0000000..f969c53 --- /dev/null +++ b/pyjack-0.5.2/debian/pyjack-0.4.egg-info @@ -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 index 0000000..a8a3c0b --- /dev/null +++ b/pyjack-0.5.2/debian/python-jack-demos.install @@ -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 index 0000000..0c3ecfc --- /dev/null +++ b/pyjack-0.5.2/debian/python-jack.install @@ -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 index 0000000..f700e94 --- /dev/null +++ b/pyjack-0.5.2/debian/rules @@ -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 index 0000000..bf0b297 --- /dev/null +++ b/pyjack-0.5.2/demos/.directory @@ -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 index 0000000..2471c0c --- /dev/null +++ b/pyjack-0.5.2/demos/alsa_midi_busconnect.py @@ -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 index 0000000..f791d80 --- /dev/null +++ b/pyjack-0.5.2/demos/capture.py @@ -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 index 0000000..9f8b5d6 --- /dev/null +++ b/pyjack-0.5.2/demos/just_capture.py @@ -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 index 0000000..1e9991f --- /dev/null +++ b/pyjack-0.5.2/demos/qtransport.py @@ -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 index 0000000..1523bbd --- /dev/null +++ b/pyjack-0.5.2/demos/qtransport_gui.ui @@ -0,0 +1,151 @@ + + + Dialog + + + + 0 + 0 + 376 + 115 + + + + QTransport Example + + + + + + + + Transport Frame: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 00000000 + + + + + + + + + + + Transport Time: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 0:00:00 + + + + + + + + + + + Transport State: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Unkown + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + << + + + true + + + + + + + |> + + + true + + + + + + + [] + + + + + + + >> + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + diff --git a/pyjack-0.5.2/demos/testtone.py b/pyjack-0.5.2/demos/testtone.py new file mode 100755 index 0000000..5b61858 --- /dev/null +++ b/pyjack-0.5.2/demos/testtone.py @@ -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 index 0000000..f117dd1 --- /dev/null +++ b/pyjack-0.5.2/demos/transporter.py @@ -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 index 0000000..28c3450 --- /dev/null +++ b/pyjack-0.5.2/install.sh @@ -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 index 0000000..baa1bb7 --- /dev/null +++ b/pyjack-0.5.2/patches/enable-jack2.diff @@ -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 index 0000000..711a8a8 --- /dev/null +++ b/pyjack-0.5.2/pyjack.c @@ -0,0 +1,1360 @@ +/** + * pyjackc - C module implementation for pyjack + * + * Copyright 2003 Andrew W. Schmeder + * Copyright 2010 Filipe Coelho (aka 'falkTX') + * + * 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 +#include + +// C standard +#include +#include +#include +#include +#include +#include +#include + +/* +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;inum_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 (;inum_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;inum_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 (;inum_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, µ, &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 index 0000000..f59459d --- /dev/null +++ b/pyjack-0.5.2/setup.py @@ -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)], + ) + -- 2.11.4.GIT