Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
multimedia:libs
jack-example-tools
jack-example-tools-1.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File jack-example-tools-1.obscpio of Package jack-example-tools
07070100000000000081A400000000000000000000000161E2F7EE00000627000000000000000000000000000000000000002100000000jack-example-tools-1/.cirrus.ymltask: freebsd_instance: matrix: - image_family: freebsd-12-3 - image_family: freebsd-13-0 environment: CFLAGS: -O2 -pipe -fPIC -fstack-protector-strong -fno-strict-aliasing -I/usr/local/include CPPFLAGS: -O2 -pipe -fPIC -fstack-protector-strong -fno-strict-aliasing -I/usr/local/include LDFLAGS: -lreadline -L/usr/local/lib -fstack-protector-strong # Install jack2 from source - replace by package once 1.9.20 is out. jack2_dependencies_script: - pkg install -y pkgconf python3 libsndfile libsamplerate libsysinfo readline alsa-lib dbus expat opus git jack2_source_script: - git clone --branch develop --depth 1 https://github.com/jackaudio/jack2.git /jack2 jack2_config_script: - cd /jack2 && python3 ./waf configure --celt=no --sndfile=yes --samplerate=yes --alsa=yes --dbus --classic --autostart=dbus --readline=yes --opus=yes --example-tools=no --prefix /usr/local --pkgconfigdir libdata/pkgconfig jack2_build_script: - cd /jack2 && python3 ./waf jack2_install_script: - cd /jack2 && python3 ./waf install prepare_script: - mkdir /Install dependencies_script: - pkg install -y pkgconf python3 libsndfile libsamplerate libsysinfo readline alsa-lib zita-alsa-pcmi zita-resampler opus meson ninja config_script: - meson --prefix /Install --mandir man --buildtype release --strip build build_script: # Workaround for missing alloca headers - remove when resolved. - touch build/tools/alloca.h - ninja -C build install_script: - DESTDIR="/Install" meson install -C build 07070100000001000041ED00000000000000000000000161E2F7EE00000000000000000000000000000000000000000000001D00000000jack-example-tools-1/.github07070100000002000041ED00000000000000000000000161E2F7EE00000000000000000000000000000000000000000000002700000000jack-example-tools-1/.github/workflows07070100000003000081A400000000000000000000000161E2F7EE0000054D000000000000000000000000000000000000003100000000jack-example-tools-1/.github/workflows/build.yml--- name: Build on various Operating Systems on: push: branches: [main] pull_request: branches: [main] jobs: build_arch_linux_jack1: runs-on: ubuntu-latest container: image: archlinux:latest steps: - uses: actions/checkout@v2 - name: Install dependencies run: pacman --noconfirm -Syu alsa-lib base-devel celt meson opus readline libsamplerate libsndfile zita-alsa-pcmi zita-resampler - name: Install jack1 run: | printf "[pro-audio]\nServer = https://pkgbuild.com/~dvzrv/repos/pro-audio/\$arch\n" >> /etc/pacman.conf pacman -Syy pacman --noconfirm -S jack - name: Build jack-example-tools run: meson build && ninja -C build - name: Install jack-example-tools run: ninja -C build install build_arch_linux_jack2: runs-on: ubuntu-latest container: image: archlinux:latest steps: - uses: actions/checkout@v2 - name: Install dependencies run: pacman --noconfirm -Syu alsa-lib base-devel celt meson opus readline libsamplerate libsndfile zita-alsa-pcmi zita-resampler - name: Install jack2 run: pacman --noconfirm -S jack2 - name: Build jack-example-tools run: meson build && ninja -C build - name: Install jack-example-tools run: ninja -C build install 07070100000004000081A400000000000000000000000161E2F7EE00000241000000000000000000000000000000000000002F00000000jack-example-tools-1/.github/workflows/irc.ymlname: irc on: [push] jobs: notification: runs-on: ubuntu-latest name: IRC notification steps: - name: Format message id: message run: | message="${{ github.actor }} pushed $(echo '${{ github.event.commits[0].message }}' | head -n 1) ${{ github.event.commits[0].url }}" echo ::set-output name=message::"${message}" - name: IRC notification uses: Gottox/irc-message-action@v2 with: channel: '#jack' nickname: jackaudio-bot message: ${{ steps.message.outputs.message }} 07070100000005000081A400000000000000000000000161E2F7EE00000008000000000000000000000000000000000000002000000000jack-example-tools-1/.gitignore/build/ 07070100000006000081A400000000000000000000000161E2F7EE00000458000000000000000000000000000000000000002200000000jack-example-tools-1/CHANGELOG.md# Changelog ## [Unreleased] ### Added ### Changed ### Deleted ## [1] ### Added - Add legacy [example-clients](https://github.com/jackaudio/example-clients) and [tools](https://github.com/jackaudio/tools) - Add man pages for example-clients and tools from [jack2](https://github.com/jackaudio/jack2) - Add jack2-only example-clients - Add license files for example-clients and tools and imported zalsa files - Add meson build system - Add CI builds against jack1 and jack2 in an Arch Linux container - Add supported jack version to project description: jack1 (>=0.126.0), jack2 (>=1.9.20), pipewire-jack (>=0.3.44) - Add support to compile against different jack implementations based on available features and function definitions ### Changed - Consolidate example-clients and tools with the versions in [jack2](https://github.com/jackaudio/jack2) - Apply commits from open pull requests in [example-clients](https://github.com/jackaudio/example-clients) and [tools](https://github.com/jackaudio/tools) - Make target executables and libraries compatible with jack1 and jack2 (if possible) 07070100000007000081A400000000000000000000000161E2F7EE000006E1000000000000000000000000000000000000002500000000jack-example-tools-1/CONTRIBUTING.md# Contributing Guidelines These are the contributing guidelines for jack-example-tools. All contributions, unless noted otherwise, are licensed under the terms of the GPL-2.0-or-later (see [LICENSE](LICENSE)). Contributions to the [tools/zalsa/](tools/zalsa/) are licensed under the terms of the GPL-3.0-or-later (see [tools/zalsa/LICENSE](tools/zalsa/LICENSE)). Problems with and feature requests for the project may be reported in the [issue tracker](https://github.com/jackaudio/jack-example-tools/issues). Changes to the code-base can be provided via [pull requests](https://github.com/jackaudio/jack-example-tools/pulls). ## Continuous Integration The project is built in a [continuous integration (CI)](https://github.com/jackaudio/jack-example-tools/actions) pipeline handled by github actions upon pull request and push to the default branch. The integration aims at covering all jack implementations on as many operating systems as possible. Changes to the project may only be merged if the CI finishes successfully. ## Releases New releases are created by * adding a commit that * updates the project version in [meson.build](meson.build) * updates the [changelog](CHANGELOG.md) to the current version while adding a new (empty) subsection for `[Unreleased]` modifications with `Added`, `Changed` and `Deleted` subsubsections. * tagging the commit using a signed tag (i.e. `tag -s <VERSION>`) according to the new project version ### Versioning The project's version is defined as `<MAJOR>` (e.g. `1` or `2`), which is reflected both in the build system and the tag. ## Testing Contributors are expected to test their changes to the project on as many operating systems as available to them *before* opening a pull request. 07070100000008000081A400000000000000000000000161E2F7EE00003B74000000000000000000000000000000000000001D00000000jack-example-tools-1/LICENSE GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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 07070100000009000081A400000000000000000000000161E2F7EE00000BF4000000000000000000000000000000000000001F00000000jack-example-tools-1/README.md# JACK example tools This repository holds the official JACK example clients and tools, which have been tracked in the [example-clients](https://github.com/jackaudio/example-clients) and [tools](https://github.com/jackaudio/tools) repositories in the past. ## Dependencies The project requires the following dependencies: * [alsa-lib](https://www.alsa-project.org/wiki/Main_Page) (required when building `alsa_in` and `alsa_out` or ZALSA internal clients) * [jack1](https://github.com/jackaudio/jack1) >= 0.126.0, [jack2](https://github.com/jackaudio/jack2) >= 1.9.20, or [pipewire-jack](https://gitlab.freedesktop.org/pipewire/pipewire) >= 0.3.44 (other versions may work but are not supported) * [opus](https://www.opus-codec.org/) (optional buildtime/ runtime dependency for `jack_netsource`) * [readline](https://tiswww.case.edu/php/chet/readline/rltop.html) (optional buildtime/ runtime dependency for `jack_transport`) * [libsamplerate](https://libsndfile.github.io/libsamplerate/) (required when building `alsa_in` and `alsa_out` or `jack_netsource`) * [libsndfile](https://libsndfile.github.io/libsndfile/) (required when building `jack_rec`) * [libzita-alsa-pcmi](https://kokkinizita.linuxaudio.org/linuxaudio/) (required when building ZALSA internal clients) * [libzita-resampler](https://kokkinizita.linuxaudio.org/linuxaudio/) (required when building ZALSA internal clients) For all available options please refer to [meson_options.txt](meson_options.txt) or run `meson configure` in the project directory. ## Building jack-example-tools uses the [meson build system](https://mesonbuild.com). To configure the project, meson's [universal options](https://mesonbuild.com/Builtin-options.html#universal-options) (e.g. **--prefix**) can be used to prepare a build directory: ```bash meson --prefix=/usr build ``` To build the applications and libraries [ninja](https://ninja-build.org/) is required: ```bash ninja -C build ``` ## Installing Meson is able to install the project components to the system directories (when run as root), while honoring the **DESTDIR** environment variable: ```bash DESTDIR="/some/other/location" meson install -C build ``` ## Releases [Releases of jack-example-tools](https://github.com/jackaudio/jack-example-tools/tags) are created by its current maintainer [Filipe Coelho](https://github.com/falktx) (`62B11043D2F6EB6672D93103CDBAA37ABC74FBA0`). To verify a tag, first import the relevant PGP key: ``` gpg --auto-key-locate wkd,keyserver --search-keys falktx@falktx.com ``` Afterwards a tag can be verified from a clone of this repository: ``` git verify-tag <tag> ``` ## License All files (unless noted otherwise) are licensed under the terms of the **GPL-2.0-or-later** (see [LICENSE](LICENSE)). The code in [tools/zalsa](tools/zalsa) is provided via [Fons Adriansen's zita-ajbridge](https://kokkinizita.linuxaudio.org/linuxaudio/zita-ajbridge-doc/quickguide.html) and licensed under the terms of the **GPL-3.0-or-later** (see [tools/zalsa/LICENSE](tools/zalsa/LICENSE)). 0707010000000A000041ED00000000000000000000000161E2F7EE00000000000000000000000000000000000000000000001C00000000jack-example-tools-1/common0707010000000B000081A400000000000000000000000161E2F7EE0000ABAD000000000000000000000000000000000000002500000000jack-example-tools-1/common/memops.c/* Copyright (C) 2000 Paul Davis 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _ISOC9X_SOURCE 1 #define _ISOC99_SOURCE 1 #define __USE_ISOC9X 1 #define __USE_ISOC99 1 #include <stdio.h> #include <string.h> #include <math.h> #include <memory.h> #include <stdlib.h> #include <stdint.h> #include <limits.h> #ifdef __linux__ #include <endian.h> #endif #include "memops.h" #if defined (__SSE2__) && !defined (__sun__) #include <emmintrin.h> #ifdef __SSE4_1__ #include <smmintrin.h> #endif #endif #if defined (__ARM_NEON__) || defined (__ARM_NEON) #include <arm_neon.h> #endif /* Notes about these *_SCALING values. the MAX_<N>BIT values are floating point. when multiplied by a full-scale normalized floating point sample value (-1.0..+1.0) they should give the maximum value representable with an integer sample type of N bits. Note that this is asymmetric. Sample ranges for signed integer, 2's complement values are -(2^(N-1) to +(2^(N-1)-1) Complications ------------- If we use +2^(N-1) for the scaling factors, we run into a problem: if we start with a normalized float value of -1.0, scaling to 24 bits would give -8388608 (-2^23), which is ideal. But with +1.0, we get +8388608, which is technically out of range. We never multiply a full range normalized value by this constant, but we could multiply it by a positive value that is close enough to +1.0 to produce a value > +(2^(N-1)-1. There is no way around this paradox without wasting CPU cycles to determine which scaling factor to use (i.e. determine if its negative or not, use the right factor). So, for now (October 2008) we use 2^(N-1)-1 as the scaling factor. */ #define SAMPLE_32BIT_SCALING 2147483647.0 #define SAMPLE_24BIT_SCALING 8388607.0f #define SAMPLE_16BIT_SCALING 32767.0f /* these are just values to use if the floating point value was out of range advice from Fons Adriaensen: make the limits symmetrical */ #define SAMPLE_32BIT_MAX 2147483647 #define SAMPLE_32BIT_MIN -2147483647 #define SAMPLE_32BIT_MAX_D 2147483647.0 #define SAMPLE_32BIT_MIN_D -2147483647.0 #define SAMPLE_24BIT_MAX 8388607 #define SAMPLE_24BIT_MIN -8388607 #define SAMPLE_24BIT_MAX_F 8388607.0f #define SAMPLE_24BIT_MIN_F -8388607.0f #define SAMPLE_16BIT_MAX 32767 #define SAMPLE_16BIT_MIN -32767 #define SAMPLE_16BIT_MAX_F 32767.0f #define SAMPLE_16BIT_MIN_F -32767.0f /* these mark the outer edges of the range considered "within" range for a floating point sample value. values outside (and on the boundaries) of this range will be clipped before conversion; values within this range will be scaled to appropriate values for the target sample type. */ #define NORMALIZED_FLOAT_MIN -1.0f #define NORMALIZED_FLOAT_MAX 1.0f /* define this in case we end up on a platform that is missing the real lrintf functions */ #define f_round(f) lrintf(f) #define d_round(f) lrint(f) #define float_16(s, d)\ if ((s) <= NORMALIZED_FLOAT_MIN) {\ (d) = SAMPLE_16BIT_MIN;\ } else if ((s) >= NORMALIZED_FLOAT_MAX) {\ (d) = SAMPLE_16BIT_MAX;\ } else {\ (d) = f_round ((s) * SAMPLE_16BIT_SCALING);\ } /* call this when "s" has already been scaled (e.g. when dithering) */ #define float_16_scaled(s, d)\ if ((s) <= SAMPLE_16BIT_MIN_F) {\ (d) = SAMPLE_16BIT_MIN_F;\ } else if ((s) >= SAMPLE_16BIT_MAX_F) { \ (d) = SAMPLE_16BIT_MAX;\ } else {\ (d) = f_round ((s));\ } #define float_24u32(s, d) \ if ((s) <= NORMALIZED_FLOAT_MIN) {\ (d) = SAMPLE_24BIT_MIN << 8;\ } else if ((s) >= NORMALIZED_FLOAT_MAX) {\ (d) = SAMPLE_24BIT_MAX << 8;\ } else {\ (d) = f_round ((s) * SAMPLE_24BIT_SCALING) << 8;\ } #define float_24l32(s, d) \ if ((s) <= NORMALIZED_FLOAT_MIN) {\ (d) = SAMPLE_24BIT_MIN; \ } else if ((s) >= NORMALIZED_FLOAT_MAX) {\ (d) = SAMPLE_24BIT_MAX; \ } else {\ (d) = f_round ((s) * SAMPLE_24BIT_SCALING); \ } #define float_32(s, d) \ do { \ double clipped = fmin(NORMALIZED_FLOAT_MAX, \ fmax((double)(s), NORMALIZED_FLOAT_MIN)); \ double scaled = clipped * SAMPLE_32BIT_MAX_D; \ (d) = d_round(scaled); \ } \ while (0) /* call this when "s" has already been scaled (e.g. when dithering) */ #define float_24u32_scaled(s, d)\ if ((s) <= SAMPLE_24BIT_MIN_F) {\ (d) = SAMPLE_24BIT_MIN << 8;\ } else if ((s) >= SAMPLE_24BIT_MAX_F) { \ (d) = SAMPLE_24BIT_MAX << 8; \ } else {\ (d) = f_round ((s)) << 8; \ } #define float_24(s, d) \ if ((s) <= NORMALIZED_FLOAT_MIN) {\ (d) = SAMPLE_24BIT_MIN;\ } else if ((s) >= NORMALIZED_FLOAT_MAX) {\ (d) = SAMPLE_24BIT_MAX;\ } else {\ (d) = f_round ((s) * SAMPLE_24BIT_SCALING);\ } /* call this when "s" has already been scaled (e.g. when dithering) */ #define float_24_scaled(s, d)\ if ((s) <= SAMPLE_24BIT_MIN_F) {\ (d) = SAMPLE_24BIT_MIN;\ } else if ((s) >= SAMPLE_24BIT_MAX_F) { \ (d) = SAMPLE_24BIT_MAX; \ } else {\ (d) = f_round ((s)); \ } #if defined (__SSE2__) && !defined (__sun__) /* generates same as _mm_set_ps(1.f, 1.f, 1f., 1f) but faster */ static inline __m128 gen_one(void) { volatile __m128i x = { 0 }; /* shut up, GCC */ __m128i ones = _mm_cmpeq_epi32(x, x); return (__m128)_mm_slli_epi32 (_mm_srli_epi32(ones, 25), 23); } static inline __m128 clip(__m128 s, __m128 min, __m128 max) { return _mm_min_ps(max, _mm_max_ps(s, min)); } static inline __m128d clip_double(__m128d s, __m128d min, __m128d max) { return _mm_min_pd(max, _mm_max_pd(s, min)); } static inline __m128i float_24_sse(__m128 s) { const __m128 upper_bound = gen_one(); /* NORMALIZED_FLOAT_MAX */ const __m128 lower_bound = _mm_sub_ps(_mm_setzero_ps(), upper_bound); __m128 clipped = clip(s, lower_bound, upper_bound); __m128 scaled = _mm_mul_ps(clipped, _mm_set1_ps(SAMPLE_24BIT_SCALING)); return _mm_cvtps_epi32(scaled); } #endif #if defined (__ARM_NEON__) || defined (__ARM_NEON) static inline float32x4_t clip(float32x4_t s, float32x4_t min, float32x4_t max) { return vminq_f32(max, vmaxq_f32(s, min)); } static inline int32x4_t float_24_neon(float32x4_t s) { const float32x4_t upper_bound = vdupq_n_f32(NORMALIZED_FLOAT_MAX); const float32x4_t lower_bound = vdupq_n_f32(NORMALIZED_FLOAT_MIN); float32x4_t clipped = clip(s, lower_bound, upper_bound); float32x4_t scaled = vmulq_f32(clipped, vdupq_n_f32(SAMPLE_24BIT_SCALING)); return vcvtq_s32_f32(scaled); } static inline int16x4_t float_16_neon(float32x4_t s) { const float32x4_t upper_bound = vdupq_n_f32(NORMALIZED_FLOAT_MAX); const float32x4_t lower_bound = vdupq_n_f32(NORMALIZED_FLOAT_MIN); float32x4_t clipped = clip(s, lower_bound, upper_bound); float32x4_t scaled = vmulq_f32(clipped, vdupq_n_f32(SAMPLE_16BIT_SCALING)); return vmovn_s32(vcvtq_s32_f32(scaled)); } #endif /* Linear Congruential noise generator. From the music-dsp list * less random than rand(), but good enough and 10x faster */ static unsigned int seed = 22222; static inline unsigned int fast_rand() { seed = (seed * 196314165) + 907633515; return seed; } /* functions for native float sample data */ void sample_move_floatLE_sSs (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { while (nsamples--) { *dst = *((float *) src); dst++; src += src_skip; } } void sample_move_dS_floatLE (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { while (nsamples--) { *((float *) dst) = *src; dst += dst_skip; src++; } } /* NOTES on function naming: foo_bar_d<TYPE>_s<TYPE> the "d<TYPE>" component defines the destination type for the operation the "s<TYPE>" component defines the source type for the operation TYPE can be one of: S - sample is a jack_default_audio_sample_t, currently (October 2008) a 32 bit floating point value Ss - like S but reverse endian from the host CPU 32 - sample is a signed 32 bit integer value 32u24 - sample is a signed 32 bit integer value, but data is in upper 24 bits only 32u24s - like 32u24 but reverse endian from the host CPU 32l24 - sample is a signed 32 bit integer value, but data is in lower 24 bits only 32l24s - like 32l24 but reverse endian from the host CPU 24 - sample is a signed 24 bit integer value 24s - like 24 but reverse endian from the host CPU 16 - sample is a signed 16 bit integer value 16s - like 16 but reverse endian from the host CPU For obvious reasons, the reverse endian versions only show as source types. This covers all known sample formats at 16 bits or larger. */ /* functions for native integer sample data */ void sample_move_d32_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { while (nsamples--) { int32_t z; float_32(*src, z); #if __BYTE_ORDER == __LITTLE_ENDIAN dst[0]=(char)(z>>24); dst[1]=(char)(z>>16); dst[2]=(char)(z>>8); dst[3]=(char)(z); #elif __BYTE_ORDER == __BIG_ENDIAN dst[0]=(char)(z); dst[1]=(char)(z>>8); dst[2]=(char)(z>>16); dst[3]=(char)(z>>24); #endif dst += dst_skip; src++; } } void sample_move_d32_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { while (nsamples--) { float_32(*src, *(int32_t *)dst); dst += dst_skip; src++; } } void sample_move_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { #if defined (__ARM_NEON__) || defined (__ARM_NEON) unsigned long unrolled = nsamples / 4; nsamples = nsamples & 3; while (unrolled--) { float32x4_t samples = vld1q_f32(src); int32x4_t converted = float_24_neon(samples); int32x4_t shifted = vshlq_n_s32(converted, 8); shifted = vreinterpretq_s32_u8(vrev32q_u8(vreinterpretq_u8_s32(shifted))); switch(dst_skip) { case 4: vst1q_s32((int32_t*)dst, shifted); break; default: vst1q_lane_s32((int32_t*)(dst), shifted, 0); vst1q_lane_s32((int32_t*)(dst+dst_skip), shifted, 1); vst1q_lane_s32((int32_t*)(dst+2*dst_skip), shifted, 2); vst1q_lane_s32((int32_t*)(dst+3*dst_skip), shifted, 3); break; } dst += 4*dst_skip; src+= 4; } #endif int32_t z; while (nsamples--) { float_24u32 (*src, z); #if __BYTE_ORDER == __LITTLE_ENDIAN dst[0]=(char)(z>>24); dst[1]=(char)(z>>16); dst[2]=(char)(z>>8); dst[3]=(char)(z); #elif __BYTE_ORDER == __BIG_ENDIAN dst[0]=(char)(z); dst[1]=(char)(z>>8); dst[2]=(char)(z>>16); dst[3]=(char)(z>>24); #endif dst += dst_skip; src++; } } void sample_move_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { #if defined (__SSE2__) && !defined (__sun__) __m128 int_max = _mm_set1_ps(SAMPLE_24BIT_MAX_F); __m128 int_min = _mm_sub_ps(_mm_setzero_ps(), int_max); __m128 factor = int_max; unsigned long unrolled = nsamples / 4; nsamples = nsamples & 3; while (unrolled--) { __m128 in = _mm_load_ps(src); __m128 scaled = _mm_mul_ps(in, factor); __m128 clipped = clip(scaled, int_min, int_max); __m128i y = _mm_cvttps_epi32(clipped); __m128i shifted = _mm_slli_epi32(y, 8); #ifdef __SSE4_1__ *(int32_t*)dst = _mm_extract_epi32(shifted, 0); *(int32_t*)(dst+dst_skip) = _mm_extract_epi32(shifted, 1); *(int32_t*)(dst+2*dst_skip) = _mm_extract_epi32(shifted, 2); *(int32_t*)(dst+3*dst_skip) = _mm_extract_epi32(shifted, 3); #else __m128i shuffled1 = _mm_shuffle_epi32(shifted, _MM_SHUFFLE(0, 3, 2, 1)); __m128i shuffled2 = _mm_shuffle_epi32(shifted, _MM_SHUFFLE(1, 0, 3, 2)); __m128i shuffled3 = _mm_shuffle_epi32(shifted, _MM_SHUFFLE(2, 1, 0, 3)); _mm_store_ss((float*)dst, (__m128)shifted); _mm_store_ss((float*)(dst+dst_skip), (__m128)shuffled1); _mm_store_ss((float*)(dst+2*dst_skip), (__m128)shuffled2); _mm_store_ss((float*)(dst+3*dst_skip), (__m128)shuffled3); #endif dst += 4*dst_skip; src+= 4; } while (nsamples--) { __m128 in = _mm_load_ss(src); __m128 scaled = _mm_mul_ss(in, factor); __m128 clipped = _mm_min_ss(int_max, _mm_max_ss(scaled, int_min)); int y = _mm_cvttss_si32(clipped); *((int *) dst) = y<<8; dst += dst_skip; src++; } #elif defined (__ARM_NEON__) || defined (__ARM_NEON) unsigned long unrolled = nsamples / 4; nsamples = nsamples & 3; while (unrolled--) { float32x4_t samples = vld1q_f32(src); int32x4_t converted = float_24_neon(samples); int32x4_t shifted = vshlq_n_s32(converted, 8); switch(dst_skip) { case 4: vst1q_s32((int32_t*)dst, shifted); break; default: vst1q_lane_s32((int32_t*)(dst), shifted, 0); vst1q_lane_s32((int32_t*)(dst+dst_skip), shifted, 1); vst1q_lane_s32((int32_t*)(dst+2*dst_skip), shifted, 2); vst1q_lane_s32((int32_t*)(dst+3*dst_skip), shifted, 3); break; } dst += 4*dst_skip; src+= 4; } #endif #if !defined (__SSE2__) while (nsamples--) { float_24u32 (*src, *((int32_t*) dst)); dst += dst_skip; src++; } #endif } void sample_move_dS_s32u24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { #if defined (__ARM_NEON__) || defined (__ARM_NEON) float32x4_t factor = vdupq_n_f32(1.0 / SAMPLE_24BIT_SCALING); unsigned long unrolled = nsamples / 4; while (unrolled--) { int32x4_t src128; switch(src_skip) { case 4: src128 = vld1q_s32((int32_t*)src); break; case 8: src128 = vld2q_s32((int32_t*)src).val[0]; break; default: src128 = vld1q_lane_s32((int32_t*)src, src128, 0); src128 = vld1q_lane_s32((int32_t*)(src+src_skip), src128, 1); src128 = vld1q_lane_s32((int32_t*)(src+2*src_skip), src128, 2); src128 = vld1q_lane_s32((int32_t*)(src+3*src_skip), src128, 3); break; } src128 = vreinterpretq_s32_u8(vrev32q_u8(vreinterpretq_u8_s32(src128))); int32x4_t shifted = vshrq_n_s32(src128, 8); float32x4_t as_float = vcvtq_f32_s32(shifted); float32x4_t divided = vmulq_f32(as_float, factor); vst1q_f32(dst, divided); src += 4*src_skip; dst += 4; } nsamples = nsamples & 3; #endif /* ALERT: signed sign-extension portability !!! */ const jack_default_audio_sample_t scaling = 1.0/SAMPLE_24BIT_SCALING; while (nsamples--) { int x; #if __BYTE_ORDER == __LITTLE_ENDIAN x = (unsigned char)(src[0]); x <<= 8; x |= (unsigned char)(src[1]); x <<= 8; x |= (unsigned char)(src[2]); x <<= 8; x |= (unsigned char)(src[3]); #elif __BYTE_ORDER == __BIG_ENDIAN x = (unsigned char)(src[3]); x <<= 8; x |= (unsigned char)(src[2]); x <<= 8; x |= (unsigned char)(src[1]); x <<= 8; x |= (unsigned char)(src[0]); #endif *dst = (x >> 8) * scaling; dst++; src += src_skip; } } void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { #if defined (__SSE2__) && !defined (__sun__) unsigned long unrolled = nsamples / 4; static float inv_sample_max_24bit = 1.0 / SAMPLE_24BIT_SCALING; __m128 factor = _mm_set1_ps(inv_sample_max_24bit); while (unrolled--) { int i1 = *((int *) src); src+= src_skip; int i2 = *((int *) src); src+= src_skip; int i3 = *((int *) src); src+= src_skip; int i4 = *((int *) src); src+= src_skip; __m128i src = _mm_set_epi32(i4, i3, i2, i1); __m128i shifted = _mm_srai_epi32(src, 8); __m128 as_float = _mm_cvtepi32_ps(shifted); __m128 divided = _mm_mul_ps(as_float, factor); _mm_storeu_ps(dst, divided); dst += 4; } nsamples = nsamples & 3; #elif defined (__ARM_NEON__) || defined (__ARM_NEON) unsigned long unrolled = nsamples / 4; float32x4_t factor = vdupq_n_f32(1.0 / SAMPLE_24BIT_SCALING); while (unrolled--) { int32x4_t src128; switch(src_skip) { case 4: src128 = vld1q_s32((int32_t*)src); break; case 8: src128 = vld2q_s32((int32_t*)src).val[0]; break; default: src128 = vld1q_lane_s32((int32_t*)src, src128, 0); src128 = vld1q_lane_s32((int32_t*)(src+src_skip), src128, 1); src128 = vld1q_lane_s32((int32_t*)(src+2*src_skip), src128, 2); src128 = vld1q_lane_s32((int32_t*)(src+3*src_skip), src128, 3); break; } int32x4_t shifted = vshrq_n_s32(src128, 8); float32x4_t as_float = vcvtq_f32_s32(shifted); float32x4_t divided = vmulq_f32(as_float, factor); vst1q_f32(dst, divided); src += 4*src_skip; dst += 4; } nsamples = nsamples & 3; #endif /* ALERT: signed sign-extension portability !!! */ const jack_default_audio_sample_t scaling = 1.0/SAMPLE_24BIT_SCALING; while (nsamples--) { *dst = (*((int *) src) >> 8) * scaling; dst++; src += src_skip; } } void sample_move_d32l24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { #if defined (__ARM_NEON__) || defined (__ARM_NEON) unsigned long unrolled = nsamples / 4; nsamples = nsamples & 3; while (unrolled--) { float32x4_t samples = vld1q_f32(src); int32x4_t converted = float_24_neon(samples); converted = vreinterpretq_s32_u8(vrev32q_u8(vreinterpretq_u8_s32(converted))); switch(dst_skip) { case 4: vst1q_s32((int32_t*)dst, converted); break; default: vst1q_lane_s32((int32_t*)(dst), converted, 0); vst1q_lane_s32((int32_t*)(dst+dst_skip), converted, 1); vst1q_lane_s32((int32_t*)(dst+2*dst_skip), converted, 2); vst1q_lane_s32((int32_t*)(dst+3*dst_skip), converted, 3); break; } dst += 4*dst_skip; src+= 4; } #endif int32_t z; while (nsamples--) { float_24l32 (*src, z); #if __BYTE_ORDER == __LITTLE_ENDIAN dst[0]=(char)(z>>24); dst[1]=(char)(z>>16); dst[2]=(char)(z>>8); dst[3]=(char)(z); #elif __BYTE_ORDER == __BIG_ENDIAN dst[0]=(char)(z); dst[1]=(char)(z>>8); dst[2]=(char)(z>>16); dst[3]=(char)(z>>24); #endif dst += dst_skip; src++; } } void sample_move_d32l24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { #if defined (__SSE2__) && !defined (__sun__) __m128 int_max = _mm_set1_ps(SAMPLE_24BIT_MAX_F); __m128 int_min = _mm_sub_ps(_mm_setzero_ps(), int_max); __m128 factor = int_max; unsigned long unrolled = nsamples / 4; nsamples = nsamples & 3; while (unrolled--) { __m128 in = _mm_load_ps(src); __m128 scaled = _mm_mul_ps(in, factor); __m128 clipped = clip(scaled, int_min, int_max); __m128i shifted = _mm_cvttps_epi32(clipped); #ifdef __SSE4_1__ *(int32_t*)dst = _mm_extract_epi32(shifted, 0); *(int32_t*)(dst+dst_skip) = _mm_extract_epi32(shifted, 1); *(int32_t*)(dst+2*dst_skip) = _mm_extract_epi32(shifted, 2); *(int32_t*)(dst+3*dst_skip) = _mm_extract_epi32(shifted, 3); #else __m128i shuffled1 = _mm_shuffle_epi32(shifted, _MM_SHUFFLE(0, 3, 2, 1)); __m128i shuffled2 = _mm_shuffle_epi32(shifted, _MM_SHUFFLE(1, 0, 3, 2)); __m128i shuffled3 = _mm_shuffle_epi32(shifted, _MM_SHUFFLE(2, 1, 0, 3)); _mm_store_ss((float*)dst, (__m128)shifted); _mm_store_ss((float*)(dst+dst_skip), (__m128)shuffled1); _mm_store_ss((float*)(dst+2*dst_skip), (__m128)shuffled2); _mm_store_ss((float*)(dst+3*dst_skip), (__m128)shuffled3); #endif dst += 4*dst_skip; src+= 4; } while (nsamples--) { __m128 in = _mm_load_ss(src); __m128 scaled = _mm_mul_ss(in, factor); __m128 clipped = _mm_min_ss(int_max, _mm_max_ss(scaled, int_min)); int y = _mm_cvttss_si32(clipped); *((int *) dst) = y<<8; dst += dst_skip; src++; } #elif defined (__ARM_NEON__) || defined (__ARM_NEON) unsigned long unrolled = nsamples / 4; nsamples = nsamples & 3; while (unrolled--) { float32x4_t samples = vld1q_f32(src); int32x4_t converted = float_24_neon(samples); switch(dst_skip) { case 4: vst1q_s32((int32_t*)dst, converted); break; default: vst1q_lane_s32((int32_t*)(dst), converted, 0); vst1q_lane_s32((int32_t*)(dst+dst_skip), converted, 1); vst1q_lane_s32((int32_t*)(dst+2*dst_skip), converted, 2); vst1q_lane_s32((int32_t*)(dst+3*dst_skip), converted, 3); break; } dst += 4*dst_skip; src+= 4; } #endif #if !defined (__SSE2__) while (nsamples--) { float_24l32 (*src, *((int32_t*) dst)); dst += dst_skip; src++; } #endif } void sample_move_dS_s32s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { const jack_default_audio_sample_t scaling = 1.0/SAMPLE_32BIT_SCALING; while (nsamples--) { int32_t x; #if __BYTE_ORDER == __LITTLE_ENDIAN x = (unsigned char)(src[0]); x <<= 8; x |= (unsigned char)(src[1]); x <<= 8; x |= (unsigned char)(src[2]); x <<= 8; x |= (unsigned char)(src[3]); #elif __BYTE_ORDER == __BIG_ENDIAN x = (unsigned char)(src[3]); x <<= 8; x |= (unsigned char)(src[2]); x <<= 8; x |= (unsigned char)(src[1]); x <<= 8; x |= (unsigned char)(src[0]); #endif double extended = x * scaling; *dst = (float)extended; dst++; src += src_skip; } } void sample_move_dS_s32l24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { #if defined (__ARM_NEON__) || defined (__ARM_NEON) float32x4_t factor = vdupq_n_f32(1.0 / SAMPLE_24BIT_SCALING); unsigned long unrolled = nsamples / 4; while (unrolled--) { uint32x4_t src128; switch(src_skip) { case 4: src128 = vld1q_u32((uint32_t*)src); break; case 8: src128 = vld2q_u32((uint32_t*)src).val[0]; break; default: src128 = vld1q_lane_u32((uint32_t*)src, src128, 0); src128 = vld1q_lane_u32((uint32_t*)(src+src_skip), src128, 1); src128 = vld1q_lane_u32((uint32_t*)(src+2*src_skip), src128, 2); src128 = vld1q_lane_u32((uint32_t*)(src+3*src_skip), src128, 3); break; } src128 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(src128))); uint32x4_t toupper = vshlq_n_u32(src128, 8); int32x4_t shifted = vshrq_n_s32((int32x4_t)toupper, 8); float32x4_t as_float = vcvtq_f32_s32(shifted); float32x4_t divided = vmulq_f32(as_float, factor); vst1q_f32(dst, divided); src += 4*src_skip; dst += 4; } nsamples = nsamples & 3; #endif /* ALERT: signed sign-extension portability !!! */ const jack_default_audio_sample_t scaling = 1.0/SAMPLE_24BIT_SCALING; while (nsamples--) { int32_t x; #if __BYTE_ORDER == __LITTLE_ENDIAN x = (unsigned char)(src[0]); x <<= 8; x |= (unsigned char)(src[1]); x <<= 8; x |= (unsigned char)(src[2]); x <<= 8; x |= (unsigned char)(src[3]); #elif __BYTE_ORDER == __BIG_ENDIAN x = (unsigned char)(src[3]); x <<= 8; x |= (unsigned char)(src[2]); x <<= 8; x |= (unsigned char)(src[1]); x <<= 8; x |= (unsigned char)(src[0]); #endif *dst = (x >> 0) * scaling; dst++; src += src_skip; } } void sample_move_dS_s32 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { const double scaling = 1.0 / SAMPLE_32BIT_SCALING; while (nsamples--) { int32_t val=(*((int32_t*)src)); double extended = val * scaling; *dst = (float)extended; dst++; src += src_skip; } } void sample_move_dS_s32l24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { #if defined (__SSE2__) && !defined (__sun__) unsigned long unrolled = nsamples / 4; static float inv_sample_max_24bit = 1.0 / SAMPLE_24BIT_SCALING; __m128 factor = _mm_set1_ps(inv_sample_max_24bit); while (unrolled--) { int i1 = *((int *) src); src+= src_skip; int i2 = *((int *) src); src+= src_skip; int i3 = *((int *) src); src+= src_skip; int i4 = *((int *) src); src+= src_skip; __m128i shifted = _mm_set_epi32(i4, i3, i2, i1); __m128 as_float = _mm_cvtepi32_ps(shifted); __m128 divided = _mm_mul_ps(as_float, factor); _mm_storeu_ps(dst, divided); dst += 4; } nsamples = nsamples & 3; #elif defined (__ARM_NEON__) || defined (__ARM_NEON) unsigned long unrolled = nsamples / 4; float32x4_t factor = vdupq_n_f32(1.0 / SAMPLE_24BIT_SCALING); while (unrolled--) { uint32x4_t src128; switch(src_skip) { case 4: src128 = vld1q_u32((uint32_t*)src); break; case 8: src128 = vld2q_u32((uint32_t*)src).val[0]; break; default: src128 = vld1q_lane_u32((uint32_t*)src, src128, 0); src128 = vld1q_lane_u32((uint32_t*)(src+src_skip), src128, 1); src128 = vld1q_lane_u32((uint32_t*)(src+2*src_skip), src128, 2); src128 = vld1q_lane_u32((uint32_t*)(src+3*src_skip), src128, 3); break; } // Sign extension by moving to upper as unsigned, then down uint32x4_t toupper = vshlq_n_u32(src128, 8); int32x4_t shifted = vshrq_n_s32((int32x4_t)toupper, 8); float32x4_t as_float = vcvtq_f32_s32(shifted); float32x4_t divided = vmulq_f32(as_float, factor); vst1q_f32(dst, divided); src += 4*src_skip; dst += 4; } nsamples = nsamples & 3; #endif /* ALERT: signed sign-extension portability !!! */ const jack_default_audio_sample_t scaling = 1.0/SAMPLE_24BIT_SCALING; while (nsamples--) { uint32_t val=(*((uint32_t*)src)); if (val & 0x800000u) val|=0xFF000000u; *dst = (*((int32_t *) &val)) * scaling; dst++; src += src_skip; } } void sample_move_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { #if defined (__ARM_NEON__) || defined (__ARM_NEON) unsigned long unrolled = nsamples / 4; while (unrolled--) { int i; int32_t z[4]; float32x4_t samples = vld1q_f32(src); int32x4_t converted = float_24_neon(samples); converted = vreinterpretq_s32_u8(vrev32q_u8(vreinterpretq_u8_s32(converted))); vst1q_s32(z, converted); for (i = 0; i != 4; ++i) { memcpy (dst, ((char*)(z+i))+1, 3); dst += dst_skip; } src += 4; } nsamples = nsamples & 3; #endif int32_t z; while (nsamples--) { float_24 (*src, z); #if __BYTE_ORDER == __LITTLE_ENDIAN dst[0]=(char)(z>>16); dst[1]=(char)(z>>8); dst[2]=(char)(z); #elif __BYTE_ORDER == __BIG_ENDIAN dst[0]=(char)(z); dst[1]=(char)(z>>8); dst[2]=(char)(z>>16); #endif dst += dst_skip; src++; } } void sample_move_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { #if defined (__SSE2__) && !defined (__sun__) _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); while (nsamples >= 4) { int i; int32_t z[4]; __m128 samples = _mm_loadu_ps(src); __m128i converted = float_24_sse(samples); #ifdef __SSE4_1__ z[0] = _mm_extract_epi32(converted, 0); z[1] = _mm_extract_epi32(converted, 1); z[2] = _mm_extract_epi32(converted, 2); z[3] = _mm_extract_epi32(converted, 3); #else __m128i shuffled1 = _mm_shuffle_epi32(converted, _MM_SHUFFLE(0, 3, 2, 1)); __m128i shuffled2 = _mm_shuffle_epi32(converted, _MM_SHUFFLE(1, 0, 3, 2)); __m128i shuffled3 = _mm_shuffle_epi32(converted, _MM_SHUFFLE(2, 1, 0, 3)); _mm_store_ss((float*)z, (__m128)converted); _mm_store_ss((float*)z+1, (__m128)shuffled1); _mm_store_ss((float*)z+2, (__m128)shuffled2); _mm_store_ss((float*)z+3, (__m128)shuffled3); #endif for (i = 0; i != 4; ++i) { memcpy (dst, z+i, 3); dst += dst_skip; } nsamples -= 4; src += 4; } #elif defined (__ARM_NEON__) || defined (__ARM_NEON) unsigned long unrolled = nsamples / 4; while (unrolled--) { int i; int32_t z[4]; float32x4_t samples = vld1q_f32(src); int32x4_t converted = float_24_neon(samples); vst1q_s32(z, converted); for (i = 0; i != 4; ++i) { memcpy (dst, z+i, 3); dst += dst_skip; } src += 4; } nsamples = nsamples & 3; #endif int32_t z; while (nsamples--) { float_24 (*src, z); #if __BYTE_ORDER == __LITTLE_ENDIAN memcpy (dst, &z, 3); #elif __BYTE_ORDER == __BIG_ENDIAN memcpy (dst, (char *)&z + 1, 3); #endif dst += dst_skip; src++; } } void sample_move_dS_s24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { const jack_default_audio_sample_t scaling = 1.0/SAMPLE_24BIT_SCALING; #if defined (__ARM_NEON__) || defined (__ARM_NEON) // we shift 8 to the right by dividing by 256.0 -> no sign extra handling const float32x4_t vscaling = vdupq_n_f32(scaling/256.0); int32_t x[4]; memset(x, 0, sizeof(x)); unsigned long unrolled = nsamples / 4; while (unrolled--) { #if __BYTE_ORDER == __BIG_ENDIAN /* ARM big endian?? */ // right aligned / inverse sequence below -> *256 memcpy(((char*)&x[0])+1, src, 3); memcpy(((char*)&x[1])+1, src+src_skip, 3); memcpy(((char*)&x[2])+1, src+2*src_skip, 3); memcpy(((char*)&x[3])+1, src+3*src_skip, 3); #else memcpy(&x[0], src, 3); memcpy(&x[1], src+src_skip, 3); memcpy(&x[2], src+2*src_skip, 3); memcpy(&x[3], src+3*src_skip, 3); #endif src += 4 * src_skip; int32x4_t source = vld1q_s32(x); source = vreinterpretq_s32_u8(vrev32q_u8(vreinterpretq_u8_s32(source))); float32x4_t converted = vcvtq_f32_s32(source); float32x4_t scaled = vmulq_f32(converted, vscaling); vst1q_f32(dst, scaled); dst += 4; } nsamples = nsamples & 3; #endif /* ALERT: signed sign-extension portability !!! */ while (nsamples--) { int x; #if __BYTE_ORDER == __LITTLE_ENDIAN x = (unsigned char)(src[0]); x <<= 8; x |= (unsigned char)(src[1]); x <<= 8; x |= (unsigned char)(src[2]); /* correct sign bit and the rest of the top byte */ if (src[0] & 0x80) { x |= 0xff << 24; } #elif __BYTE_ORDER == __BIG_ENDIAN x = (unsigned char)(src[2]); x <<= 8; x |= (unsigned char)(src[1]); x <<= 8; x |= (unsigned char)(src[0]); /* correct sign bit and the rest of the top byte */ if (src[2] & 0x80) { x |= 0xff << 24; } #endif *dst = x * scaling; dst++; src += src_skip; } } void sample_move_dS_s24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { const jack_default_audio_sample_t scaling = 1.f/SAMPLE_24BIT_SCALING; #if defined (__SSE2__) && !defined (__sun__) const __m128 scaling_block = _mm_set_ps1(scaling); while (nsamples >= 4) { int x0, x1, x2, x3; memcpy((char*)&x0 + 1, src, 3); memcpy((char*)&x1 + 1, src+src_skip, 3); memcpy((char*)&x2 + 1, src+2*src_skip, 3); memcpy((char*)&x3 + 1, src+3*src_skip, 3); src += 4 * src_skip; const __m128i block_i = _mm_set_epi32(x3, x2, x1, x0); const __m128i shifted = _mm_srai_epi32(block_i, 8); const __m128 converted = _mm_cvtepi32_ps (shifted); const __m128 scaled = _mm_mul_ps(converted, scaling_block); _mm_storeu_ps(dst, scaled); dst += 4; nsamples -= 4; } #elif defined (__ARM_NEON__) || defined (__ARM_NEON) // we shift 8 to the right by dividing by 256.0 -> no sign extra handling const float32x4_t vscaling = vdupq_n_f32(scaling/256.0); int32_t x[4]; memset(x, 0, sizeof(x)); unsigned long unrolled = nsamples / 4; while (unrolled--) { #if __BYTE_ORDER == __BIG_ENDIAN /* ARM big endian?? */ // left aligned -> *256 memcpy(&x[0], src, 3); memcpy(&x[1], src+src_skip, 3); memcpy(&x[2], src+2*src_skip, 3); memcpy(&x[3], src+3*src_skip, 3); #else memcpy(((char*)&x[0])+1, src, 3); memcpy(((char*)&x[1])+1, src+src_skip, 3); memcpy(((char*)&x[2])+1, src+2*src_skip, 3); memcpy(((char*)&x[3])+1, src+3*src_skip, 3); #endif src += 4 * src_skip; int32x4_t source = vld1q_s32(x); float32x4_t converted = vcvtq_f32_s32(source); float32x4_t scaled = vmulq_f32(converted, vscaling); vst1q_f32(dst, scaled); dst += 4; } nsamples = nsamples & 3; #endif while (nsamples--) { int x; #if __BYTE_ORDER == __LITTLE_ENDIAN memcpy((char*)&x + 1, src, 3); #elif __BYTE_ORDER == __BIG_ENDIAN memcpy(&x, src, 3); #endif x >>= 8; *dst = x * scaling; dst++; src += src_skip; } } void sample_move_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { #if defined (__ARM_NEON__) || defined (__ARM_NEON) unsigned long unrolled = nsamples / 4; nsamples = nsamples & 3; while (unrolled--) { float32x4_t samples = vld1q_f32(src); int16x4_t converted = float_16_neon(samples); converted = vreinterpret_s16_u8(vrev16_u8(vreinterpret_u8_s16(converted))); switch(dst_skip) { case 2: vst1_s16((int16_t*)dst, converted); break; default: vst1_lane_s16((int16_t*)(dst), converted, 0); vst1_lane_s16((int16_t*)(dst+dst_skip), converted, 1); vst1_lane_s16((int16_t*)(dst+2*dst_skip), converted, 2); vst1_lane_s16((int16_t*)(dst+3*dst_skip), converted, 3); break; } dst += 4*dst_skip; src+= 4; } #endif int16_t tmp; while (nsamples--) { // float_16 (*src, tmp); if (*src <= NORMALIZED_FLOAT_MIN) { tmp = SAMPLE_16BIT_MIN; } else if (*src >= NORMALIZED_FLOAT_MAX) { tmp = SAMPLE_16BIT_MAX; } else { tmp = (int16_t) f_round (*src * SAMPLE_16BIT_SCALING); } #if __BYTE_ORDER == __LITTLE_ENDIAN dst[0]=(char)(tmp>>8); dst[1]=(char)(tmp); #elif __BYTE_ORDER == __BIG_ENDIAN dst[0]=(char)(tmp); dst[1]=(char)(tmp>>8); #endif dst += dst_skip; src++; } } void sample_move_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { #if defined (__ARM_NEON__) || defined (__ARM_NEON) unsigned long unrolled = nsamples / 4; nsamples = nsamples & 3; while (unrolled--) { float32x4_t samples = vld1q_f32(src); int16x4_t converted = float_16_neon(samples); switch(dst_skip) { case 2: vst1_s16((int16_t*)dst, converted); break; default: vst1_lane_s16((int16_t*)(dst), converted, 0); vst1_lane_s16((int16_t*)(dst+dst_skip), converted, 1); vst1_lane_s16((int16_t*)(dst+2*dst_skip), converted, 2); vst1_lane_s16((int16_t*)(dst+3*dst_skip), converted, 3); break; } dst += 4*dst_skip; src+= 4; } #endif while (nsamples--) { float_16 (*src, *((int16_t*) dst)); dst += dst_skip; src++; } } void sample_move_dither_rect_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { jack_default_audio_sample_t val; int16_t tmp; while (nsamples--) { val = (*src * SAMPLE_16BIT_SCALING) + fast_rand() / (float) UINT_MAX - 0.5f; float_16_scaled (val, tmp); #if __BYTE_ORDER == __LITTLE_ENDIAN dst[0]=(char)(tmp>>8); dst[1]=(char)(tmp); #elif __BYTE_ORDER == __BIG_ENDIAN dst[0]=(char)(tmp); dst[1]=(char)(tmp>>8); #endif dst += dst_skip; src++; } } void sample_move_dither_rect_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { jack_default_audio_sample_t val; while (nsamples--) { val = (*src * SAMPLE_16BIT_SCALING) + fast_rand() / (float)UINT_MAX - 0.5f; float_16_scaled (val, *((int16_t*) dst)); dst += dst_skip; src++; } } void sample_move_dither_tri_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { jack_default_audio_sample_t val; int16_t tmp; while (nsamples--) { val = (*src * SAMPLE_16BIT_SCALING) + ((float)fast_rand() + (float)fast_rand()) / (float)UINT_MAX - 1.0f; float_16_scaled (val, tmp); #if __BYTE_ORDER == __LITTLE_ENDIAN dst[0]=(char)(tmp>>8); dst[1]=(char)(tmp); #elif __BYTE_ORDER == __BIG_ENDIAN dst[0]=(char)(tmp); dst[1]=(char)(tmp>>8); #endif dst += dst_skip; src++; } } void sample_move_dither_tri_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { jack_default_audio_sample_t val; while (nsamples--) { val = (*src * SAMPLE_16BIT_SCALING) + ((float)fast_rand() + (float)fast_rand()) / (float)UINT_MAX - 1.0f; float_16_scaled (val, *((int16_t*) dst)); dst += dst_skip; src++; } } void sample_move_dither_shaped_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { jack_default_audio_sample_t x; jack_default_audio_sample_t xe; /* the innput sample - filtered error */ jack_default_audio_sample_t xp; /* x' */ float r; float rm1 = state->rm1; unsigned int idx = state->idx; int16_t tmp; while (nsamples--) { x = *src * SAMPLE_16BIT_SCALING; r = ((float)fast_rand() + (float)fast_rand()) / (float)UINT_MAX - 1.0f; /* Filter the error with Lipshitz's minimally audible FIR: [2.033 -2.165 1.959 -1.590 0.6149] */ xe = x - state->e[idx] * 2.033f + state->e[(idx - 1) & DITHER_BUF_MASK] * 2.165f - state->e[(idx - 2) & DITHER_BUF_MASK] * 1.959f + state->e[(idx - 3) & DITHER_BUF_MASK] * 1.590f - state->e[(idx - 4) & DITHER_BUF_MASK] * 0.6149f; xp = xe + r - rm1; rm1 = r; float_16_scaled (xp, tmp); /* Intrinsic z^-1 delay */ idx = (idx + 1) & DITHER_BUF_MASK; state->e[idx] = xp - xe; #if __BYTE_ORDER == __LITTLE_ENDIAN dst[0]=(char)(tmp>>8); dst[1]=(char)(tmp); #elif __BYTE_ORDER == __BIG_ENDIAN dst[0]=(char)(tmp); dst[1]=(char)(tmp>>8); #endif dst += dst_skip; src++; } state->rm1 = rm1; state->idx = idx; } void sample_move_dither_shaped_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { jack_default_audio_sample_t x; jack_default_audio_sample_t xe; /* the innput sample - filtered error */ jack_default_audio_sample_t xp; /* x' */ float r; float rm1 = state->rm1; unsigned int idx = state->idx; while (nsamples--) { x = *src * SAMPLE_16BIT_SCALING; r = ((float)fast_rand() + (float)fast_rand()) / (float)UINT_MAX - 1.0f; /* Filter the error with Lipshitz's minimally audible FIR: [2.033 -2.165 1.959 -1.590 0.6149] */ xe = x - state->e[idx] * 2.033f + state->e[(idx - 1) & DITHER_BUF_MASK] * 2.165f - state->e[(idx - 2) & DITHER_BUF_MASK] * 1.959f + state->e[(idx - 3) & DITHER_BUF_MASK] * 1.590f - state->e[(idx - 4) & DITHER_BUF_MASK] * 0.6149f; xp = xe + r - rm1; rm1 = r; float_16_scaled (xp, *((int16_t*) dst)); /* Intrinsic z^-1 delay */ idx = (idx + 1) & DITHER_BUF_MASK; state->e[idx] = *((int16_t*) dst) - xe; dst += dst_skip; src++; } state->rm1 = rm1; state->idx = idx; } void sample_move_dS_s16s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { short z; const jack_default_audio_sample_t scaling = 1.0/SAMPLE_16BIT_SCALING; #if defined (__ARM_NEON__) || defined (__ARM_NEON) const float32x4_t vscaling = vdupq_n_f32(scaling); unsigned long unrolled = nsamples / 4; while (unrolled--) { int16x4_t source16x4; switch(src_skip) { case 2: source16x4 = vld1_s16((int16_t*)src); break; case 4: source16x4 = vld2_s16((int16_t*)src).val[0]; break; default: source16x4 = vld1_lane_s16((int16_t*)src, source16x4, 0); source16x4 = vld1_lane_s16((int16_t*)(src+src_skip), source16x4, 1); source16x4 = vld1_lane_s16((int16_t*)(src+2*src_skip), source16x4, 2); source16x4 = vld1_lane_s16((int16_t*)(src+3*src_skip), source16x4, 3); break; } source16x4 = vreinterpret_s16_u8(vrev16_u8(vreinterpret_u8_s16(source16x4))); int32x4_t source32x4 = vmovl_s16(source16x4); src += 4 * src_skip; float32x4_t converted = vcvtq_f32_s32(source32x4); float32x4_t scaled = vmulq_f32(converted, vscaling); vst1q_f32(dst, scaled); dst += 4; } nsamples = nsamples & 3; #endif /* ALERT: signed sign-extension portability !!! */ while (nsamples--) { #if __BYTE_ORDER == __LITTLE_ENDIAN z = (unsigned char)(src[0]); z <<= 8; z |= (unsigned char)(src[1]); #elif __BYTE_ORDER == __BIG_ENDIAN z = (unsigned char)(src[1]); z <<= 8; z |= (unsigned char)(src[0]); #endif *dst = z * scaling; dst++; src += src_skip; } } void sample_move_dS_s16 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { /* ALERT: signed sign-extension portability !!! */ const jack_default_audio_sample_t scaling = 1.0/SAMPLE_16BIT_SCALING; #if defined (__ARM_NEON__) || defined (__ARM_NEON) const float32x4_t vscaling = vdupq_n_f32(scaling); unsigned long unrolled = nsamples / 4; while (unrolled--) { int16x4_t source16x4; switch(src_skip) { case 2: source16x4 = vld1_s16((int16_t*)src); break; case 4: source16x4 = vld2_s16((int16_t*)src).val[0]; break; default: source16x4 = vld1_lane_s16((int16_t*)src, source16x4, 0); source16x4 = vld1_lane_s16((int16_t*)(src+src_skip), source16x4, 1); source16x4 = vld1_lane_s16((int16_t*)(src+2*src_skip), source16x4, 2); source16x4 = vld1_lane_s16((int16_t*)(src+3*src_skip), source16x4, 3); break; } int32x4_t source32x4 = vmovl_s16(source16x4); src += 4 * src_skip; float32x4_t converted = vcvtq_f32_s32(source32x4); float32x4_t scaled = vmulq_f32(converted, vscaling); vst1q_f32(dst, scaled); dst += 4; } nsamples = nsamples & 3; #endif while (nsamples--) { *dst = (*((short *) src)) * scaling; dst++; src += src_skip; } } void memset_interleave (char *dst, char val, unsigned long bytes, unsigned long unit_bytes, unsigned long skip_bytes) { switch (unit_bytes) { case 1: while (bytes--) { *dst = val; dst += skip_bytes; } break; case 2: while (bytes) { *((short *) dst) = (short) val; dst += skip_bytes; bytes -= 2; } break; case 4: while (bytes) { *((int *) dst) = (int) val; dst += skip_bytes; bytes -= 4; } break; default: while (bytes) { memset(dst, val, unit_bytes); dst += skip_bytes; bytes -= unit_bytes; } break; } } /* COPY FUNCTIONS: used to move data from an input channel to an output channel. Note that we assume that the skip distance is the same for both channels. This is completely fine unless the input and output were on different audio interfaces that were interleaved differently. We don't try to handle that. */ void memcpy_fake (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar) { memcpy (dst, src, src_bytes); } void memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes) { while (src_bytes) { *((short *) dst) = *((short *) src); dst += dst_skip_bytes; src += src_skip_bytes; src_bytes -= 2; } } void memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes) { while (src_bytes) { memcpy(dst, src, 3); dst += dst_skip_bytes; src += src_skip_bytes; src_bytes -= 3; } } void memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes) { while (src_bytes) { *((int *) dst) = *((int *) src); dst += dst_skip_bytes; src += src_skip_bytes; src_bytes -= 4; } } 0707010000000C000081A400000000000000000000000161E2F7EE0000249B000000000000000000000000000000000000002500000000jack-example-tools-1/common/memops.h/* Copyright (C) 1999-2000 Paul Davis 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __jack_memops_h__ #define __jack_memops_h__ #include <jack/types.h> #ifdef __cplusplus extern "C" { #endif #ifdef sun #define __inline__ #endif typedef enum { None, Rectangular, Triangular, Shaped } DitherAlgorithm; #define DITHER_BUF_SIZE 8 #define DITHER_BUF_MASK 7 typedef struct { unsigned int depth; float rm1; unsigned int idx; float e[DITHER_BUF_SIZE]; } dither_state_t; /* float functions */ void sample_move_floatLE_sSs (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long dst_skip); void sample_move_dS_floatLE (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); /* integer functions */ void sample_move_d32_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d32_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d32l24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d32l24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_rect_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_rect_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_tri_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_tri_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_rect_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_rect_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_tri_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_tri_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_rect_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_rect_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_tri_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_tri_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dS_s32s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s32 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s32u24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s32l24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s32l24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s16s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s16 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_merge_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_merge_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); static __inline__ void sample_merge (jack_default_audio_sample_t *dst, jack_default_audio_sample_t *src, unsigned long cnt) { while (cnt--) { *dst += *src; dst++; src++; } } static __inline__ void sample_memcpy (jack_default_audio_sample_t *dst, jack_default_audio_sample_t *src, unsigned long cnt) { memcpy (dst, src, cnt * sizeof (jack_default_audio_sample_t)); } void memset_interleave (char *dst, char val, unsigned long bytes, unsigned long unit_bytes, unsigned long skip_bytes); void memcpy_fake (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar); void memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); void memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); void memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); void merge_memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); void merge_memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); void merge_memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); void merge_memcpy_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar); void merge_memcpy_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar); #ifdef __cplusplus } #endif #endif /* __jack_memops_h__ */ 0707010000000D000081A400000000000000000000000161E2F7EE0000A9DE000000000000000000000000000000000000002D00000000jack-example-tools-1/common/netjack_packet.c /* * NetJack - Packet Handling functions * * used by the driver and the jacknet_client * * Copyright (C) 2019 Karl Linden <karl.j.linden@gmail.com> * Copyright (C) 2008 Marc-Olivier Barre <marco@marcochapeau.org> * Copyright (C) 2008 Pieter Palmers <pieterpalmers@users.sourceforge.net> * Copyright (C) 2006 Torben Hohn <torbenh@gmx.de> * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: net_driver.c,v 1.16 2006/03/20 19:41:37 torbenh Exp $ * */ #if defined(HAVE_CONFIG_H) #include "config.h" #endif #ifdef __APPLE__ #define _DARWIN_C_SOURCE #endif #if HAVE_PPOLL #define _GNU_SOURCE #endif #include <alloca.h> #include <math.h> #include <stdio.h> #include <memory.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #include <stdarg.h> #include <jack/types.h> #include <sys/types.h> #ifdef WIN32 #include <winsock2.h> #include <malloc.h> #define socklen_t int #else #include <sys/socket.h> #include <netinet/in.h> #include <poll.h> #endif #include <errno.h> #include <signal.h> #include <samplerate.h> #if HAVE_OPUS #include <opus/opus.h> #include <opus/opus_custom.h> #endif #include "netjack_packet.h" // TODO: we explicitly do not include JackError.h here, as that includes half of jack2 as well // #include "JackError.h" #ifdef NO_JACK_ERROR #define jack_error printf #endif int fraggo = 0; void packet_header_hton (jacknet_packet_header *pkthdr) { pkthdr->capture_channels_audio = htonl(pkthdr->capture_channels_audio); pkthdr->playback_channels_audio = htonl(pkthdr->playback_channels_audio); pkthdr->capture_channels_midi = htonl(pkthdr->capture_channels_midi); pkthdr->playback_channels_midi = htonl(pkthdr->playback_channels_midi); pkthdr->period_size = htonl(pkthdr->period_size); pkthdr->sample_rate = htonl(pkthdr->sample_rate); pkthdr->sync_state = htonl(pkthdr->sync_state); pkthdr->transport_frame = htonl(pkthdr->transport_frame); pkthdr->transport_state = htonl(pkthdr->transport_state); pkthdr->framecnt = htonl(pkthdr->framecnt); pkthdr->latency = htonl(pkthdr->latency); pkthdr->reply_port = htonl(pkthdr->reply_port); pkthdr->mtu = htonl(pkthdr->mtu); pkthdr->fragment_nr = htonl(pkthdr->fragment_nr); } void packet_header_ntoh (jacknet_packet_header *pkthdr) { pkthdr->capture_channels_audio = ntohl(pkthdr->capture_channels_audio); pkthdr->playback_channels_audio = ntohl(pkthdr->playback_channels_audio); pkthdr->capture_channels_midi = ntohl(pkthdr->capture_channels_midi); pkthdr->playback_channels_midi = ntohl(pkthdr->playback_channels_midi); pkthdr->period_size = ntohl(pkthdr->period_size); pkthdr->sample_rate = ntohl(pkthdr->sample_rate); pkthdr->sync_state = ntohl(pkthdr->sync_state); pkthdr->transport_frame = ntohl(pkthdr->transport_frame); pkthdr->transport_state = ntohl(pkthdr->transport_state); pkthdr->framecnt = ntohl(pkthdr->framecnt); pkthdr->latency = ntohl(pkthdr->latency); pkthdr->reply_port = ntohl(pkthdr->reply_port); pkthdr->mtu = ntohl(pkthdr->mtu); pkthdr->fragment_nr = ntohl(pkthdr->fragment_nr); } int get_sample_size (int bitdepth) { if (bitdepth == 8) return sizeof (int8_t); if (bitdepth == 16) return sizeof (int16_t); //JN: why? is this for buffer sizes before or after encoding? //JN: if the former, why not int16_t, if the latter, shouldn't it depend on -c N? if( bitdepth == OPUS_MODE ) return sizeof( unsigned char ); return sizeof (int32_t); } int jack_port_is_audio(const char *porttype) { return (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0); } int jack_port_is_midi(const char *porttype) { return (strncmp (porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0); } // fragment management functions. packet_cache *packet_cache_new (int num_packets, int pkt_size, int mtu) { int fragment_payload_size = mtu - sizeof (jacknet_packet_header); int i, fragment_number; if( pkt_size == sizeof(jacknet_packet_header) ) fragment_number = 1; else fragment_number = (pkt_size - sizeof (jacknet_packet_header) - 1) / fragment_payload_size + 1; packet_cache *pcache = malloc (sizeof (packet_cache)); if (pcache == NULL) { jack_error ("could not allocate packet cache (1)"); return NULL; } pcache->size = num_packets; pcache->packets = malloc (sizeof (cache_packet) * num_packets); pcache->master_address_valid = 0; pcache->last_framecnt_retreived = 0; pcache->last_framecnt_retreived_valid = 0; if (pcache->packets == NULL) { jack_error ("could not allocate packet cache (2)"); return NULL; } for (i = 0; i < num_packets; i++) { pcache->packets[i].valid = 0; pcache->packets[i].num_fragments = fragment_number; pcache->packets[i].packet_size = pkt_size; pcache->packets[i].mtu = mtu; pcache->packets[i].framecnt = 0; pcache->packets[i].fragment_array = malloc (sizeof (char) * fragment_number); pcache->packets[i].packet_buf = malloc (pkt_size); if ((pcache->packets[i].fragment_array == NULL) || (pcache->packets[i].packet_buf == NULL)) { jack_error ("could not allocate packet cache (3)"); return NULL; } } pcache->mtu = mtu; return pcache; } void packet_cache_free (packet_cache *pcache) { int i; if( pcache == NULL ) return; for (i = 0; i < pcache->size; i++) { free (pcache->packets[i].fragment_array); free (pcache->packets[i].packet_buf); } free (pcache->packets); free (pcache); } cache_packet *packet_cache_get_packet (packet_cache *pcache, jack_nframes_t framecnt) { int i; cache_packet *retval; for (i = 0; i < pcache->size; i++) { if (pcache->packets[i].valid && (pcache->packets[i].framecnt == framecnt)) return &(pcache->packets[i]); } // The Packet is not in the packet cache. // find a free packet. retval = packet_cache_get_free_packet (pcache); if (retval != NULL) { cache_packet_set_framecnt (retval, framecnt); return retval; } // No Free Packet available // Get The Oldest packet and reset it. retval = packet_cache_get_oldest_packet (pcache); //printf( "Dropping %d from Cache :S\n", retval->framecnt ); cache_packet_reset (retval); cache_packet_set_framecnt (retval, framecnt); return retval; } // TODO: fix wrapping case... need to pass // current expected frame here. // // or just save framecount into packet_cache. cache_packet *packet_cache_get_oldest_packet (packet_cache *pcache) { jack_nframes_t minimal_frame = JACK_MAX_FRAMES; cache_packet *retval = &(pcache->packets[0]); int i; for (i = 0; i < pcache->size; i++) { if (pcache->packets[i].valid && (pcache->packets[i].framecnt < minimal_frame)) { minimal_frame = pcache->packets[i].framecnt; retval = &(pcache->packets[i]); } } return retval; } cache_packet *packet_cache_get_free_packet (packet_cache *pcache) { int i; for (i = 0; i < pcache->size; i++) { if (pcache->packets[i].valid == 0) return &(pcache->packets[i]); } return NULL; } void cache_packet_reset (cache_packet *pack) { int i; pack->valid = 0; // XXX: i don't think this is necessary here... // fragment array is cleared in _set_framecnt() for (i = 0; i < pack->num_fragments; i++) pack->fragment_array[i] = 0; } void cache_packet_set_framecnt (cache_packet *pack, jack_nframes_t framecnt) { int i; pack->framecnt = framecnt; for (i = 0; i < pack->num_fragments; i++) pack->fragment_array[i] = 0; pack->valid = 1; } void cache_packet_add_fragment (cache_packet *pack, char *packet_buf, int rcv_len) { jacknet_packet_header *pkthdr = (jacknet_packet_header *) packet_buf; int fragment_payload_size = pack->mtu - sizeof (jacknet_packet_header); char *packet_bufX = pack->packet_buf + sizeof (jacknet_packet_header); char *dataX = packet_buf + sizeof (jacknet_packet_header); jack_nframes_t fragment_nr = ntohl (pkthdr->fragment_nr); jack_nframes_t framecnt = ntohl (pkthdr->framecnt); if (framecnt != pack->framecnt) { jack_error ("error. framecnts don't match"); return; } if (fragment_nr == 0) { memcpy (pack->packet_buf, packet_buf, rcv_len); pack->fragment_array[0] = 1; return; } if ((fragment_nr < pack->num_fragments) && (fragment_nr > 0)) { if ((fragment_nr * fragment_payload_size + rcv_len - sizeof (jacknet_packet_header)) <= (pack->packet_size - sizeof (jacknet_packet_header))) { memcpy (packet_bufX + fragment_nr * fragment_payload_size, dataX, rcv_len - sizeof (jacknet_packet_header)); pack->fragment_array[fragment_nr] = 1; } else jack_error ("too long packet received..."); } } int cache_packet_is_complete (cache_packet *pack) { int i; for (i = 0; i < pack->num_fragments; i++) if (pack->fragment_array[i] == 0) return 0; return 1; } #ifndef WIN32 // new poll using nanoseconds resolution and // not waiting forever. int netjack_poll_deadline (int sockfd, jack_time_t deadline) { struct pollfd fds; int poll_err = 0; #if HAVE_PPOLL struct timespec timeout_spec = { 0, 0 }; #else int timeout; #endif jack_time_t now = jack_get_time(); if( now >= deadline ) return 0; if( (deadline - now) >= 1000000 ) { jack_error( "deadline more than 1 second in the future, trimming it." ); deadline = now + 500000; } #if HAVE_PPOLL timeout_spec.tv_nsec = (deadline - now) * 1000; #else timeout = lrintf( (float)(deadline - now) / 1000.0 ); #endif fds.fd = sockfd; fds.events = POLLIN; #if HAVE_PPOLL poll_err = ppoll (&fds, 1, &timeout_spec, NULL); #else poll_err = poll (&fds, 1, timeout); #endif if (poll_err == -1) { switch (errno) { case EBADF: jack_error ("Error %d: An invalid file descriptor was given in one of the sets", errno); break; case EFAULT: jack_error ("Error %d: The array given as argument was not contained in the calling program's address space", errno); break; case EINTR: jack_error ("Error %d: A signal occurred before any requested event", errno); break; case EINVAL: jack_error ("Error %d: The nfds value exceeds the RLIMIT_NOFILE value", errno); break; case ENOMEM: jack_error ("Error %d: There was no space to allocate file descriptor tables", errno); break; } } return poll_err; } int netjack_poll (int sockfd, int timeout) { struct pollfd fds; int i, poll_err = 0; sigset_t sigmask, rsigmask; struct sigaction action; sigemptyset(&sigmask); sigaddset(&sigmask, SIGHUP); sigaddset(&sigmask, SIGINT); sigaddset(&sigmask, SIGQUIT); sigaddset(&sigmask, SIGPIPE); sigaddset(&sigmask, SIGTERM); sigaddset(&sigmask, SIGUSR1); sigaddset(&sigmask, SIGUSR2); action.sa_handler = SIG_DFL; action.sa_mask = sigmask; action.sa_flags = SA_RESTART; for (i = 1; i < NSIG; i++) if (sigismember (&sigmask, i)) sigaction (i, &action, 0); fds.fd = sockfd; fds.events = POLLIN; sigprocmask(SIG_UNBLOCK, &sigmask, &rsigmask); while (poll_err == 0) { poll_err = poll (&fds, 1, timeout); } sigprocmask(SIG_SETMASK, &rsigmask, NULL); if (poll_err == -1) { switch (errno) { case EBADF: jack_error ("Error %d: An invalid file descriptor was given in one of the sets", errno); break; case EFAULT: jack_error ("Error %d: The array given as argument was not contained in the calling program's address space", errno); break; case EINTR: jack_error ("Error %d: A signal occurred before any requested event", errno); break; case EINVAL: jack_error ("Error %d: The nfds value exceeds the RLIMIT_NOFILE value", errno); break; case ENOMEM: jack_error ("Error %d: There was no space to allocate file descriptor tables", errno); break; } return 0; } return 1; } #else int netjack_poll (int sockfd, int timeout) { jack_error( "netjack_poll not implemented" ); return 0; } int netjack_poll_deadline (int sockfd, jack_time_t deadline) { fd_set fds; FD_ZERO( &fds ); FD_SET( sockfd, &fds ); struct timeval timeout; while( 1 ) { jack_time_t now = jack_get_time(); if( now >= deadline ) return 0; int timeout_usecs = (deadline - now); //jack_error( "timeout = %d", timeout_usecs ); timeout.tv_sec = 0; timeout.tv_usec = (timeout_usecs < 500) ? 500 : timeout_usecs; timeout.tv_usec = (timeout_usecs > 1000000) ? 500000 : timeout_usecs; int poll_err = select (0, &fds, NULL, NULL, &timeout); if( poll_err != 0 ) return poll_err; } return 0; } #endif // This now reads all a socket has into the cache. // replacing netjack_recv functions. void packet_cache_drain_socket( packet_cache *pcache, int sockfd ) { char *rx_packet = alloca (pcache->mtu); jacknet_packet_header *pkthdr = (jacknet_packet_header *) rx_packet; int rcv_len; jack_nframes_t framecnt; cache_packet *cpack; struct sockaddr_in sender_address; #ifdef WIN32 int senderlen = sizeof( struct sockaddr_in ); u_long parm = 1; ioctlsocket( sockfd, FIONBIO, &parm ); #else unsigned int senderlen = sizeof( struct sockaddr_in ); #endif while (1) { #ifdef WIN32 rcv_len = recvfrom (sockfd, rx_packet, pcache->mtu, 0, (struct sockaddr*) &sender_address, &senderlen); #else rcv_len = recvfrom (sockfd, rx_packet, pcache->mtu, MSG_DONTWAIT, (struct sockaddr*) &sender_address, &senderlen); #endif if (rcv_len < 0) return; if (pcache->master_address_valid) { // Verify its from our master. if (memcmp (&sender_address, &(pcache->master_address), senderlen) != 0) continue; } else { // Setup this one as master //printf( "setup master...\n" ); memcpy ( &(pcache->master_address), &sender_address, senderlen ); pcache->master_address_valid = 1; } framecnt = ntohl (pkthdr->framecnt); if( pcache->last_framecnt_retreived_valid && (framecnt <= pcache->last_framecnt_retreived )) continue; cpack = packet_cache_get_packet (pcache, framecnt); cache_packet_add_fragment (cpack, rx_packet, rcv_len); cpack->recv_timestamp = jack_get_time(); } } void packet_cache_reset_master_address( packet_cache *pcache ) { pcache->master_address_valid = 0; pcache->last_framecnt_retreived = 0; pcache->last_framecnt_retreived_valid = 0; } void packet_cache_clear_old_packets (packet_cache *pcache, jack_nframes_t framecnt ) { int i; for (i = 0; i < pcache->size; i++) { if (pcache->packets[i].valid && (pcache->packets[i].framecnt < framecnt)) { cache_packet_reset (&(pcache->packets[i])); } } } int packet_cache_retreive_packet_pointer( packet_cache *pcache, jack_nframes_t framecnt, char **packet_buf, int pkt_size, jack_time_t *timestamp ) { int i; cache_packet *cpack = NULL; for (i = 0; i < pcache->size; i++) { if (pcache->packets[i].valid && (pcache->packets[i].framecnt == framecnt)) { cpack = &(pcache->packets[i]); break; } } if( cpack == NULL ) { //printf( "retrieve packet: %d....not found\n", framecnt ); return -1; } if( !cache_packet_is_complete( cpack ) ) { return -1; } // ok. cpack is the one we want and its complete. *packet_buf = cpack->packet_buf; if( timestamp ) *timestamp = cpack->recv_timestamp; pcache->last_framecnt_retreived_valid = 1; pcache->last_framecnt_retreived = framecnt; return pkt_size; } int packet_cache_release_packet( packet_cache *pcache, jack_nframes_t framecnt ) { int i; cache_packet *cpack = NULL; for (i = 0; i < pcache->size; i++) { if (pcache->packets[i].valid && (pcache->packets[i].framecnt == framecnt)) { cpack = &(pcache->packets[i]); break; } } if( cpack == NULL ) { //printf( "retrieve packet: %d....not found\n", framecnt ); return -1; } if( !cache_packet_is_complete( cpack ) ) { return -1; } cache_packet_reset (cpack); packet_cache_clear_old_packets( pcache, framecnt ); return 0; } float packet_cache_get_fill( packet_cache *pcache, jack_nframes_t expected_framecnt ) { int num_packets_before_us = 0; int i; for (i = 0; i < pcache->size; i++) { cache_packet *cpack = &(pcache->packets[i]); if (cpack->valid && cache_packet_is_complete( cpack )) if( cpack->framecnt >= expected_framecnt ) num_packets_before_us += 1; } return 100.0 * (float)num_packets_before_us / (float)( pcache->size ); } // Returns 0 when no valid packet is inside the cache. int packet_cache_get_next_available_framecnt( packet_cache *pcache, jack_nframes_t expected_framecnt, jack_nframes_t *framecnt ) { int i; jack_nframes_t best_offset = JACK_MAX_FRAMES / 2 - 1; int retval = 0; for (i = 0; i < pcache->size; i++) { cache_packet *cpack = &(pcache->packets[i]); //printf( "p%d: valid=%d, frame %d\n", i, cpack->valid, cpack->framecnt ); if (!cpack->valid || !cache_packet_is_complete( cpack )) { //printf( "invalid\n" ); continue; } if( cpack->framecnt < expected_framecnt ) continue; if( (cpack->framecnt - expected_framecnt) > best_offset ) { continue; } best_offset = cpack->framecnt - expected_framecnt; retval = 1; if (best_offset == 0) break; } if (retval && framecnt) *framecnt = expected_framecnt + best_offset; return retval; } int packet_cache_get_highest_available_framecnt( packet_cache *pcache, jack_nframes_t *framecnt ) { int i; jack_nframes_t best_value = 0; int retval = 0; for (i = 0; i < pcache->size; i++) { cache_packet *cpack = &(pcache->packets[i]); //printf( "p%d: valid=%d, frame %d\n", i, cpack->valid, cpack->framecnt ); if (!cpack->valid || !cache_packet_is_complete( cpack )) { //printf( "invalid\n" ); continue; } if (cpack->framecnt < best_value) { continue; } best_value = cpack->framecnt; retval = 1; } if (retval && framecnt) *framecnt = best_value; return retval; } // Returns 0 when no valid packet is inside the cache. int packet_cache_find_latency( packet_cache *pcache, jack_nframes_t expected_framecnt, jack_nframes_t *framecnt ) { int i; jack_nframes_t best_offset = 0; int retval = 0; for (i = 0; i < pcache->size; i++) { cache_packet *cpack = &(pcache->packets[i]); //printf( "p%d: valid=%d, frame %d\n", i, cpack->valid, cpack->framecnt ); if (!cpack->valid || !cache_packet_is_complete( cpack )) { //printf( "invalid\n" ); continue; } if ((cpack->framecnt - expected_framecnt) < best_offset) { continue; } best_offset = cpack->framecnt - expected_framecnt; retval = 1; if( best_offset == 0 ) break; } if (retval && framecnt) *framecnt = JACK_MAX_FRAMES - best_offset; return retval; } // fragmented packet IO void netjack_sendto (int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, int addr_size, int mtu) { int frag_cnt = 0; char *tx_packet, *dataX; jacknet_packet_header *pkthdr; tx_packet = alloca (mtu + 10); dataX = tx_packet + sizeof (jacknet_packet_header); pkthdr = (jacknet_packet_header *) tx_packet; int fragment_payload_size = mtu - sizeof (jacknet_packet_header); if (pkt_size <= mtu) { int err; pkthdr = (jacknet_packet_header *) packet_buf; pkthdr->fragment_nr = htonl (0); err = sendto(sockfd, packet_buf, pkt_size, flags, addr, addr_size); if( err < 0 ) { //printf( "error in send\n" ); perror( "send" ); } } else { int err; // Copy the packet header to the tx pack first. memcpy(tx_packet, packet_buf, sizeof (jacknet_packet_header)); // Now loop and send all char *packet_bufX = packet_buf + sizeof (jacknet_packet_header); while (packet_bufX < (packet_buf + pkt_size - fragment_payload_size)) { pkthdr->fragment_nr = htonl (frag_cnt++); memcpy (dataX, packet_bufX, fragment_payload_size); sendto (sockfd, tx_packet, mtu, flags, addr, addr_size); packet_bufX += fragment_payload_size; } int last_payload_size = packet_buf + pkt_size - packet_bufX; memcpy (dataX, packet_bufX, last_payload_size); pkthdr->fragment_nr = htonl (frag_cnt); //jack_log("last fragment_count = %d, payload_size = %d\n", fragment_count, last_payload_size); // sendto(last_pack_size); err = sendto(sockfd, tx_packet, last_payload_size + sizeof(jacknet_packet_header), flags, addr, addr_size); if( err < 0 ) { //printf( "error in send\n" ); perror( "send" ); } } } void decode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf) { int i; jack_midi_clear_buffer (buf); for (i = 0; i < buffer_size_uint32 - 3;) { uint32_t payload_size; payload_size = buffer_uint32[i]; payload_size = ntohl (payload_size); if (payload_size) { jack_midi_event_t event; event.time = ntohl (buffer_uint32[i + 1]); event.size = ntohl (buffer_uint32[i + 2]); event.buffer = (jack_midi_data_t*) (&(buffer_uint32[i + 3])); jack_midi_event_write (buf, event.time, event.buffer, event.size); // skip to the next event unsigned int nb_data_quads = (((event.size - 1) & ~0x3) >> 2) + 1; i += 3 + nb_data_quads; } else break; // no events can follow an empty event, we're done } } void encode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf) { int i; unsigned int written = 0; // midi port, encode midi events unsigned int nevents = jack_midi_get_event_count (buf); for (i = 0; i < nevents; ++i) { jack_midi_event_t event; jack_midi_event_get (&event, buf, i); unsigned int nb_data_quads = (((event.size - 1) & ~0x3) >> 2) + 1; unsigned int payload_size = 3 + nb_data_quads; // only write if we have sufficient space for the event // otherwise drop it if (written + payload_size < buffer_size_uint32 - 1) { // write header buffer_uint32[written] = htonl (payload_size); written++; buffer_uint32[written] = htonl (event.time); written++; buffer_uint32[written] = htonl (event.size); written++; // write data jack_midi_data_t* tmpbuff = (jack_midi_data_t*)(&(buffer_uint32[written])); memcpy (tmpbuff, event.buffer, event.size); written += nb_data_quads; } else { // buffer overflow jack_error ("midi buffer overflow"); break; } } // now put a netjack_midi 'no-payload' event, signaling EOF buffer_uint32[written] = 0; } // render functions for float void render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats) { int chn = 0; JSList *node = capture_ports; JSList *src_node = capture_srcs; uint32_t *packet_bufX = (uint32_t *)packet_payload; if (!packet_payload) return; while (node != NULL) { int i; int_float_t val; SRC_DATA src; jack_port_t *port = (jack_port_t *) node->data; jack_default_audio_sample_t* buf = jack_port_get_buffer (port, nframes); const char *porttype = jack_port_type (port); if (jack_port_is_audio (porttype)) { // audio port, resample if necessary if (net_period_down != nframes) { SRC_STATE *src_state = src_node->data; for (i = 0; i < net_period_down; i++) { packet_bufX[i] = ntohl (packet_bufX[i]); } src.data_in = (float *) packet_bufX; src.input_frames = net_period_down; src.data_out = buf; src.output_frames = nframes; src.src_ratio = (float) nframes / (float) net_period_down; src.end_of_input = 0; src_set_ratio (src_state, src.src_ratio); src_process (src_state, &src); src_node = jack_slist_next (src_node); } else { if( dont_htonl_floats ) { memcpy( buf, packet_bufX, net_period_down * sizeof(jack_default_audio_sample_t)); } else { for (i = 0; i < net_period_down; i++) { val.i = packet_bufX[i]; val.i = ntohl (val.i); buf[i] = val.f; } } } } else if (jack_port_is_midi (porttype)) { // midi port, decode midi events // convert the data buffer to a standard format (uint32_t based) unsigned int buffer_size_uint32 = net_period_down; uint32_t * buffer_uint32 = (uint32_t*)packet_bufX; decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); } packet_bufX = (packet_bufX + net_period_down); node = jack_slist_next (node); chn++; } } void render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats ) { int chn = 0; JSList *node = playback_ports; JSList *src_node = playback_srcs; uint32_t *packet_bufX = (uint32_t *) packet_payload; while (node != NULL) { SRC_DATA src; int i; int_float_t val; jack_port_t *port = (jack_port_t *) node->data; jack_default_audio_sample_t* buf = jack_port_get_buffer (port, nframes); const char *porttype = jack_port_type (port); if (jack_port_is_audio (porttype)) { // audio port, resample if necessary if (net_period_up != nframes) { SRC_STATE *src_state = src_node->data; src.data_in = buf; src.input_frames = nframes; src.data_out = (float *) packet_bufX; src.output_frames = net_period_up; src.src_ratio = (float) net_period_up / (float) nframes; src.end_of_input = 0; src_set_ratio (src_state, src.src_ratio); src_process (src_state, &src); for (i = 0; i < net_period_up; i++) { packet_bufX[i] = htonl (packet_bufX[i]); } src_node = jack_slist_next (src_node); } else { if( dont_htonl_floats ) { memcpy( packet_bufX, buf, net_period_up * sizeof(jack_default_audio_sample_t) ); } else { for (i = 0; i < net_period_up; i++) { val.f = buf[i]; val.i = htonl (val.i); packet_bufX[i] = val.i; } } } } else if (jack_port_is_midi (porttype)) { // encode midi events from port to packet // convert the data buffer to a standard format (uint32_t based) unsigned int buffer_size_uint32 = net_period_up; uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); } packet_bufX = (packet_bufX + net_period_up); node = jack_slist_next (node); chn++; } } // render functions for 16bit void render_payload_to_jack_ports_16bit (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes) { int chn = 0; JSList *node = capture_ports; JSList *src_node = capture_srcs; uint16_t *packet_bufX = (uint16_t *)packet_payload; if( !packet_payload ) return; while (node != NULL) { int i; //uint32_t val; SRC_DATA src; jack_port_t *port = (jack_port_t *) node->data; jack_default_audio_sample_t* buf = jack_port_get_buffer (port, nframes); float *floatbuf = alloca (sizeof(float) * net_period_down); const char *porttype = jack_port_type (port); if (jack_port_is_audio (porttype)) { // audio port, resample if necessary if (net_period_down != nframes) { SRC_STATE *src_state = src_node->data; for (i = 0; i < net_period_down; i++) { floatbuf[i] = ((float) ntohs(packet_bufX[i])) / 32767.0 - 1.0; } src.data_in = floatbuf; src.input_frames = net_period_down; src.data_out = buf; src.output_frames = nframes; src.src_ratio = (float) nframes / (float) net_period_down; src.end_of_input = 0; src_set_ratio (src_state, src.src_ratio); src_process (src_state, &src); src_node = jack_slist_next (src_node); } else for (i = 0; i < net_period_down; i++) buf[i] = ((float) ntohs (packet_bufX[i])) / 32768.0 - 1.0; } else if (jack_port_is_midi (porttype)) { // midi port, decode midi events // convert the data buffer to a standard format (uint32_t based) unsigned int buffer_size_uint32 = net_period_down / 2; uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); } packet_bufX = (packet_bufX + net_period_down); node = jack_slist_next (node); chn++; } } void render_jack_ports_to_payload_16bit (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up) { int chn = 0; JSList *node = playback_ports; JSList *src_node = playback_srcs; uint16_t *packet_bufX = (uint16_t *)packet_payload; while (node != NULL) { SRC_DATA src; int i; jack_port_t *port = (jack_port_t *) node->data; jack_default_audio_sample_t* buf = jack_port_get_buffer (port, nframes); const char *porttype = jack_port_type (port); if (jack_port_is_audio (porttype)) { // audio port, resample if necessary if (net_period_up != nframes) { SRC_STATE *src_state = src_node->data; float *floatbuf = alloca (sizeof(float) * net_period_up); src.data_in = buf; src.input_frames = nframes; src.data_out = floatbuf; src.output_frames = net_period_up; src.src_ratio = (float) net_period_up / (float) nframes; src.end_of_input = 0; src_set_ratio (src_state, src.src_ratio); src_process (src_state, &src); for (i = 0; i < net_period_up; i++) { packet_bufX[i] = htons (((uint16_t)((floatbuf[i] + 1.0) * 32767.0))); } src_node = jack_slist_next (src_node); } else for (i = 0; i < net_period_up; i++) packet_bufX[i] = htons(((uint16_t)((buf[i] + 1.0) * 32767.0))); } else if (jack_port_is_midi (porttype)) { // encode midi events from port to packet // convert the data buffer to a standard format (uint32_t based) unsigned int buffer_size_uint32 = net_period_up / 2; uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); } packet_bufX = (packet_bufX + net_period_up); node = jack_slist_next (node); chn++; } } // render functions for 8bit void render_payload_to_jack_ports_8bit (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes) { int chn = 0; JSList *node = capture_ports; JSList *src_node = capture_srcs; int8_t *packet_bufX = (int8_t *)packet_payload; if (!packet_payload) return; while (node != NULL) { int i; //uint32_t val; SRC_DATA src; jack_port_t *port = (jack_port_t *) node->data; jack_default_audio_sample_t* buf = jack_port_get_buffer (port, nframes); float *floatbuf = alloca (sizeof (float) * net_period_down); const char *porttype = jack_port_type (port); if (jack_port_is_audio(porttype)) { // audio port, resample if necessary if (net_period_down != nframes) { SRC_STATE *src_state = src_node->data; for (i = 0; i < net_period_down; i++) floatbuf[i] = ((float) packet_bufX[i]) / 127.0; src.data_in = floatbuf; src.input_frames = net_period_down; src.data_out = buf; src.output_frames = nframes; src.src_ratio = (float) nframes / (float) net_period_down; src.end_of_input = 0; src_set_ratio (src_state, src.src_ratio); src_process (src_state, &src); src_node = jack_slist_next (src_node); } else for (i = 0; i < net_period_down; i++) buf[i] = ((float) packet_bufX[i]) / 127.0; } else if (jack_port_is_midi (porttype)) { // midi port, decode midi events // convert the data buffer to a standard format (uint32_t based) unsigned int buffer_size_uint32 = net_period_down / 2; uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); } packet_bufX = (packet_bufX + net_period_down); node = jack_slist_next (node); chn++; } } void render_jack_ports_to_payload_8bit (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up) { int chn = 0; JSList *node = playback_ports; JSList *src_node = playback_srcs; int8_t *packet_bufX = (int8_t *)packet_payload; while (node != NULL) { SRC_DATA src; int i; jack_port_t *port = (jack_port_t *) node->data; jack_default_audio_sample_t* buf = jack_port_get_buffer (port, nframes); const char *porttype = jack_port_type (port); if (jack_port_is_audio (porttype)) { // audio port, resample if necessary if (net_period_up != nframes) { SRC_STATE *src_state = src_node->data; float *floatbuf = alloca (sizeof (float) * net_period_up); src.data_in = buf; src.input_frames = nframes; src.data_out = floatbuf; src.output_frames = net_period_up; src.src_ratio = (float) net_period_up / (float) nframes; src.end_of_input = 0; src_set_ratio (src_state, src.src_ratio); src_process (src_state, &src); for (i = 0; i < net_period_up; i++) packet_bufX[i] = floatbuf[i] * 127.0; src_node = jack_slist_next (src_node); } else for (i = 0; i < net_period_up; i++) packet_bufX[i] = buf[i] * 127.0; } else if (jack_port_is_midi (porttype)) { // encode midi events from port to packet // convert the data buffer to a standard format (uint32_t based) unsigned int buffer_size_uint32 = net_period_up / 4; uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); } packet_bufX = (packet_bufX + net_period_up); node = jack_slist_next (node); chn++; } } #if HAVE_OPUS #define CDO (sizeof(short)) ///< compressed data offset (first 2 bytes are length) // render functions for Opus. void render_payload_to_jack_ports_opus (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes) { int chn = 0; JSList *node = capture_ports; JSList *src_node = capture_srcs; unsigned char *packet_bufX = (unsigned char *)packet_payload; while (node != NULL) { jack_port_t *port = (jack_port_t *) node->data; jack_default_audio_sample_t* buf = jack_port_get_buffer (port, nframes); const char *porttype = jack_port_type (port); if (jack_port_is_audio (porttype)) { // audio port, decode opus data. OpusCustomDecoder *decoder = (OpusCustomDecoder*) src_node->data; if( !packet_payload ) memset(buf, 0, nframes * sizeof(float)); else { unsigned short len; memcpy(&len, packet_bufX, CDO); len = ntohs(len); opus_custom_decode_float( decoder, packet_bufX + CDO, len, buf, nframes ); } src_node = jack_slist_next (src_node); } else if (jack_port_is_midi (porttype)) { // midi port, decode midi events // convert the data buffer to a standard format (uint32_t based) unsigned int buffer_size_uint32 = net_period_down / 2; uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; if( packet_payload ) decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); } packet_bufX = (packet_bufX + net_period_down); node = jack_slist_next (node); chn++; } } void render_jack_ports_to_payload_opus (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up) { int chn = 0; JSList *node = playback_ports; JSList *src_node = playback_srcs; unsigned char *packet_bufX = (unsigned char *)packet_payload; while (node != NULL) { jack_port_t *port = (jack_port_t *) node->data; jack_default_audio_sample_t* buf = jack_port_get_buffer (port, nframes); const char *porttype = jack_port_type (port); if (jack_port_is_audio (porttype)) { // audio port, encode opus data. int encoded_bytes; float *floatbuf = alloca (sizeof(float) * nframes ); memcpy( floatbuf, buf, nframes * sizeof(float) ); OpusCustomEncoder *encoder = (OpusCustomEncoder*) src_node->data; encoded_bytes = opus_custom_encode_float( encoder, floatbuf, nframes, packet_bufX + CDO, net_period_up - CDO ); unsigned short len = htons(encoded_bytes); memcpy(packet_bufX, &len, CDO); src_node = jack_slist_next( src_node ); } else if (jack_port_is_midi (porttype)) { // encode midi events from port to packet // convert the data buffer to a standard format (uint32_t based) unsigned int buffer_size_uint32 = net_period_up / 2; uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); } packet_bufX = (packet_bufX + net_period_up); node = jack_slist_next (node); chn++; } } #endif /* Wrapper functions with bitdepth argument... */ void render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats) { if (bitdepth == 8) render_payload_to_jack_ports_8bit (packet_payload, net_period_down, capture_ports, capture_srcs, nframes); else if (bitdepth == 16) render_payload_to_jack_ports_16bit (packet_payload, net_period_down, capture_ports, capture_srcs, nframes); #if HAVE_OPUS else if (bitdepth == OPUS_MODE) render_payload_to_jack_ports_opus (packet_payload, net_period_down, capture_ports, capture_srcs, nframes); #endif else render_payload_to_jack_ports_float (packet_payload, net_period_down, capture_ports, capture_srcs, nframes, dont_htonl_floats); } void render_jack_ports_to_payload (int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats) { if (bitdepth == 8) render_jack_ports_to_payload_8bit (playback_ports, playback_srcs, nframes, packet_payload, net_period_up); else if (bitdepth == 16) render_jack_ports_to_payload_16bit (playback_ports, playback_srcs, nframes, packet_payload, net_period_up); #if HAVE_OPUS else if (bitdepth == OPUS_MODE) render_jack_ports_to_payload_opus (playback_ports, playback_srcs, nframes, packet_payload, net_period_up); #endif else render_jack_ports_to_payload_float (playback_ports, playback_srcs, nframes, packet_payload, net_period_up, dont_htonl_floats); } 0707010000000E000081A400000000000000000000000161E2F7EE000015D2000000000000000000000000000000000000002D00000000jack-example-tools-1/common/netjack_packet.h /* * NetJack - Packet Handling functions * * used by the driver and the jacknet_client * * Copyright (C) 2006 Torben Hohn <torbenh@gmx.de> * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: net_driver.c,v 1.16 2006/03/20 19:41:37 torbenh Exp $ * */ #ifndef __JACK_NET_PACKET_H__ #define __JACK_NET_PACKET_H__ #ifdef __cplusplus extern "C" { #endif #include <jack/jack.h> #include <jack/types.h> #include <jack/jslist.h> #include <jack/midiport.h> // The Packet Header. #define OPUS_MODE 999 // Magic bitdepth value that indicates OPUS compression #define MASTER_FREEWHEELS 0x80000000 typedef struct _jacknet_packet_header jacknet_packet_header; struct _jacknet_packet_header { // General AutoConf Data jack_nframes_t capture_channels_audio; jack_nframes_t playback_channels_audio; jack_nframes_t capture_channels_midi; jack_nframes_t playback_channels_midi; jack_nframes_t period_size; jack_nframes_t sample_rate; // Transport Sync jack_nframes_t sync_state; jack_nframes_t transport_frame; jack_nframes_t transport_state; // Packet loss Detection, and latency reduction jack_nframes_t framecnt; jack_nframes_t latency; jack_nframes_t reply_port; jack_nframes_t mtu; jack_nframes_t fragment_nr; }; typedef union _int_float int_float_t; union _int_float { uint32_t i; float f; }; // fragment reorder cache. typedef struct _cache_packet cache_packet; struct _cache_packet { int valid; int num_fragments; int packet_size; int mtu; jack_time_t recv_timestamp; jack_nframes_t framecnt; char * fragment_array; char * packet_buf; }; typedef struct _packet_cache packet_cache; struct _packet_cache { int size; cache_packet *packets; int mtu; struct sockaddr_in master_address; int master_address_valid; jack_nframes_t last_framecnt_retreived; int last_framecnt_retreived_valid; }; // fragment cache function prototypes // XXX: Some of these are private. packet_cache *packet_cache_new(int num_packets, int pkt_size, int mtu); void packet_cache_free(packet_cache *pkt_cache); cache_packet *packet_cache_get_packet(packet_cache *pkt_cache, jack_nframes_t framecnt); cache_packet *packet_cache_get_oldest_packet(packet_cache *pkt_cache); cache_packet *packet_cache_get_free_packet(packet_cache *pkt_cache); void cache_packet_reset(cache_packet *pack); void cache_packet_set_framecnt(cache_packet *pack, jack_nframes_t framecnt); void cache_packet_add_fragment(cache_packet *pack, char *packet_buf, int rcv_len); int cache_packet_is_complete(cache_packet *pack); void packet_cache_drain_socket( packet_cache *pcache, int sockfd ); void packet_cache_reset_master_address( packet_cache *pcache ); float packet_cache_get_fill( packet_cache *pcache, jack_nframes_t expected_framecnt ); int packet_cache_retreive_packet_pointer( packet_cache *pcache, jack_nframes_t framecnt, char **packet_buf, int pkt_size, jack_time_t *timestamp ); int packet_cache_release_packet( packet_cache *pcache, jack_nframes_t framecnt ); int packet_cache_get_next_available_framecnt( packet_cache *pcache, jack_nframes_t expected_framecnt, jack_nframes_t *framecnt ); int packet_cache_get_highest_available_framecnt( packet_cache *pcache, jack_nframes_t *framecnt ); int packet_cache_find_latency( packet_cache *pcache, jack_nframes_t expected_framecnt, jack_nframes_t *framecnt ); // Function Prototypes int netjack_poll_deadline (int sockfd, jack_time_t deadline); void netjack_sendto(int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, int addr_size, int mtu); int get_sample_size(int bitdepth); void packet_header_hton(jacknet_packet_header *pkthdr); void packet_header_ntoh(jacknet_packet_header *pkthdr); void render_payload_to_jack_ports(int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats ); void render_jack_ports_to_payload(int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats ); // XXX: This is sort of deprecated: // This one waits forever. an is not using ppoll int netjack_poll(int sockfd, int timeout); void decode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf); void encode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf); #ifdef __cplusplus } #endif #endif 0707010000000F000041ED00000000000000000000000161E2F7EE00000000000000000000000000000000000000000000002500000000jack-example-tools-1/example-clients07070100000010000081A400000000000000000000000161E2F7EE000001B5000000000000000000000000000000000000003000000000jack-example-tools-1/example-clients/.gitignore.deps/ .libs/ Makefile Makefile.in capture_client.o impulse_grabber.o inprocess.la inprocess.lo intime.la intime.lo jack_impulse_grabber jack_latent_client jack_metro jack_midiseq jack_midisine jack_rec jack_server_control jack_showtime jack_simple_client jack_simple_session_client jack_transport_client latent_client.o metro.o midiseq.o midisine.o server_control.o showtime.o simple_client.o simple_session_client.o transport_client.o 07070100000011000081A400000000000000000000000161E2F7EE00002449000000000000000000000000000000000000003600000000jack-example-tools-1/example-clients/capture_client.c/* Copyright (C) 2001 Paul Davis Copyright (C) 2003 Jack O'Quin 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., 675 Mass Ave, Cambridge, MA 02139, USA. * 2002/08/23 - modify for libsndfile 1.0.0 <andy@alsaplayer.org> * 2003/05/26 - use ringbuffers - joq */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sndfile.h> #include <pthread.h> #include <signal.h> #include <getopt.h> #include <inttypes.h> #include <jack/jack.h> #include <jack/ringbuffer.h> typedef struct _thread_info { pthread_t thread_id; SNDFILE *sf; jack_nframes_t duration; jack_nframes_t rb_size; jack_client_t *client; unsigned int channels; int bitdepth; char *path; volatile int can_capture; volatile int can_process; volatile int status; } jack_thread_info_t; /* JACK data */ unsigned int nports; jack_port_t **ports; jack_default_audio_sample_t **in; jack_nframes_t nframes; const size_t sample_size = sizeof(jack_default_audio_sample_t); /* Synchronization between process thread and disk thread. */ #define DEFAULT_RB_SIZE 16384 /* ringbuffer size in frames */ jack_ringbuffer_t *rb; pthread_mutex_t disk_thread_lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER; long overruns = 0; jack_client_t *client; static void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } static void * disk_thread (void *arg) { jack_thread_info_t *info = (jack_thread_info_t *) arg; static jack_nframes_t total_captured = 0; jack_nframes_t samples_per_frame = info->channels; size_t bytes_per_frame = samples_per_frame * sample_size; void *framebuf = malloc (bytes_per_frame); pthread_mutex_lock (&disk_thread_lock); info->status = 0; while (1) { /* Write the data one frame at a time. This is * inefficient, but makes things simpler. */ while (info->can_capture && (jack_ringbuffer_read_space (rb) >= bytes_per_frame)) { jack_ringbuffer_read (rb, framebuf, bytes_per_frame); if (sf_writef_float (info->sf, framebuf, 1) != 1) { char errstr[256]; sf_error_str (0, errstr, sizeof (errstr) - 1); fprintf (stderr, "cannot write sndfile (%s)\n", errstr); info->status = EIO; /* write failed */ goto done; } if (++total_captured >= info->duration) { printf ("disk thread finished\n"); goto done; } } /* wait until process() signals more data */ pthread_cond_wait (&data_ready, &disk_thread_lock); } done: pthread_mutex_unlock (&disk_thread_lock); free (framebuf); return 0; } static int process (jack_nframes_t nframes, void *arg) { unsigned chn; size_t i; jack_thread_info_t *info = (jack_thread_info_t *) arg; /* Do nothing until we're ready to begin. */ if ((!info->can_process) || (!info->can_capture)) return 0; for (chn = 0; chn < nports; chn++) in[chn] = jack_port_get_buffer (ports[chn], nframes); /* Sndfile requires interleaved data. It is simpler here to * just queue interleaved samples to a single ringbuffer. */ for (i = 0; i < nframes; i++) { for (chn = 0; chn < nports; chn++) { if (jack_ringbuffer_write (rb, (void *) (in[chn]+i), sample_size) < sample_size) overruns++; } } /* Tell the disk thread there is work to do. If it is already * running, the lock will not be available. We can't wait * here in the process() thread, but we don't need to signal * in that case, because the disk thread will read all the * data queued before waiting again. */ if (pthread_mutex_trylock (&disk_thread_lock) == 0) { pthread_cond_signal (&data_ready); pthread_mutex_unlock (&disk_thread_lock); } return 0; } static void jack_shutdown (void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } static void setup_disk_thread (jack_thread_info_t *info) { SF_INFO sf_info; int short_mask; sf_info.samplerate = jack_get_sample_rate (info->client); sf_info.channels = info->channels; switch (info->bitdepth) { case 8: short_mask = SF_FORMAT_PCM_U8; break; case 16: short_mask = SF_FORMAT_PCM_16; break; case 24: short_mask = SF_FORMAT_PCM_24; break; case 32: short_mask = SF_FORMAT_PCM_32; break; default: short_mask = SF_FORMAT_PCM_16; break; } sf_info.format = SF_FORMAT_WAV|short_mask; if ((info->sf = sf_open (info->path, SFM_WRITE, &sf_info)) == NULL) { char errstr[256]; sf_error_str (0, errstr, sizeof (errstr) - 1); fprintf (stderr, "cannot open sndfile \"%s\" for output (%s)\n", info->path, errstr); jack_client_close (info->client); exit (1); } info->duration *= sf_info.samplerate; info->can_capture = 0; pthread_create (&info->thread_id, NULL, disk_thread, info); } static void run_disk_thread (jack_thread_info_t *info) { info->can_capture = 1; pthread_join (info->thread_id, NULL); sf_close (info->sf); if (overruns > 0) { fprintf (stderr, "jackrec failed with %ld overruns.\n", overruns); fprintf (stderr, " try a bigger buffer than -B %" PRIu32 ".\n", info->rb_size); info->status = EPIPE; } } static void setup_ports (int sources, char *source_names[], jack_thread_info_t *info) { unsigned int i; size_t in_size; /* Allocate data structures that depend on the number of ports. */ nports = sources; ports = (jack_port_t **) malloc (sizeof (jack_port_t *) * nports); in_size = nports * sizeof (jack_default_audio_sample_t *); in = (jack_default_audio_sample_t **) malloc (in_size); rb = jack_ringbuffer_create (nports * sample_size * info->rb_size); /* When JACK is running realtime, jack_activate() will have * called mlockall() to lock our pages into memory. But, we * still need to touch any newly allocated pages before * process() starts using them. Otherwise, a page fault could * create a delay that would force JACK to shut us down. */ memset(in, 0, in_size); memset(rb->buf, 0, rb->size); for (i = 0; i < nports; i++) { char name[64]; sprintf (name, "input%d", i+1); if ((ports[i] = jack_port_register (info->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0)) == 0) { fprintf (stderr, "cannot register input port \"%s\"!\n", name); jack_client_close (info->client); exit (1); } } for (i = 0; i < nports; i++) { if (jack_connect (info->client, source_names[i], jack_port_name (ports[i]))) { fprintf (stderr, "cannot connect input port %s to %s\n", jack_port_name (ports[i]), source_names[i]); jack_client_close (info->client); exit (1); } } info->can_process = 1; /* process() can start, now */ } int main (int argc, char *argv[]) { jack_thread_info_t thread_info; int c; int longopt_index = 0; extern int optind, opterr; int show_usage = 0; char *optstring = "d:f:b:B:h"; struct option long_options[] = { { "help", 0, 0, 'h' }, { "duration", 1, 0, 'd' }, { "file", 1, 0, 'f' }, { "bitdepth", 1, 0, 'b' }, { "bufsize", 1, 0, 'B' }, { 0, 0, 0, 0 } }; memset (&thread_info, 0, sizeof (thread_info)); thread_info.rb_size = DEFAULT_RB_SIZE; opterr = 0; while ((c = getopt_long (argc, argv, optstring, long_options, &longopt_index)) != -1) { switch (c) { case 1: /* getopt signals end of '-' options */ break; case 'h': show_usage++; break; case 'd': thread_info.duration = atoi (optarg); break; case 'f': thread_info.path = optarg; break; case 'b': thread_info.bitdepth = atoi (optarg); break; case 'B': thread_info.rb_size = atoi (optarg); break; default: fprintf (stderr, "error\n"); show_usage++; break; } } if (show_usage || thread_info.path == NULL || optind == argc) { fprintf (stderr, "usage: jackrec -f filename [ -d second ] [ -b bitdepth ] [ -B bufsize ] port1 [ port2 ... ]\n"); exit (1); } if ((client = jack_client_open ("jackrec", JackNullOption, NULL)) == 0) { fprintf (stderr, "JACK server not running?\n"); exit (1); } thread_info.client = client; thread_info.channels = argc - optind; thread_info.can_process = 0; setup_disk_thread (&thread_info); jack_set_process_callback (client, process, &thread_info); jack_on_shutdown (client, jack_shutdown, &thread_info); if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); } setup_ports (argc - optind, &argv[optind], &thread_info); /* install a signal handler to properly quits jack client */ #ifndef WIN32 signal(SIGQUIT, signal_handler); signal(SIGHUP, signal_handler); #endif signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); run_disk_thread (&thread_info); jack_client_close (client); jack_ringbuffer_free (rb); exit (0); } 07070100000012000081A400000000000000000000000161E2F7EE0000064E000000000000000000000000000000000000002F00000000jack-example-tools-1/example-clients/control.c/** @file control.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. */ #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <math.h> #include <jack/jack.h> jack_client_t *client; static int reorder = 0; static int Jack_Graph_Order_Callback(void *arg) { const char **ports; int i; printf("Jack_Graph_Order_Callback count = %d\n", reorder++); ports = jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); if (ports) { for (i = 0; ports[i]; ++i) { printf("name: %s\n", ports[i]); } jack_free(ports); } ports = jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); if (ports) { for (i = 0; ports[i]; ++i) { printf("name: %s\n", ports[i]); } jack_free(ports); } return 0; } int main (int argc, char *argv[]) { jack_options_t options = JackNullOption; jack_status_t status; /* open a client connection to the JACK server */ client = jack_client_open("control_client", options, &status); if (client == NULL) { printf("jack_client_open() failed \n"); exit(1); } if (jack_set_graph_order_callback(client, Jack_Graph_Order_Callback, 0) != 0) { printf("Error when calling jack_set_graph_order_callback() !\n"); } /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if (jack_activate(client)) { printf("cannot activate client"); exit(1); } printf("Type 'q' to quit\n"); while ((getchar() != 'q')) {} jack_client_close(client); exit (0); } 07070100000013000081A400000000000000000000000161E2F7EE0000073F000000000000000000000000000000000000003000000000jack-example-tools-1/example-clients/cpu_load.c/** @file cpu_load.c * */ #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <signal.h> #ifndef WIN32 #include <unistd.h> #endif #include <jack/jack.h> jack_client_t *client; static void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } /** * JACK calls this shutdown_callback if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown(void *arg) { exit(1); } int main(int argc, char *argv[]) { jack_options_t options = JackNullOption; jack_status_t status; /* open a client connection to the JACK server */ client = jack_client_open ("jack_cpu_load", options, &status); if (client == NULL) { fprintf(stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf(stderr, "Unable to connect to JACK server\n"); } exit(1); } jack_on_shutdown(client, jack_shutdown, 0); /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if (jack_activate(client)) { fprintf(stderr, "cannot activate client"); exit(1); } /* install a signal handler to properly quits jack client */ #ifdef WIN32 signal(SIGINT, signal_handler); signal(SIGABRT, signal_handler); signal(SIGTERM, signal_handler); #else signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); #endif while (1) { printf("jack DSP load %f\n", jack_cpu_load(client)); #ifdef WIN32 Sleep(1000); #else sleep(1); #endif } jack_client_close(client); exit(0 ); } 07070100000014000081A400000000000000000000000161E2F7EE0000185A000000000000000000000000000000000000003700000000jack-example-tools-1/example-clients/impulse_grabber.c/* * Copyright (C) 2001 Steve Harris * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include <stdio.h> #include <errno.h> #ifndef WIN32 #include <unistd.h> #endif #include <stdlib.h> #include <signal.h> #include <math.h> #include <getopt.h> #include <jack/jack.h> jack_port_t *input_port; jack_port_t *output_port; unsigned int impulse_sent = 0; float *response; unsigned long response_duration; unsigned long response_pos; int grab_finished = 0; jack_client_t *client; static void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } static int process (jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes); jack_default_audio_sample_t *in = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port, nframes); unsigned int i; if (grab_finished) { return 0; } else if (impulse_sent) { for(i=0; i<nframes && response_pos < response_duration; i++) { response[response_pos++] = in[i]; } if (response_pos >= response_duration) { grab_finished = 1; } for (i=0; i<nframes; i++) { out[i] = 0.0f; } } else { out[0] = 1.0f; for (i=1; i<nframes; i++) { out[i] = 0.0f; } impulse_sent = 1; } return 0; } static void jack_shutdown (void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit (1); } int main (int argc, char *argv[]) { const char **ports; float fs; // The sample rate float peak; unsigned long peak_sample; unsigned int i; float duration = 0.0f; unsigned int c_format = 0; int longopt_index = 0; int c; extern int optind, opterr; int show_usage = 0; char *optstring = "d:f:h"; struct option long_options[] = { { "help", 1, 0, 'h' }, { "duration", 1, 0, 'd' }, { "format", 1, 0, 'f' }, { 0, 0, 0, 0 } }; while ((c = getopt_long (argc, argv, optstring, long_options, &longopt_index)) != -1) { switch (c) { case 1: // end of opts, but don't care break; case 'h': show_usage++; break; case 'd': duration = (float)atof(optarg); break; case 'f': if (*optarg == 'c' || *optarg == 'C') { c_format = 1; } break; default: show_usage++; break; } } if (show_usage || duration <= 0.0f) { fprintf(stderr, "usage: jack_impulse_grab -d duration [-f (C|gnuplot)]\n"); exit(1); } /* try to become a client of the JACK server */ if ((client = jack_client_open("impulse_grabber", JackNullOption, NULL)) == 0) { fprintf (stderr, "JACK server not running?\n"); return 1; } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, 0); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* display the current sample rate. once the client is activated (see below), you should rely on your own sample rate callback (see above) for this value. */ fs = jack_get_sample_rate(client); response_duration = (unsigned long) (fs * duration); response = malloc(response_duration * sizeof(float)); fprintf(stderr, "Grabbing %f seconds (%lu samples) of impulse response\n", duration, response_duration); /* create two ports */ input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); /* tell the JACK server that we are ready to roll */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); return 1; } /* connect the ports. Note: you can't do this before the client is activated (this may change in the future). */ if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput)) == NULL) { fprintf(stderr, "Cannot find any physical capture ports"); exit(1); } if (jack_connect (client, ports[0], jack_port_name (input_port))) { fprintf (stderr, "cannot connect input ports\n"); } free (ports); if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) { fprintf(stderr, "Cannot find any physical playback ports"); exit(1); } if (jack_connect (client, jack_port_name (output_port), ports[0])) { fprintf (stderr, "cannot connect output ports\n"); } free (ports); /* install a signal handler to properly quits jack client */ #ifdef WIN32 signal(SIGQUIT, signal_handler); signal(SIGHUP, signal_handler); #endif signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); /* Wait for grab to finish */ while (!grab_finished) { #ifdef WIN32 Sleep(1000); #else sleep (1); #endif } jack_client_close (client); peak = response[0]; peak_sample = 0; if (c_format) { printf("impulse[%lu] = {", response_duration); for (i=0; i<response_duration; i++) { if (i % 4 != 0) { printf(" "); } else { printf("\n\t"); } printf("\"%+1.10f\"", response[i]); if (i < response_duration - 1) { printf(","); } if (fabs(response[i]) > peak) { peak = fabs(response[i]); peak_sample = i; } } printf("\n};\n"); } else { for (i=0; i<response_duration; i++) { printf("%1.12f\n", response[i]); if (fabs(response[i]) > peak) { peak = fabs(response[i]); peak_sample = i; } } } fprintf(stderr, "Peak value was %f at sample %lu\n", peak, peak_sample); exit (0); } 07070100000015000081A400000000000000000000000161E2F7EE00000D57000000000000000000000000000000000000003100000000jack-example-tools-1/example-clients/inprocess.c/** @file inprocess.c * * @brief This demonstrates the basic concepts for writing a client * that runs within the JACK server process. * * For the sake of example, a port_pair_t is allocated in * jack_initialize(), passed to inprocess() as an argument, then freed * in jack_finish(). */ #include <stdlib.h> #include <stdio.h> #include <memory.h> #include <jack/jack.h> /** * For the sake of example, an instance of this struct is allocated in * jack_initialize(), passed to inprocess() as an argument, then freed * in jack_finish(). */ typedef struct { jack_port_t *input_port; jack_port_t *output_port; } port_pair_t; /** * Called in the realtime thread on every process cycle. The entry * point name was passed to jack_set_process_callback() from * jack_initialize(). Although this is an internal client, its * process() interface is identical to @ref simple_client.c. * * @return 0 if successful; otherwise jack_finish() will be called and * the client terminated immediately. */ int inprocess (jack_nframes_t nframes, void *arg) { port_pair_t *pp = arg; jack_default_audio_sample_t *out = jack_port_get_buffer (pp->output_port, nframes); jack_default_audio_sample_t *in = jack_port_get_buffer (pp->input_port, nframes); memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); return 0; /* continue */ } /** * This required entry point is called after the client is loaded by * jack_internal_client_load(). * * @param client pointer to JACK client structure. * @param load_init character string passed to the load operation. * * @return 0 if successful; otherwise jack_finish() will be called and * the client terminated immediately. */ JACK_LIB_EXPORT int jack_initialize (jack_client_t *client, const char *load_init) { port_pair_t *pp = malloc (sizeof (port_pair_t)); const char **ports; if (pp == NULL) return 1; /* heap exhausted */ jack_set_process_callback (client, inprocess, pp); /* create a pair of ports */ pp->input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); pp->output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); /* join the process() cycle */ jack_activate (client); ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); if (ports == NULL) { fprintf(stderr, "no physical capture ports\n"); return 1; /* terminate client */ } if (jack_connect (client, ports[0], jack_port_name (pp->input_port))) { fprintf (stderr, "cannot connect input ports\n"); } jack_free (ports); ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); if (ports == NULL) { fprintf(stderr, "no physical playback ports\n"); return 1; /* terminate client */ } if (jack_connect (client, jack_port_name (pp->output_port), ports[0])) { fprintf (stderr, "cannot connect output ports\n"); } jack_free (ports); return 0; /* success */ } /** * This required entry point is called immediately before the client * is unloaded, which could happen due to a call to * jack_internal_client_unload(), or a nonzero return from either * jack_initialize() or inprocess(). * * @param arg the same parameter provided to inprocess(). */ JACK_LIB_EXPORT void jack_finish (void *arg) { if (arg) free ((port_pair_t *) arg); } 07070100000016000081A400000000000000000000000161E2F7EE00001025000000000000000000000000000000000000003800000000jack-example-tools-1/example-clients/internal_metro.cpp/* Copyright (C) 2002 Anthony Van Groningen Copyright (C) 2005 Grame 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "internal_metro.h" typedef jack_default_audio_sample_t sample_t; const double PI = 3.14; static int process_audio (jack_nframes_t nframes, void* arg) { InternalMetro* metro = (InternalMetro*)arg; sample_t *buffer = (sample_t *) jack_port_get_buffer (metro->output_port, nframes); jack_nframes_t frames_left = nframes; while (metro->wave_length - metro->offset < frames_left) { memcpy (buffer + (nframes - frames_left), metro->wave + metro->offset, sizeof (sample_t) * (metro->wave_length - metro->offset)); frames_left -= metro->wave_length - metro->offset; metro->offset = 0; } if (frames_left > 0) { memcpy (buffer + (nframes - frames_left), metro->wave + metro->offset, sizeof (sample_t) * frames_left); metro->offset += frames_left; } return 0; } InternalMetro::InternalMetro(int freq, double max_amp, int dur_arg, int bpm, char* client_name) { sample_t scale; int i, attack_length, decay_length; int attack_percent = 1, decay_percent = 10; const char *bpm_string = "bpm"; offset = 0; /* Initial Jack setup, get sample rate */ if (!client_name) { client_name = (char *) malloc (9 * sizeof (char)); strcpy (client_name, "metro"); } if ((client = jack_client_open (client_name, JackNullOption, NULL)) == 0) { fprintf (stderr, "jack server not running?\n"); return; } jack_set_process_callback (client, process_audio, this); output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); input_port = jack_port_register (client, "metro_in", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); sr = jack_get_sample_rate (client); /* setup wave table parameters */ wave_length = 60 * sr / bpm; tone_length = sr * dur_arg / 1000; attack_length = tone_length * attack_percent / 100; decay_length = tone_length * decay_percent / 100; scale = 2 * PI * freq / sr; if (tone_length >= wave_length) { /* fprintf (stderr, "invalid duration (tone length = %" PRIu32 ", wave length = %" PRIu32 "\n", tone_length, wave_length); */ return; } if (attack_length + decay_length > (int)tone_length) { fprintf (stderr, "invalid attack/decay\n"); return; } /* Build the wave table */ wave = (sample_t *) malloc (wave_length * sizeof(sample_t)); amp = (double *) malloc (tone_length * sizeof(double)); for (i = 0; i < attack_length; i++) { amp[i] = max_amp * i / ((double) attack_length); } for (i = attack_length; i < (int) tone_length - decay_length; i++) { amp[i] = max_amp; } for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) { amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length); } for (i = 0; i < (int) tone_length; i++) { wave[i] = amp[i] * sin (scale * i); } for (i = tone_length; i < (int) wave_length; i++) { wave[i] = 0; } if (jack_activate (client)) { fprintf(stderr, "cannot activate client"); } } InternalMetro::~InternalMetro() { jack_deactivate(client); jack_port_unregister(client, input_port); jack_port_unregister(client, output_port); jack_client_close(client); free(amp); free(wave); } 07070100000017000081A400000000000000000000000161E2F7EE00000658000000000000000000000000000000000000003600000000jack-example-tools-1/example-clients/internal_metro.h/* Copyright (C) 2001 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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. */ #ifndef __internal_metro__ #define __internal_metro__ #ifdef __cplusplus extern "C" { #endif #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <math.h> #include <getopt.h> #include <string.h> #include <jack/jack.h> #include <jack/transport.h> typedef jack_default_audio_sample_t sample_t; /*! \brief A class to test internal clients */ struct InternalMetro { jack_client_t *client; jack_port_t *input_port; jack_port_t *output_port; unsigned long sr; int freq; int bpm; jack_nframes_t tone_length, wave_length; sample_t *wave; double *amp; long offset ; InternalMetro(int freq, double max_amp, int dur_arg, int bpm, char* client_name); virtual ~InternalMetro(); }; #ifdef __cplusplus } #endif #endif 07070100000018000081A400000000000000000000000161E2F7EE00001359000000000000000000000000000000000000002E00000000jack-example-tools-1/example-clients/intime.c/* * intime.c -- JACK internal timebase master example client. * * To run: first start `jackd', then `jack_load intime intime 6/8,180bpm'. */ /* Copyright (C) 2003 Jack O'Quin. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <string.h> #include <jack/jack.h> /* Time and tempo variables, global to the entire transport timeline. * There is no attempt to keep a true tempo map. The default time * signature is "march time": 4/4, 120bpm */ float time_beats_per_bar = 4.0; float time_beat_type = 4.0; double time_ticks_per_beat = 1920.0; double time_beats_per_minute = 120.0; /* BBT timebase callback. * * Runs in the process thread. Realtime, must not wait. */ void timebbt (jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void *arg) { double min; /* minutes since frame 0 */ long abs_tick; /* ticks since frame 0 */ long abs_beat; /* beats since frame 0 */ if (new_pos) { pos->valid = JackPositionBBT; pos->beats_per_bar = time_beats_per_bar; pos->beat_type = time_beat_type; pos->ticks_per_beat = time_ticks_per_beat; pos->beats_per_minute = time_beats_per_minute; /* Compute BBT info from frame number. This is * relatively simple here, but would become complex if * we supported tempo or time signature changes at * specific locations in the transport timeline. I * make no claims for the numerical accuracy or * efficiency of these calculations. */ min = pos->frame / ((double) pos->frame_rate * 60.0); abs_tick = min * pos->beats_per_minute * pos->ticks_per_beat; abs_beat = abs_tick / pos->ticks_per_beat; pos->bar = abs_beat / pos->beats_per_bar; pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1; pos->tick = abs_tick - (abs_beat * pos->ticks_per_beat); pos->bar_start_tick = pos->bar * pos->beats_per_bar * pos->ticks_per_beat; pos->bar++; /* adjust start to bar 1 */ /* some debug code... */ fprintf(stderr, "\nnew position: %" PRIu32 "\tBBT: %3" PRIi32 "|%" PRIi32 "|%04" PRIi32 "\n", pos->frame, pos->bar, pos->beat, pos->tick); } else { /* Compute BBT info based on previous period. */ pos->tick += (nframes * pos->ticks_per_beat * pos->beats_per_minute / (pos->frame_rate * 60)); while (pos->tick >= pos->ticks_per_beat) { pos->tick -= pos->ticks_per_beat; if (++pos->beat > pos->beats_per_bar) { pos->beat = 1; ++pos->bar; pos->bar_start_tick += (pos->beats_per_bar * pos->ticks_per_beat); } } } } /* experimental timecode callback * * Fill in extended timecode fields using the trivial assumption that * we are running at nominal speed, hence with no drift. * * It would probably be faster to compute frame_time without the * conditional expression. But, this demonstrates the invariant: * next_time[i] == frame_time[i+1], unless a reposition occurs. * * Runs in the process thread. Realtime, must not wait. */ void timecode (jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void *arg) { /* nominal transport speed */ double seconds_per_frame = 1.0 / (double) pos->frame_rate; pos->valid = JackPositionTimecode; pos->frame_time = (new_pos? pos->frame * seconds_per_frame: pos->next_time); pos->next_time = (pos->frame + nframes) * seconds_per_frame; } /* after internal client loaded */ int jack_initialize (jack_client_t *client, const char *load_init) { JackTimebaseCallback callback = timebbt; int rc = sscanf(load_init, " %f/%f, %lf bpm ", &time_beats_per_bar, &time_beat_type, &time_beats_per_minute); if (rc > 0) { fprintf (stderr, "counting %.1f/%.1f at %.2f bpm\n", time_beats_per_bar, time_beat_type, time_beats_per_minute); } else { int len = strlen(load_init); if ((len > 0) && (strncmp(load_init, "timecode", len) == 0)) callback = timecode; } if (jack_set_timebase_callback(client, 0, callback, NULL) != 0) { fprintf (stderr, "Unable to take over timebase.\n"); return 1; /* terminate */ } fprintf (stderr, "Internal timebase master defined.\n"); jack_activate (client); return 0; /* success */ } /* before unloading */ void jack_finish (void *arg) { fprintf (stderr, "Internal timebase client exiting.\n"); } 07070100000019000081A400000000000000000000000161E2F7EE000014F5000000000000000000000000000000000000003500000000jack-example-tools-1/example-clients/latent_client.c/** @file latent_client.c * * @brief This simple client demonstrates the most basic features of JACK * as they would be used by many applications. */ #include <stdio.h> #include <errno.h> #ifndef WIN32 #include <unistd.h> #endif #include <stdlib.h> #include <string.h> #include <inttypes.h> #include <jack/jack.h> jack_port_t *input_port; jack_port_t *output_port; jack_client_t *client; jack_default_audio_sample_t *delay_line; jack_nframes_t delay_index; jack_nframes_t latency = 1024; /** * The process callback for this JACK application is called in a * special realtime thread once for each audio cycle. * * This client does nothing more than copy data from its input * port to its output port. It will exit when stopped by * the user (e.g. using Ctrl-C on a unix-ish operating system) */ int process (jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *in, *out; int k; in = jack_port_get_buffer (input_port, nframes); out = jack_port_get_buffer (output_port, nframes); for (k=0; k<nframes; k++) { out[k] = delay_line[delay_index]; delay_line[delay_index] = in[k]; delay_index = (delay_index + 1) % latency; } return 0; } void latency_cb (jack_latency_callback_mode_t mode, void *arg) { jack_latency_range_t range; if (mode == JackCaptureLatency) { jack_port_get_latency_range (input_port, mode, &range); range.min += latency; range.max += latency; jack_port_set_latency_range (output_port, mode, &range); } else { jack_port_get_latency_range (output_port, mode, &range); range.min += latency; range.max += latency; jack_port_set_latency_range (input_port, mode, &range); } } /** * JACK calls this shutdown_callback if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit (1); } int main (int argc, char *argv[]) { const char **ports; const char *client_name = "latent"; const char *server_name = NULL; jack_options_t options = JackNullOption; jack_status_t status; if (argc == 2) latency = atoi(argv[1]); delay_line = malloc( latency * sizeof(jack_default_audio_sample_t)); if (delay_line == NULL) { fprintf (stderr, "no memory"); exit(1); } memset (delay_line, 0, latency * sizeof(jack_default_audio_sample_t)); /* open a client connection to the JACK server */ client = jack_client_open (client_name, options, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } exit (1); } if (status & JackServerStarted) { fprintf (stderr, "JACK server started\n"); } if (status & JackNameNotUnique) { client_name = jack_get_client_name(client); fprintf (stderr, "unique name `%s' assigned\n", client_name); } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, 0); /* tell the JACK server to call `latency()' whenever the latency needs to be recalculated. */ if (jack_set_latency_callback) jack_set_latency_callback (client, latency_cb, 0); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* display the current sample rate. */ printf ("engine sample rate: %" PRIu32 "\n", jack_get_sample_rate (client)); /* create two ports */ input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if ((input_port == NULL) || (output_port == NULL)) { fprintf(stderr, "no more JACK ports available\n"); exit (1); } /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); exit (1); } /* Connect the ports. You can't do this before the client is * activated, because we can't make connections to clients * that aren't running. Note the confusing (but necessary) * orientation of the driver backend ports: playback ports are * "input" to the backend, and capture ports are "output" from * it. */ ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); if (ports == NULL) { fprintf(stderr, "no physical capture ports\n"); exit (1); } if (jack_connect (client, ports[0], jack_port_name (input_port))) { fprintf (stderr, "cannot connect input ports\n"); exit (1); } free (ports); ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); if (ports == NULL) { fprintf(stderr, "no physical playback ports\n"); exit (1); } if (jack_connect (client, jack_port_name (output_port), ports[0])) { fprintf (stderr, "cannot connect output ports\n"); } free (ports); /* keep running until stopped by the user */ #ifdef WIN32 Sleep (-1); #else sleep (-1); #endif /* this is never reached but if the program had some other way to exit besides being killed, they would be important to call. */ jack_client_close (client); return 0; } 0707010000001A000081A400000000000000000000000161E2F7EE00000E29000000000000000000000000000000000000003100000000jack-example-tools-1/example-clients/meson.buildexe_jack_control_client = executable( 'jack_control_client', sources: ['control.c'], dependencies: [dep_jack], install: true ) exe_jack_cpu_load = executable( 'jack_cpu_load', sources: ['cpu_load.c'], dependencies: [dep_jack], install: true ) if build_jack_rec exe_jack_rec = executable( 'jack_rec', sources: ['capture_client.c'], dependencies: [dep_jack, dep_sndfile, dep_threads], install: true ) endif exe_jack_impulse_grabber = executable( 'jack_impulse_grabber', sources: ['impulse_grabber.c'], dependencies: [dep_jack], install: true ) lib_jack_inprocess = library( 'jack_inprocess', name_prefix: '', sources: ['inprocess.c'], dependencies: [dep_jack], install: true, install_dir: get_option('libdir') / 'jack', ) lib_jack_internal_metro = library( 'jack_internal_metro', name_prefix: '', sources: ['internal_metro.cpp'], dependencies: [dep_jack], install: true, install_dir: get_option('libdir') / 'jack', ) lib_jack_intime = library( 'jack_intime', name_prefix: '', sources: ['intime.c'], dependencies: [dep_jack], install: true, install_dir: get_option('libdir') / 'jack', ) exe_jack_latent_client = executable( 'jack_latent_client', sources: ['latent_client.c'], dependencies: [dep_jack], install: true ) exe_jack_metro = executable( 'jack_metro', sources: ['metro.c'], dependencies: [dep_jack, lib_m], install: true ) exe_jack_midiseq = executable( 'jack_midiseq', sources: ['midiseq.c'], dependencies: [dep_jack], install: true ) exe_jack_midisine = executable( 'jack_midisine', sources: ['midisine.c'], dependencies: [dep_jack, lib_m], install: true ) exe_jack_midi_latency_test = executable( 'jack_midi_latency_test', sources: ['midi_latency_test.c'], dependencies: [dep_jack, dep_threads, lib_m], install: true ) if build_jack_net exe_jack_net_master = executable( 'jack_net_master', sources: ['netmaster.c'], dependencies: [lib_jacknet], install: true ) exe_jack_net_slave = executable( 'jack_net_slave', sources: ['netslave.c'], dependencies: [lib_jacknet], install: true ) endif if has_jackctl_server_create2 c_args_jack_server_control = c_args_common + ['-D__JACK2__'] else c_args_jack_server_control = c_args_common + ['-D__JACK1__'] endif exe_jack_server_control = executable( 'jack_server_control', c_args: c_args_jack_server_control, sources: ['server_control.c'], dependencies: [dep_jack, lib_jackserver], install: true ) exe_jack_showtime = executable( 'jack_showtime', sources: ['showtime.c'], dependencies: [dep_jack], install: true ) exe_jack_simdtests = executable( 'jack_simdtests', sources: ['simdtests.cpp'], include_directories: ['../common'], dependencies: [lib_m], install: true ) exe_jack_simple_client = executable( 'jack_simple_client', sources: ['simple_client.c'], dependencies: [dep_jack, lib_m], install: true ) # dont install, jack session is deprecated exe_jack_simple_session_client = executable( 'jack_simple_session_client', sources: ['simple_session_client.c'], dependencies: [dep_jack], c_args: ['-Wno-deprecated-declarations'], install: false ) exe_jack_transport_client = executable( 'jack_transport_client', sources: ['transport_client.c'], dependencies: [dep_jack], install: true ) exe_jack_thru_client = executable( 'jack_thru_client', sources: ['thru_client.c'], dependencies: [dep_jack], install: true ) exe_jack_zombie = executable( 'jack_zombie', sources: ['zombie.c'], dependencies: [dep_jack], install: true ) 0707010000001B000081A400000000000000000000000161E2F7EE00001E39000000000000000000000000000000000000002D00000000jack-example-tools-1/example-clients/metro.c/* Copyright (C) 2002 Anthony Van Groningen 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdlib.h> #include <stdio.h> #include <errno.h> #ifndef WIN32 #include <unistd.h> #endif #include <math.h> #include <signal.h> #include <getopt.h> #include <string.h> #include <jack/jack.h> #include <jack/transport.h> typedef jack_default_audio_sample_t sample_t; const double PI = 3.14; jack_client_t *client; jack_port_t *output_port; unsigned long sr; int freq = 880; int bpm; jack_nframes_t tone_length, wave_length; sample_t *wave; long offset = 0; int transport_aware = 0; jack_transport_state_t transport_state; static void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } static void usage () { fprintf (stderr, "\n" "usage: jack_metro \n" " [ --frequency OR -f frequency (in Hz) ]\n" " [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n" " [ --duration OR -D duration (in ms) ]\n" " [ --attack OR -a attack (in percent of duration) ]\n" " [ --decay OR -d decay (in percent of duration) ]\n" " [ --name OR -n jack name for metronome client ]\n" " [ --transport OR -t transport aware ]\n" " --bpm OR -b beats per minute\n" ); } static void process_silence (jack_nframes_t nframes) { sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes); memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes); } jack_nframes_t last_time; jack_time_t last_micro_time; static void process_audio (jack_nframes_t nframes) { sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes); jack_nframes_t frames_left = nframes; while (wave_length - offset < frames_left) { memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset)); frames_left -= wave_length - offset; offset = 0; } if (frames_left > 0) { memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left); offset += frames_left; } /* jack_nframes_t cur_time = jack_frame_time(client); jack_time_t cur_micro_time = jack_get_time(); printf("jack_frame_time %lld micro %lld delta %d\n", cur_time, (cur_micro_time - last_micro_time), cur_time - last_time); last_time = cur_time; last_micro_time = cur_micro_time; */ } static int process (jack_nframes_t nframes, void *arg) { if (transport_aware) { jack_position_t pos; if (jack_transport_query (client, &pos) != JackTransportRolling) { process_silence (nframes); return 0; } offset = pos.frame % wave_length; } process_audio (nframes); return 0; } int main (int argc, char *argv[]) { sample_t scale; int i, attack_length, decay_length; double *amp; double max_amp = 0.5; int option_index; int opt; int got_bpm = 0; int attack_percent = 1, decay_percent = 10, dur_arg = 100; char *client_name = 0; char *bpm_string = "bpm"; jack_status_t status; const char *options = "f:A:D:a:d:b:n:thv"; struct option long_options[] = { {"frequency", 1, 0, 'f'}, {"amplitude", 1, 0, 'A'}, {"duration", 1, 0, 'D'}, {"attack", 1, 0, 'a'}, {"decay", 1, 0, 'd'}, {"bpm", 1, 0, 'b'}, {"name", 1, 0, 'n'}, {"transport", 0, 0, 't'}, {"help", 0, 0, 'h'}, {"verbose", 0, 0, 'v'}, {0, 0, 0, 0} }; while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != -1) { switch (opt) { case 'f': if ((freq = atoi (optarg)) <= 0) { fprintf (stderr, "invalid frequency\n"); return -1; } break; case 'A': if (((max_amp = atof (optarg)) <= 0)|| (max_amp > 1)) { fprintf (stderr, "invalid amplitude\n"); return -1; } break; case 'D': dur_arg = atoi (optarg); fprintf (stderr, "durarg = %u\n", dur_arg); break; case 'a': if (((attack_percent = atoi (optarg)) < 0) || (attack_percent > 100)) { fprintf (stderr, "invalid attack percent\n"); return -1; } break; case 'd': if (((decay_percent = atoi (optarg)) < 0) || (decay_percent > 100)) { fprintf (stderr, "invalid decay percent\n"); return -1; } break; case 'b': got_bpm = 1; if ((bpm = atoi (optarg)) < 0) { fprintf (stderr, "invalid bpm\n"); return -1; } bpm_string = (char *) malloc ((strlen (optarg) + 5) * sizeof (char)); strcpy (bpm_string, optarg); strcat (bpm_string, "_bpm"); break; case 'n': client_name = (char *) malloc ((strlen (optarg) + 1) * sizeof (char)); strcpy (client_name, optarg); break; case 'v': break; case 't': transport_aware = 1; break; default: fprintf (stderr, "unknown option %c\n", opt); case 'h': usage (); return -1; } } if (!got_bpm) { fprintf (stderr, "bpm not specified\n"); usage (); return -1; } /* Initial Jack setup, get sample rate */ if (!client_name) { client_name = (char *) malloc (9 * sizeof (char)); strcpy (client_name, "metro"); } if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) { fprintf (stderr, "JACK server not running?\n"); return 1; } jack_set_process_callback (client, process, 0); output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); sr = jack_get_sample_rate (client); /* setup wave table parameters */ wave_length = 60 * sr / bpm; tone_length = sr * dur_arg / 1000; attack_length = tone_length * attack_percent / 100; decay_length = tone_length * decay_percent / 100; scale = 2 * PI * freq / sr; if (tone_length >= wave_length) { fprintf (stderr, "invalid duration (tone length = %u, wave length = %u\n", tone_length, wave_length); return -1; } if (attack_length + decay_length > (int)tone_length) { fprintf (stderr, "invalid attack/decay\n"); return -1; } /* Build the wave table */ wave = (sample_t *) malloc (wave_length * sizeof(sample_t)); amp = (double *) malloc (tone_length * sizeof(double)); for (i = 0; i < attack_length; i++) { amp[i] = max_amp * i / ((double) attack_length); } for (i = attack_length; i < (int)tone_length - decay_length; i++) { amp[i] = max_amp; } for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) { amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length); } for (i = 0; i < (int)tone_length; i++) { wave[i] = amp[i] * sin (scale * i); } for (i = tone_length; i < (int)wave_length; i++) { wave[i] = 0; } if (jack_activate (client)) { fprintf (stderr, "cannot activate client\n"); goto error; } /* install a signal handler to properly quits jack client */ #ifdef WIN32 signal(SIGINT, signal_handler); signal(SIGABRT, signal_handler); signal(SIGTERM, signal_handler); #else signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); #endif /* run until interrupted */ while (1) { #ifdef WIN32 Sleep(1000); #else sleep(1); #endif }; jack_client_close(client); error: free(amp); free(wave); exit (0); } 0707010000001C000081A400000000000000000000000161E2F7EE000075C2000000000000000000000000000000000000003900000000jack-example-tools-1/example-clients/midi_latency_test.c/* Copyright (C) 2010 Devin Anderson This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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. */ /* * This program is used to measure MIDI latency and jitter. It writes MIDI * messages to one port and calculates how long it takes before it reads the * same MIDI message over another port. It was written to calculate the * latency and jitter of hardware and JACK hardware drivers, but might have * other practical applications. * * The latency results of the program include the latency introduced by the * JACK system. Because JACK has sample accurate MIDI, the same latency * imposed on audio is also imposed on MIDI going through the system. Make * sure you take this into account before complaining to me or (*especially*) * other JACK developers about reported MIDI latency. * * The jitter results are a little more interesting. The program attempts to * calculate 'average jitter' and 'peak jitter', as defined here: * * http://openmuse.org/transport/fidelity.html * * It also outputs a jitter plot, which gives you a more specific idea about * the MIDI jitter for the ports you're testing. This is useful for catching * extreme jitter values, and for analyzing the amount of truth in the * technical specifications for your MIDI interface(s). :) * * This program is loosely based on 'alsa-midi-latency-test' in the ALSA test * suite. * * To port this program to non-POSIX platforms, you'll have to include * implementations for semaphores and command-line argument handling. */ #include <assert.h> #include <errno.h> #include <math.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <getopt.h> #include <jack/jack.h> #include <jack/midiport.h> #ifdef WIN32 #include <windows.h> #include <unistd.h> #else #include <semaphore.h> #endif #define ABS(x) (((x) >= 0) ? (x) : (-(x))) #ifdef WIN32 typedef HANDLE semaphore_t; #else typedef sem_t *semaphore_t; #endif const char *ERROR_MSG_TIMEOUT = "timed out while waiting for MIDI message"; const char *ERROR_RESERVE = "could not reserve MIDI event on port buffer"; const char *ERROR_SHUTDOWN = "the JACK server has been shutdown"; const char *SOURCE_EVENT_RESERVE = "jack_midi_event_reserve"; const char *SOURCE_PROCESS = "handle_process"; const char *SOURCE_SHUTDOWN = "handle_shutdown"; const char *SOURCE_SIGNAL_SEMAPHORE = "signal_semaphore"; const char *SOURCE_WAIT_SEMAPHORE = "wait_semaphore"; char *alias1; char *alias2; jack_client_t *client; semaphore_t connect_semaphore; volatile int connections_established; const char *error_message; const char *error_source; jack_nframes_t highest_latency; jack_time_t highest_latency_time; jack_latency_range_t in_latency_range; jack_port_t *in_port; semaphore_t init_semaphore; jack_nframes_t last_activity; jack_time_t last_activity_time; jack_time_t *latency_time_values; jack_nframes_t *latency_values; jack_nframes_t lowest_latency; jack_time_t lowest_latency_time; jack_midi_data_t *message_1; jack_midi_data_t *message_2; int messages_received; int messages_sent; size_t message_size; jack_latency_range_t out_latency_range; jack_port_t *out_port; semaphore_t process_semaphore; volatile sig_atomic_t process_state; char *program_name; jack_port_t *remote_in_port; jack_port_t *remote_out_port; size_t samples; const char *target_in_port_name; const char *target_out_port_name; int timeout; jack_nframes_t total_latency; jack_time_t total_latency_time; int unexpected_messages; int xrun_count; #ifdef WIN32 char semaphore_error_msg[1024]; #endif static void output_error(const char *source, const char *message); static void output_usage(void); static void set_process_error(const char *source, const char *message); static int signal_semaphore(semaphore_t semaphore); static jack_port_t * update_connection(jack_port_t *remote_port, int connected, jack_port_t *local_port, jack_port_t *current_port, const char *target_name); static int wait_semaphore(semaphore_t semaphore, int block); static semaphore_t create_semaphore(int id) { semaphore_t semaphore; #ifdef WIN32 semaphore = CreateSemaphore(NULL, 0, 2, NULL); #elif defined (__APPLE__) char name[128]; sprintf(name, "midi_sem_%d", id); semaphore = sem_open(name, O_CREAT, 0777, 0); if (semaphore == (sem_t *) SEM_FAILED) { semaphore = NULL; } #else semaphore = malloc(sizeof(semaphore_t)); if (semaphore != NULL) { if (sem_init(semaphore, 0, 0)) { free(semaphore); semaphore = NULL; } } #endif return semaphore; } static void destroy_semaphore(semaphore_t semaphore, int id) { #ifdef WIN32 CloseHandle(semaphore); #else sem_destroy(semaphore); #ifdef __APPLE__ { char name[128]; sprintf(name, "midi_sem_%d", id); sem_close(semaphore); sem_unlink(name); } #else free(semaphore); #endif #endif } static void die(const char *source, const char *error_message) { output_error(source, error_message); output_usage(); exit(EXIT_FAILURE); } static const char * get_semaphore_error(void) { #ifdef WIN32 DWORD error = GetLastError(); if (! FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), semaphore_error_msg, 1024, NULL)) { snprintf(semaphore_error_msg, 1023, "Unknown OS error code '%ld'", error); } return semaphore_error_msg; #else return strerror(errno); #endif } static void handle_info(const char *message) { /* Suppress info */ } static void handle_port_connection_change(jack_port_id_t port_id_1, jack_port_id_t port_id_2, int connected, void *arg) { jack_port_t *port_1; jack_port_t *port_2; if ((remote_in_port != NULL) && (remote_out_port != NULL)) { return; } port_1 = jack_port_by_id(client, port_id_1); port_2 = jack_port_by_id(client, port_id_2); /* The 'update_connection' call is not RT-safe. It calls 'jack_port_get_connections' and 'jack_free'. This might be a problem with JACK 1, as this callback runs in the process thread in JACK 1. */ if (port_1 == in_port) { remote_in_port = update_connection(port_2, connected, in_port, remote_in_port, target_in_port_name); } else if (port_2 == in_port) { remote_in_port = update_connection(port_1, connected, in_port, remote_in_port, target_in_port_name); } else if (port_1 == out_port) { remote_out_port = update_connection(port_2, connected, out_port, remote_out_port, target_out_port_name); } else if (port_2 == out_port) { remote_out_port = update_connection(port_1, connected, out_port, remote_out_port, target_out_port_name); } if ((remote_in_port != NULL) && (remote_out_port != NULL)) { connections_established = 1; if (! signal_semaphore(connect_semaphore)) { /* Sigh ... */ die("post_semaphore", get_semaphore_error()); } if (! signal_semaphore(init_semaphore)) { /* Sigh ... */ die("post_semaphore", get_semaphore_error()); } } } static int handle_process(jack_nframes_t frames, void *arg) { jack_midi_data_t *buffer; jack_midi_event_t event; jack_nframes_t event_count; jack_nframes_t event_time; jack_nframes_t frame; size_t i; jack_nframes_t last_frame_time; jack_midi_data_t *message; jack_time_t microseconds; void *port_buffer; jack_time_t time; jack_midi_clear_buffer(jack_port_get_buffer(out_port, frames)); switch (process_state) { case 0: /* State: initializing */ switch (wait_semaphore(init_semaphore, 0)) { case -1: set_process_error(SOURCE_WAIT_SEMAPHORE, get_semaphore_error()); /* Fallthrough on purpose */ case 0: return 0; } highest_latency = 0; lowest_latency = 0; messages_received = 0; messages_sent = 0; process_state = 1; total_latency = 0; total_latency_time = 0; unexpected_messages = 0; xrun_count = 0; jack_port_get_latency_range(remote_in_port, JackCaptureLatency, &in_latency_range); jack_port_get_latency_range(remote_out_port, JackPlaybackLatency, &out_latency_range); goto send_message; case 1: /* State: processing */ port_buffer = jack_port_get_buffer(in_port, frames); event_count = jack_midi_get_event_count(port_buffer); last_frame_time = jack_last_frame_time(client); for (i = 0; i < event_count; i++) { jack_midi_event_get(&event, port_buffer, i); message = (messages_received % 2) ? message_2 : message_1; if ((event.size == message_size) && (! memcmp(message, event.buffer, message_size * sizeof(jack_midi_data_t)))) { goto found_message; } unexpected_messages++; } microseconds = jack_frames_to_time(client, last_frame_time) - last_activity_time; if ((microseconds / 1000000) >= timeout) { set_process_error(SOURCE_PROCESS, ERROR_MSG_TIMEOUT); } break; found_message: event_time = last_frame_time + event.time; frame = event_time - last_activity; time = jack_frames_to_time(client, event_time) - last_activity_time; if ((! highest_latency) || (frame > highest_latency)) { highest_latency = frame; highest_latency_time = time; } if ((! lowest_latency) || (frame < lowest_latency)) { lowest_latency = frame; lowest_latency_time = time; } latency_time_values[messages_received] = time; latency_values[messages_received] = frame; total_latency += frame; total_latency_time += time; messages_received++; if (messages_received == samples) { process_state = 2; if (! signal_semaphore(process_semaphore)) { /* Sigh ... */ die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error()); } break; } send_message: frame = (jack_nframes_t) ((((double) rand()) / RAND_MAX) * frames); if (frame >= frames) { frame = frames - 1; } port_buffer = jack_port_get_buffer(out_port, frames); buffer = jack_midi_event_reserve(port_buffer, frame, message_size); if (buffer == NULL) { set_process_error(SOURCE_EVENT_RESERVE, ERROR_RESERVE); break; } message = (messages_sent % 2) ? message_2 : message_1; memcpy(buffer, message, message_size * sizeof(jack_midi_data_t)); last_activity = jack_last_frame_time(client) + frame; last_activity_time = jack_frames_to_time(client, last_activity); messages_sent++; case 2: /* State: finished - do nothing */ case -1: /* State: error - do nothing */ case -2: /* State: signalled - do nothing */ ; } return 0; } static void handle_shutdown(void *arg) { set_process_error(SOURCE_SHUTDOWN, ERROR_SHUTDOWN); } static void handle_signal(int sig) { process_state = -2; if (! signal_semaphore(connect_semaphore)) { /* Sigh ... */ die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error()); } if (! signal_semaphore(process_semaphore)) { /* Sigh ... */ die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error()); } } static int handle_xrun(void *arg) { xrun_count++; return 0; } static void output_error(const char *source, const char *message) { fprintf(stderr, "%s: %s: %s\n", program_name, source, message); } static void output_usage(void) { fprintf(stderr, "Usage: %s [options] [out-port-name in-port-name]\n\n" "\t-h, --help print program usage\n" "\t-m, --message-size=size set size of MIDI messages to send " "(default: 3)\n" "\t-s, --samples=n number of MIDI messages to send " "(default: 1024)\n" "\t-t, --timeout=seconds message timeout (default: 5)\n\n", program_name); } static unsigned long parse_positive_number_arg(char *s, char *name) { char *end_ptr; unsigned long result; errno = 0; result = strtoul(s, &end_ptr, 10); if (errno) { die(name, strerror(errno)); } if (*s == '\0') { die(name, "argument value cannot be empty"); } if (*end_ptr != '\0') { die(name, "invalid value"); } if (! result) { die(name, "must be a positive number"); } return result; } static int register_signal_handler(void (*func)(int)) { #ifdef WIN32 if (signal(SIGABRT, func) == SIG_ERR) { return 0; } #else if (signal(SIGQUIT, func) == SIG_ERR) { return 0; } if (signal(SIGHUP, func) == SIG_ERR) { return 0; } #endif if (signal(SIGINT, func) == SIG_ERR) { return 0; } if (signal(SIGTERM, func) == SIG_ERR) { return 0; } return 1; } static void set_process_error(const char *source, const char *message) { error_source = source; error_message = message; process_state = -1; if (! signal_semaphore(process_semaphore)) { /* Sigh ... */ output_error(source, message); die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error()); } } static int signal_semaphore(semaphore_t semaphore) { #ifdef WIN32 return ReleaseSemaphore(semaphore, 1, NULL); #else return ! sem_post(semaphore); #endif } static jack_port_t * update_connection(jack_port_t *remote_port, int connected, jack_port_t *local_port, jack_port_t *current_port, const char *target_name) { if (connected) { if (current_port) { return current_port; } if (target_name) { char *aliases[2]; if (! strcmp(target_name, jack_port_name(remote_port))) { return remote_port; } aliases[0] = alias1; aliases[1] = alias2; switch (jack_port_get_aliases(remote_port, aliases)) { case -1: /* Sigh ... */ die("jack_port_get_aliases", "Failed to get port aliases"); case 2: if (! strcmp(target_name, alias2)) { return remote_port; } /* Fallthrough on purpose */ case 1: if (! strcmp(target_name, alias1)) { return remote_port; } /* Fallthrough on purpose */ case 0: return NULL; } /* This shouldn't happen. */ assert(0); } return remote_port; } if (! strcmp(jack_port_name(remote_port), jack_port_name(current_port))) { const char **port_names; if (target_name) { return NULL; } port_names = jack_port_get_connections(local_port); if (port_names == NULL) { return NULL; } /* If a connected port is disconnected and other ports are still connected, then we take the first port name in the array and use it as our remote port. It's a dumb implementation. */ current_port = jack_port_by_name(client, port_names[0]); jack_free(port_names); if (current_port == NULL) { /* Sigh */ die("jack_port_by_name", "failed to get port by name"); } } return current_port; } static int wait_semaphore(semaphore_t semaphore, int block) { #ifdef WIN32 DWORD result = WaitForSingleObject(semaphore, block ? INFINITE : 0); switch (result) { case WAIT_OBJECT_0: return 1; case WAIT_TIMEOUT: return 0; } return -1; #else if (block) { while (sem_wait(semaphore)) { if (errno != EINTR) { return -1; } } } else { while (sem_trywait(semaphore)) { switch (errno) { case EAGAIN: return 0; case EINTR: continue; default: return -1; } } } return 1; #endif } int main(int argc, char **argv) { int jitter_plot[101]; int latency_plot[101]; int long_index = 0; struct option long_options[] = { {"help", 0, NULL, 'h'}, {"message-size", 1, NULL, 'm'}, {"samples", 1, NULL, 's'}, {"timeout", 1, NULL, 't'} }; size_t name_arg_count; size_t name_size; char *option_string = "hm:s:t:"; int show_usage = 0; connections_established = 0; error_message = NULL; message_size = 3; program_name = argv[0]; remote_in_port = 0; remote_out_port = 0; samples = 1024; timeout = 5; for (;;) { signed char c = getopt_long(argc, argv, option_string, long_options, &long_index); switch (c) { case 'h': show_usage = 1; break; case 'm': message_size = parse_positive_number_arg(optarg, "message-size"); break; case 's': samples = parse_positive_number_arg(optarg, "samples"); break; case 't': timeout = parse_positive_number_arg(optarg, "timeout"); break; default: { char *s = "'- '"; s[2] = c; die(s, "invalid switch"); } case -1: if (show_usage) { output_usage(); exit(EXIT_SUCCESS); } goto parse_port_names; case 1: /* end of switch :) */ ; } } parse_port_names: name_arg_count = argc - optind; switch (name_arg_count) { case 2: target_in_port_name = argv[optind + 1]; target_out_port_name = argv[optind]; break; case 0: target_in_port_name = 0; target_out_port_name = 0; break; default: output_usage(); return EXIT_FAILURE; } name_size = jack_port_name_size(); alias1 = malloc(name_size * sizeof(char)); if (alias1 == NULL) { error_message = strerror(errno); error_source = "malloc"; goto show_error; } alias2 = malloc(name_size * sizeof(char)); if (alias2 == NULL) { error_message = strerror(errno); error_source = "malloc"; goto free_alias1; } latency_values = malloc(sizeof(jack_nframes_t) * samples); if (latency_values == NULL) { error_message = strerror(errno); error_source = "malloc"; goto free_alias2; } latency_time_values = malloc(sizeof(jack_time_t) * samples); if (latency_time_values == NULL) { error_message = strerror(errno); error_source = "malloc"; goto free_latency_values; } message_1 = malloc(message_size * sizeof(jack_midi_data_t)); if (message_1 == NULL) { error_message = strerror(errno); error_source = "malloc"; goto free_latency_time_values; } message_2 = malloc(message_size * sizeof(jack_midi_data_t)); if (message_2 == NULL) { error_message = strerror(errno); error_source = "malloc"; goto free_message_1; } switch (message_size) { case 1: message_1[0] = 0xf6; message_2[0] = 0xfe; break; case 2: message_1[0] = 0xc0; message_1[1] = 0x00; message_2[0] = 0xd0; message_2[1] = 0x7f; break; case 3: message_1[0] = 0x80; message_1[1] = 0x00; message_1[2] = 0x00; message_2[0] = 0x90; message_2[1] = 0x7f; message_2[2] = 0x7f; break; default: message_1[0] = 0xf0; memset(message_1 + 1, 0, (message_size - 2) * sizeof(jack_midi_data_t)); message_1[message_size - 1] = 0xf7; message_2[0] = 0xf0; memset(message_2 + 1, 0x7f, (message_size - 2) * sizeof(jack_midi_data_t)); message_2[message_size - 1] = 0xf7; } client = jack_client_open(program_name, JackNullOption, NULL); if (client == NULL) { error_message = "failed to open JACK client"; error_source = "jack_client_open"; goto free_message_2; } in_port = jack_port_register(client, "in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); if (in_port == NULL) { error_message = "failed to register MIDI-in port"; error_source = "jack_port_register"; goto close_client; } out_port = jack_port_register(client, "out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); if (out_port == NULL) { error_message = "failed to register MIDI-out port"; error_source = "jack_port_register"; goto unregister_in_port; } if (jack_set_process_callback(client, handle_process, NULL)) { error_message = "failed to set process callback"; error_source = "jack_set_process_callback"; goto unregister_out_port; } if (jack_set_xrun_callback(client, handle_xrun, NULL)) { error_message = "failed to set xrun callback"; error_source = "jack_set_xrun_callback"; goto unregister_out_port; } if (jack_set_port_connect_callback(client, handle_port_connection_change, NULL)) { error_message = "failed to set port connection callback"; error_source = "jack_set_port_connect_callback"; goto unregister_out_port; } jack_on_shutdown(client, handle_shutdown, NULL); jack_set_info_function(handle_info); process_state = 0; connect_semaphore = create_semaphore(0); if (connect_semaphore == NULL) { error_message = get_semaphore_error(); error_source = "create_semaphore"; goto unregister_out_port; } init_semaphore = create_semaphore(1); if (init_semaphore == NULL) { error_message = get_semaphore_error(); error_source = "create_semaphore"; goto destroy_connect_semaphore; } process_semaphore = create_semaphore(2); if (process_semaphore == NULL) { error_message = get_semaphore_error(); error_source = "create_semaphore"; goto destroy_init_semaphore; } if (jack_activate(client)) { error_message = "could not activate client"; error_source = "jack_activate"; goto destroy_process_semaphore; } if (name_arg_count) { if (jack_connect(client, jack_port_name(out_port), target_out_port_name)) { error_message = "could not connect MIDI out port"; error_source = "jack_connect"; goto deactivate_client; } if (jack_connect(client, target_in_port_name, jack_port_name(in_port))) { error_message = "could not connect MIDI in port"; error_source = "jack_connect"; goto deactivate_client; } } if (! register_signal_handler(handle_signal)) { error_message = strerror(errno); error_source = "register_signal_handler"; goto deactivate_client; } printf("Waiting for connections ...\n"); if (wait_semaphore(connect_semaphore, 1) == -1) { error_message = get_semaphore_error(); error_source = "wait_semaphore"; goto deactivate_client; } if (connections_established) { printf("Waiting for test completion ...\n\n"); if (wait_semaphore(process_semaphore, 1) == -1) { error_message = get_semaphore_error(); error_source = "wait_semaphore"; goto deactivate_client; } } if (! register_signal_handler(SIG_DFL)) { error_message = strerror(errno); error_source = "register_signal_handler"; goto deactivate_client; } if (process_state == 2) { double average_latency = ((double) total_latency) / samples; double average_latency_time = total_latency_time / samples; size_t i; double latency_plot_offset = floor(((double) lowest_latency_time) / 100.0) / 10.0; double sample_rate = (double) jack_get_sample_rate(client); jack_nframes_t total_jitter = 0; jack_time_t total_jitter_time = 0; for (i = 0; i <= 100; i++) { jitter_plot[i] = 0; latency_plot[i] = 0; } for (i = 0; i < samples; i++) { double latency_time_value = (double) latency_time_values[i]; double latency_plot_time = (latency_time_value / 1000.0) - latency_plot_offset; double jitter_time = ABS(average_latency_time - latency_time_value); if (latency_plot_time >= 10.0) { (latency_plot[100])++; } else { (latency_plot[(int) (latency_plot_time * 10.0)])++; } if (jitter_time >= 10000.0) { (jitter_plot[100])++; } else { (jitter_plot[(int) (jitter_time / 100.0)])++; } total_jitter += ABS(average_latency - ((double) latency_values[i])); total_jitter_time += jitter_time; } printf("Reported out-port latency: %.2f-%.2f ms (%u-%u frames)\n" "Reported in-port latency: %.2f-%.2f ms (%u-%u frames)\n" "Average latency: %.2f ms (%.2f frames)\n" "Lowest latency: %.2f ms (%u frames)\n" "Highest latency: %.2f ms (%u frames)\n" "Peak MIDI jitter: %.2f ms (%u frames)\n" "Average MIDI jitter: %.2f ms (%.2f frames)\n", (out_latency_range.min / sample_rate) * 1000.0, (out_latency_range.max / sample_rate) * 1000.0, out_latency_range.min, out_latency_range.max, (in_latency_range.min / sample_rate) * 1000.0, (in_latency_range.max / sample_rate) * 1000.0, in_latency_range.min, in_latency_range.max, average_latency_time / 1000.0, average_latency, lowest_latency_time / 1000.0, lowest_latency, highest_latency_time / 1000.0, highest_latency, (highest_latency_time - lowest_latency_time) / 1000.0, highest_latency - lowest_latency, (total_jitter_time / 1000.0) / samples, ((double) total_jitter) / samples); printf("\nJitter Plot:\n"); for (i = 0; i < 100; i++) { if (jitter_plot[i]) { printf("%.1f - %.1f ms: %d\n", ((float) i) / 10.0, ((float) (i + 1)) / 10.0, jitter_plot[i]); } } if (jitter_plot[100]) { printf(" > 10 ms: %d\n", jitter_plot[100]); } printf("\nLatency Plot:\n"); for (i = 0; i < 100; i++) { if (latency_plot[i]) { printf("%.1f - %.1f ms: %d\n", latency_plot_offset + (((float) i) / 10.0), latency_plot_offset + (((float) (i + 1)) / 10.0), latency_plot[i]); } } if (latency_plot[100]) { printf(" > %.1f ms: %d\n", latency_plot_offset + 10.0, latency_plot[100]); } } deactivate_client: jack_deactivate(client); printf("\nMessages sent: %d\nMessages received: %d\n", messages_sent, messages_received); if (unexpected_messages) { printf("Unexpected messages received: %d\n", unexpected_messages); } if (xrun_count) { printf("Xruns: %d\n", xrun_count); } destroy_process_semaphore: destroy_semaphore(process_semaphore, 2); destroy_init_semaphore: destroy_semaphore(init_semaphore, 1); destroy_connect_semaphore: destroy_semaphore(connect_semaphore, 0); unregister_out_port: jack_port_unregister(client, out_port); unregister_in_port: jack_port_unregister(client, in_port); close_client: jack_client_close(client); free_message_2: free(message_2); free_message_1: free(message_1); free_latency_time_values: free(latency_time_values); free_latency_values: free(latency_values); free_alias2: free(alias2); free_alias1: free(alias1); if (error_message != NULL) { show_error: output_error(error_source, error_message); exit(EXIT_FAILURE); } return EXIT_SUCCESS; } 0707010000001D000081A400000000000000000000000161E2F7EE00000F79000000000000000000000000000000000000002F00000000jack-example-tools-1/example-clients/midiseq.c/* Copyright (C) 2004 Ian Esten 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <jack/jack.h> #include <jack/midiport.h> #include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> jack_client_t *client; jack_port_t *output_port; unsigned char* note_frqs; jack_nframes_t* note_starts; jack_nframes_t* note_lengths; jack_nframes_t num_notes; jack_nframes_t loop_nsamp; jack_nframes_t loop_index; static void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } static void usage() { fprintf(stderr, "usage: jack_midiseq name nsamp [startindex note nsamp] ...... [startindex note nsamp]\n"); fprintf(stderr, "eg: jack_midiseq Sequencer 24000 0 60 8000 12000 63 8000\n"); fprintf(stderr, "will play a 1/2 sec loop (if srate is 48khz) with a c4 note at the start of the loop\n"); fprintf(stderr, "that lasts for 12000 samples, then a d4# that starts at 1/4 sec that lasts for 800 samples\n"); } static int process(jack_nframes_t nframes, void *arg) { int i,j; void* port_buf = jack_port_get_buffer(output_port, nframes); unsigned char* buffer; jack_midi_clear_buffer(port_buf); /*memset(buffer, 0, nframes*sizeof(jack_default_audio_sample_t));*/ for (i = 0; i < nframes; i++) { for (j = 0; j < num_notes; j++) { if (note_starts[j] == loop_index) { if ((buffer = jack_midi_event_reserve(port_buf, i, 3))) { /* printf("wrote a note on, port buffer = 0x%x, event buffer = 0x%x\n", port_buf, buffer); */ buffer[2] = 64; /* velocity */ buffer[1] = note_frqs[j]; buffer[0] = 0x90; /* note on */ } } else if (note_starts[j] + note_lengths[j] == loop_index) { if ((buffer = jack_midi_event_reserve(port_buf, i, 3))) { /* printf("wrote a note off, port buffer = 0x%x, event buffer = 0x%x\n", port_buf, buffer); */ buffer[2] = 64; /* velocity */ buffer[1] = note_frqs[j]; buffer[0] = 0x80; /* note off */ } } } loop_index = loop_index+1 >= loop_nsamp ? 0 : loop_index+1; } return 0; } int main(int narg, char **args) { int i; if ((narg<6) || ((narg-3)%3 != 0)) { usage(); exit(1); } if ((client = jack_client_open (args[1], JackNullOption, NULL)) == 0) { fprintf (stderr, "JACK server not running?\n"); return 1; } jack_set_process_callback (client, process, 0); output_port = jack_port_register (client, "out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); loop_index = 0; num_notes = (narg - 3)/3; note_frqs = malloc(num_notes*sizeof(unsigned char)); note_starts = malloc(num_notes*sizeof(jack_nframes_t)); note_lengths = malloc(num_notes*sizeof(jack_nframes_t)); loop_nsamp = atoi(args[2]); for (i = 0; i < num_notes; i++) { note_starts[i] = atoi(args[3 + 3*i]); note_frqs[i] = atoi(args[4 + 3*i]); note_lengths[i] = atoi(args[5 + 3*i]); } if (jack_activate(client)) { fprintf (stderr, "cannot activate client"); return 1; } /* install a signal handler to properly quits jack client */ #ifndef WIN32 signal(SIGQUIT, signal_handler); signal(SIGHUP, signal_handler); #endif signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); /* run until interrupted */ while (1) { #ifdef WIN32 Sleep(1000); #else sleep(1); #endif }; jack_client_close(client); exit (0); } 0707010000001E000081A400000000000000000000000161E2F7EE000010C1000000000000000000000000000000000000003000000000jack-example-tools-1/example-clients/midisine.c/* Copyright (C) 2004 Ian Esten 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <math.h> #include <inttypes.h> #include <jack/jack.h> #include <jack/midiport.h> jack_port_t *input_port; jack_port_t *output_port; jack_default_audio_sample_t ramp=0.0; jack_default_audio_sample_t note_on; unsigned char note = 0; jack_default_audio_sample_t note_frqs[128]; jack_client_t *client; static void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } static void calc_note_frqs(jack_default_audio_sample_t srate) { int i; for(i=0; i<128; i++) { note_frqs[i] = (2.0 * 440.0 / 32.0) * pow(2, (((jack_default_audio_sample_t)i - 9.0) / 12.0)) / srate; } } static int process(jack_nframes_t nframes, void *arg) { int i; void* port_buf = jack_port_get_buffer(input_port, nframes); jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes); jack_midi_event_t in_event; jack_nframes_t event_index = 0; jack_nframes_t event_count = jack_midi_get_event_count(port_buf); if(event_count > 1) { printf(" midisine: have %d events\n", event_count); for(i=0; i<event_count; i++) { jack_midi_event_get(&in_event, port_buf, i); printf(" event %d time is %d. 1st byte is 0x%x\n", i, in_event.time, *(in_event.buffer)); } /* printf("1st byte of 1st event addr is %p\n", in_events[0].buffer);*/ } jack_midi_event_get(&in_event, port_buf, 0); for(i = 0; i < nframes; i++) { if ((in_event.time == i) && (event_index < event_count)) { if (((*(in_event.buffer) & 0xf0)) == 0x90) { /* note on */ note = *(in_event.buffer + 1); if (*(in_event.buffer + 2) == 0) { note_on = 0.0; } else { note_on = (float)(*(in_event.buffer + 2)) / 127.f; } } else if (((*(in_event.buffer)) & 0xf0) == 0x80) { /* note off */ note = *(in_event.buffer + 1); note_on = 0.0; } event_index++; if(event_index < event_count) jack_midi_event_get(&in_event, port_buf, event_index); } ramp += note_frqs[note]; ramp = (ramp > 1.0) ? ramp - 2.0 : ramp; out[i] = note_on*sin(2*M_PI*ramp); } return 0; } static int srate(jack_nframes_t nframes, void *arg) { printf("the sample rate is now %" PRIu32 "/sec\n", nframes); calc_note_frqs((jack_default_audio_sample_t)nframes); return 0; } static void jack_shutdown(void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } int main(int narg, char **args) { if ((client = jack_client_open("midisine", JackNullOption, NULL)) == 0) { fprintf(stderr, "JACK server not running?\n"); return 1; } calc_note_frqs(jack_get_sample_rate (client)); jack_set_process_callback (client, process, 0); jack_set_sample_rate_callback (client, srate, 0); jack_on_shutdown (client, jack_shutdown, 0); input_port = jack_port_register (client, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); output_port = jack_port_register (client, "audio_out", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (jack_activate (client)) { fprintf(stderr, "cannot activate client"); return 1; } /* install a signal handler to properly quits jack client */ #ifndef WIN32 signal(SIGQUIT, signal_handler); signal(SIGHUP, signal_handler); #endif signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); /* run until interrupted */ while(1) { #ifdef WIN32 Sleep(1*1000); #else sleep(1); #endif } jack_client_close(client); exit (0); } 0707010000001F000081A400000000000000000000000161E2F7EE0000160C000000000000000000000000000000000000003100000000jack-example-tools-1/example-clients/netmaster.c/* Copyright (C) 2009 Grame 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdlib.h> #include <stdbool.h> #include <stdio.h> #include <errno.h> #ifndef WIN32 #include <unistd.h> #endif #include <math.h> #include <signal.h> #include <getopt.h> #include <string.h> #include <assert.h> #include <jack/net.h> jack_net_master_t* net; #define BUFFER_SIZE 512 #define SAMPLE_RATE 44100 static void signal_handler(int sig) { jack_net_master_close(net); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } static void usage () { fprintf (stderr, "\n" "usage: jack_net_master \n" " [ -b buffer size (default = %d) ]\n" " [ -r sample rate (default = %d) ]\n" " [ -a hostname (default = %s) ]\n" " [ -p port (default = %d) ]\n", BUFFER_SIZE, SAMPLE_RATE, DEFAULT_MULTICAST_IP, DEFAULT_PORT); } int main (int argc, char *argv[]) { int buffer_size = BUFFER_SIZE; int sample_rate = SAMPLE_RATE; int udp_port = DEFAULT_PORT; const char* multicast_ip = DEFAULT_MULTICAST_IP; const char *options = "b:r:a:p:h"; int option_index; int opt; struct option long_options[] = { {"buffer size", 1, 0, 'b'}, {"sample rate", 1, 0, 'r'}, {"hostname", 1, 0, 'a'}, {"port", 1, 0, 'p'}, {0, 0, 0, 0} }; while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != -1) { switch (opt) { case 'b': buffer_size = atoi(optarg); break; case 'r': sample_rate = atoi(optarg); break; case 'a': multicast_ip = strdup(optarg); break; case 'p': udp_port = atoi(optarg); break; case 'h': usage(); return -1; } } int i; //jack_master_t request = { 4, 4, -1, -1, buffer_size, sample_rate, "master", -1 }; jack_master_t request = { -1, -1, -1, -1, buffer_size, sample_rate, "net_master", 6, true }; jack_slave_t result; float** audio_input_buffer; float** audio_output_buffer; int wait_usec = (int) ((((float)buffer_size) * 1000000) / ((float)sample_rate)); printf("Waiting for a slave...\n"); if ((net = jack_net_master_open(multicast_ip, udp_port, &request, &result)) == 0) { fprintf(stderr, "NetJack master can not be opened\n"); return 1; } printf("Slave is running...\n"); /* install a signal handler to properly quits jack client */ #ifdef WIN32 signal(SIGINT, signal_handler); signal(SIGABRT, signal_handler); signal(SIGTERM, signal_handler); #else signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); #endif // Allocate buffers audio_input_buffer = (float**)calloc(result.audio_input, sizeof(float*)); for (i = 0; i < result.audio_input; i++) { audio_input_buffer[i] = (float*)calloc(buffer_size, sizeof(float)); } audio_output_buffer = (float**)calloc(result.audio_output, sizeof(float*)); for (i = 0; i < result.audio_output; i++) { audio_output_buffer[i] = (float*)calloc(buffer_size, sizeof(float)); } /* Run until interrupted. WARNING !! : this code is given for demonstration purpose. For proper timing bevahiour it has to be called in a real-time context (which is *not* the case here...) */ //usleep(5*1000000); printf("Wait...\n"); //sleep(10); usleep(1000000); printf("Wait...OK\n"); while (1) { // Copy input to output assert(result.audio_input == result.audio_output); for (i = 0; i < result.audio_input; i++) { memcpy(audio_output_buffer[i], audio_input_buffer[i], buffer_size * sizeof(float)); } /* if (jack_net_master_send(net, result.audio_output, audio_output_buffer, 0, NULL) < 0) { printf("jack_net_master_send failure, exiting\n"); break; } usleep(10000); if (jack_net_master_recv(net, result.audio_input, audio_input_buffer, 0, NULL) < 0) { printf("jack_net_master_recv failure, exiting\n"); break; } */ if (jack_net_master_send_slice(net, result.audio_output, audio_output_buffer, 0, NULL, BUFFER_SIZE/2) < 0) { printf("jack_net_master_send failure, exiting\n"); break; } usleep(10000); if (jack_net_master_recv_slice(net, result.audio_input, audio_input_buffer, 0, NULL, BUFFER_SIZE/2) < 0) { printf("jack_net_master_recv failure, exiting\n"); break; } usleep(wait_usec); }; // Wait for application end jack_net_master_close(net); for (i = 0; i < result.audio_input; i++) { free(audio_input_buffer[i]); } free(audio_input_buffer); for (i = 0; i < result.audio_output; i++) { free(audio_output_buffer[i]); } free(audio_output_buffer); exit (0); } 07070100000020000081A400000000000000000000000161E2F7EE0000103D000000000000000000000000000000000000003000000000jack-example-tools-1/example-clients/netslave.c/* Copyright (C) 2009 Grame 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdlib.h> #include <stdio.h> #include <errno.h> #ifndef WIN32 #include <unistd.h> #endif #include <math.h> #include <signal.h> #include <getopt.h> #include <string.h> #include <jack/net.h> jack_net_slave_t* net; static void signal_handler(int sig) { jack_net_slave_close(net); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } static void usage () { fprintf (stderr, "\n" "usage: jack_net_slave \n" " [ -C capture channels (default = 2)]\n" " [ -P playback channels (default = 2) ]\n" " [ -a hostname (default = %s) ]\n" " [ -p port (default = %d)]\n", DEFAULT_MULTICAST_IP, DEFAULT_PORT); } static void net_shutdown(void* data) { printf("Restarting...\n"); } static int net_process(jack_nframes_t buffer_size, int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer, int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer, void* data) { int i; // Copy input to output for (i = 0; i < audio_input; i++) { memcpy(audio_output_buffer[i], audio_input_buffer[i], buffer_size * sizeof(float)); } return 0; } int main (int argc, char *argv[]) { int audio_input = 2; int audio_output = 2; int udp_port = DEFAULT_PORT; const char* multicast_ip = DEFAULT_MULTICAST_IP; const char *options = "C:P:a:p:h"; int option_index; int opt; struct option long_options[] = { {"audio input", 1, 0, 'C'}, {"audio output", 1, 0, 'P'}, {"hostname", 1, 0, 'a'}, {"port", 1, 0, 'p'}, {0, 0, 0, 0} }; while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) { switch (opt) { case 'C': audio_input = atoi(optarg); break; case 'P': audio_output = atoi(optarg); break; case 'a': multicast_ip = strdup(optarg); break; case 'p': udp_port = atoi(optarg); break; case 'h': usage(); return -1; } } jack_slave_t request = { audio_input, audio_output, 0, 0, DEFAULT_MTU, -1, JackFloatEncoder, 0, 2 }; jack_master_t result; printf("Waiting for a master...\n"); if ((net = jack_net_slave_open(multicast_ip, udp_port, "net_slave", &request, &result)) == 0) { fprintf(stderr, "JACK server not running?\n"); return 1; } printf("Master is found and running...\n"); jack_set_net_slave_process_callback(net, net_process, NULL); jack_set_net_slave_shutdown_callback(net, net_shutdown, NULL); if (jack_net_slave_activate(net) != 0) { fprintf(stderr, "Cannot activate slave client\n"); return 1; } /* install a signal handler to properly quits jack client */ #ifdef WIN32 signal(SIGINT, signal_handler); signal(SIGABRT, signal_handler); signal(SIGTERM, signal_handler); #else signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); #endif /* run until interrupted */ while (1) { #ifdef WIN32 Sleep(1000); #else sleep(1); #endif }; // Wait for application end jack_net_slave_deactivate(net); jack_net_slave_close(net); exit(0); } 07070100000021000081A400000000000000000000000161E2F7EE00001F0D000000000000000000000000000000000000003600000000jack-example-tools-1/example-clients/server_control.c/* Copyright (C) 2008 Grame 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #if !defined(__JACK1__) && !defined(__JACK2__) # error neither __JACK1__ or __JACK2__ is defined, this cannot happen #endif #include <stdio.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <getopt.h> #include <jack/jack.h> #include <jack/control.h> static jackctl_driver_t * jackctl_server_get_driver(jackctl_server_t *server, const char *driver_name) { const JSList * node_ptr = jackctl_server_get_drivers_list(server); while (node_ptr) { if (strcmp(jackctl_driver_get_name((jackctl_driver_t *)node_ptr->data), driver_name) == 0) { return (jackctl_driver_t *)node_ptr->data; } node_ptr = jack_slist_next(node_ptr); } return NULL; } static jackctl_internal_t * jackctl_server_get_internal(jackctl_server_t *server, const char *internal_name) { const JSList * node_ptr = jackctl_server_get_internals_list(server); while (node_ptr) { if (strcmp(jackctl_internal_get_name((jackctl_internal_t *)node_ptr->data), internal_name) == 0) { return (jackctl_internal_t *)node_ptr->data; } node_ptr = jack_slist_next(node_ptr); } return NULL; } #ifdef __JACK1__ static jackctl_parameter_t * jackctl_get_parameter( const JSList * parameters_list, const char * parameter_name) { while (parameters_list) { if (strcmp(jackctl_parameter_get_name((jackctl_parameter_t *)parameters_list->data), parameter_name) == 0) { return (jackctl_parameter_t *)parameters_list->data; } parameters_list = jack_slist_next(parameters_list); } return NULL; } #endif static void print_value(union jackctl_parameter_value value, jackctl_param_type_t type) { switch (type) { case JackParamInt: printf("parameter value = %d\n", value.i); break; case JackParamUInt: printf("parameter value = %u\n", value.ui); break; case JackParamChar: printf("parameter value = %c\n", value.c); break; case JackParamString: printf("parameter value = %s\n", value.str); break; case JackParamBool: printf("parameter value = %d\n", value.b); break; } } static void print_parameters(const JSList * node_ptr) { while (node_ptr != NULL) { jackctl_parameter_t * parameter = (jackctl_parameter_t *)node_ptr->data; printf("\nparameter name = %s\n", jackctl_parameter_get_name(parameter)); printf("parameter id = %c\n", jackctl_parameter_get_id(parameter)); printf("parameter short decs = %s\n", jackctl_parameter_get_short_description(parameter)); printf("parameter long decs = %s\n", jackctl_parameter_get_long_description(parameter)); print_value(jackctl_parameter_get_default_value(parameter), jackctl_parameter_get_type(parameter)); node_ptr = jack_slist_next(node_ptr); } } static void print_driver(jackctl_driver_t * driver) { printf("\n--------------------------\n"); printf("driver = %s\n", jackctl_driver_get_name(driver)); printf("-------------------------- \n"); print_parameters(jackctl_driver_get_parameters(driver)); } static void print_internal(jackctl_internal_t * internal) { printf("\n-------------------------- \n"); printf("internal = %s\n", jackctl_internal_get_name(internal)); printf("-------------------------- \n"); print_parameters(jackctl_internal_get_parameters(internal)); } static void usage() { fprintf (stderr, "\n" "usage: jack_server_control \n" " [ --driver OR -d driver_name ]\n" " [ --client OR -c client_name ]\n" ); } int main(int argc, char *argv[]) { jackctl_server_t * server; const JSList * parameters; const JSList * drivers; const JSList * internals; const JSList * node_ptr; #ifdef __JACK1__ sigset_t signals; #endif #ifdef __JACK2__ jackctl_sigmask_t * sigmask; #endif int opt, option_index; const char* driver_name = "dummy"; const char* client_name = "audioadapter"; const char *options = "d:c:"; struct option long_options[] = { {"driver", 1, 0, 'd'}, {"client", 1, 0, 'c'}, }; #ifdef __JACK1__ while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) { #endif #ifdef __JACK2__ while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != -1) { #endif switch (opt) { case 'd': driver_name = optarg; break; case 'c': client_name = optarg; break; default: usage(); exit(0); } } #ifdef __JACK1__ server = jackctl_server_create(NULL, NULL); #endif #ifdef __JACK2__ server = jackctl_server_create2(NULL, NULL, NULL); #endif parameters = jackctl_server_get_parameters(server); /* jackctl_parameter_t* param; union jackctl_parameter_value value; param = jackctl_get_parameter(parameters, "verbose"); if (param != NULL) { value.b = true; jackctl_parameter_set_value(param, &value); } */ printf("\n========================== \n"); printf("List of server parameters \n"); printf("========================== \n"); print_parameters(parameters); printf("\n========================== \n"); printf("List of drivers \n"); printf("========================== \n"); drivers = jackctl_server_get_drivers_list(server); node_ptr = drivers; while (node_ptr != NULL) { print_driver((jackctl_driver_t *)node_ptr->data); node_ptr = jack_slist_next(node_ptr); } printf("\n========================== \n"); printf("List of internal clients \n"); printf("========================== \n"); internals = jackctl_server_get_internals_list(server); node_ptr = internals; while (node_ptr != NULL) { print_internal((jackctl_internal_t *)node_ptr->data); node_ptr = jack_slist_next(node_ptr); } #ifdef __JACK1__ signals = jackctl_setup_signals(0); jackctl_server_start(server, jackctl_server_get_driver(server, driver_name)); #endif #ifdef __JACK2__ jackctl_server_open(server, jackctl_server_get_driver(server, driver_name)); jackctl_server_start(server); #endif jackctl_server_load_internal(server, jackctl_server_get_internal(server, client_name)); /* // Switch master test jackctl_driver_t* master; usleep(5000000); printf("jackctl_server_load_master\n"); master = jackctl_server_get_driver(server, "coreaudio"); jackctl_server_switch_master(server, master); usleep(5000000); printf("jackctl_server_load_master\n"); master = jackctl_server_get_driver(server, "dummy"); jackctl_server_switch_master(server, master); */ #ifdef __JACK1__ jackctl_wait_signals(signals); #endif #ifdef __JACK2__ sigmask = jackctl_setup_signals(0); jackctl_wait_signals(sigmask); jackctl_server_stop(server); jackctl_server_close(server); #endif jackctl_server_destroy(server); return 0; } 07070100000022000081A400000000000000000000000161E2F7EE00000CB1000000000000000000000000000000000000003000000000jack-example-tools-1/example-clients/showtime.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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <errno.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <inttypes.h> #include <jack/jack.h> #include <jack/transport.h> jack_client_t *client; static void showtime () { jack_position_t current; jack_transport_state_t transport_state; jack_nframes_t frame_time; transport_state = jack_transport_query (client, ¤t); frame_time = jack_frame_time (client); printf ("frame = %u frame_time = %u usecs = %" PRIu64 "\t", current.frame, frame_time, current.usecs); switch (transport_state) { case JackTransportStopped: printf ("state: Stopped"); break; case JackTransportRolling: printf ("state: Rolling"); break; case JackTransportStarting: printf ("state: Starting"); break; default: printf ("state: [unknown]"); } if (current.valid & JackPositionBBT) printf ("\tBBT: %3" PRIi32 "|%" PRIi32 "|%04" PRIi32, current.bar, current.beat, current.tick); if (current.valid & JackPositionTimecode) printf ("\tTC: (%.6f, %.6f)", current.frame_time, current.next_time); if (current.valid & JackBBTFrameOffset) printf ("\tBBT offset: (%" PRIi32 ")", current.bbt_offset); if (current.valid & JackAudioVideoRatio) printf ("\taudio/video: (%f)", current.audio_frames_per_video_frame); if (current.valid & JackVideoFrameOffset) { if (current.video_offset) { printf ("\t video@: (%" PRIi32 ")", current.video_offset); } else { printf ("\t no video"); } } printf ("\n"); } static void jack_shutdown (void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit (1); } void signal_handler (int sig) { jack_client_close (client); fprintf (stderr, "signal received, exiting ...\n"); exit (0); } int main (int argc, char *argv[]) { /* try to become a client of the JACK server */ if ((client = jack_client_open ("showtime", JackNullOption, NULL)) == 0) { fprintf (stderr, "JACK server not running?\n"); return 1; } #ifndef WIN32 signal (SIGQUIT, signal_handler); signal (SIGHUP, signal_handler); #endif signal (SIGTERM, signal_handler); signal (SIGINT, signal_handler); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* tell the JACK server that we are ready to roll */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); return 1; } while (1) { usleep (20); showtime (); } jack_client_close (client); exit (0); } 07070100000023000081A400000000000000000000000161E2F7EE00002DD0000000000000000000000000000000000000003300000000jack-example-tools-1/example-clients/simdtests.cpp/* * simdtests.c -- test accuracy and performance of simd optimizations * * Copyright (C) 2017 Andreas Mueller. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* We must include all headers memops.c includes to avoid trouble with * out namespace game below. */ #include <stdio.h> #include <string.h> #include <math.h> #include <memory.h> #include <stdlib.h> #include <stdint.h> #include <limits.h> #ifdef __linux__ #include <endian.h> #endif #include "memops.h" #if defined (__SSE2__) && !defined (__sun__) #include <emmintrin.h> #ifdef __SSE4_1__ #include <smmintrin.h> #endif #endif #if defined (__ARM_NEON__) || defined (__ARM_NEON) #include <arm_neon.h> #endif // our additional headers #include <time.h> /* Dirty: include mempos.c twice the second time with SIMD disabled * so we can compare aceelerated non accelerated */ namespace accelerated { #include "../common/memops.c" } namespace origerated { #ifdef __SSE2__ #undef __SSE2__ #endif #ifdef __ARM_NEON__ #undef __ARM_NEON__ #endif #ifdef __ARM_NEON #undef __ARM_NEON #endif #include "../common/memops.c" } // define conversion function types typedef void (*t_jack_to_integer)( char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); typedef void (*t_integer_to_jack)( jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); // define/setup test case data typedef struct test_case_data { uint32_t frame_size; uint32_t sample_size; bool reverse; t_jack_to_integer jack_to_integer_accel; t_jack_to_integer jack_to_integer_orig; t_integer_to_jack integer_to_jack_accel; t_integer_to_jack integer_to_jack_orig; dither_state_t *ditherstate; const char *name; } test_case_data_t; test_case_data_t test_cases[] = { { 4, 3, true, accelerated::sample_move_d32u24_sSs, origerated::sample_move_d32u24_sSs, accelerated::sample_move_dS_s32u24s, origerated::sample_move_dS_s32u24s, NULL, "32u24s" }, { 4, 3, false, accelerated::sample_move_d32u24_sS, origerated::sample_move_d32u24_sS, accelerated::sample_move_dS_s32u24, origerated::sample_move_dS_s32u24, NULL, "32u24" }, { 4, 3, true, accelerated::sample_move_d32l24_sSs, origerated::sample_move_d32l24_sSs, accelerated::sample_move_dS_s32l24s, origerated::sample_move_dS_s32l24s, NULL, "32l24s" }, { 4, 3, false, accelerated::sample_move_d32l24_sS, origerated::sample_move_d32l24_sS, accelerated::sample_move_dS_s32l24, origerated::sample_move_dS_s32l24, NULL, "32l24" }, { 3, 3, true, accelerated::sample_move_d24_sSs, origerated::sample_move_d24_sSs, accelerated::sample_move_dS_s24s, origerated::sample_move_dS_s24s, NULL, "24s" }, { 3, 3, false, accelerated::sample_move_d24_sS, origerated::sample_move_d24_sS, accelerated::sample_move_dS_s24, origerated::sample_move_dS_s24, NULL, "24" }, { 2, 2, true, accelerated::sample_move_d16_sSs, origerated::sample_move_d16_sSs, accelerated::sample_move_dS_s16s, origerated::sample_move_dS_s16s, NULL, "16s" }, { 2, 2, false, accelerated::sample_move_d16_sS, origerated::sample_move_d16_sS, accelerated::sample_move_dS_s16, origerated::sample_move_dS_s16, NULL, "16" }, }; // we need to repeat for better accuracy at time measurement const uint32_t retry_per_case = 1000; // setup test buffers #define TESTBUFF_SIZE 1024 jack_default_audio_sample_t jackbuffer_source[TESTBUFF_SIZE]; // integer buffers: max 4 bytes per value / * 2 for stereo char integerbuffer_accel[TESTBUFF_SIZE*4*2]; char integerbuffer_orig[TESTBUFF_SIZE*4*2]; // float buffers jack_default_audio_sample_t jackfloatbuffer_accel[TESTBUFF_SIZE]; jack_default_audio_sample_t jackfloatbuffer_orig[TESTBUFF_SIZE]; // comparing unsigned makes life easier uint32_t extract_integer( char* buff, uint32_t offset, uint32_t frame_size, uint32_t sample_size, bool big_endian) { uint32_t retval = 0; unsigned char* curr; uint32_t mult = 1; if(big_endian) { curr = (unsigned char*)buff + offset + sample_size-1; for(uint32_t i=0; i<sample_size; i++) { retval += *(curr--) * mult; mult*=256; } } else { curr = (unsigned char*)buff + offset + frame_size-sample_size; for(uint32_t i=0; i<sample_size; i++) { retval += *(curr++) * mult; mult*=256; } } return retval; } int main(int argc, char *argv[]) { // parse_arguments(argc, argv); uint32_t maxerr_displayed = 10; // fill jackbuffer for(int i=0; i<TESTBUFF_SIZE; i++) { // ramp jack_default_audio_sample_t value = ((jack_default_audio_sample_t)((i % TESTBUFF_SIZE) - TESTBUFF_SIZE/2)) / (TESTBUFF_SIZE/2); // force clipping value *= 1.02; jackbuffer_source[i] = value; } for(uint32_t testcase=0; testcase<sizeof(test_cases)/sizeof(test_case_data_t); testcase++) { // test mono/stereo for(uint32_t channels=1; channels<=2; channels++) { ////////////////////////////////////////////////////////////////////////////// // jackfloat -> integer // clean target buffers memset(integerbuffer_accel, 0, sizeof(integerbuffer_accel)); memset(integerbuffer_orig, 0, sizeof(integerbuffer_orig)); // accel clock_t time_to_integer_accel = clock(); for(uint32_t repetition=0; repetition<retry_per_case; repetition++) { test_cases[testcase].jack_to_integer_accel( integerbuffer_accel, jackbuffer_source, TESTBUFF_SIZE, test_cases[testcase].frame_size*channels, test_cases[testcase].ditherstate); } float timediff_to_integer_accel = ((float)(clock() - time_to_integer_accel)) / CLOCKS_PER_SEC; // orig clock_t time_to_integer_orig = clock(); for(uint32_t repetition=0; repetition<retry_per_case; repetition++) { test_cases[testcase].jack_to_integer_orig( integerbuffer_orig, jackbuffer_source, TESTBUFF_SIZE, test_cases[testcase].frame_size*channels, test_cases[testcase].ditherstate); } float timediff_to_integer_orig = ((float)(clock() - time_to_integer_orig)) / CLOCKS_PER_SEC; // output performance results printf( "JackFloat->Integer @%7.7s/%u: Orig %7.6f sec / Accel %7.6f sec -> Win: %5.2f %%\n", test_cases[testcase].name, channels, timediff_to_integer_orig, timediff_to_integer_accel, (timediff_to_integer_orig/timediff_to_integer_accel-1)*100.0); uint32_t int_deviation_max = 0; uint32_t int_error_count = 0; // output error (avoid spam -> limit error lines per test case) for(uint32_t sample=0; sample<TESTBUFF_SIZE; sample++) { uint32_t sample_offset = sample*test_cases[testcase].frame_size*channels; // compare both results uint32_t intval_accel=extract_integer( integerbuffer_accel, sample_offset, test_cases[testcase].frame_size, test_cases[testcase].sample_size, #if __BYTE_ORDER == __BIG_ENDIAN !test_cases[testcase].reverse); #else test_cases[testcase].reverse); #endif uint32_t intval_orig=extract_integer( integerbuffer_orig, sample_offset, test_cases[testcase].frame_size, test_cases[testcase].sample_size, #if __BYTE_ORDER == __BIG_ENDIAN !test_cases[testcase].reverse); #else test_cases[testcase].reverse); #endif // allow a deviation of 1 if(intval_accel>intval_orig+1 || intval_orig>intval_accel+1) { if(int_error_count<maxerr_displayed) { printf("Value error sample %u:", sample); printf(" Orig 0x"); char formatstr[10]; sprintf(formatstr, "%%0%uX", test_cases[testcase].sample_size*2); printf(formatstr, intval_orig); printf(" Accel 0x"); printf(formatstr, intval_accel); printf("\n"); } int_error_count++; uint32_t int_deviation; if(intval_accel > intval_orig) int_deviation = intval_accel-intval_orig; else int_deviation = intval_orig-intval_accel; if(int_deviation > int_deviation_max) int_deviation_max = int_deviation; } } printf( "JackFloat->Integer @%7.7s/%u: Errors: %u Max deviation %u\n", test_cases[testcase].name, channels, int_error_count, int_deviation_max); ////////////////////////////////////////////////////////////////////////////// // integer -> jackfloat // clean target buffers memset(jackfloatbuffer_accel, 0, sizeof(jackfloatbuffer_accel)); memset(jackfloatbuffer_orig, 0, sizeof(jackfloatbuffer_orig)); // accel clock_t time_to_float_accel = clock(); for(uint32_t repetition=0; repetition<retry_per_case; repetition++) { test_cases[testcase].integer_to_jack_accel( jackfloatbuffer_accel, integerbuffer_orig, TESTBUFF_SIZE, test_cases[testcase].frame_size*channels); } float timediff_to_float_accel = ((float)(clock() - time_to_float_accel)) / CLOCKS_PER_SEC; // orig clock_t time_to_float_orig = clock(); for(uint32_t repetition=0; repetition<retry_per_case; repetition++) { test_cases[testcase].integer_to_jack_orig( jackfloatbuffer_orig, integerbuffer_orig, TESTBUFF_SIZE, test_cases[testcase].frame_size*channels); } float timediff_to_float_orig = ((float)(clock() - time_to_float_orig)) / CLOCKS_PER_SEC; // output performance results printf( "Integer->JackFloat @%7.7s/%u: Orig %7.6f sec / Accel %7.6f sec -> Win: %5.2f %%\n", test_cases[testcase].name, channels, timediff_to_float_orig, timediff_to_float_accel, (timediff_to_float_orig/timediff_to_float_accel-1)*100.0); jack_default_audio_sample_t float_deviation_max = 0.0; uint32_t float_error_count = 0; // output error (avoid spam -> limit error lines per test case) for(uint32_t sample=0; sample<TESTBUFF_SIZE; sample++) { // For easier estimation/readability we scale floats back to integer jack_default_audio_sample_t sample_scaling; switch(test_cases[testcase].sample_size) { case 2: sample_scaling = SAMPLE_16BIT_SCALING; break; default: sample_scaling = SAMPLE_24BIT_SCALING; break; } jack_default_audio_sample_t floatval_accel = jackfloatbuffer_accel[sample] * sample_scaling; jack_default_audio_sample_t floatval_orig = jackfloatbuffer_orig[sample] * sample_scaling; // compare both results jack_default_audio_sample_t float_deviation; if(floatval_accel > floatval_orig) float_deviation = floatval_accel-floatval_orig; else float_deviation = floatval_orig-floatval_accel; if(float_deviation > float_deviation_max) float_deviation_max = float_deviation; // deviation > half bit => error if(float_deviation > 0.5) { if(float_error_count<maxerr_displayed) { printf("Value error sample %u:", sample); printf(" Orig %8.1f Accel %8.1f\n", floatval_orig, floatval_accel); } float_error_count++; } } printf( "Integer->JackFloat @%7.7s/%u: Errors: %u Max deviation %f\n", test_cases[testcase].name, channels, float_error_count, float_deviation_max); printf("\n"); } } return 0; } 07070100000024000081A400000000000000000000000161E2F7EE0000151A000000000000000000000000000000000000003500000000jack-example-tools-1/example-clients/simple_client.c/** @file simple_client.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. */ #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <signal.h> #ifndef WIN32 #include <unistd.h> #endif #include <jack/jack.h> jack_port_t *output_port1, *output_port2; jack_client_t *client; #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { float sine[TABLE_SIZE]; int left_phase; int right_phase; } paTestData; static void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } /** * The process callback for this JACK application is called in a * special realtime thread once for each audio cycle. * * This client follows a simple rule: when the JACK transport is * running, copy the input port to the output. When it stops, exit. */ int process (jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *out1, *out2; paTestData *data = (paTestData*)arg; int i; out1 = (jack_default_audio_sample_t*)jack_port_get_buffer (output_port1, nframes); out2 = (jack_default_audio_sample_t*)jack_port_get_buffer (output_port2, nframes); for( i=0; i<nframes; i++ ) { out1[i] = data->sine[data->left_phase]; /* left */ out2[i] = data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } return 0; } /** * JACK calls this shutdown_callback if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { exit (1); } int main (int argc, char *argv[]) { const char **ports; const char *client_name; const char *server_name = NULL; jack_options_t options = JackNullOption; jack_status_t status; paTestData data; int i; if (argc >= 2) { /* client name specified? */ client_name = argv[1]; if (argc >= 3) { /* server name specified? */ server_name = argv[2]; int my_option = JackNullOption | JackServerName; options = (jack_options_t)my_option; } } else { /* use basename of argv[0] */ client_name = strrchr(argv[0], '/'); if (client_name == 0) { client_name = argv[0]; } else { client_name++; } } for( i=0; i<TABLE_SIZE; i++ ) { data.sine[i] = 0.2 * (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ); } data.left_phase = data.right_phase = 0; /* open a client connection to the JACK server */ client = jack_client_open (client_name, options, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } exit (1); } if (status & JackServerStarted) { fprintf (stderr, "JACK server started\n"); } if (status & JackNameNotUnique) { client_name = jack_get_client_name(client); fprintf (stderr, "unique name `%s' assigned\n", client_name); } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, &data); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* create two ports */ output_port1 = jack_port_register (client, "output1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); output_port2 = jack_port_register (client, "output2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if ((output_port1 == NULL) || (output_port2 == NULL)) { fprintf(stderr, "no more JACK ports available\n"); exit (1); } /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); exit (1); } /* Connect the ports. You can't do this before the client is * activated, because we can't make connections to clients * that aren't running. Note the confusing (but necessary) * orientation of the driver backend ports: playback ports are * "input" to the backend, and capture ports are "output" from * it. */ ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); if (ports == NULL) { fprintf(stderr, "no physical playback ports\n"); exit (1); } if (jack_connect (client, jack_port_name (output_port1), ports[0])) { fprintf (stderr, "cannot connect output ports\n"); } if (jack_connect (client, jack_port_name (output_port2), ports[1])) { fprintf (stderr, "cannot connect output ports\n"); } jack_free (ports); /* install a signal handler to properly quits jack client */ #ifdef WIN32 signal(SIGINT, signal_handler); signal(SIGABRT, signal_handler); signal(SIGTERM, signal_handler); #else signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); #endif /* keep running until the Ctrl+C */ while (1) { #ifdef WIN32 Sleep(1000); #else sleep (1); #endif } jack_client_close (client); exit (0); } 07070100000025000081A400000000000000000000000161E2F7EE000013D7000000000000000000000000000000000000003D00000000jack-example-tools-1/example-clients/simple_session_client.c/** @file simple_session_client.c * * @brief This simple client demonstrates the most basic features of JACK * as they would be used by many applications. * this version also adds session manager functionality. */ #include <stdio.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <inttypes.h> #include <jack/jack.h> #include <jack/types.h> #include <jack/session.h> jack_port_t *input_port; jack_port_t *output_port; jack_client_t *client; int simple_quit = 0; /** * The process callback for this JACK application is called in a * special realtime thread once for each audio cycle. * * This client does nothing more than copy data from its input * port to its output port. It will exit when stopped by * the user (e.g. using Ctrl-C on a unix-ish operating system) */ int process (jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *in, *out; in = jack_port_get_buffer (input_port, nframes); out = jack_port_get_buffer (output_port, nframes); memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); return 0; } void session_callback (jack_session_event_t *event, void *arg) { char retval[100]; printf ("session notification\n"); printf ("path %s, uuid %s, type: %s\n", event->session_dir, event->client_uuid, event->type == JackSessionSave ? "save" : "quit"); snprintf (retval, 100, "jack_simple_session_client %s", event->client_uuid); event->command_line = strdup (retval); jack_session_reply( client, event ); if (event->type == JackSessionSaveAndQuit) { simple_quit = 1; } jack_session_event_free (event); } /** * JACK calls this shutdown_callback if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { exit (1); } int main (int argc, char *argv[]) { const char **ports; const char *client_name = "simple"; jack_status_t status; /* open a client connection to the JACK server */ if( argc == 1 ) client = jack_client_open (client_name, JackNullOption, &status ); else if( argc == 2 ) client = jack_client_open (client_name, JackSessionID, &status, argv[1] ); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } exit (1); } if (status & JackServerStarted) { fprintf (stderr, "JACK server started\n"); } if (status & JackNameNotUnique) { client_name = jack_get_client_name(client); fprintf (stderr, "unique name `%s' assigned\n", client_name); } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, 0); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* tell the JACK server to call `session_callback()' if the session is saved. */ jack_set_session_callback (client, session_callback, NULL); /* display the current sample rate. */ printf ("engine sample rate: %" PRIu32 "\n", jack_get_sample_rate (client)); /* create two ports */ input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if ((input_port == NULL) || (output_port == NULL)) { fprintf(stderr, "no more JACK ports available\n"); exit (1); } /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); exit (1); } /* Connect the ports. You can't do this before the client is * activated, because we can't make connections to clients * that aren't running. Note the confusing (but necessary) * orientation of the driver backend ports: playback ports are * "input" to the backend, and capture ports are "output" from * it. */ /* only do the autoconnect when not reloading from a session. * in case of a session reload, the SM will restore our connections */ if (argc==1) { ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); if (ports == NULL) { fprintf(stderr, "no physical capture ports\n"); exit (1); } if (jack_connect (client, ports[0], jack_port_name (input_port))) { fprintf (stderr, "cannot connect input ports\n"); } free (ports); ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); if (ports == NULL) { fprintf(stderr, "no physical playback ports\n"); exit (1); } if (jack_connect (client, jack_port_name (output_port), ports[0])) { fprintf (stderr, "cannot connect output ports\n"); } free (ports); } /* keep running until until we get a quit event */ while (!simple_quit) #ifdef WIN32 Sleep(1*1000); #else sleep(1); #endif jack_client_close (client); exit (0); } 07070100000026000081A400000000000000000000000161E2F7EE00001738000000000000000000000000000000000000003300000000jack-example-tools-1/example-clients/thru_client.c/** @file thru_client.c * * @brief This simple through client demonstrates the basic features of JACK * as they would be used by many applications. */ #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <signal.h> #ifndef WIN32 #include <unistd.h> #endif #include <jack/jack.h> jack_port_t **input_ports; jack_port_t **output_ports; jack_client_t *client; static void signal_handler ( int sig ) { jack_client_close ( client ); fprintf ( stderr, "signal received, exiting ...\n" ); exit ( 0 ); } /** * The process callback for this JACK application is called in a * special realtime thread once for each audio cycle. * * This client follows a simple rule: when the JACK transport is * running, copy the input port to the output. When it stops, exit. */ int process ( jack_nframes_t nframes, void *arg ) { int i; jack_default_audio_sample_t *in, *out; for ( i = 0; i < 2; i++ ) { in = jack_port_get_buffer ( input_ports[i], nframes ); out = jack_port_get_buffer ( output_ports[i], nframes ); memcpy ( out, in, nframes * sizeof ( jack_default_audio_sample_t ) ); } return 0; } /** * JACK calls this shutdown_callback if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown ( void *arg ) { free ( input_ports ); free ( output_ports ); exit ( 1 ); } int main ( int argc, char *argv[] ) { int i; const char **ports; const char *client_name; const char *server_name = NULL; jack_options_t options = JackNullOption; jack_status_t status; if ( argc >= 2 ) /* client name specified? */ { client_name = argv[1]; if ( argc >= 3 ) /* server name specified? */ { server_name = argv[2]; options |= JackServerName; } } else /* use basename of argv[0] */ { client_name = strrchr ( argv[0], '/' ); if ( client_name == 0 ) { client_name = argv[0]; } else { client_name++; } } /* open a client connection to the JACK server */ client = jack_client_open ( client_name, options, &status, server_name ); if ( client == NULL ) { fprintf ( stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status ); if ( status & JackServerFailed ) { fprintf ( stderr, "Unable to connect to JACK server\n" ); } exit ( 1 ); } if ( status & JackServerStarted ) { fprintf ( stderr, "JACK server started\n" ); } if ( status & JackNameNotUnique ) { client_name = jack_get_client_name ( client ); fprintf ( stderr, "unique name `%s' assigned\n", client_name ); } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback ( client, process, 0 ); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown ( client, jack_shutdown, 0 ); /* create two ports pairs*/ input_ports = ( jack_port_t** ) calloc ( 2, sizeof ( jack_port_t* ) ); output_ports = ( jack_port_t** ) calloc ( 2, sizeof ( jack_port_t* ) ); char port_name[16]; for ( i = 0; i < 2; i++ ) { sprintf ( port_name, "input_%d", i + 1 ); input_ports[i] = jack_port_register ( client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ); sprintf ( port_name, "output_%d", i + 1 ); output_ports[i] = jack_port_register ( client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); if ( ( input_ports[i] == NULL ) || ( output_ports[i] == NULL ) ) { fprintf ( stderr, "no more JACK ports available\n" ); exit ( 1 ); } } /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if ( jack_activate ( client ) ) { fprintf ( stderr, "cannot activate client" ); exit ( 1 ); } /* Connect the ports. You can't do this before the client is * activated, because we can't make connections to clients * that aren't running. Note the confusing (but necessary) * orientation of the driver backend ports: playback ports are * "input" to the backend, and capture ports are "output" from * it. */ ports = jack_get_ports ( client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput ); if ( ports == NULL ) { fprintf ( stderr, "no physical capture ports\n" ); exit ( 1 ); } for ( i = 0; i < 2; i++ ) if ( jack_connect ( client, ports[i], jack_port_name ( input_ports[i] ) ) ) fprintf ( stderr, "cannot connect input ports\n" ); free ( ports ); ports = jack_get_ports ( client, NULL, NULL, JackPortIsPhysical|JackPortIsInput ); if ( ports == NULL ) { fprintf ( stderr, "no physical playback ports\n" ); exit ( 1 ); } for ( i = 0; i < 2; i++ ) if ( jack_connect ( client, jack_port_name ( output_ports[i] ), ports[i] ) ) fprintf ( stderr, "cannot connect input ports\n" ); free ( ports ); /* install a signal handler to properly quits jack client */ #ifdef WIN32 signal ( SIGINT, signal_handler ); signal ( SIGABRT, signal_handler ); signal ( SIGTERM, signal_handler ); #else signal ( SIGQUIT, signal_handler ); signal ( SIGTERM, signal_handler ); signal ( SIGHUP, signal_handler ); signal ( SIGINT, signal_handler ); #endif /* keep running until the transport stops */ while (1) { #ifdef WIN32 Sleep ( 1000 ); #else sleep ( 1 ); #endif } jack_client_close ( client ); exit ( 0 ); } 07070100000027000081A400000000000000000000000161E2F7EE000012E6000000000000000000000000000000000000003800000000jack-example-tools-1/example-clients/transport_client.c/** @file transport_client.c * * @brief This client demonstrates very simple use of the JACK * transport API. Compare it with the simple_client example, * which is even simpler. It also demonstrates taking a client * name and optionally server name from the command line, rather * than hard-coding either of these names. */ #include <stdio.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <jack/jack.h> jack_port_t *input_port; jack_port_t *output_port; jack_client_t *client; /* a simple state machine for this client */ volatile enum { Init, Run, Exit } client_state = Init; /** * The process callback for this JACK application is called in a * special realtime thread once for each audio cycle. * * This client follows a simple rule: when the JACK transport is * running, copy the input port to the output. When it stops, exit. */ int process (jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *in, *out; jack_transport_state_t ts = jack_transport_query(client, NULL); if (ts == JackTransportRolling) { if (client_state == Init) client_state = Run; in = jack_port_get_buffer (input_port, nframes); out = jack_port_get_buffer (output_port, nframes); memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); } else if (ts == JackTransportStopped) { if (client_state == Run) client_state = Exit; } return 0; } /** * JACK calls this shutdown_callback if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { exit (1); } int main (int argc, char *argv[]) { const char **ports; const char *client_name; const char *server_name = NULL; jack_options_t options = JackNullOption; jack_status_t status; if (argc >= 2) { /* client name specified? */ client_name = argv[1]; if (argc >= 3) { /* server name specified? */ server_name = argv[2]; options |= JackServerName; } } else { /* use basename of argv[0] */ client_name = strrchr(argv[0], '/'); if (client_name == 0) { client_name = argv[0]; } else { client_name++; } } /* open a client connection to the JACK server */ client = jack_client_open (client_name, options, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } exit (1); } if (status & JackServerStarted) { fprintf (stderr, "JACK server started\n"); } if (status & JackNameNotUnique) { client_name = jack_get_client_name(client); fprintf (stderr, "unique name `%s' assigned\n", client_name); } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, 0); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* display the current sample rate. */ printf ("engine sample rate: %" PRIu32 "\n", jack_get_sample_rate (client)); /* create two ports */ input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if ((input_port == NULL) || (output_port == NULL)) { fprintf(stderr, "no more JACK ports available\n"); exit (1); } /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); exit (1); } /* Connect the ports. You can't do this before the client is * activated, because we can't make connections to clients * that aren't running. Note the confusing (but necessary) * orientation of the driver backend ports: playback ports are * "input" to the backend, and capture ports are "output" from * it. */ ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); if (ports == NULL) { fprintf(stderr, "no physical capture ports\n"); exit (1); } if (jack_connect (client, ports[0], jack_port_name (input_port))) { fprintf (stderr, "cannot connect input ports\n"); } free (ports); ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); if (ports == NULL) { fprintf(stderr, "no physical playback ports\n"); exit (1); } if (jack_connect (client, jack_port_name (output_port), ports[0])) { fprintf (stderr, "cannot connect output ports\n"); } free (ports); /* keep running until the transport stops */ while (client_state != Exit) { sleep (1); } jack_client_close (client); exit (0); } 07070100000028000081A400000000000000000000000161E2F7EE000008D6000000000000000000000000000000000000002E00000000jack-example-tools-1/example-clients/zombie.c/* Copyright (C) 2002 Jeremy Hall 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., 675 Mass Ave, Cambridge, MA 02139, USA. $Id: zombie.c,v 1.1 2005/08/18 11:42:08 letz Exp $ */ #include <stdio.h> #include <errno.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <jack/jack.h> int running = 1; int count = 0; jack_port_t* output_port; static int process(jack_nframes_t nframes, void* arg) { if (count++ == 1000) { printf("process block\n"); //while (1) {} #if WIN32 Sleep(1*1000); #else sleep(1); #endif } return 0; } static void shutdown_handler (void *arg) { printf("shutdown \n"); running = 0; } int main (int argc, char *argv[]) { jack_client_t* client = NULL; /* try to become a client of the JACK server */ if ((client = jack_client_open ("zombie", JackNullOption, NULL)) == 0) { fprintf (stderr, "JACK server not running?\n"); goto error; } jack_set_process_callback (client, process, NULL); jack_on_shutdown(client, shutdown_handler, NULL); output_port = jack_port_register (client, "port1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); /* tell the JACK server that we are ready to roll */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); goto error; } jack_connect(client, jack_port_name(output_port), "coreaudio:Built-in Audio:in2"); while (running) { #if WIN32 Sleep(1*1000); #else sleep(1); #endif printf ("run\n"); } jack_deactivate (client); jack_client_close (client); return 0; error: if (client) jack_client_close (client); return 1; } 07070100000029000041ED00000000000000000000000161E2F7EE00000000000000000000000000000000000000000000001900000000jack-example-tools-1/man0707010000002A000081A400000000000000000000000161E2F7EE00000E57000000000000000000000000000000000000002300000000jack-example-tools-1/man/alsa_in.0.TH ALSA_IO "1" "@DATE@" "@VERSION@" .SH NAME \fBalsa_in\fR, \fBalsa_out\fR \- Jack clients that perform I/O with an alternate audio interface .SH SYNOPSIS \fBalsa_in\fR [\fIoptions\fR] .br \fBalsa_out\fR [\fIoptions\fR] .SH DESCRIPTION A JACK client that opens a specified audio interface (different to the one used by the JACK server, if any) and moves audio data between its JACK ports and the interface. alsa_in will provide data from the interface (potentially for capture); alsa_out will deliver data to it (for playback). The audio interface used by alsa_in/alsa_out does not need to be synchronized with JACK backend (or the hardware it might be using). alsa_in/alsa_out tries to resample the output stream in an attempt to compensate for drift between the two clocks. As of jack-0.116.3 this works almost perfectly. It takes some time, to reach absolute resample-rate stability. So give it some minutes (its intended to be running permanently anyways) .SH OPTIONS .TP \fB\-j \fI jack_client_name\fR .br Set Client Name. .TP \fB\-d \fI alsa_device\fR .br Use this Soundcard. .TP \fB\-v\fR .br Verbose, prints out resample coefficient and other parameters useful for debugging, every 500ms. also reports soft xruns. .TP \fB\-i\fR .br Instrumentation. This logs the 4 important parameters of the samplerate control algorithm every 1ms. You can pipe this into a file, and plot it. Should only be necessary, if it does not work as expected, and we need to adjust some of the obscure parameters, to make it work. Find me on irc.freenode.org #jack in order to set this up correctly. .TP \fB\-c \fI channels\fR .br Set Number of channels. .TP \fB\-r \fI sample_rate\fR .br Set sample_rate. The program resamples as necessary. So you can connect a 44100 jackd to a soundcard only supporting 48000. (default is jack sample_rate) .TP \fB\-p \fI period_size\fR .br Set the period size. It is not related to the jackd period_size. Sometimes it affects the quality of the delay measurements. Setting this lower than the jackd period_size will only work, if you use a higher number of periods. .TP \fB\-n \fI num_period\fR .br Set number of periods. See note for period_size. .TP \fB\-q \fI quality\fR .br Set the quality of the resampler from 0 to 4. can significanly reduce cpu usage. .TP \fB\-m \fI max_diff\fR .br The value when a soft xrun occurs. Basically the window, in which the dma pointer may jitter. I don't think its necessary to play with this anymore. .TP \fB\-t \fI target_delay\fR .br The delay alsa_io should try to approach. Same as for max_diff. It will be setup based on \-p and \-n which is generally sufficient. .TP \fB\-s \fI smooth_array_size\fR .br This parameter controls the size of the array used for smoothing the delay measurement. Its default is 256. If you use a pretty low period size, you can lower the CPU usage a bit by decreasing this parameter. However most CPU time is spent in the resampling so this will not be much. .TP \fB\-C \fI P Control Clamp\fR .br If you have a PCI card, then the default value (15) of this parameter is too high for \-p64 \-n2... Setting it to 5 should fix that. Be aware that setting this parameter too low, lets the hf noise on the delay measurement come through onto the resamplerate, so this might degrade the quality of the output. (but its a threshold value, and it has been chosen, to mask the noise of a USB card, which has an amplitude which is 50 times higher than that of a PCI card, so 5 won't lose you any quality on a PCI card) .TP \fB\-S \fI server_name\fR .br Server to connect to. This option permits to attach to a named jack2 server. .SH AUTHOR Torben Hohn 0707010000002B000081A400000000000000000000000161E2F7EE00000013000000000000000000000000000000000000002400000000jack-example-tools-1/man/alsa_out.0.so man1/alsa_in.1 0707010000002C000081A400000000000000000000000161E2F7EE000001B3000000000000000000000000000000000000002800000000jack-example-tools-1/man/jack_bufsize.0.TH JACK_BUFSIZE "1" "@DATE@" "@VERSION@" .SH NAME jack_bufsize \- JACK toolkit client to change the JACK buffer size .SH SYNOPSIS .B jack_bufsize bufsize .SH DESCRIPTION .B jack_bufsize jack_bufsize sets the size of the buffer (frames per period) used in JACK. This change happens on-line (the JACK server and its clients do not need to be restarted). .br When invoked without arguments, it prints the current bufsize, and exits. 0707010000002D000081A400000000000000000000000161E2F7EE0000022A000000000000000000000000000000000000002800000000jack-example-tools-1/man/jack_connect.0.TH JACK_CONNECT "1" "@DATE@" "@VERSION@" .SH NAME \fBjack_connect\fR, \fBjack_disconnect\fR \- JACK toolkit clients for connecting & disconnecting ports .SH SYNOPSIS \fB jack_connect\fR [ \fI-s\fR | \fI--server servername\fR ] [\fI-h\fR | \fI--help\fR ] port1 port2 \fB jack_disconnect\fR [ \fI-s\fR | \fI--server servername\fR ] [\fI-h\fR | \fI--help\fR ] port1 port2 .SH DESCRIPTION \fBjack_connect\fR connects the two named ports. \fBjack_disconnect\fR disconnects the two named ports. .SH RETURNS The exit status is zero if successful, 1 otherwise 0707010000002E000081A400000000000000000000000161E2F7EE00000018000000000000000000000000000000000000002B00000000jack-example-tools-1/man/jack_disconnect.0.so man1/jack_connect.1 0707010000002F000081A400000000000000000000000161E2F7EE00000280000000000000000000000000000000000000002A00000000jack-example-tools-1/man/jack_freewheel.0.TH JACK_FREEWHEEL "1" "@DATE@" "@VERSION@" .SH NAME jack_freewheel \- JACK toolkit client to control freewheeling mode .SH SYNOPSIS .B jack_freewheel [y|n] .SH DESCRIPTION .B jack_freewheel Turns freewheeling mode on (y) or off (n). While in freewheeling mode, the JACK server does not wait in between process() calls, and does not read or write data from/to any audio interface. That results in the JACK graph processing data as fast as possible. Freewheeling makes fast exports to files possible. .PP There is no useful reason to use this tool other than testing. JACK clients that use freewheeling will turn it on and off themselves. 07070100000030000081A400000000000000000000000161E2F7EE00000157000000000000000000000000000000000000003000000000jack-example-tools-1/man/jack_impulse_grabber.0.TH JACK_IMPULSE_GRABBER "1" "@DATE@" "@VERSION@" .SH NAME jack_impulse_grabber \- JACK toolkit client to grab an impulse (response) .SH SYNOPSIS \fBjack_impulse_grabber\fR \fB-d\fR \fIduration\fR [\fI-f\fR (C|gnuplot)] .SH DESCRIPTION \fBjack_impulse_grabber\fR is a JACK example client for collecting impulses recordings from JACK ports. 07070100000031000081A400000000000000000000000161E2F7EE00000B83000000000000000000000000000000000000002800000000jack-example-tools-1/man/jack_iodelay.0.TH JACK_IODELAY "1" "@DATE@" "@VERSION@" .SH NAME jack_iodelay \- JACK toolkit client to measure roundtrip latency .SH SYNOPSIS .B jack_iodelay .SH DESCRIPTION .B jack_iodelay will create one input and one output port, and then measures the latency (signal delay) between them. For this to work, the output port must be connected to its input port. The measurement is accurate to a resolution of greater than 1 sample. .PP The expected use is to connect jack_iodelay's output port to a hardware playback port, then use a physical loopback cable from the corresponding hardware output connector to an input connector, and to connect that corresponding hardware capture port to jack_iodelay's input port. This creates a roundtrip that goes through any analog-to-digital and digital-to-analog converters that are present in the audio hardware. .PP Although the hardware loopback latency is the expected use, it is also possible to use jack_iodelay to measure the latency along any fully connected signal path, such as those involving other JACK clients. .PP Once jack_iodelay completes its measurement it will print the total latency it has detected. This will include the JACK buffer length in addition to any other latency in the signal path. It will continue to print the value every 0.5 seconds so that if you wish you can vary aspects of the signal path to see their effect on the measured latency. .PP If no incoming signal is detected from the input port, jack_iodelay will print .PP \fT Signal below threshold... .\fR .PP every second until this changes (e.g. until you establish the correct connections). .PP To use the value measured by jack_iodelay with the -I and -O arguments of a JACK backend (also called Input Latency and Output Latency in the setup dialog of qjackctl), you must subtract the JACK buffer size from the result. The buffer size is determined by multiplying the number of frames per period (given to the jackd backend by the -p or --period option) by the number of periods per buffer (given to the jackd backend by the -n or --nperiods option). Note that JACK2 will add an implicit additional period when using the default asynchronous mode, so for JACK1 or JACK2 in synchronous mode, the buffer size is n*p, but for JACK2 in asynchronous mode the buffer size is (n+1)*p. Once the JACK buffer size is subtracted from the measured latency, the result is the "extra" latency due to the interface hardware. Then, if you believe that the latency is equally distributed between the input and output parts of your audio hardware (extremely likely), divide the result by two and use that for input and output latency values. Doing this measurement will enable JACK clients that use the JACK latency API to accurately position/delay audio to keep signals synchronized even when there are inherent delays in the end-to-end signal pathways. .SH AUTHOR Originally written in C++ by Fons Adriaensen, ported to C by Torben Hohn. 07070100000032000081A400000000000000000000000161E2F7EE00000392000000000000000000000000000000000000002500000000jack-example-tools-1/man/jack_load.0.TH JACK_LOAD "1" "@DATE@" "@VERSION@" .SH NAME jack_load \- JACK toolkit client for loading in-process clients .SH SYNOPSIS \fBjack_load\fR [ \fI-i\fR initstring ] [ \fI-s\fR servername ] [\fI-w\fR ] client-name so-name [ initstring ] .SH DESCRIPTION \fBjack_load\fR is a JACK toolkit client. It loads the specified plugin and creates an in-process client. .SH ARGUMENTS .PP The client-name must be a currently unused client name. .PP The so-name is the name of file that client code is stored in (typically, \fIclientname.so\fR) .SH OPTIONS .TP \fB-i\fR, \fB--init\fR init-string .br initialization string passed to the in-process client. Note that this can also be specified as the last argument on the command line. .TP \fB-s\fR, \fB--server\fR servername .br Name of JACK server to connect to .TP \fB-w\fR, \fB--wait\fR Wait for a signal (eg. from Ctrl-c) and then unload the client. .SH AUTHOR Jeremy Hall 07070100000033000081A400000000000000000000000161E2F7EE0000042C000000000000000000000000000000000000002400000000jack-example-tools-1/man/jack_lsp.0.TH JACK_LSP "1" "@DATE@" "@VERSION@" .SH NAME jack_lsp \- JACK toolkit client to list information on ports .SH SYNOPSIS \fBjack_lsp\fR [ \fI-s\fR | \fI--server\fR servername ] [ \fI-AclLptvh\fR ] .SH DESCRIPTION \fBjack_lsp\fR lists all known ports associated with a JACK server. It can also optionally list various kinds of information about each port. .SH OPTIONS .TP \fB-s\fR, \fB--server\fR \fIservername\fR .br Connect to the jack server named \fIservername\fR .TP \fB-A\fR, \fB--aliases\fR .br List aliases for each port .TP \fB-c\fR, \fB--connections\fR .br List connections to/from each port .TP \fB-l\fR, \fB--latency\fR .br Display per-port latency in frames at each port .TP \fB-L\fR, \fI--latency\fR .br Display total latency in frames at each port .TP \fB-p\fR, \fB--properties\fR .br Display port properties. Output may include input|output, can-monitor, physical, terminal .TP \fB-t\fR, \fB--type\fR .br Display port type .TP \fB-h\fR, \fB--help\fR .br Display help/usage message .TP \fB-v\fR, \fB--version\fR .br Output version information and exit 07070100000034000081A400000000000000000000000161E2F7EE00000445000000000000000000000000000000000000002600000000jack-example-tools-1/man/jack_metro.0.TH JACK_METRO "1" "@DATE@" "@VERSION@" .SH NAME jack_metro \- JACK toolkit metronome .SH SYNOPSIS \fBjack_metro\fR [ \fI-n\fR name ] [ \fI-f\fR hz ] [ \fI-D\fR msecs ] [\fI-a\fR % ] [ \fI-d\fR % ] \fI-b\fR bpm .SH DESCRIPTION \fBjack_metro\fR is a simple metronome for JACK. It generates a synthetic "tick" sound for every beat. Note that is does \fBnot\fR connect its output port by default - to hear the sound it makes you must connect them using some other tool. .SH OPTIONS .TP \fB-n\fR, \fB--name\fR .br Specify a name for this instance of the metronome. .TP \fB-f\fR, \fB--frequency\fR Hz .br Define the frequency of the "tick" in Hz. .TP \fB-D\fR, \fB--duration\fR msecs .br Define the duration of the "tick" in milliseconds. .TP \fB-a\fR, \fB--attack\fR %-age .br Define the duration of the attack phase of the "tick" as a percentage of the duration. .TP \fB-d\fR, \fB--decay\fR %-age .br Define the duration of the decay phase of the "tick" as a percentage of the duration. .TP \fB--b\fR, \fB--bpm\fR bpm .br Define the number of beats per minute. .SH AUTHOR Anthony Van Groningen 07070100000035000081A400000000000000000000000161E2F7EE000001FF000000000000000000000000000000000000002F00000000jack-example-tools-1/man/jack_monitor_client.0.TH JACK_CONNECT "1" "@DATE@" "@VERSION@" .SH NAME jack_monitor_client \- The JACK Audio Connection Kit example client .SH SYNOPSIS .B jack_monitor_client client-name .PP The client-name must be the name of a existing client that monitoring is to be enabled for. .SH DESCRIPTION .B jack_monitor_client is an example client for the JACK Audio Connection Kit. It enables monitoring for the specified client. .SH AUTHOR Jeremy Hall .PP This manpage was written by Robert Jordens <jordens@debian.org> for Debian. 07070100000036000081A400000000000000000000000161E2F7EE0000093C000000000000000000000000000000000000002A00000000jack-example-tools-1/man/jack_netsource.0.TH JACK_NETSOURCE "1" "@DATE@" "@VERSION@" .SH NAME jack_netsource \- Netjack Master client for one slave .SH SYNOPSIS \fBjack_netsource\fR [ \fI-H\fR hostname ] [ \fIoptions\fR ] .SH DESCRIPTION \fBjack_netsource\fR The Master side of a netjack connection. Represents the slave jackd -dnet in the master jack graph. Most connection parameters are configured via the netsource, and the slave will set itself up according to the commandline option given to jack_netsource. .br Netjack allows low latency audio connections over general IP networks. When using opus for compression, it is even possible to establish transatlantic links, with latencies not much over the actual ping time. .br But the main usecase is of course a LAN, where it can achieve one jack period of latency. .SH OPTIONS .TP \fB-h\fR this help text .TP \fB-H\fR \fIslave host\fR .br Host name of the slave JACK .TP \fB-o\fR \fInum channels\fR .br Number of audio playback channels .TP \fB-i\fR \fInum channels\fR .br Number of audio capture channels .TP \fB-O\fR \fInum channels\fR .br Number of midi playback channels .TP \fB-I\fR \fInum channels\fR .br Number of midi capture channels .TP \fB-n\fR \fIperiods\fR .br Network latency in JACK periods .TP \fB-p\fR \fIport\fR .br UDP port that the slave is listening on .TP \fB-r\fR \fIreply port\fR .br UDP port that we are listening on .TP \fB-B\fR \fIbind port\fR .br reply port, for use in NAT environments .TP \fB-b\fR \fIbitdepth\fR .br Set transport to use 16bit or 8bit .TP \fB-P\fR \fIkbits\fR .br Use Opus encoding with <kbits> per channel .TP \fB-m\fR \fImtu\fR .br Assume this mtu for the link .TP \fB-R\fR \fIN\fR .br Redundancy: send out packets N times. .TP \fB-e\fR .br skip host-to-network endianness conversion .TP \fB-N\fR \fIjack name\fR .br Reports a different client name to jack .TP .TP \fB-s\fR, \fB--server\fR \fIservername\fR .br Connect to the jack server named \fIservername\fR .TP \fB-h\fR, \fB--help\fR .br Display help/usage message .TP \fB-v\fR, \fB--version\fR .br Output version information and exit .SH EXAMPLES .PP run a 4 audio channel bidirectional link with one period of latency and no midi channels. Audio data is flowing uncompressed over the wire: .br On \fIhostA\fR: .IP \fBjackd \-d alsa \fR .br \fBjack_netsource \-H hostB -n1 -i4 -o4 -I0 -O0 \fR .PP On \fIhostB\fR: .IP \fBjackd \-d net \fR 07070100000037000081A400000000000000000000000161E2F7EE00000965000000000000000000000000000000000000002900000000jack-example-tools-1/man/jack_property.0.TH JACK_PROPERTY "1" "@DATE@" "@VERSION@" .SH NAME jack_property \- JACK client to list, set and delete metadata information .SH SYNOPSIS \fBjack_property\fR -l .br \fBjack_property\fR [ -c | -p ] -l \fIidentifier\fR .br \fBjack_property\fR [ -c | -p ] -l \fIidentifier\fR \fIkey\fR .br \fBjack_property\fR [ -c | -p ] -s \fIidentifier\fR \fIkey\fR \fIvalue\fR [ \fItype\fR ] .br \fBjack_property\fR [ -c | -p ] -d \fIidentifier\fR .br \fBjack_property\fR [ -c | -p ] -d \fIidentifier\fR \fIkey\fR .br \fBjack_property\fR -D .SH DESCRIPTION \fBjack_property\fR can be used to list, set and delete any and all metadata associated with the ports and clients of a JACK server. .P There are three main ways to use the command. The \fB-l\fR option is used to list existing metadata. The \fB-s\fR option is used to set metadata. The \fB-d/-D\fR options are used to delete metadata. .P The \fIidentifier\fR is normally a UUID (UUIDs for ports and clients can be shown with jack_lsp(1)). If the \fB-c\fR option is used, then \fIidentifier\fR will be interpreted as a client name, and its UUID will be looked up internally and used for the relevant metadata operation. If the \fB-p\fR option is used, then \fIidentifier\fR will be interpreted as a port name and its UUID will be looked up internally and used for the relevant metadata operation. .P The \fIkey\fR is an arbitrary string that identifies the metadata to be operated upon. .P The \fIvalue\fR is an arbitrary string that defines the value of the metadata to be created. .P The \fItype\fR is an optional MIME type, given as a string. An empty type for a piece of metadata results in it being interpreted as "text/UTF-8". .SH OPTIONS .TP 6 -l list all metadata currently defined .TP -l identifier list all metadata currently defined for \fIidentifier\fR .TP -l identifier key show the value of the metadata associated with key for \fIidentifier\fR .TP -d identifier deletes all metadata for \fIidentifier\fR .TP -d identifier key deletes the metadata associated with \fIkey\fR for \fIidentifier\fR .TP -D delete all currently defined metadata .TP -s identifier key value [ type ] sets the metadata associated with \fIkey\fR to \fIvalue\fR for \fIidentifer\fR, with its type set to \fItype\fR if given .TP -c interpret a given identifier as a client name rather than a UUID .TP -p interpret a given identifier as a port name rather than a UUID 07070100000038000081A400000000000000000000000161E2F7EE00000414000000000000000000000000000000000000002400000000jack-example-tools-1/man/jack_rec.0.TH JACK_REC "1" "@DATE@" "@VERSION@" .SH NAME jack_rec \- JACK toolkit client for recording audio .SH SYNOPSIS .B jack_rec \-f filename \-d seconds [ \-b bitdepth ] port1 [ port2 ... ] .SH DESCRIPTION .B jack_rec is a basic, but useful, audio recorder that will record audio from 1 or more JACK ports to a file on disk. The file format is always RIFF/WAV, with samples stored as signed integers. The sample bit depth can be selected using the \fI-b\fR option. The file will have as many channels as there are ports specified on the command line - each channel will contain the data recorded from one port. The user should generally specify the duration (in seconds) using the \fI-d\fR option. If not specified, jack_rec will record until terminated by a signal (eg. from Ctrl-c). .PP This application is not intended to be a heavy duty audio recorder, and originated as an example client to show how to handle threading and disk I/O in a JACK client. However, it is a useful, simple recorder and is included in the JACK toolkit as a result. 07070100000039000081A400000000000000000000000161E2F7EE000000E8000000000000000000000000000000000000002B00000000jack-example-tools-1/man/jack_samplerate.0.TH JACK_SAMPLERATE "1" "@DATE@" "@VERSION@" .SH NAME jack_samplerate \- JACK toolkit client to print current samplerate .SH SYNOPSIS .B jack_samplerate .SH DESCRIPTION .B jack_samplerate prints the current samplerate, and exits. 0707010000003A000081A400000000000000000000000161E2F7EE0000013E000000000000000000000000000000000000002900000000jack-example-tools-1/man/jack_showtime.0.TH JACK_SHOWTIME "1" "@DATE@" "@VERSION@" .SH NAME jack_showtime \- The JACK Audio Connection Kit example client .SH SYNOPSIS .B jack_showtime .SH DESCRIPTION .B jack_showtime prints the current timebase information to stdout .SH AUTHOR Paul Davis .PP This manpage was written by Stefan Schwandter <swan@debian.org> 0707010000003B000081A400000000000000000000000161E2F7EE0000022F000000000000000000000000000000000000002E00000000jack-example-tools-1/man/jack_simple_client.0.TH JACK_CONNECT "1" "@DATE@" "@VERSION@" .SH NAME jack_simple_client \- The JACK Audio Connection Kit example client .SH SYNOPSIS .B jack_simple_client client-name .PP The client-name must be a yet unused client name. .SH DESCRIPTION .B jack_simple_client is an example client for the JACK Audio Connection Kit. It creates two ports (client-name:input and client-name:output) that pass the data unmodified. .SH EXAMPLE jack_simple_client in_process_test .SH AUTHOR Jeremy Hall .PP This manpage was written by Robert Jordens <jordens@debian.org> for Debian. 0707010000003C000081A400000000000000000000000161E2F7EE0000018E000000000000000000000000000000000000002A00000000jack-example-tools-1/man/jack_transport.0.TH JACK_TRANSPORT "1" "@DATE@" "@VERSION@" .SH NAME jack_transport \- JACK toolkit client for transport control .SH SYNOPSIS .B jack_transport .SH DESCRIPTION .B jack_transport is a toolkit client for the JACK Audio Connection Kit. It provides command-line control over the JACK transport system. Type help at jack_transport's command prompt to see the available commands. .SH AUTHOR Jeremy Hall 0707010000003D000081A400000000000000000000000161E2F7EE000001DC000000000000000000000000000000000000002700000000jack-example-tools-1/man/jack_unload.0.TH JACK_UNLOAD "1" "@DATE@" "@VERSION@" .SH NAME jack_unload \- The JACK Audio Connection Kit example client .SH SYNOPSIS .B jack_unload client-name .PP The client-name must be the name of a loaded client that can be unloaded. .SH DESCRIPTION .B jack_unload is the counterpart to .B jack_load and unloads the specified client. .SH EXAMPLE .B jack_unload in_process_test .SH AUTHOR Jeremy Hall .PP This manpage was written by Robert Jordens <jordens@debian.org> for Debian. 0707010000003E000081A400000000000000000000000161E2F7EE00000400000000000000000000000000000000000000002500000000jack-example-tools-1/man/jack_wait.0.TH JACK_WAIT "1" "@DATE@" "@VERSION@" .SH NAME jack_wait \- JACK toolkit client to check and wait for existence/exit of jackd. .SH SYNOPSIS \fBjack_wait\fR [ \fI-s\fR | \fI--server\fR servername ] [ \fI-t\fR | \fI--timeout\fR timeout_seconds [ \fI-cqwhv\fR ] .SH DESCRIPTION \fBjack_wait\fR When invoked with \fI-c\fR it only checks for the existence of a jack server. When invoked with \fI-w\fR the program will wait for a jackd to be available. The \fI-q\fR makes it wait for the jackd to exit. .SH OPTIONS .TP \fB-w\fR, \fB--wait\fR .br Wait for jackd to be available. .TP \fB-q\fR, \fB--quit\fR .br Wait for jackd quit. .TP \fB-c\fR, \fB--check\fR .br Only check for existence of jackd, and exit. .TP \fB-s\fR, \fB--server\fR \fIservername\fR .br Connect to the jack server named \fIservername\fR .TP \fB-t\fR, \fB--timeout\fR \fItimeout_seconds\fR .br Only wait \fItimeout_seconds\fR. .TP \fB-h\fR, \fB--help\fR .br Display help/usage message .TP \fB-v\fR, \fB--version\fR .br Output version information and exit 0707010000003F000081A400000000000000000000000161E2F7EE00000311000000000000000000000000000000000000002500000000jack-example-tools-1/man/meson.buildman_pages = [ 'jack_bufsize', 'jack_connect', 'jack_disconnect', 'jack_freewheel', 'jack_impulse_grabber', 'jack_iodelay', 'jack_load', 'jack_lsp', 'jack_metro', 'jack_monitor_client', 'jack_property', 'jack_samplerate', 'jack_showtime', 'jack_simple_client', 'jack_transport', 'jack_unload', 'jack_wait', ] if build_alsa_in_out man_pages += ['alsa_in', 'alsa_out'] endif if build_jack_netsource man_pages += ['jack_netsource'] endif if build_jack_rec man_pages += ['jack_rec'] endif if os != 'windows' foreach man_page: man_pages configure_file( configuration: conf_data, input: man_page + '.0', output: man_page + '.1', install_dir: get_option('mandir') + '/man1', install: true, ) endforeach endif 07070100000040000081A400000000000000000000000161E2F7EE0000131C000000000000000000000000000000000000002100000000jack-example-tools-1/meson.buildproject( 'jack-example-tools', ['c', 'cpp'], meson_version: '>=0.58.0', license: ['GPL2+'], version: '1', ) os = build_machine.system() cc = meson.get_compiler('c') lib_m = cc.find_library('m') lib_rt = cc.find_library('rt') alsa_required = false if get_option('alsa_in_out').enabled() or get_option('zalsa').enabled() alsa_required = true endif libsamplerate_required = false if get_option('alsa_in_out').enabled() or get_option('jack_netsource').enabled() libsamplerate_required = true endif dep_jack = dependency('jack') jack_implementation = '' jack_implementation = dep_jack.get_variable('jack_implementation') if jack_implementation == '' warning('No compatible jack implementation detected. This may mean conflicting files when installing!') endif has_jack1_internal_client = cc.compiles( ''' #include <stdio.h> #include <jack/jack.h> #include <jack/intclient.h> int main (int argc, char *argv[]) { const char *client_name; jack_client_t *client; jack_status_t status; jack_intclient_t intclient; client_name = "foo"; client = jack_client_open(client_name, JackNoStartServer, &status); jack_internal_client_handle(client, client_name, &status, &intclient); } ''' ) message('Provides jack1-style jack_internal_client_handle(): ' + has_jack1_internal_client.to_string()) has_jack2_internal_client = cc.compiles( ''' #include <jack/jack.h> #include <jack/intclient.h> int main (int argc, char *argv[]) { const char *client_name; jack_client_t *client; jack_status_t status; jack_intclient_t intclient; client_name = "foo"; client = jack_client_open(client_name, JackNoStartServer, &status); intclient = jack_internal_client_handle (client, client_name, &status); } ''' ) message('Provides jack2-style jack_internal_client_handle(): ' + has_jack2_internal_client.to_string()) lib_jackserver = cc.find_library('jackserver', required: true) has_jackctl_server_create2 = cc.has_function('jackctl_server_create2', dependencies: lib_jackserver, prefix: '#include <jack/control.h>') lib_jacknet = cc.find_library('jacknet', required: get_option('jack_net')) dep_alsa = dependency('alsa', version: '>=1.0.18', required: alsa_required) dep_opus = dependency('opus', version: '>=0.9.0', required: get_option('opus_support')) dep_readline = dependency('readline', required: get_option('readline_support')) dep_samplerate = dependency('samplerate', required: libsamplerate_required) dep_sndfile = dependency('sndfile', required: get_option('jack_rec')) dep_threads = dependency('threads') lib_zita_alsa_pcmi = cc.find_library('zita-alsa-pcmi', required: get_option('zalsa')) lib_zita_resampler = cc.find_library('zita-resampler', required: get_option('zalsa')) has_ppoll = cc.has_function('ppoll', prefix: '#define _GNU_SOURCE\n#include <sys/poll.h>') build_alsa_in_out = false if get_option('alsa_in_out').enabled() or ( get_option('alsa_in_out').auto() and dep_alsa.found() and dep_samplerate.found() ) build_alsa_in_out = true endif build_jack_net = false if get_option('jack_net').enabled() or (get_option('jack_net').auto() and lib_jacknet.found()) build_jack_net = true endif build_jack_netsource = false if get_option('jack_netsource').enabled() or (get_option('jack_netsource').auto() and dep_samplerate.found()) build_jack_netsource = true endif opus_support = false if get_option('opus_support').enabled() or (get_option('opus_support').auto() and dep_opus.found()) opus_support = true endif readline_support = false if get_option('readline_support').enabled() or (get_option('readline_support').auto() and dep_readline.found()) readline_support = true endif build_jack_rec = false if get_option('jack_rec').enabled() or (get_option('jack_rec').auto() and dep_sndfile.found()) build_jack_rec = true endif build_zalsa = false if get_option('zalsa').enabled() or ( get_option('zalsa').auto() and dep_alsa.found() and lib_zita_alsa_pcmi.found() and lib_zita_resampler.found() ) build_zalsa = true endif message('Build alsa_in and alsa_out executables: ' + build_alsa_in_out.to_string()) message('Build jack_net_master and jack_net_slave executables: ' + build_jack_net.to_string()) message('Build jack_netsource executable: ' + build_jack_netsource.to_string()) if build_jack_netsource message('Build jack_netsource with opus support: ' + opus_support.to_string()) endif message('Build jack_rec executable: ' + build_jack_rec.to_string()) message('Build jack_transport with readline support: ' + readline_support.to_string()) message('Build ZALSA internal clients: ' + build_zalsa.to_string()) conf_data = configuration_data() conf_data.set('VERSION', meson.project_version()) conf_data.set('DATE', '2022') c_args_common = [ '-D__PROJECT_VERSION__="@0@"'.format(conf_data.get('VERSION')), ] subdir('tools') subdir('example-clients') subdir('man') 07070100000041000081A400000000000000000000000161E2F7EE0000038D000000000000000000000000000000000000002700000000jack-example-tools-1/meson_options.txtoption('alsa_in_out', type: 'feature', value: 'auto', description: 'Build the alsa_in and alsa_out executables (default: auto)') option('jack_net', type: 'feature', value: 'auto', description: 'Build the jack_net_master and jack_net_slave executables (default: auto)') option('jack_netsource', type: 'feature', value: 'auto', description: 'Build the jack_netsource executable (default: auto)') option('jack_rec', type: 'feature', value: 'auto', description: 'Build the jack_rec executable (default: auto)') option('opus_support', type: 'feature', value: 'auto', description: 'Build the jack_netsource executable with opus support (default: auto)') option('readline_support', type: 'feature', value: 'auto', description: 'Build the jack_transport executable with readline support (default: auto)') option('zalsa', type: 'feature', value: 'auto', description: 'Build the ZALSA internal client (default: auto)') 07070100000042000041ED00000000000000000000000161E2F7EE00000000000000000000000000000000000000000000001D00000000jack-example-tools-1/scripts07070100000043000081ED00000000000000000000000161E2F7EE00000145000000000000000000000000000000000000003200000000jack-example-tools-1/scripts/meson_create_symlink#!/usr/bin/env sh # # Script to create a symlink for an arbitrary file ($2) in a directory ($1) # below $MESON_INSTALL_DESTDIR_PREFIX of a specific name ($3). # # E.g. `meson_create_symlink bin test2 test` creates: # $MESON_INSTALL_DESTDIR_PREFIX/bin/test2 -> test set -eu ln -sv "$2" "$MESON_INSTALL_DESTDIR_PREFIX/$1/$3" 07070100000044000041ED00000000000000000000000161E2F7EE00000000000000000000000000000000000000000000001B00000000jack-example-tools-1/tools07070100000045000081A400000000000000000000000161E2F7EE000009AD000000000000000000000000000000000000002300000000jack-example-tools-1/tools/alias.c#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <getopt.h> #include <jack/jack.h> char * my_name; void show_version (void) { fprintf (stderr, "%s: JACK example tools version %s\n", my_name, __PROJECT_VERSION__); } void show_usage (void) { show_version (); fprintf (stderr, "\nUsage: %s [options] portname alias\n", my_name); fprintf (stderr, "List active Jack ports, and optionally display extra information.\n\n"); fprintf (stderr, "Display options:\n"); fprintf (stderr, " -u, --unalias remove `alias' as an alias for `port'\n"); fprintf (stderr, " -h, --help Display this help message\n"); fprintf (stderr, " --version Output version information and exit\n\n"); fprintf (stderr, "For more information see http://jackaudio.org/\n"); } int main (int argc, char *argv[]) { jack_client_t *client; jack_status_t status; char* portname; char* alias; int unset = 0; int ret; int c; int option_index; extern int optind; jack_port_t* port; struct option long_options[] = { { "unalias", 0, 0, 'u' }, { "help", 0, 0, 'h' }, { "version", 0, 0, 'v' }, { 0, 0, 0, 0 } }; if (argc < 3) { show_usage (); return 1; } my_name = strrchr(argv[0], '/'); if (my_name == 0) { my_name = argv[0]; } else { my_name ++; } while ((c = getopt_long (argc, argv, "uhv", long_options, &option_index)) >= 0) { switch (c) { case 'u': unset = 1; break; case 'h': show_usage (); return 1; break; case 'v': show_version (); return 1; break; default: show_usage (); return 1; break; } } portname = argv[optind++]; alias = argv[optind]; /* Open a client connection to the JACK server. Starting a * new server only to list its ports seems pointless, so we * specify JackNoStartServer. */ //JOQ: need a new server name option client = jack_client_open ("lsp", JackNoStartServer, &status); if (client == NULL) { if (status & JackServerFailed) { fprintf (stderr, "JACK server not running\n"); } else { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); } return 1; } if ((port = jack_port_by_name (client, portname)) == 0) { fprintf (stderr, "No port named \"%s\"\n", portname); return 1; } if (!unset) { ret = jack_port_set_alias (port, alias); } else { ret = jack_port_unset_alias (port, alias); } jack_client_close (client); return ret; } 07070100000046000081A400000000000000000000000161E2F7EE00005C89000000000000000000000000000000000000002500000000jack-example-tools-1/tools/alsa_in.c/** @file simple_client.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. */ #include <stdio.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <math.h> #include <jack/jack.h> #include <jack/jslist.h> #include "memops.h" #include "alsa/asoundlib.h" #include <samplerate.h> // Here are the lists of the jack ports... JSList *capture_ports = NULL; JSList *capture_srcs = NULL; JSList *playback_ports = NULL; JSList *playback_srcs = NULL; jack_client_t *client; snd_pcm_t *alsa_handle; int jack_sample_rate; int jack_buffer_size; int quit = 0; double resample_mean = 1.0; double static_resample_factor = 1.0; double resample_lower_limit = 0.25; double resample_upper_limit = 4.0; double *offset_array; double *window_array; int offset_differential_index = 0; double offset_integral = 0; // ------------------------------------------------------ commandline parameters const char* alsa_device = "hw:0"; int sample_rate = 0; /* stream rate */ int num_channels = 2; /* count of channels */ int period_size = 1024; int num_periods = 2; int target_delay = 0; /* the delay which the program should try to approach. */ int max_diff = 0; /* the diff value, when a hard readpointer skip should occur */ int catch_factor = 100000; int catch_factor2 = 10000; double pclamp = 15.0; double controlquant = 10000.0; int smooth_size = 256; int good_window=0; int verbose = 0; int instrument = 0; int samplerate_quality = 2; // Debug stuff: volatile float output_resampling_factor = 1.0; volatile int output_new_delay = 0; volatile float output_offset = 0.0; volatile float output_integral = 0.0; volatile float output_diff = 0.0; snd_pcm_uframes_t real_buffer_size; snd_pcm_uframes_t real_period_size; // buffers char *tmpbuf; char *outbuf; float *resampbuf; // format selection, and corresponding functions from memops in a nice set of structs. typedef struct alsa_format { snd_pcm_format_t format_id; size_t sample_size; void (*jack_to_soundcard) (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void (*soundcard_to_jack) (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); const char *name; } alsa_format_t; alsa_format_t formats[] = { { SND_PCM_FORMAT_FLOAT_LE, 4, sample_move_dS_floatLE, sample_move_floatLE_sSs, "float" }, { SND_PCM_FORMAT_S32, 4, sample_move_d32u24_sS, sample_move_dS_s32u24, "32bit" }, { SND_PCM_FORMAT_S24_3LE, 3, sample_move_d24_sS, sample_move_dS_s24, "24bit - real" }, { SND_PCM_FORMAT_S24, 4, sample_move_d32l24_sS, sample_move_dS_s32l24, "24bit" }, { SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" } #ifdef __ANDROID__ ,{ SND_PCM_FORMAT_S16_LE, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit little-endian" } #endif }; #define NUMFORMATS (sizeof(formats)/sizeof(formats[0])) int format=0; // Alsa stuff... i don't want to touch this bullshit in the next years.... please... static int xrun_recovery(snd_pcm_t *handle, int err) { // printf( "xrun !!!.... %d\n", err ); if (err == -EPIPE) { /* under-run */ err = snd_pcm_prepare(handle); if (err < 0) printf("Can't recover from underrun, prepare failed: %s\n", snd_strerror(err)); return 0; } else if (err == -ESTRPIPE) { while ((err = snd_pcm_resume(handle)) == -EAGAIN) usleep(100); /* wait until the suspend flag is released */ if (err < 0) { err = snd_pcm_prepare(handle); if (err < 0) printf("Can't recover from suspend, prepare failed: %s\n", snd_strerror(err)); } return 0; } return err; } static int set_hwformat( snd_pcm_t *handle, snd_pcm_hw_params_t *params ) { #ifdef __ANDROID__ format = 5; snd_pcm_hw_params_set_format(handle, params, formats[format].format_id); return 0; #else int i; int err; for( i=0; i<NUMFORMATS; i++ ) { /* set the sample format */ err = snd_pcm_hw_params_set_format(handle, params, formats[i].format_id); if (err == 0) { format = i; return 0; } } return err; #endif } static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access, int rate, int channels, int period, int nperiods ) { int err, dir=0; unsigned int buffer_time; unsigned int period_time; unsigned int rrate; unsigned int rchannels; /* choose all parameters */ err = snd_pcm_hw_params_any(handle, params); if (err < 0) { printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)); return err; } /* set the interleaved read/write format */ err = snd_pcm_hw_params_set_access(handle, params, access); if (err < 0) { printf("Access type not available for playback: %s\n", snd_strerror(err)); return err; } /* set the sample format */ err = set_hwformat(handle, params); if (err < 0) { printf("Sample format not available for playback: %s\n", snd_strerror(err)); return err; } /* set the count of channels */ rchannels = channels; err = snd_pcm_hw_params_set_channels_near(handle, params, &rchannels); if (err < 0) { printf("Channels count (%i) not available for record: %s\n", channels, snd_strerror(err)); return err; } if (rchannels != channels) { printf("WARNING: channel count does not match (requested %d got %d)\n", channels, rchannels); num_channels = rchannels; } /* set the stream rate */ rrate = rate; err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); if (err < 0) { printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); return err; } if (rrate != rate) { printf("WARNING: Rate doesn't match (requested %iHz, get %iHz)\n", rate, rrate); sample_rate = rrate; } /* set the buffer time */ buffer_time = 1000000*(uint64_t)period*nperiods/rate; err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir); if (err < 0) { printf("Unable to set buffer time %i for playback: %s\n", 1000000*period*nperiods/rate, snd_strerror(err)); return err; } err = snd_pcm_hw_params_get_buffer_size( params, &real_buffer_size ); if (err < 0) { printf("Unable to get buffer size back: %s\n", snd_strerror(err)); return err; } if( real_buffer_size != nperiods * period ) { printf( "WARNING: buffer size does not match: (requested %d, got %d)\n", nperiods * period, (int) real_buffer_size ); } /* set the period time */ period_time = 1000000*(uint64_t)period/rate; err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir); if (err < 0) { printf("Unable to set period time %i for playback: %s\n", 1000000*period/rate, snd_strerror(err)); return err; } err = snd_pcm_hw_params_get_period_size(params, &real_period_size, NULL ); if (err < 0) { printf("Unable to get period size back: %s\n", snd_strerror(err)); return err; } if( real_period_size != period ) { printf( "WARNING: period size does not match: (requested %i, got %i)\n", period, (int)real_period_size ); } /* write the parameters to device */ err = snd_pcm_hw_params(handle, params); if (err < 0) { printf("Unable to set hw params for playback: %s\n", snd_strerror(err)); return err; } return 0; } static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int period) { int err; /* get the current swparams */ err = snd_pcm_sw_params_current(handle, swparams); if (err < 0) { printf("Unable to determine current swparams for capture: %s\n", snd_strerror(err)); return err; } /* start the transfer when the buffer is full */ err = snd_pcm_sw_params_set_start_threshold(handle, swparams, period ); if (err < 0) { printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err)); return err; } err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, -1 ); if (err < 0) { printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err)); return err; } /* allow the transfer when at least period_size samples can be processed */ err = snd_pcm_sw_params_set_avail_min(handle, swparams, 2*period ); if (err < 0) { printf("Unable to set avail min for capture: %s\n", snd_strerror(err)); return err; } /* write the parameters to the playback device */ err = snd_pcm_sw_params(handle, swparams); if (err < 0) { printf("Unable to set sw params for capture: %s\n", snd_strerror(err)); return err; } return 0; } // ok... i only need this function to communicate with the alsa bloat api... static snd_pcm_t *open_audiofd( const char *device_name, int capture, int rate, int channels, int period, int nperiods ) { int err; snd_pcm_t *handle; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); if ((err = snd_pcm_open(&(handle), device_name, capture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK )) < 0) { printf("Capture open error: %s\n", snd_strerror(err)); return NULL; } if ((err = set_hwparams(handle, hwparams,SND_PCM_ACCESS_RW_INTERLEAVED, rate, channels, period, nperiods )) < 0) { printf("Setting of hwparams failed: %s\n", snd_strerror(err)); return NULL; } if ((err = set_swparams(handle, swparams, period)) < 0) { printf("Setting of swparams failed: %s\n", snd_strerror(err)); return NULL; } snd_pcm_start( handle ); snd_pcm_wait( handle, 200 ); return handle; } double hann( double x ) { return 0.5 * (1.0 - cos( 2*M_PI * x ) ); } /** * The freewheel callback. */ void freewheel (int freewheel_starting, void* ignored_arg) { if( freewheel_starting ) { snd_pcm_close( alsa_handle ); alsa_handle = 0; // reset resampling parameters resample_mean = 1.0; static_resample_factor = 1.0; resample_lower_limit = 0.25; resample_upper_limit = 4.0; offset_differential_index = 0; offset_integral = 0; } else { alsa_handle = open_audiofd( alsa_device, 1, sample_rate, num_channels, period_size, num_periods); if( alsa_handle == 0 ) exit(20); } } /** * The process callback for this JACK application. * It is called by JACK at the appropriate times. */ int process (jack_nframes_t nframes, void *arg) { if (alsa_handle == 0) { JSList *node = capture_ports; while ( node != NULL) { jack_port_t *port = (jack_port_t *) node->data; float *buf = jack_port_get_buffer (port, nframes); memset(buf, 0, sizeof(float)*nframes); node = jack_slist_next (node); } return 0; } int rlen; int err; snd_pcm_sframes_t delay = target_delay; int put_back_samples=0; int i; delay = snd_pcm_avail( alsa_handle ); delay -= round( jack_frames_since_cycle_start( client ) * static_resample_factor ); // Do it the hard way. // this is for compensating xruns etc... if( delay > (target_delay+max_diff) ) { output_new_delay = (int) delay; while ((delay-target_delay) > 0) { snd_pcm_uframes_t to_read = ((delay-target_delay) > 512) ? 512 : (delay-target_delay); snd_pcm_readi( alsa_handle, tmpbuf, to_read ); delay -= to_read; } delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. // first look at the PI controller, this code is just a special case, which should never execute once // everything is swung in. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i<smooth_size; i++ ) offset_array[i] = 0.0; } if( delay < (target_delay-max_diff) ) { snd_pcm_rewind( alsa_handle, target_delay - delay ); output_new_delay = (int) delay; delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i<smooth_size; i++ ) offset_array[i] = 0.0; } /* ok... now we should have target_delay +- max_diff on the alsa side. * * calculate the number of frames, we want to get. */ double offset = delay - target_delay; // Save offset. offset_array[(offset_differential_index++)% smooth_size ] = offset; // Build the mean of the windowed offset array // basically fir lowpassing. double smooth_offset = 0.0; for( i=0; i<smooth_size; i++ ) smooth_offset += offset_array[ (i + offset_differential_index-1) % smooth_size] * window_array[i]; smooth_offset /= (double) smooth_size; // this is the integral of the smoothed_offset offset_integral += smooth_offset; // Clamp offset. // the smooth offset still contains unwanted noise // which would go straight onto the resample coeff. // it only used in the P component and the I component is used for the fine tuning anyways. if( fabs( smooth_offset ) < pclamp ) smooth_offset = 0.0; // ok. now this is the PI controller. // u(t) = K * ( e(t) + 1/T \int e(t') dt' ) // K = 1/catch_factor and T = catch_factor2 double current_resample_factor = static_resample_factor - smooth_offset / (double) catch_factor - offset_integral / (double) catch_factor / (double)catch_factor2; // now quantize this value around resample_mean, so that the noise which is in the integral component doesn't hurt. current_resample_factor = floor( (current_resample_factor - resample_mean) * controlquant + 0.5 ) / controlquant + resample_mean; // Output "instrumentatio" gonna change that to real instrumentation in a few. output_resampling_factor = (float) current_resample_factor; output_diff = (float) smooth_offset; output_integral = (float) offset_integral; output_offset = (float) offset; // Clamp a bit. if( current_resample_factor < resample_lower_limit ) current_resample_factor = resample_lower_limit; if( current_resample_factor > resample_upper_limit ) current_resample_factor = resample_upper_limit; // Now Calculate how many samples we need. rlen = ceil( ((double)nframes) * current_resample_factor )+2; assert( rlen > 2 ); // Calculate resample_mean so we can init ourselves to saner values. resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor; // get the data... again: err = snd_pcm_readi(alsa_handle, outbuf, rlen); if( err < 0 ) { printf( "err = %d\n", err ); if (xrun_recovery(alsa_handle, err) < 0) { //printf("Write error: %s\n", snd_strerror(err)); //exit(EXIT_FAILURE); } goto again; } if( err != rlen ) { //printf( "read = %d\n", rlen ); } /* * render jack ports to the outbuf... */ int chn = 0; JSList *node = capture_ports; JSList *src_node = capture_srcs; SRC_DATA src; while ( node != NULL) { jack_port_t *port = (jack_port_t *) node->data; float *buf = jack_port_get_buffer (port, nframes); SRC_STATE *src_state = src_node->data; formats[format].soundcard_to_jack( resampbuf, outbuf + format[formats].sample_size * chn, rlen, num_channels*format[formats].sample_size ); src.data_in = resampbuf; src.input_frames = rlen; src.data_out = buf; src.output_frames = nframes; src.end_of_input = 0; src.src_ratio = current_resample_factor; src_process( src_state, &src ); put_back_samples = rlen-src.input_frames_used; src_node = jack_slist_next (src_node); node = jack_slist_next (node); chn++; } // Put back the samples libsamplerate did not consume. //printf( "putback = %d\n", put_back_samples ); snd_pcm_rewind( alsa_handle, put_back_samples ); return 0; } /** * the latency callback. * sets up the latencies on the ports. */ void latency_cb (jack_latency_callback_mode_t mode, void *arg) { jack_latency_range_t range; JSList *node; range.min = range.max = round(target_delay / static_resample_factor); if (mode == JackCaptureLatency) { for (node = capture_ports; node; node = jack_slist_next (node)) { jack_port_t *port = node->data; jack_port_set_latency_range (port, mode, &range); } } else { for (node = playback_ports; node; node = jack_slist_next (node)) { jack_port_t *port = node->data; jack_port_set_latency_range (port, mode, &range); } } } /** * Allocate the necessary jack ports... */ void alloc_ports( int n_capture, int n_playback ) { int port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal; int chn; jack_port_t *port; char buf[32]; capture_ports = NULL; for (chn = 0; chn < n_capture; chn++) { snprintf (buf, sizeof(buf) - 1, "capture_%u", chn+1); port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); if (!port) { printf( "jacknet_client: cannot register port for %s", buf); break; } capture_srcs = jack_slist_append( capture_srcs, src_new( 4-samplerate_quality, 1, NULL ) ); capture_ports = jack_slist_append (capture_ports, port); } port_flags = JackPortIsInput; playback_ports = NULL; for (chn = 0; chn < n_playback; chn++) { snprintf (buf, sizeof(buf) - 1, "playback_%u", chn+1); port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); if (!port) { printf( "jacknet_client: cannot register port for %s", buf); break; } playback_srcs = jack_slist_append( playback_srcs, src_new( 4-samplerate_quality, 1, NULL ) ); playback_ports = jack_slist_append (playback_ports, port); } } /** * This is the shutdown callback for this JACK application. * It is called by JACK if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { exit (1); } /** * be user friendly. * be user friendly. * be user friendly. */ void printUsage() { fprintf(stderr, "usage: alsa_out [options]\n" "\n" " -j <jack name> - client name\n" " -S <server name> - server to connect\n" " -d <alsa_device> \n" " -c <channels> \n" " -p <period_size> \n" " -n <num_period> \n" " -r <sample_rate> \n" " -q <sample_rate quality [0..4]\n" " -m <max_diff> \n" " -t <target_delay> \n" " -i turns on instrumentation\n" " -v turns on printouts\n" "\n"); } /** * the main function.... */ void sigterm_handler( int signal ) { quit = 1; } int main (int argc, char *argv[]) { char jack_name[30] = "alsa_in"; int jack_opts = 0; char *server_name = NULL; extern char *optarg; extern int optind, optopt; int errflg=0; int c; while ((c = getopt(argc, argv, "ivj:r:c:p:n:d:q:m:t:f:F:C:Q:s:S:")) != -1) { switch(c) { case 'j': strcpy(jack_name,optarg); break; case 'r': sample_rate = atoi(optarg); break; case 'c': num_channels = atoi(optarg); break; case 'p': period_size = atoi(optarg); break; case 'n': num_periods = atoi(optarg); break; case 'd': alsa_device = strdup (optarg); break; case 't': target_delay = atoi(optarg); break; case 'q': samplerate_quality = atoi(optarg); break; case 'm': max_diff = atoi(optarg); break; case 'f': catch_factor = atoi(optarg); break; case 'F': catch_factor2 = atoi(optarg); break; case 'C': pclamp = (double) atoi(optarg); break; case 'Q': controlquant = (double) atoi(optarg); break; case 'v': verbose = 1; break; case 'i': instrument = 1; break; case 's': smooth_size = atoi(optarg); break; case 'S': server_name = optarg; jack_opts |= JackServerName; break; case ':': fprintf(stderr, "Option -%c requires an operand\n", optopt); errflg++; break; case '?': fprintf(stderr, "Unrecognized option: -%c\n", optopt); errflg++; } } if (errflg) { printUsage(); exit(2); } if( (samplerate_quality < 0) || (samplerate_quality > 4) ) { fprintf (stderr, "invalid samplerate quality\n"); return 1; } if ((client = jack_client_open (jack_name, jack_opts, NULL, server_name)) == 0) { fprintf (stderr, "jack server not running?\n"); return 1; } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, 0); /* tell the JACK server to call `freewheel()' whenever freewheel mode changes. */ jack_set_freewheel_callback (client, freewheel, 0); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); if (jack_set_latency_callback) jack_set_latency_callback (client, latency_cb, 0); // get jack sample_rate jack_sample_rate = jack_get_sample_rate( client ); if( !sample_rate ) sample_rate = jack_sample_rate; // now open the alsa fd... alsa_handle = open_audiofd( alsa_device, 1, sample_rate, num_channels, period_size, num_periods); if( alsa_handle == 0 ) exit(20); printf( "selected sample format: %s\n", formats[format].name ); static_resample_factor = (double) sample_rate / (double) jack_sample_rate; resample_lower_limit = static_resample_factor * 0.25; resample_upper_limit = static_resample_factor * 4.0; resample_mean = static_resample_factor; offset_array = malloc( sizeof(double) * smooth_size ); if( offset_array == NULL ) { fprintf( stderr, "no memory for offset_array !!!\n" ); exit(20); } window_array = malloc( sizeof(double) * smooth_size ); if( window_array == NULL ) { fprintf( stderr, "no memory for window_array !!!\n" ); exit(20); } int i; for( i=0; i<smooth_size; i++ ) { offset_array[i] = 0.0; window_array[i] = hann( (double) i / ((double) smooth_size - 1.0) ); } jack_buffer_size = jack_get_buffer_size( client ); // Setup target delay and max_diff for the normal user, who does not play with them... if( !target_delay ) target_delay = (num_periods*period_size / 2) + jack_buffer_size/2; if( !max_diff ) max_diff = num_periods*period_size - target_delay ; if( max_diff > target_delay ) { fprintf( stderr, "target_delay (%d) can not be smaller than max_diff(%d)\n", target_delay, max_diff ); exit(20); } if( (target_delay+max_diff) > (num_periods*period_size) ) { fprintf( stderr, "target_delay+max_diff (%d) can not be bigger than buffersize(%d)\n", target_delay+max_diff, num_periods*period_size ); exit(20); } // alloc input ports, which are blasted out to alsa... alloc_ports( num_channels, 0 ); outbuf = malloc( num_periods * period_size * formats[format].sample_size * num_channels ); resampbuf = malloc( num_periods * period_size * sizeof( float ) ); tmpbuf = malloc( 512 * formats[format].sample_size * num_channels ); if ((outbuf == NULL) || (resampbuf == NULL) || (tmpbuf == NULL)) { fprintf( stderr, "no memory for buffers.\n" ); exit(20); } memset( tmpbuf, 0, 512 * formats[format].sample_size * num_channels); /* tell the JACK server that we are ready to roll */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); return 1; } signal( SIGTERM, sigterm_handler ); signal( SIGINT, sigterm_handler ); if( verbose ) { while(!quit) { usleep(500000); if( output_new_delay ) { printf( "delay = %d\n", output_new_delay ); output_new_delay = 0; } printf( "res: %f, \tdiff = %f, \toffset = %f \n", output_resampling_factor, output_diff, output_offset ); } } else if( instrument ) { printf( "# n\tresamp\tdiff\toffseti\tintegral\n"); int n=0; while(!quit) { usleep(1000); printf( "%d\t%f\t%f\t%f\t%f\n", n++, output_resampling_factor, output_diff, output_offset, output_integral ); } } else { while(!quit) { usleep(500000); if( output_new_delay ) { printf( "delay = %d\n", output_new_delay ); output_new_delay = 0; } } } jack_deactivate( client ); jack_client_close (client); exit (0); } 07070100000047000081A400000000000000000000000161E2F7EE00005D52000000000000000000000000000000000000002600000000jack-example-tools-1/tools/alsa_out.c/** @file simple_client.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. */ #include <alloca.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <math.h> #include <jack/jack.h> #include <jack/jslist.h> #include "memops.h" #include "alsa/asoundlib.h" #include <samplerate.h> // Here are the lists of the jack ports... JSList *capture_ports = NULL; JSList *capture_srcs = NULL; JSList *playback_ports = NULL; JSList *playback_srcs = NULL; jack_client_t *client; snd_pcm_t *alsa_handle; int jack_sample_rate; int jack_buffer_size; int quit = 0; double resample_mean = 1.0; double static_resample_factor = 1.0; double resample_lower_limit = 0.25; double resample_upper_limit = 4.0; double *offset_array; double *window_array; int offset_differential_index = 0; double offset_integral = 0; // ------------------------------------------------------ commandline parameters const char* alsa_device = "hw:0"; int sample_rate = 0; /* stream rate */ int num_channels = 2; /* count of channels */ int period_size = 1024; int num_periods = 2; int target_delay = 0; /* the delay which the program should try to approach. */ int max_diff = 0; /* the diff value, when a hard readpointer skip should occur */ int catch_factor = 100000; int catch_factor2 = 10000; double pclamp = 15.0; double controlquant = 10000.0; int smooth_size = 256; int good_window=0; int verbose = 0; int instrument = 0; int samplerate_quality = 2; // Debug stuff: volatile float output_resampling_factor = 1.0; volatile int output_new_delay = 0; volatile float output_offset = 0.0; volatile float output_integral = 0.0; volatile float output_diff = 0.0; snd_pcm_uframes_t real_buffer_size; snd_pcm_uframes_t real_period_size; // buffers char *tmpbuf; char *outbuf; float *resampbuf; // format selection, and corresponding functions from memops in a nice set of structs. typedef struct alsa_format { snd_pcm_format_t format_id; size_t sample_size; void (*jack_to_soundcard) (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void (*soundcard_to_jack) (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); const char *name; } alsa_format_t; alsa_format_t formats[] = { { SND_PCM_FORMAT_FLOAT_LE, 4, sample_move_dS_floatLE, sample_move_floatLE_sSs, "float" }, { SND_PCM_FORMAT_S32, 4, sample_move_d32u24_sS, sample_move_dS_s32u24, "32bit" }, { SND_PCM_FORMAT_S24_3LE, 3, sample_move_d24_sS, sample_move_dS_s24, "24bit - real" }, { SND_PCM_FORMAT_S24, 4, sample_move_d32l24_sS, sample_move_dS_s32l24, "24bit" }, { SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" } #ifdef __ANDROID__ ,{ SND_PCM_FORMAT_S16_LE, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit little-endian" } #endif }; #define NUMFORMATS (sizeof(formats)/sizeof(formats[0])) int format=0; // Alsa stuff... i don't want to touch this bullshit in the next years.... please... static int xrun_recovery(snd_pcm_t *handle, int err) { // printf( "xrun !!!.... %d\n", err ); if (err == -EPIPE) { /* under-run */ err = snd_pcm_prepare(handle); if (err < 0) printf("Can't recover from underrun, prepare failed: %s\n", snd_strerror(err)); return 0; } else if (err == -ESTRPIPE) { while ((err = snd_pcm_resume(handle)) == -EAGAIN) usleep(100); /* wait until the suspend flag is released */ if (err < 0) { err = snd_pcm_prepare(handle); if (err < 0) printf("Can't recover from suspend, prepare failed: %s\n", snd_strerror(err)); } return 0; } return err; } static int set_hwformat( snd_pcm_t *handle, snd_pcm_hw_params_t *params ) { #ifdef __ANDROID__ format = 5; snd_pcm_hw_params_set_format(handle, params, formats[format].format_id); return 0; #else int i; int err; for( i=0; i<NUMFORMATS; i++ ) { /* set the sample format */ err = snd_pcm_hw_params_set_format(handle, params, formats[i].format_id); if (err == 0) { format = i; return 0; } } return err; #endif } static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access, int rate, int channels, int period, int nperiods ) { int err, dir=0; unsigned int buffer_time; unsigned int period_time; unsigned int rrate; unsigned int rchannels; /* choose all parameters */ err = snd_pcm_hw_params_any(handle, params); if (err < 0) { printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)); return err; } /* set the interleaved read/write format */ err = snd_pcm_hw_params_set_access(handle, params, access); if (err < 0) { printf("Access type not available for playback: %s\n", snd_strerror(err)); return err; } /* set the sample format */ err = set_hwformat(handle, params); if (err < 0) { printf("Sample format not available for playback: %s\n", snd_strerror(err)); return err; } /* set the count of channels */ rchannels = channels; err = snd_pcm_hw_params_set_channels_near(handle, params, &rchannels); if (err < 0) { printf("Channels count (%i) not available for record: %s\n", channels, snd_strerror(err)); return err; } if (rchannels != channels) { printf("WARNING: channel count does not match (requested %d got %d)\n", channels, rchannels); num_channels = rchannels; } /* set the stream rate */ rrate = rate; err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); if (err < 0) { printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); return err; } if (rrate != rate) { printf("WARNING: Rate doesn't match (requested %iHz, get %iHz)\n", rate, rrate); sample_rate = rrate; } /* set the buffer time */ buffer_time = 1000000*(uint64_t)period*nperiods/rate; err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir); if (err < 0) { printf("Unable to set buffer time %i for playback: %s\n", 1000000*period*nperiods/rate, snd_strerror(err)); return err; } err = snd_pcm_hw_params_get_buffer_size( params, &real_buffer_size ); if (err < 0) { printf("Unable to get buffer size back: %s\n", snd_strerror(err)); return err; } if( real_buffer_size != nperiods * period ) { printf( "WARNING: buffer size does not match: (requested %d, got %d)\n", nperiods * period, (int) real_buffer_size ); } /* set the period time */ period_time = 1000000*(uint64_t)period/rate; err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir); if (err < 0) { printf("Unable to set period time %i for playback: %s\n", 1000000*period/rate, snd_strerror(err)); return err; } err = snd_pcm_hw_params_get_period_size(params, &real_period_size, NULL ); if (err < 0) { printf("Unable to get period size back: %s\n", snd_strerror(err)); return err; } if( real_period_size != period ) { printf( "WARNING: period size does not match: (requested %i, got %i)\n", period, (int)real_period_size ); } /* write the parameters to device */ err = snd_pcm_hw_params(handle, params); if (err < 0) { printf("Unable to set hw params for playback: %s\n", snd_strerror(err)); return err; } return 0; } static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int period, int nperiods) { int err; /* get the current swparams */ err = snd_pcm_sw_params_current(handle, swparams); if (err < 0) { printf("Unable to determine current swparams for capture: %s\n", snd_strerror(err)); return err; } /* start the transfer when the buffer is full */ err = snd_pcm_sw_params_set_start_threshold(handle, swparams, period ); if (err < 0) { printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err)); return err; } err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, -1 ); if (err < 0) { printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err)); return err; } /* allow the transfer when at least period_size samples can be processed */ err = snd_pcm_sw_params_set_avail_min(handle, swparams, 1 ); if (err < 0) { printf("Unable to set avail min for capture: %s\n", snd_strerror(err)); return err; } /* write the parameters to the playback device */ err = snd_pcm_sw_params(handle, swparams); if (err < 0) { printf("Unable to set sw params for capture: %s\n", snd_strerror(err)); return err; } return 0; } // ok... i only need this function to communicate with the alsa bloat api... static snd_pcm_t *open_audiofd( const char *device_name, int capture, int rate, int channels, int period, int nperiods ) { int err; snd_pcm_t *handle; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); if ((err = snd_pcm_open(&(handle), device_name, capture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK )) < 0) { printf("Capture open error: %s\n", snd_strerror(err)); return NULL; } if ((err = set_hwparams(handle, hwparams,SND_PCM_ACCESS_RW_INTERLEAVED, rate, channels, period, nperiods )) < 0) { printf("Setting of hwparams failed: %s\n", snd_strerror(err)); return NULL; } if ((err = set_swparams(handle, swparams, period, nperiods)) < 0) { printf("Setting of swparams failed: %s\n", snd_strerror(err)); return NULL; } //snd_pcm_start( handle ); //snd_pcm_wait( handle, 200 ); int num_null_samples = nperiods * period * channels; char *tmp = alloca( num_null_samples * formats[format].sample_size ); memset( tmp, 0, num_null_samples * formats[format].sample_size ); snd_pcm_writei( handle, tmp, num_null_samples ); return handle; } double hann( double x ) { return 0.5 * (1.0 - cos( 2*M_PI * x ) ); } /** * The freewheel callback. */ void freewheel (int freewheel_starting, void* ignored_arg) { if( freewheel_starting ) { snd_pcm_close( alsa_handle ); alsa_handle = 0; // reset resampling parameters resample_mean = 1.0; static_resample_factor = 1.0; resample_lower_limit = 0.25; resample_upper_limit = 4.0; offset_differential_index = 0; offset_integral = 0; } else { alsa_handle = open_audiofd( alsa_device, 1, sample_rate, num_channels, period_size, num_periods); if( alsa_handle == 0 ) exit(20); } } /** * The process callback for this JACK application. * It is called by JACK at the appropriate times. */ int process (jack_nframes_t nframes, void *arg) { if (alsa_handle == 0) { JSList *node = playback_ports; while ( node != NULL) { jack_port_t *port = (jack_port_t *) node->data; float *buf = jack_port_get_buffer (port, nframes); memset(buf, 0, sizeof(float)*nframes); node = jack_slist_next (node); } return 0; } int rlen; int err; snd_pcm_sframes_t delay = target_delay; int i; delay = (num_periods*period_size)-snd_pcm_avail( alsa_handle ) ; delay -= round( jack_frames_since_cycle_start( client ) * static_resample_factor ); // Do it the hard way. // this is for compensating xruns etc... if( delay > (target_delay+max_diff) ) { snd_pcm_rewind( alsa_handle, delay - target_delay ); output_new_delay = (int) delay; delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. // first look at the PI controller, this code is just a special case, which should never execute once // everything is swung in. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i<smooth_size; i++ ) offset_array[i] = 0.0; } if( delay < (target_delay-max_diff) ) { output_new_delay = (int) delay; while ((target_delay-delay) > 0) { snd_pcm_uframes_t to_write = ((target_delay-delay) > 512) ? 512 : (target_delay-delay); snd_pcm_writei( alsa_handle, tmpbuf, to_write ); delay += to_write; } delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i<smooth_size; i++ ) offset_array[i] = 0.0; } /* ok... now we should have target_delay +- max_diff on the alsa side. * * calculate the number of frames, we want to get. */ double offset = delay - target_delay; // Save offset. offset_array[(offset_differential_index++)% smooth_size ] = offset; // Build the mean of the windowed offset array // basically fir lowpassing. double smooth_offset = 0.0; for( i=0; i<smooth_size; i++ ) smooth_offset += offset_array[ (i + offset_differential_index-1) % smooth_size] * window_array[i]; smooth_offset /= (double) smooth_size; // this is the integral of the smoothed_offset offset_integral += smooth_offset; // Clamp offset. // the smooth offset still contains unwanted noise // which would go straight onto the resample coeff. // it only used in the P component and the I component is used for the fine tuning anyways. if( fabs( smooth_offset ) < pclamp ) smooth_offset = 0.0; // ok. now this is the PI controller. // u(t) = K * ( e(t) + 1/T \int e(t') dt' ) // K = 1/catch_factor and T = catch_factor2 double current_resample_factor = static_resample_factor - smooth_offset / (double) catch_factor - offset_integral / (double) catch_factor / (double)catch_factor2; // now quantize this value around resample_mean, so that the noise which is in the integral component doesn't hurt. current_resample_factor = floor( (current_resample_factor - resample_mean) * controlquant + 0.5 ) / controlquant + resample_mean; // Output "instrumentatio" gonna change that to real instrumentation in a few. output_resampling_factor = (float) current_resample_factor; output_diff = (float) smooth_offset; output_integral = (float) offset_integral; output_offset = (float) offset; // Clamp a bit. if( current_resample_factor < resample_lower_limit ) current_resample_factor = resample_lower_limit; if( current_resample_factor > resample_upper_limit ) current_resample_factor = resample_upper_limit; // Now Calculate how many samples we need. rlen = ceil( ((double)nframes) * current_resample_factor )+2; assert( rlen > 2 ); // Calculate resample_mean so we can init ourselves to saner values. resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor; /* * now this should do it... */ outbuf = alloca( rlen * formats[format].sample_size * num_channels ); resampbuf = alloca( rlen * sizeof( float ) ); /* * render jack ports to the outbuf... */ int chn = 0; JSList *node = playback_ports; JSList *src_node = playback_srcs; SRC_DATA src; while ( node != NULL) { jack_port_t *port = (jack_port_t *) node->data; float *buf = jack_port_get_buffer (port, nframes); SRC_STATE *src_state = src_node->data; src.data_in = buf; src.input_frames = nframes; src.data_out = resampbuf; src.output_frames = rlen; src.end_of_input = 0; src.src_ratio = current_resample_factor; src_process( src_state, &src ); formats[format].jack_to_soundcard( outbuf + format[formats].sample_size * chn, resampbuf, src.output_frames_gen, num_channels*format[formats].sample_size, NULL); src_node = jack_slist_next (src_node); node = jack_slist_next (node); chn++; } // now write the output... again: err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen); //err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen); if( err < 0 ) { printf( "err = %d\n", err ); if (xrun_recovery(alsa_handle, err) < 0) { printf("Write error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } goto again; } return 0; } /** * the latency callback. * sets up the latencies on the ports. */ void latency_cb (jack_latency_callback_mode_t mode, void *arg) { jack_latency_range_t range; JSList *node; range.min = range.max = round(target_delay / static_resample_factor); if (mode == JackCaptureLatency) { for (node = capture_ports; node; node = jack_slist_next (node)) { jack_port_t *port = node->data; jack_port_set_latency_range (port, mode, &range); } } else { for (node = playback_ports; node; node = jack_slist_next (node)) { jack_port_t *port = node->data; jack_port_set_latency_range (port, mode, &range); } } } /** * Allocate the necessary jack ports... */ void alloc_ports( int n_capture, int n_playback ) { int port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal; int chn; jack_port_t *port; char buf[32]; capture_ports = NULL; for (chn = 0; chn < n_capture; chn++) { snprintf (buf, sizeof(buf) - 1, "capture_%u", chn+1); port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); if (!port) { printf( "jacknet_client: cannot register port for %s", buf); break; } capture_srcs = jack_slist_append( capture_srcs, src_new( 4-samplerate_quality, 1, NULL ) ); capture_ports = jack_slist_append (capture_ports, port); } port_flags = JackPortIsInput; playback_ports = NULL; for (chn = 0; chn < n_playback; chn++) { snprintf (buf, sizeof(buf) - 1, "playback_%u", chn+1); port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); if (!port) { printf( "jacknet_client: cannot register port for %s", buf); break; } playback_srcs = jack_slist_append( playback_srcs, src_new( 4-samplerate_quality, 1, NULL ) ); playback_ports = jack_slist_append (playback_ports, port); } } /** * This is the shutdown callback for this JACK application. * It is called by JACK if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { exit (1); } /** * be user friendly. * be user friendly. * be user friendly. */ void printUsage() { fprintf(stderr, "usage: alsa_out [options]\n" "\n" " -j <jack name> - client name\n" " -S <server name> - server to connect\n" " -d <alsa_device> \n" " -c <channels> \n" " -p <period_size> \n" " -n <num_period> \n" " -r <sample_rate> \n" " -q <sample_rate quality [0..4]\n" " -m <max_diff> \n" " -t <target_delay> \n" " -i turns on instrumentation\n" " -v turns on printouts\n" "\n"); } /** * the main function.... */ void sigterm_handler( int signal ) { quit = 1; } int main (int argc, char *argv[]) { char jack_name[30] = "alsa_out"; int jack_opts = 0; char *server_name = NULL; extern char *optarg; extern int optind, optopt; int errflg=0; int c; while ((c = getopt(argc, argv, "ivj:r:c:p:n:d:q:m:t:f:F:C:Q:s:S:")) != -1) { switch(c) { case 'j': strcpy(jack_name,optarg); break; case 'r': sample_rate = atoi(optarg); break; case 'c': num_channels = atoi(optarg); break; case 'p': period_size = atoi(optarg); break; case 'n': num_periods = atoi(optarg); break; case 'd': alsa_device = strdup (optarg); break; case 't': target_delay = atoi(optarg); break; case 'q': samplerate_quality = atoi(optarg); break; case 'm': max_diff = atoi(optarg); break; case 'f': catch_factor = atoi(optarg); break; case 'F': catch_factor2 = atoi(optarg); break; case 'C': pclamp = (double) atoi(optarg); break; case 'Q': controlquant = (double) atoi(optarg); break; case 'v': verbose = 1; break; case 'i': instrument = 1; break; case 's': smooth_size = atoi(optarg); break; case 'S': server_name = optarg; jack_opts |= JackServerName; break; case ':': fprintf(stderr, "Option -%c requires an operand\n", optopt); errflg++; break; case '?': fprintf(stderr, "Unrecognized option: -%c\n", optopt); errflg++; } } if (errflg) { printUsage(); exit(2); } if( (samplerate_quality < 0) || (samplerate_quality > 4) ) { fprintf (stderr, "invalid samplerate quality\n"); return 1; } if ((client = jack_client_open (jack_name, jack_opts, NULL, server_name)) == 0) { fprintf (stderr, "jack server not running?\n"); return 1; } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, 0); /* tell the JACK server to call `freewheel()' whenever freewheel mode changes. */ jack_set_freewheel_callback (client, freewheel, 0); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); if (jack_set_latency_callback) jack_set_latency_callback (client, latency_cb, 0); // get jack sample_rate jack_sample_rate = jack_get_sample_rate( client ); if( !sample_rate ) sample_rate = jack_sample_rate; static_resample_factor = (double) sample_rate / (double) jack_sample_rate; resample_lower_limit = static_resample_factor * 0.25; resample_upper_limit = static_resample_factor * 4.0; resample_mean = static_resample_factor; offset_array = malloc( sizeof(double) * smooth_size ); if( offset_array == NULL ) { fprintf( stderr, "no memory for offset_array !!!\n" ); exit(20); } window_array = malloc( sizeof(double) * smooth_size ); if( window_array == NULL ) { fprintf( stderr, "no memory for window_array !!!\n" ); exit(20); } int i; for( i=0; i<smooth_size; i++ ) { offset_array[i] = 0.0; window_array[i] = hann( (double) i / ((double) smooth_size - 1.0) ); } jack_buffer_size = jack_get_buffer_size( client ); // Setup target delay and max_diff for the normal user, who does not play with them... if( !target_delay ) target_delay = (num_periods*period_size / 2) - jack_buffer_size/2; if( !max_diff ) max_diff = target_delay; if( max_diff > target_delay ) { fprintf( stderr, "target_delay (%d) can not be smaller than max_diff(%d)\n", target_delay, max_diff ); exit(20); } if( (target_delay+max_diff) > (num_periods*period_size) ) { fprintf( stderr, "target_delay+max_diff (%d) can not be bigger than buffersize(%d)\n", target_delay+max_diff, num_periods*period_size ); exit(20); } // now open the alsa fd... alsa_handle = open_audiofd( alsa_device, 0, sample_rate, num_channels, period_size, num_periods); if( alsa_handle == 0 ) exit(20); printf( "selected sample format: %s\n", formats[format].name ); // alloc input ports, which are blasted out to alsa... alloc_ports( 0, num_channels ); outbuf = malloc( num_periods * period_size * formats[format].sample_size * num_channels ); resampbuf = malloc( num_periods * period_size * sizeof( float ) ); tmpbuf = malloc( 512 * formats[format].sample_size * num_channels ); if ((outbuf == NULL) || (resampbuf == NULL) || (tmpbuf == NULL)) { fprintf( stderr, "no memory for buffers.\n" ); exit(20); } /* tell the JACK server that we are ready to roll */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); return 1; } signal( SIGTERM, sigterm_handler ); signal( SIGINT, sigterm_handler ); if( verbose ) { while(!quit) { usleep(500000); if( output_new_delay ) { printf( "delay = %d\n", output_new_delay ); output_new_delay = 0; } printf( "res: %f, \tdiff = %f, \toffset = %f \n", output_resampling_factor, output_diff, output_offset ); } } else if( instrument ) { printf( "# n\tresamp\tdiff\toffseti\tintegral\n"); int n=0; while(!quit) { usleep(1000); printf( "%d\t%f\t%f\t%f\t%f\n", n++, output_resampling_factor, output_diff, output_offset, output_integral ); } } else { while(!quit) { usleep(500000); if( output_new_delay ) { printf( "delay = %d\n", output_new_delay ); output_new_delay = 0; } } } jack_deactivate( client ); jack_client_close (client); exit (0); } 07070100000048000081A400000000000000000000000161E2F7EE00000B44000000000000000000000000000000000000002500000000jack-example-tools-1/tools/bufsize.c/* * bufsize.c -- change JACK buffer size. * * Copyright (C) 2003 Jack O'Quin. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <errno.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <jack/jack.h> #include <jack/transport.h> char *package; /* program name */ jack_client_t *client; jack_nframes_t nframes; int just_print_bufsize=0; void jack_shutdown(void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } void parse_arguments(int argc, char *argv[]) { /* basename $0 */ package = strrchr(argv[0], '/'); if (package == 0) package = argv[0]; else package++; if (argc==1) { just_print_bufsize = 1; return; } if (argc < 2) { fprintf(stderr, "usage: %s <bufsize>\n", package); exit(9); } if (strspn (argv[1], "0123456789") != strlen (argv[1])) { fprintf(stderr, "usage: %s <bufsize>\n", package); exit(8); } nframes = strtoul(argv[1], NULL, 0); if (errno == ERANGE) { fprintf(stderr, "%s: invalid buffer size: %s (range is 1-16384)\n", package, argv[1]); exit(2); } if (nframes < 1 || nframes > 16384) { fprintf(stderr, "%s: invalid buffer size: %s (range is 1-16384)\n", package, argv[1]); exit(3); } } void silent_function( const char *ignore ) { } int main(int argc, char *argv[]) { int rc; parse_arguments(argc, argv); if (just_print_bufsize) jack_set_info_function( silent_function ); /* become a JACK client */ if ((client = jack_client_open(package, JackNoStartServer, NULL)) == 0) { fprintf(stderr, "JACK server not running?\n"); exit(1); } #ifndef WIN32 signal(SIGQUIT, signal_handler); signal(SIGHUP, signal_handler); #endif signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); jack_on_shutdown(client, jack_shutdown, 0); if (just_print_bufsize) { fprintf(stdout, "%d\n", jack_get_buffer_size( client ) ); rc = 0; } else { rc = jack_set_buffer_size(client, nframes); if (rc) fprintf(stderr, "jack_set_buffer_size(): %s\n", strerror(rc)); } jack_client_close(client); return rc; } 07070100000049000081A400000000000000000000000161E2F7EE000017F6000000000000000000000000000000000000002500000000jack-example-tools-1/tools/connect.c/* Copyright (C) 2002 Jeremy Hall 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <errno.h> #ifndef WIN32 #include <unistd.h> #endif #include <string.h> #include <stdlib.h> #include <getopt.h> #include <jack/jack.h> #include <jack/session.h> #define TRUE 1 #define FALSE 0 volatile int done = 0; void port_connect_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg) { done = 1; } void show_version (char *my_name) { fprintf (stderr, "%s: JACK example tools version %s\n", my_name, __PROJECT_VERSION__); } void show_usage (char *my_name) { show_version (my_name); fprintf (stderr, "\nusage: %s [options] port1 port2\n", my_name); fprintf (stderr, "Connects two JACK ports together.\n\n"); fprintf (stderr, " -s, --server <name> Connect to the jack server named <name>\n"); fprintf (stderr, " -v, --version Output version information and exit\n"); fprintf (stderr, " -h, --help Display this help message\n\n"); fprintf (stderr, "For more information see http://jackaudio.org/\n"); } int main (int argc, char *argv[]) { jack_client_t *client; jack_status_t status; char *server_name = NULL; int c; int option_index; jack_options_t options = JackNoStartServer; char *my_name = strrchr(argv[0], '/'); jack_port_t *src_port = 0; jack_port_t *dst_port = 0; jack_port_t *port1 = 0; jack_port_t *port2 = 0; char portA[300]; char portB[300]; int use_uuid=0; int connecting, disconnecting; int port1_flags, port2_flags; int rc = 1; struct option long_options[] = { { "server", 1, 0, 's' }, { "help", 0, 0, 'h' }, { "version", 0, 0, 'v' }, { "uuid", 0, 0, 'u' }, { 0, 0, 0, 0 } }; while ((c = getopt_long (argc, argv, "s:hvu", long_options, &option_index)) >= 0) { switch (c) { case 's': server_name = (char *) malloc (sizeof (char) * (strlen(optarg) + 1)); strcpy (server_name, optarg); options |= JackServerName; break; case 'u': use_uuid = 1; break; case 'h': show_usage (my_name); return 1; break; case 'v': show_version (my_name); return 1; break; default: show_usage (my_name); return 1; break; } } connecting = disconnecting = FALSE; if (my_name == 0) { my_name = argv[0]; } else { my_name ++; } if (strstr(my_name, "disconnect")) { disconnecting = 1; } else if (strstr(my_name, "connect")) { connecting = 1; } else { fprintf(stderr, "ERROR! client should be called jack_connect or jack_disconnect. client is called %s\n", my_name); return 1; } if (argc < 3) { show_usage(my_name); return 1; } /* try to become a client of the JACK server */ if ((client = jack_client_open (my_name, options, &status, server_name)) == 0) { fprintf (stderr, "jack server not running?\n"); return 1; } jack_set_port_connect_callback(client, port_connect_callback, NULL); /* find the two ports */ if( use_uuid ) { char *tmpname; char *clientname; char *portname; tmpname = strdup( argv[argc-1] ); portname = strchr( tmpname, ':' ); portname[0] = '\0'; portname+=1; clientname = jack_get_client_name_by_uuid( client, tmpname ); if( clientname ) { snprintf( portA, sizeof(portA), "%s:%s", clientname, portname ); jack_free( clientname ); } else { snprintf( portA, sizeof(portA), "%s", argv[argc-1] ); } free( tmpname ); tmpname = strdup( argv[argc-2] ); portname = strchr( tmpname, ':' ); portname[0] = '\0'; portname+=1; clientname = jack_get_client_name_by_uuid( client, tmpname ); if( clientname ) { snprintf( portB, sizeof(portB), "%s:%s", clientname, portname ); jack_free( clientname ); } else { snprintf( portB, sizeof(portB), "%s", argv[argc-2] ); } free( tmpname ); } else { snprintf( portA, sizeof(portA), "%s", argv[argc-1] ); snprintf( portB, sizeof(portB), "%s", argv[argc-2] ); } if ((port1 = jack_port_by_name(client, portA)) == 0) { fprintf (stderr, "ERROR %s not a valid port\n", portA); goto exit; } if ((port2 = jack_port_by_name(client, portB)) == 0) { fprintf (stderr, "ERROR %s not a valid port\n", portB); goto exit; } port1_flags = jack_port_flags (port1); port2_flags = jack_port_flags (port2); if (port1_flags & JackPortIsInput) { if (port2_flags & JackPortIsOutput) { src_port = port2; dst_port = port1; } } else { if (port2_flags & JackPortIsInput) { src_port = port1; dst_port = port2; } } if (!src_port || !dst_port) { fprintf (stderr, "arguments must include 1 input port and 1 output port\n"); goto exit; } /* tell the JACK server that we are ready to roll */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); goto exit; } /* connect the ports. Note: you can't do this before the client is activated (this may change in the future). */ if (connecting) { if (jack_connect(client, jack_port_name(src_port), jack_port_name(dst_port))) { fprintf (stderr, "cannot connect client, already connected?\n"); goto exit; } } if (disconnecting) { if (jack_disconnect(client, jack_port_name(src_port), jack_port_name(dst_port))) { fprintf (stderr, "cannot disconnect client, already disconnected?\n"); goto exit; } } // Wait for connection/disconnection to be effective while(!done) { #ifdef WIN32 Sleep(10); #else usleep(10000); #endif } /* everything was ok, so setting exitcode to 0 */ rc = 0; exit: jack_client_close (client); exit (rc); } 0707010000004A000081A400000000000000000000000161E2F7EE00001003000000000000000000000000000000000000002300000000jack-example-tools-1/tools/evmon.c/* Copyright (C) 2007 Paul Davis 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <errno.h> #ifndef WIN32 #include <unistd.h> #endif #include <string.h> #include <signal.h> #include <stdlib.h> #include <jack/jack.h> #include <jack/metadata.h> #include <jack/uuid.h> jack_client_t *client; static void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } static void port_rename_callback (jack_port_id_t port, const char* old_name, const char* new_name, void* arg) { printf ("Port %d renamed from %s to %s\n", port, old_name, new_name); } static void port_callback (jack_port_id_t port, int yn, void* arg) { printf ("Port %d %s\n", port, (yn ? "registered" : "unregistered")); } static void connect_callback (jack_port_id_t a, jack_port_id_t b, int yn, void* arg) { printf ("Ports %d and %d %s\n", a, b, (yn ? "connected" : "disconnected")); } static void client_callback (const char* client, int yn, void* arg) { printf ("Client %s %s\n", client, (yn ? "registered" : "unregistered")); } static int graph_callback (void* arg) { printf ("Graph reordered\n"); return 0; } static void propchange (jack_uuid_t subject, const char* key, jack_property_change_t change, void* arg) { char buf[JACK_UUID_STRING_SIZE]; const char* action = ""; switch (change) { case PropertyCreated: action = "created"; break; case PropertyChanged: action = "changed"; break; case PropertyDeleted: action = "deleted"; break; } if (jack_uuid_empty (subject)) { printf ("All properties changed!\n"); } else { jack_uuid_unparse (subject, buf); if (key) { printf ("key [%s] for %s %s\n", key, buf, action); } else { printf ("all keys for %s %s\n", buf, action); } } } int main (int argc, char *argv[]) { jack_options_t options = JackNullOption; jack_status_t status; if ((client = jack_client_open ("event-monitor", options, &status, NULL)) == 0) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } return 1; } if (jack_set_port_registration_callback (client, port_callback, NULL)) { fprintf (stderr, "cannot set port registration callback\n"); return 1; } if (jack_set_port_rename_callback (client, port_rename_callback, NULL)) { fprintf (stderr, "cannot set port registration callback\n"); return 1; } if (jack_set_port_connect_callback (client, connect_callback, NULL)) { fprintf (stderr, "cannot set port connect callback\n"); return 1; } if (jack_set_client_registration_callback (client, client_callback, NULL)) { fprintf (stderr, "cannot set client registration callback\n"); return 1; } if (jack_set_graph_order_callback (client, graph_callback, NULL)) { fprintf (stderr, "cannot set graph order registration callback\n"); return 1; } if (jack_set_property_change_callback (client, propchange, NULL)) { fprintf (stderr, "cannot set property change callback\n"); return 1; } if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); return 1; } #ifndef WIN32 signal(SIGINT, signal_handler); signal(SIGQUIT, signal_handler); signal(SIGHUP, signal_handler); #endif signal(SIGABRT, signal_handler); signal(SIGTERM, signal_handler); #ifdef WIN32 Sleep(INFINITE); #else sleep (-1); #endif exit (0); } 0707010000004B000081A400000000000000000000000161E2F7EE0000085A000000000000000000000000000000000000002700000000jack-example-tools-1/tools/freewheel.c/* * freewheel - start/stop JACK "freewheeling" mode * * Copyright (C) 2003 Paul Davis. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <errno.h> #ifndef WIN32 #include <unistd.h> #endif #include <signal.h> #include <stdlib.h> #include <string.h> #include <jack/jack.h> #include <jack/transport.h> char *package; /* program name */ jack_client_t *client; int onoff; static void jack_shutdown(void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } static void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } static void parse_arguments(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "usage: %s y|n\n", package); exit(9); } if (argv[1][0] == 'y' || argv[1][0] == 'Y' || argv[1][0] == '1') { onoff = 1; } else { onoff = 0; } } int main (int argc, char *argv[]) { parse_arguments (argc, argv); /* become a JACK client */ if ((client = jack_client_open ("freewheel", JackNullOption, NULL)) == 0) { fprintf (stderr, "JACK server not running?\n"); exit(1); } #ifndef WIN32 signal (SIGQUIT, signal_handler); signal (SIGHUP, signal_handler); #endif signal (SIGTERM, signal_handler); signal (SIGINT, signal_handler); jack_on_shutdown (client, jack_shutdown, 0); if (jack_set_freewheel (client, onoff)) { fprintf (stderr, "failed to reset freewheel mode\n"); } jack_client_close(client); return 0; } 0707010000004C000081A400000000000000000000000161E2F7EE00001C76000000000000000000000000000000000000002700000000jack-example-tools-1/tools/iodelay.cpp/* Copyright (C) 2003-2008 Fons Adriaensen <fons@kokkinizita.net> 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ // -------------------------------------------------------------------------------- #include <stdlib.h> #include <stdio.h> #define __STDC_LIMIT_MACROS #include <stdint.h> #include <math.h> #include <unistd.h> #include <jack/jack.h> struct Freq { int p; int f; float xa; float ya; float x1; float y1; float x2; float y2; }; struct MTDM { double _del; double _err; float _wlp; int _cnt; int _inv; struct Freq _freq [13]; }; struct MTDM * mtdm_new (double fsamp) { int i; struct Freq *F; struct MTDM *retval = (MTDM *)malloc( sizeof(struct MTDM) ); if (retval==NULL) return NULL; retval->_cnt = 0; retval->_inv = 0; retval->_freq [0].f = 4096; retval->_freq [1].f = 2048; retval->_freq [2].f = 3072; retval->_freq [3].f = 2560; retval->_freq [4].f = 2304; retval->_freq [5].f = 2176; retval->_freq [6].f = 1088; retval->_freq [7].f = 1312; retval->_freq [8].f = 1552; retval->_freq [9].f = 1800; retval->_freq [10].f = 3332; retval->_freq [11].f = 3586; retval->_freq [12].f = 3841; retval->_wlp = 200.0f / fsamp; for (i = 0, F = retval->_freq; i < 13; i++, F++) { F->p = 128; F->xa = F->ya = 0.0f; F->x1 = F->y1 = 0.0f; F->x2 = F->y2 = 0.0f; } return retval; } int mtdm_process (struct MTDM *self, size_t len, float *ip, float *op) { int i; float vip, vop, a, c, s; struct Freq *F; while (len--) { vop = 0.0f; vip = *ip++; for (i = 0, F = self->_freq; i < 13; i++, F++) { a = 2 * (float) M_PI * (F->p & 65535) / 65536.0; F->p += F->f; c = cosf (a); s = -sinf (a); vop += (i ? 0.01f : 0.20f) * s; F->xa += s * vip; F->ya += c * vip; } *op++ = vop; if (++self->_cnt == 16) { for (i = 0, F = self->_freq; i < 13; i++, F++) { F->x1 += self->_wlp * (F->xa - F->x1 + 1e-20); F->y1 += self->_wlp * (F->ya - F->y1 + 1e-20); F->x2 += self->_wlp * (F->x1 - F->x2 + 1e-20); F->y2 += self->_wlp * (F->y1 - F->y2 + 1e-20); F->xa = F->ya = 0.0f; } self->_cnt = 0; } } return 0; } int mtdm_resolve (struct MTDM *self) { int i, k, m; double d, e, f0, p; struct Freq *F = self->_freq; if (hypot (F->x2, F->y2) < 0.001) return -1; d = atan2 (F->y2, F->x2) / (2 * M_PI); if (self->_inv) d += 0.5; if (d > 0.5) d -= 1.0; f0 = self->_freq [0].f; m = 1; self->_err = 0.0; for (i = 0; i < 12; i++) { F++; p = atan2 (F->y2, F->x2) / (2 * M_PI) - d * F->f / f0; if (self->_inv) p += 0.5; p -= floor (p); p *= 2; k = (int)(floor (p + 0.5)); e = fabs (p - k); if (e > self->_err) self->_err = e; if (e > 0.4) return 1; d += m * (k & 1); m *= 2; } self->_del = 16 * d; return 0; } void mtdm_invert (struct MTDM *self) { self->_inv ^= 1; } // -------------------------------------------------------------------------------- static struct MTDM *mtdm; static jack_client_t *jack_handle; static jack_port_t *jack_capt; static jack_port_t *jack_play; jack_latency_range_t capture_latency = {UINT32_MAX, UINT32_MAX}; jack_latency_range_t playback_latency = {UINT32_MAX, UINT32_MAX}; void latency_cb (jack_latency_callback_mode_t mode, void *arg) { jack_latency_range_t range; range.min = range.max = 0; if (mode == JackCaptureLatency) { jack_port_set_latency_range (jack_play, mode, &range); jack_port_get_latency_range (jack_capt, mode, &range); if ((range.min != capture_latency.min) || (range.max != capture_latency.max)) { capture_latency = range; printf ("new capture latency: [%d, %d]\n", range.min, range.max); } } else { jack_port_set_latency_range (jack_capt, mode, &range); jack_port_get_latency_range (jack_play, mode, &range); if ((range.min != playback_latency.min) || (range.max != playback_latency.max)) { playback_latency = range; printf ("new playback latency: [%d, %d]\n", range.min, range.max); } } } int jack_callback (jack_nframes_t nframes, void *arg) { float *ip, *op; ip = (float *)(jack_port_get_buffer (jack_capt, nframes)); op = (float *)(jack_port_get_buffer (jack_play, nframes)); mtdm_process (mtdm, nframes, ip, op); return 0; } int main (int ac, char *av []) { float t; jack_status_t s; jack_handle = jack_client_open ("jack_delay", JackNoStartServer, &s); if (jack_handle == 0) { fprintf (stderr, "Can't connect to Jack, is the server running ?\n"); exit (1); } mtdm = mtdm_new(jack_get_sample_rate(jack_handle)); jack_set_process_callback (jack_handle, jack_callback, 0); if (jack_set_latency_callback) jack_set_latency_callback (jack_handle, latency_cb, 0); jack_capt = jack_port_register (jack_handle, "in", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); jack_play = jack_port_register (jack_handle, "out", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); t = 1000.0f / jack_get_sample_rate (jack_handle); if (jack_activate (jack_handle)) { fprintf(stderr, "Can't activate Jack"); return 1; } while (1) { #ifdef WIN32 Sleep (250); #else usleep (250000); #endif if (mtdm_resolve (mtdm) < 0) printf ("Signal below threshold...\n"); else { jack_nframes_t systemic_latency; if (mtdm->_err > 0.3) { mtdm_invert ( mtdm ); mtdm_resolve ( mtdm ); } systemic_latency = (jack_nframes_t) floor (mtdm->_del - (capture_latency.max + playback_latency.max)); printf ("%10.3lf frames %10.3lf ms total roundtrip latency\n\textra loopback latency: %u frames\n\tuse %u for the backend arguments -I and -O", mtdm->_del, mtdm->_del * t, systemic_latency, systemic_latency/2); if (mtdm->_err > 0.2) printf (" ??"); if (mtdm->_inv) printf (" Inv"); printf ("\n"); } } return 0; } // -------------------------------------------------------------------------------- 0707010000004D000081A400000000000000000000000161E2F7EE000016A5000000000000000000000000000000000000002400000000jack-example-tools-1/tools/ipload.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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <signal.h> #ifndef WIN32 #include <unistd.h> #endif #include <getopt.h> #include <jack/jack.h> #include <jack/intclient.h> jack_client_t *client; jack_intclient_t intclient; char *client_name; char *intclient_name; char *load_name; char *load_init = ""; char *server_name = NULL; int autoclose_opt = 0; int wait_opt = 0; volatile int idling = 1; static void signal_handler (int sig) { /* do nothing if internal client closed itself */ if (idling == 0) return; jack_status_t status; fprintf (stderr, "signal received, unloading..."); status = jack_internal_client_unload (client, intclient); if (status & JackFailure) fprintf (stderr, "(failed), status = 0x%2.0x\n", status); else fprintf (stderr, "(succeeded)\n"); if (autoclose_opt) jack_deactivate(client); jack_client_close (client); exit (0); } static void registration_callback (const char *name, int reg, void *arg) { if (reg || strcmp(intclient_name, name)) return; /* this will stop the wait loop and thus close this application. */ idling = 0; return; /* unused */ (void)arg; } static void show_usage () { fprintf (stderr, "usage: %s [ options ] client-name [ load-name " "[ init-string]]\n\noptions:\n", client_name); fprintf (stderr, "\t-h, --help \t\t print help message\n" "\t-a, --autoclose\t automatically close when intclient is unloaded\n" "\t-i, --init string\t initialize string\n" "\t-s, --server name\t select JACK server\n" "\t-w, --wait \t\t wait for signal, then unload\n" "\n" ); } static int parse_args (int argc, char *argv[]) { int c; int option_index = 0; char *short_options = "hai:s:w"; struct option long_options[] = { { "help", 0, 0, 'h' }, { "autoclose", 0, 0, 'a' }, { "init", required_argument, 0, 'i' }, { "server", required_argument, 0, 's' }, { "wait", 0, 0, 'w' }, { 0, 0, 0, 0 } }; client_name = strrchr(argv[0], '/'); if (client_name == NULL) { client_name = argv[0]; } else { client_name++; } while ((c = getopt_long (argc, argv, short_options, long_options, &option_index)) >= 0) { switch (c) { case 'a': autoclose_opt = 1; break; case 'i': load_init = optarg; break; case 's': server_name = optarg; break; case 'w': wait_opt = 1; break; case 'h': default: show_usage (); return 1; } } /* autoclose makes no sense without wait */ if (autoclose_opt && ! wait_opt) autoclose_opt = 0; if (optind == argc) { /* no positional args? */ show_usage (); return 1; } if (optind < argc) load_name = intclient_name = argv[optind++]; if (optind < argc) load_name = argv[optind++]; if (optind < argc) load_init = argv[optind++]; //fprintf (stderr, "client-name = `%s', load-name = `%s', " // "load-init = `%s', wait = %d\n", // intclient_name, load_name, load_init, wait_opt); return 0; /* args OK */ } int main (int argc, char *argv[]) { jack_status_t status; char* name; /* parse and validate command arguments */ if (parse_args (argc, argv)) exit (1); /* invalid command line */ /* first, become a JACK client */ client = jack_client_open (client_name, JackServerName, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } exit (1); } if (status & JackServerStarted) { fprintf (stderr, "JACK server started\n"); } if (status & JackNameNotUnique) { client_name = jack_get_client_name(client); fprintf (stderr, "unique name `%s' assigned\n", client_name); } /* then, load the internal client */ intclient = jack_internal_client_load (client, intclient_name, (JackLoadName|JackLoadInit), &status, load_name, load_init); if (status & JackFailure) { fprintf (stderr, "could not load %s, intclient = %d status = 0x%2.0x\n", load_name, (int)intclient, status); return 2; } if (status & JackNameNotUnique) { intclient_name = jack_get_internal_client_name (client, intclient); fprintf (stderr, "unique internal client name `%s' assigned\n", intclient_name); } fprintf (stdout, "%s is running.\n", load_name); name = jack_get_internal_client_name(client, intclient); if (name) { printf("client name = %s\n", name); free(name); } fflush(stdout); if (autoclose_opt) { jack_set_client_registration_callback(client, registration_callback, NULL); jack_activate(client); } if (wait_opt) { /* define a signal handler to unload the client, then * wait for it to exit */ #ifdef WIN32 signal(SIGINT, signal_handler); signal(SIGABRT, signal_handler); signal(SIGTERM, signal_handler); #else signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); #endif while (idling) { #ifdef WIN32 Sleep(1000); #else sleep (1); #endif } } if (autoclose_opt) { jack_deactivate(client); } jack_client_close(client); return 0; } 0707010000004E000081A400000000000000000000000161E2F7EE00000B25000000000000000000000000000000000000002600000000jack-example-tools-1/tools/ipunload.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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #if !defined(__JACK1__) && !defined(__JACK2__) # error neither __JACK1__ or __JACK2__ is defined, this cannot happen #endif #include <string.h> #include <stdlib.h> #include <stdio.h> #include <jack/jack.h> #include <jack/intclient.h> int main (int argc, char *argv[]) { char *my_name; char *client_name; jack_client_t *client; jack_status_t status; jack_intclient_t intclient; /* validate args */ if ((argc < 2) || (argc > 3)) { fprintf (stderr, "usage: %s client-name [ server-name ]]\n", argv[0]); return 1; } /* use `basename $0` for my own client name */ my_name = strrchr(argv[0], '/'); if (my_name == 0) { my_name = argv[0]; } else { my_name++; } /* first, become a JACK client */ if (argc > 2) { client = jack_client_open (my_name, (JackServerName|JackNoStartServer), &status, argv[2]); } else { client = jack_client_open (my_name, JackNoStartServer, &status); } if (client == NULL) { if (status & JackServerFailed) { fprintf (stderr, "JACK server not running.\n"); } else { fprintf (stderr, "JACK open failed, " "status = 0x%2.0x\n", status); } exit (1); } /* then, get the internal client handle */ client_name = argv[1]; #ifdef __JACK1__ if (jack_internal_client_handle (client, client_name, &status, &intclient) != 0) { if (status & JackFailure) { fprintf (stderr, "client %s not found.\n", client_name); } exit (2); } #endif #ifdef __JACK2__ intclient = jack_internal_client_handle (client, client_name, &status); if (status & JackFailure) { fprintf (stderr, "client %s not found.\n", client_name); exit (2); } #endif /* now, unload the internal client */ status = jack_internal_client_unload (client, intclient); if (status & JackFailure) { if (status & JackInvalidOption) { fprintf (stderr, "I'm sorry Dave, I can't do that\n"); } else if (status & JackNoSuchClient) { fprintf (stderr, "client %s is gone.\n", client_name); } else { fprintf (stderr, "could not unload %s, " "returns 0x%2.0x\n", client_name, status); } exit (3); } else { fprintf (stdout, "%s unloaded.\n", client_name); } jack_client_close(client); return 0; } 0707010000004F000081A400000000000000000000000161E2F7EE0000094A000000000000000000000000000000000000002700000000jack-example-tools-1/tools/load_test.c#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <getopt.h> #include <signal.h> #include <time.h> #include <jack/jack.h> char * my_name; jack_client_t *client; unsigned int wait_timeout = 1000; void show_version (void) { fprintf (stderr, "%s: JACK example tools version %s\n", my_name, __PROJECT_VERSION__); } void show_usage (void) { show_version (); fprintf (stderr, "\nUsage: %s [options]\n", my_name); fprintf (stderr, "this is a test client, which just sleeps in its process_cb to simulate cpu load\n"); fprintf (stderr, "options:\n"); fprintf (stderr, " -t, --timeout Wait timeout in seconds\n"); fprintf (stderr, " -h, --help Display this help message\n"); fprintf (stderr, " --version Output version information and exit\n\n"); fprintf (stderr, "For more information see http://jackaudio.org/\n"); } void jack_shutdown(void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } int process_cb (jack_nframes_t nframes, void *arg) { jack_time_t now = jack_get_time(); jack_time_t wait = now + wait_timeout; while (jack_get_time() < wait) ; return 0; } int main (int argc, char *argv[]) { int c; int option_index; struct option long_options[] = { { "timeout", 1, 0, 't' }, { "help", 0, 0, 'h' }, { "version", 0, 0, 'v' }, { 0, 0, 0, 0 } }; my_name = strrchr(argv[0], '/'); if (my_name == 0) { my_name = argv[0]; } else { my_name ++; } while ((c = getopt_long (argc, argv, "t:hv", long_options, &option_index)) >= 0) { switch (c) { case 't': wait_timeout = atoi(optarg); break; case 'h': show_usage (); return 1; break; case 'v': show_version (); return 1; break; default: show_usage (); return 1; break; } } /* try to open server in a loop. breaking under certein conditions */ client = jack_client_open( "load_test", JackNullOption, NULL ); signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); jack_on_shutdown(client, jack_shutdown, 0); jack_set_process_callback( client, process_cb, NULL ); jack_activate (client); sleep( -1 ); exit (0); } 07070100000050000081A400000000000000000000000161E2F7EE00001EB2000000000000000000000000000000000000002100000000jack-example-tools-1/tools/lsp.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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <stdlib.h> #ifndef WIN32 #include <unistd.h> #endif #include <string.h> #include <getopt.h> #include <inttypes.h> #include <jack/jack.h> #include <jack/session.h> #include <jack/uuid.h> char * my_name; static void show_version (void) { fprintf (stderr, "%s: JACK example tools version %s\n", my_name, __PROJECT_VERSION__); } static void printf_name2uuid (jack_client_t* client, const char* pname) { char *port_component = strchr( pname, ':' ); size_t csize = port_component - pname + 1; char client_component[csize]; snprintf(client_component, csize, "%s", pname); char *uuid = jack_get_uuid_for_client_name(client, client_component); if (uuid) { printf("%s%s\n", uuid, port_component ); } else { printf("%s\n",pname); } jack_free(uuid); } static void show_usage (void) { show_version (); fprintf (stderr, "\nUsage: %s [options] [filter string]\n", my_name); fprintf (stderr, "List active Jack ports, and optionally display extra information.\n"); fprintf (stderr, "Optionally filter ports which match ALL strings provided after any options.\n\n"); fprintf (stderr, "Display options:\n"); fprintf (stderr, " -s, --server <name> Connect to the jack server named <name>\n"); fprintf (stderr, " -A, --aliases List aliases for each port\n"); fprintf (stderr, " -c, --connections List connections to/from each port\n"); fprintf (stderr, " -l, --port-latency Display per-port latency in frames at each port\n"); fprintf (stderr, " -L, --total-latency Display total latency in frames at each port\n"); fprintf (stderr, " -p, --properties Display port properties. Output may include:\n" " input|output, can-monitor, physical, terminal\n\n"); fprintf (stderr, " -t, --type Display port type\n"); fprintf (stderr, " -u, --uuid Display uuid instead of client name (if available)\n"); fprintf (stderr, " -U, --port-uuid Display port uuid\n"); fprintf (stderr, " -h, --help Display this help message\n"); fprintf (stderr, " --version Output version information and exit\n\n"); fprintf (stderr, "For more information see http://jackaudio.org/\n"); } int main (int argc, char *argv[]) { jack_client_t *client; jack_status_t status; jack_options_t options = JackNoStartServer; const char **ports, **connections; unsigned int i, j, k; int skip_port; int show_aliases = 0; int show_con = 0; int show_port_latency = 0; int show_total_latency = 0; int show_properties = 0; int show_type = 0; int show_uuid = 0; int show_port_uuid = 0; int c; int option_index; char* aliases[2]; char *server_name = NULL; struct option long_options[] = { { "server", 1, 0, 's' }, { "aliases", 0, 0, 'A' }, { "connections", 0, 0, 'c' }, { "port-latency", 0, 0, 'l' }, { "total-latency", 0, 0, 'L' }, { "properties", 0, 0, 'p' }, { "type", 0, 0, 't' }, { "uuid", 0, 0, 'u' }, { "port-uuid", 0, 0, 'U' }, { "help", 0, 0, 'h' }, { "version", 0, 0, 'v' }, { 0, 0, 0, 0 } }; my_name = strrchr(argv[0], '/'); if (my_name == 0) { my_name = argv[0]; } else { my_name ++; } while ((c = getopt_long (argc, argv, "s:AclLphvtuU", long_options, &option_index)) >= 0) { switch (c) { case 's': server_name = (char *) malloc (sizeof (char) * strlen(optarg)); strcpy (server_name, optarg); options |= JackServerName; break; case 'A': aliases[0] = (char *) malloc (jack_port_name_size()); aliases[1] = (char *) malloc (jack_port_name_size()); show_aliases = 1; break; case 'c': show_con = 1; break; case 'l': show_port_latency = 1; break; case 'L': show_total_latency = 1; break; case 'p': show_properties = 1; break; case 't': show_type = 1; break; case 'u': show_uuid = 1; break; case 'U': show_port_uuid = 1; break; case 'h': show_usage (); return 1; break; case 'v': show_version (); return 1; break; default: show_usage (); return 1; break; } } /* Open a client connection to the JACK server. Starting a * new server only to list its ports seems pointless, so we * specify JackNoStartServer. */ if ((client = jack_client_open ("lsp", options, &status, server_name)) == 0) { fprintf (stderr, "Error: cannot connect to JACK, "); if (status & JackServerFailed) { fprintf (stderr, "server is not running.\n"); } else { fprintf (stderr, "jack_client_open() failed, status = 0x%2.0x\n", status); } return 1; } ports = jack_get_ports (client, NULL, NULL, 0); for (i = 0; ports && ports[i]; ++i) { // skip over any that don't match ALL of the strings presented at command line skip_port = 0; for (k = optind; k < argc; k++){ if (strstr(ports[i], argv[k]) == NULL ){ skip_port = 1; } } if (skip_port) continue; if (show_uuid) { printf_name2uuid(client, ports[i]); } else { printf ("%s\n", ports[i]); } jack_port_t *port = jack_port_by_name (client, ports[i]); if (show_port_uuid) { char buf[JACK_UUID_STRING_SIZE]; jack_uuid_t uuid = jack_port_uuid (port); jack_uuid_unparse (uuid, buf); printf (" uuid: %s\n", buf); } if (show_aliases) { int cnt; int i; cnt = jack_port_get_aliases (port, aliases); for (i = 0; i < cnt; ++i) { printf (" %s\n", aliases[i]); } } if (show_con) { if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) { for (j = 0; connections[j]; j++) { printf(" "); if (show_uuid) { printf_name2uuid(client, connections[j]); } else { printf("%s\n", connections[j]); } } jack_free (connections); } } if (show_port_latency) { if (port) { jack_latency_range_t range; jack_port_get_latency_range (port, JackPlaybackLatency, &range); printf (" port playback latency = [ %" PRIu32 " %" PRIu32 " ] frames\n", range.min, range.max); jack_port_get_latency_range (port, JackCaptureLatency, &range); printf (" port capture latency = [ %" PRIu32 " %" PRIu32 " ] frames\n", range.min, range.max); } } if (show_total_latency) { if (port) { printf (" total latency = %d frames\n", jack_port_get_total_latency (client, port)); } } if (show_properties) { if (port) { int flags = jack_port_flags (port); printf (" properties: "); if (flags & JackPortIsInput) { fputs ("input,", stdout); } if (flags & JackPortIsOutput) { fputs ("output,", stdout); } if (flags & JackPortCanMonitor) { fputs ("can-monitor,", stdout); } if (flags & JackPortIsPhysical) { fputs ("physical,", stdout); } if (flags & JackPortIsTerminal) { fputs ("terminal,", stdout); } putc ('\n', stdout); } } if (show_type) { if (port) { putc ('\t', stdout); fputs (jack_port_type (port), stdout); putc ('\n', stdout); } } } if (show_aliases) { free(aliases[0]); free(aliases[1]); } if (ports) jack_free (ports); jack_client_close (client); exit (0); } 07070100000051000081A400000000000000000000000161E2F7EE0000104F000000000000000000000000000000000000002700000000jack-example-tools-1/tools/meson.buildexe_jack_alias = executable( 'jack_alias', c_args: c_args_common, sources: ['alias.c'], dependencies: [dep_jack], install: true ) if build_alsa_in_out exe_alsa_in = executable( 'alsa_in', sources: ['alsa_in.c', '../common/memops.c'], include_directories: ['../common'], dependencies: [dep_alsa, dep_jack, dep_samplerate, lib_m], install: true ) exe_alsa_out = executable( 'alsa_out', sources: ['alsa_out.c', '../common/memops.c'], include_directories: ['../common'], dependencies: [dep_alsa, dep_jack, dep_samplerate, lib_m], install: true ) endif exe_jack_bufsize = executable( 'jack_bufsize', sources: ['bufsize.c'], dependencies: [dep_jack, dep_threads], install: true ) exe_jack_connect = executable( 'jack_connect', c_args: c_args_common, sources: ['connect.c'], dependencies: [dep_jack], install: true ) if os != 'windows' meson.add_install_script( '../scripts/meson_create_symlink', get_option('bindir'), 'jack_connect', 'jack_disconnect' ) endif exe_jack_evmon = executable( 'jack_evmon', sources: ['evmon.c'], dependencies: [dep_jack], install: true ) exe_jack_freewheel = executable( 'jack_freewheel', sources: ['freewheel.c'], dependencies: [dep_jack], install: true ) exe_jack_iodelay = executable( 'jack_iodelay', sources: ['iodelay.cpp'], dependencies: [dep_jack, lib_m], install: true ) exe_jack_load = executable( 'jack_load', sources: ['ipload.c'], dependencies: [dep_jack], install: true ) if has_jack1_internal_client and not has_jack2_internal_client c_args_jack_unload = c_args_common + ['-D__JACK1__'] endif if not has_jack1_internal_client and has_jack2_internal_client c_args_jack_unload = c_args_common + ['-D__JACK2__'] endif exe_jack_unload = executable( 'jack_unload', c_args: c_args_jack_unload, sources: ['ipunload.c'], dependencies: [dep_jack], install: true ) exe_jack_unload = executable( 'jack_load_test', c_args: c_args_common, sources: ['load_test.c'], dependencies: [dep_jack], install: true ) exe_jack_lsp = executable( 'jack_lsp', c_args: c_args_common, sources: ['lsp.c'], dependencies: [dep_jack], install: true ) exe_jack_midi_dump = executable( 'jack_midi_dump', sources: ['midi_dump.c'], dependencies: [dep_jack, dep_threads], install: true ) exe_jack_monitor_client = executable( 'jack_monitor_client', sources: ['monitor_client.c'], dependencies: [dep_jack], install: true ) if build_jack_netsource c_args_netsource = c_args_common + ['-DNO_JACK_ERROR'] deps_netsource = [dep_jack, dep_samplerate, lib_m] if opus_support c_args_netsource += ['-DHAVE_OPUS'] deps_netsource += [dep_opus] endif if has_ppoll c_args_netsource += ['-DHAVE_PPOLL'] endif exe_jack_netsource = executable( 'jack_netsource', c_args: c_args_netsource, sources: ['netsource.c', '../common/netjack_packet.c'], include_directories: ['../common'], dependencies: deps_netsource, install: true ) endif exe_jack_property = executable( 'jack_property', sources: ['property.c'], dependencies: [dep_jack], install: true ) exe_jack_samplerate = executable( 'jack_samplerate', sources: ['samplerate.c'], dependencies: [dep_jack], install: true ) # dont install, jack session is deprecated exe_jack_session_notify = executable( 'jack_session_notify', sources: ['session_notify.c'], dependencies: [dep_jack], c_args: ['-Wno-deprecated-declarations'], install: false ) jack_transport_c_args = c_args_common jack_transport_deps = [dep_jack] if readline_support jack_transport_c_args += ['-DHAVE_READLINE'] jack_transport_deps += [dep_readline] endif exe_jack_transport = executable( 'jack_transport', c_args: jack_transport_c_args, sources: ['transport.c'], dependencies: jack_transport_deps, install: true ) exe_jack_tw = executable( 'jack_tw', sources: ['tw.c'], dependencies: [dep_jack], install: true ) exe_jack_wait = executable( 'jack_wait', c_args: c_args_common, sources: ['wait.c'], dependencies: [dep_jack], install: true ) if build_zalsa subdir('zalsa') endif 07070100000052000081A400000000000000000000000161E2F7EE0000163D000000000000000000000000000000000000002700000000jack-example-tools-1/tools/midi_dump.c// gcc -o jack_midi_dump -Wall midi_dump.c -ljack -pthread #include <stdio.h> #include <string.h> #include <unistd.h> #include <assert.h> #include <inttypes.h> #include <jack/jack.h> #include <jack/midiport.h> #include <jack/ringbuffer.h> #ifdef __MINGW32__ #include <pthread.h> #endif #ifndef WIN32 #include <signal.h> #include <pthread.h> #include <sys/mman.h> #endif static jack_port_t* port; static jack_ringbuffer_t *rb = NULL; static pthread_mutex_t msg_thread_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER; static int keeprunning = 1; static uint64_t monotonic_cnt = 0; #define RBSIZE 100 #define MSG_BUFFER_SIZE 4096 typedef struct { uint8_t buffer[MSG_BUFFER_SIZE]; uint32_t size; uint32_t tme_rel; uint64_t tme_mon; } midimsg; static void describe (midimsg* event) { if (event->size == 0) { return; } uint8_t type = event->buffer[0] & 0xf0; uint8_t channel = event->buffer[0] & 0xf; switch (type) { case 0x90: assert (event->size == 3); printf (" note on (channel %2d): pitch %3d, velocity %3d", channel, event->buffer[1], event->buffer[2]); break; case 0x80: assert (event->size == 3); printf (" note off (channel %2d): pitch %3d, velocity %3d", channel, event->buffer[1], event->buffer[2]); break; case 0xb0: assert (event->size == 3); printf (" control change (channel %2d): controller %3d, value %3d", channel, event->buffer[1], event->buffer[2]); break; default: break; } } int process (jack_nframes_t frames, void* arg) { void* buffer; jack_nframes_t N; jack_nframes_t i; buffer = jack_port_get_buffer (port, frames); assert (buffer); N = jack_midi_get_event_count (buffer); for (i = 0; i < N; ++i) { jack_midi_event_t event; int r; r = jack_midi_event_get (&event, buffer, i); if (r != 0) {continue;} if (event.size > MSG_BUFFER_SIZE) { fprintf(stderr, "Error: MIDI message was too large, skipping event. Max. allowed size: %d bytes\n", MSG_BUFFER_SIZE); } else if (jack_ringbuffer_write_space (rb) >= sizeof(midimsg)) { midimsg m; m.tme_mon = monotonic_cnt; m.tme_rel = event.time; m.size = event.size; memcpy (m.buffer, event.buffer, event.size); jack_ringbuffer_write (rb, (void *) &m, sizeof(midimsg)); } else { fprintf (stderr, "Error: ringbuffer was full, skipping event.\n"); } } monotonic_cnt += frames; if (pthread_mutex_trylock (&msg_thread_lock) == 0) { pthread_cond_signal (&data_ready); pthread_mutex_unlock (&msg_thread_lock); } return 0; } static void wearedone(int sig) { fprintf(stderr, "Shutting down\n"); keeprunning = 0; /* main loop might be blocked by data_ready when jack server dies. */ if (pthread_mutex_trylock (&msg_thread_lock) == 0) { pthread_cond_signal (&data_ready); pthread_mutex_unlock (&msg_thread_lock); } } static void usage (int status) { printf ("jack_midi_dump - JACK MIDI Monitor.\n\n"); printf ("Usage: jack_midi_dump [ OPTIONS ] [CLIENT-NAME]\n\n"); printf ("Options:\n\ -a use absolute timestamps relative to application start\n\ -h display this help and exit\n\ -r use relative timestamps to previous MIDI event\n\ \n"); printf ("\n\ This tool listens for MIDI events on a JACK MIDI port and prints\n\ the message to stdout.\n\ \n\ If no client name is given it defaults to 'midi-monitor'.\n\ \n\ See also: jackd(1)\n\ \n"); exit (status); } int main (int argc, char* argv[]) { jack_client_t* client; char const default_name[] = "midi-monitor"; char const * client_name; int time_format = 0; int r; int cn = 1; if (argc > 1) { if (!strcmp (argv[1], "-a")) { time_format = 1; cn = 2; } else if (!strcmp (argv[1], "-r")) { time_format = 2; cn = 2; } else if (!strcmp (argv[1], "-h")) { usage (EXIT_SUCCESS); } else if (argv[1][0] == '-') { usage (EXIT_FAILURE); } } if (argc > cn) { client_name = argv[cn]; } else { client_name = default_name; } client = jack_client_open (client_name, JackNullOption, NULL); if (client == NULL) { fprintf (stderr, "Could not create JACK client.\n"); exit (EXIT_FAILURE); } rb = jack_ringbuffer_create (RBSIZE * sizeof(midimsg)); jack_set_process_callback (client, process, 0); port = jack_port_register (client, "input", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); if (port == NULL) { fprintf (stderr, "Could not register port.\n"); exit (EXIT_FAILURE); } #ifndef WIN32 if (mlockall (MCL_CURRENT | MCL_FUTURE)) { fprintf (stderr, "Warning: Can not lock memory.\n"); } #endif r = jack_activate (client); if (r != 0) { fprintf (stderr, "Could not activate client.\n"); exit (EXIT_FAILURE); } #ifndef WIN32 signal(SIGHUP, wearedone); signal(SIGINT, wearedone); #endif pthread_mutex_lock (&msg_thread_lock); uint64_t prev_event = 0; while (keeprunning) { const int mqlen = jack_ringbuffer_read_space (rb) / sizeof(midimsg); int i; for (i=0; i < mqlen; ++i) { size_t j; midimsg m; jack_ringbuffer_read(rb, (char*) &m, sizeof(midimsg)); switch(time_format) { case 1: printf ("%7"PRId64":", m.tme_rel + m.tme_mon); break; case 2: printf ("%+6"PRId64":", m.tme_rel + m.tme_mon - prev_event); break; default: printf ("%4d:", m.tme_rel); break; } for (j = 0; j < m.size && j < sizeof(m.buffer); ++j) { printf (" %02x", m.buffer[j]); } describe (&m); printf("\n"); prev_event = m.tme_rel + m.tme_mon; } fflush (stdout); pthread_cond_wait (&data_ready, &msg_thread_lock); } pthread_mutex_unlock (&msg_thread_lock); jack_deactivate (client); jack_client_close (client); jack_ringbuffer_free (rb); return 0; } 07070100000053000081A400000000000000000000000161E2F7EE0000068A000000000000000000000000000000000000002C00000000jack-example-tools-1/tools/monitor_client.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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <jack/jack.h> #define TRUE 1 #define FALSE 0 int main (int argc, char *argv[]) { jack_client_t *client; char *my_name = strrchr(argv[0], '/'); if (my_name == 0) { my_name = argv[0]; } else { my_name ++; } if (argc != 2) { fprintf (stderr, "Usage: %s client\n", my_name); return 1; } if ((client = jack_client_open ("input monitoring", JackNullOption, NULL)) == 0) { fprintf (stderr, "JACK server not running?\n"); return 1; } if (jack_port_request_monitor_by_name (client, argv[1], TRUE)) { fprintf (stderr, "could not enable monitoring for %s\n", argv[1]); jack_client_close (client); return 1; } #ifdef WIN32 Sleep (30*1000); #else sleep (30); #endif if (jack_port_request_monitor_by_name (client, argv[1], FALSE)) { fprintf (stderr, "could not disable monitoring for %s\n", argv[1]); } jack_client_close (client); exit (0); } 07070100000054000081A400000000000000000000000161E2F7EE000064FE000000000000000000000000000000000000002700000000jack-example-tools-1/tools/netsource.c/* NetJack Client Copyright (C) 2008 Marc-Olivier Barre <marco@marcochapeau.org> Copyright (C) 2008 Pieter Palmers <pieterpalmers@users.sourceforge.net> Copyright (C) 2006 Torben Hohn <torbenh@gmx.de> 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file netsource.c * * @brief This client connects a remote slave JACK to a local JACK server assumed to be the master */ #include <stdio.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <signal.h> #ifdef WIN32 #include <winsock2.h> #define socklen_t int #include <malloc.h> #else #include <netinet/in.h> #include <netdb.h> #include <sys/socket.h> #endif /* These two required by FreeBSD. */ #include <sys/types.h> #include <jack/jack.h> #include <netjack_packet.h> #include <samplerate.h> #ifndef CUSTOM_MODES #define CUSTOM_MODES // for opus_custom_decoder_init #endif #if HAVE_OPUS #include <opus/opus.h> #include <opus/opus_custom.h> #endif #include <math.h> JSList *capture_ports = NULL; JSList *capture_srcs = NULL; int capture_channels = 0; int capture_channels_audio = 2; int capture_channels_midi = 1; JSList *playback_ports = NULL; JSList *playback_srcs = NULL; int playback_channels = 0; int playback_channels_audio = 2; int playback_channels_midi = 1; int dont_htonl_floats = 0; int latency = 5; jack_nframes_t kbps = 0; int bitdepth = 0; int mtu = 1400; int reply_port = 0; int bind_port = 0; int redundancy = 1; jack_client_t *client; packet_cache * packcache = 0; int state_connected = 0; int state_latency = 0; int state_netxruns = 0; int state_currentframe = 0; int state_recv_packet_queue_time = 0; int quit = 0; int outsockfd; int insockfd; #ifdef WIN32 struct sockaddr_in destaddr; struct sockaddr_in bindaddr; #else struct sockaddr destaddr; struct sockaddr bindaddr; #endif int sync_state; jack_transport_state_t last_transport_state; int framecnt = 0; int cont_miss = 0; int freewheeling = 0; /** * This Function allocates all the I/O Ports which are added the lists. */ void alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int n_playback_midi) { int port_flags = JackPortIsOutput; int chn; jack_port_t *port; char buf[32]; capture_ports = NULL; /* Allocate audio capture channels */ for (chn = 0; chn < n_capture_audio; chn++) { snprintf (buf, sizeof (buf) - 1, "capture_%u", chn + 1); port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); if (!port) { printf( "jack_netsource: cannot register %s port\n", buf); break; } if (bitdepth == 999) { #if HAVE_OPUS int err; OpusCustomMode *opus_mode = opus_custom_mode_create(jack_get_sample_rate( client ), jack_get_buffer_size(client), &err); if (err != OPUS_OK) { printf("OPUS MODE FAILED\n"); } OpusCustomDecoder *decoder = opus_custom_decoder_create(opus_mode, 1, &err); if (err != OPUS_OK) { printf("OPUS DECODER FAILED\n"); } opus_custom_decoder_init(decoder, opus_mode, 1); capture_srcs = jack_slist_append(capture_srcs, decoder); #endif } else { capture_srcs = jack_slist_append (capture_srcs, src_new (SRC_LINEAR, 1, NULL)); } capture_ports = jack_slist_append (capture_ports, port); } /* Allocate midi capture channels */ for (chn = n_capture_audio; chn < n_capture_midi + n_capture_audio; chn++) { snprintf (buf, sizeof (buf) - 1, "capture_%u", chn + 1); port = jack_port_register (client, buf, JACK_DEFAULT_MIDI_TYPE, port_flags, 0); if (!port) { printf ("jack_netsource: cannot register %s port\n", buf); break; } capture_ports = jack_slist_append(capture_ports, port); } /* Allocate audio playback channels */ port_flags = JackPortIsInput; playback_ports = NULL; for (chn = 0; chn < n_playback_audio; chn++) { snprintf (buf, sizeof (buf) - 1, "playback_%u", chn + 1); port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); if (!port) { printf ("jack_netsource: cannot register %s port\n", buf); break; } if( bitdepth == 999 ) { #if HAVE_OPUS printf("new opus encoder %d kbps\n", kbps); int err; OpusCustomMode *opus_mode = opus_custom_mode_create(jack_get_sample_rate (client), jack_get_buffer_size(client), &err ); // XXX free me if (err != OPUS_OK) { printf("OPUS MODE FAILED\n"); } OpusCustomEncoder *oe = opus_custom_encoder_create( opus_mode, 1, &err ); if (err != OPUS_OK) { printf("OPUS ENCODER FAILED\n"); } opus_custom_encoder_ctl(oe, OPUS_SET_BITRATE(kbps*1024)); // bits per second opus_custom_encoder_ctl(oe, OPUS_SET_COMPLEXITY(10)); opus_custom_encoder_ctl(oe, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); opus_custom_encoder_ctl(oe, OPUS_SET_SIGNAL(OPUS_APPLICATION_RESTRICTED_LOWDELAY)); opus_custom_encoder_init(oe, opus_mode, 1); playback_srcs = jack_slist_append(playback_srcs, oe); #endif } else { playback_srcs = jack_slist_append (playback_srcs, src_new (SRC_LINEAR, 1, NULL)); } playback_ports = jack_slist_append (playback_ports, port); } /* Allocate midi playback channels */ for (chn = n_playback_audio; chn < n_playback_midi + n_playback_audio; chn++) { snprintf (buf, sizeof (buf) - 1, "playback_%u", chn + 1); port = jack_port_register (client, buf, JACK_DEFAULT_MIDI_TYPE, port_flags, 0); if (!port) { printf ("jack_netsource: cannot register %s port\n", buf); break; } playback_ports = jack_slist_append (playback_ports, port); } } /** * The Sync callback... sync state is set elsewhere... * we will see if this is working correctly. * i don't really believe in it yet. */ int sync_cb (jack_transport_state_t state, jack_position_t *pos, void *arg) { static int latency_count = 0; int retval = sync_state; if (! state_connected) { return 1; } if (latency_count) { latency_count--; retval = 0; } else if (state == JackTransportStarting && last_transport_state != JackTransportStarting) { retval = 0; latency_count = latency - 1; } last_transport_state = state; return retval; } void freewheel_cb (int starting, void *arg) { freewheeling = starting; } int deadline_goodness = 0; /** * The process callback for this JACK application. * It is called by JACK at the appropriate times. */ int process (jack_nframes_t nframes, void *arg) { jack_nframes_t net_period; int rx_bufsize, tx_bufsize; jack_default_audio_sample_t *buf; jack_port_t *port; JSList *node; int chn; int size, i; const char *porttype; int input_fd; jack_position_t local_trans_pos; uint32_t *packet_buf_tx, *packet_bufX; uint32_t *rx_packet_ptr; jack_time_t packet_recv_timestamp; if( bitdepth == 999) net_period = (kbps * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8) & (~1) ; else net_period = (float) nframes; rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header); tx_bufsize = get_sample_size (bitdepth) * playback_channels * net_period + sizeof (jacknet_packet_header); /* Allocate a buffer where both In and Out Buffer will fit */ packet_buf_tx = alloca (tx_bufsize); jacknet_packet_header *pkthdr_tx = (jacknet_packet_header *) packet_buf_tx; /* * for latency==0 we need to send out the packet before we wait on the reply. * but this introduces a cycle of latency, when netsource is connected to itself. * so we send out before read only in zero latency mode. * */ if( latency == 0 ) { /* reset packet_bufX... */ packet_bufX = packet_buf_tx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t); /* ---------- Send ---------- */ render_jack_ports_to_payload (bitdepth, playback_ports, playback_srcs, nframes, packet_bufX, net_period, dont_htonl_floats); /* fill in packet hdr */ pkthdr_tx->transport_state = jack_transport_query (client, &local_trans_pos); pkthdr_tx->transport_frame = local_trans_pos.frame; pkthdr_tx->framecnt = framecnt; pkthdr_tx->latency = latency; pkthdr_tx->reply_port = reply_port; pkthdr_tx->sample_rate = jack_get_sample_rate (client); pkthdr_tx->period_size = nframes; /* playback for us is capture on the other side */ pkthdr_tx->capture_channels_audio = playback_channels_audio; pkthdr_tx->playback_channels_audio = capture_channels_audio; pkthdr_tx->capture_channels_midi = playback_channels_midi; pkthdr_tx->playback_channels_midi = capture_channels_midi; pkthdr_tx->mtu = mtu; if( freewheeling != 0 ) pkthdr_tx->sync_state = (jack_nframes_t)MASTER_FREEWHEELS; else pkthdr_tx->sync_state = (jack_nframes_t)deadline_goodness; //printf("goodness=%d\n", deadline_goodness ); packet_header_hton (pkthdr_tx); if (cont_miss < 3 * latency + 5) { int r; for( r = 0; r < redundancy; r++ ) netjack_sendto (outsockfd, (char *) packet_buf_tx, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu); } else if (cont_miss > 50 + 5 * latency) { state_connected = 0; packet_cache_reset_master_address( packcache ); //printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss); cont_miss = 0; } } /* * ok... now the RECEIVE code. * */ if( reply_port ) input_fd = insockfd; else input_fd = outsockfd; // for latency == 0 we can poll. if( (latency == 0) || (freewheeling != 0) ) { jack_time_t deadline = jack_get_time() + 1000000 * jack_get_buffer_size(client) / jack_get_sample_rate(client); // Now loop until we get the right packet. while(1) { jack_nframes_t got_frame; if ( ! netjack_poll_deadline( input_fd, deadline ) ) break; packet_cache_drain_socket(packcache, input_fd); if (packet_cache_get_next_available_framecnt( packcache, framecnt - latency, &got_frame )) if( got_frame == (framecnt - latency) ) break; } } else { // normally: // only drain socket. packet_cache_drain_socket(packcache, input_fd); } size = packet_cache_retreive_packet_pointer( packcache, framecnt - latency, (char**)&rx_packet_ptr, rx_bufsize, &packet_recv_timestamp ); /* First alternative : we received what we expected. Render the data * to the JACK ports so it can be played. */ if (size == rx_bufsize) { uint32_t *packet_buf_rx = rx_packet_ptr; jacknet_packet_header *pkthdr_rx = (jacknet_packet_header *) packet_buf_rx; packet_bufX = packet_buf_rx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t); // calculate how much time there would have been, if this packet was sent at the deadline. int recv_time_offset = (int) (jack_get_time() - packet_recv_timestamp); packet_header_ntoh (pkthdr_rx); deadline_goodness = recv_time_offset - (int)pkthdr_rx->latency; //printf( "deadline goodness = %d ---> off: %d\n", deadline_goodness, recv_time_offset ); if (cont_miss) { //printf("Frame %d \tRecovered from dropouts\n", framecnt); cont_miss = 0; } render_payload_to_jack_ports (bitdepth, packet_bufX, net_period, capture_ports, capture_srcs, nframes, dont_htonl_floats); state_currentframe = framecnt; state_recv_packet_queue_time = recv_time_offset; state_connected = 1; sync_state = pkthdr_rx->sync_state; packet_cache_release_packet( packcache, framecnt - latency ); } /* Second alternative : we've received something that's not * as big as expected or we missed a packet. We render silence * to the output ports */ else { jack_nframes_t latency_estimate; if( packet_cache_find_latency( packcache, framecnt, &latency_estimate ) ) //if( (state_latency == 0) || (latency_estimate < state_latency) ) state_latency = latency_estimate; // Set the counters up. state_currentframe = framecnt; //state_latency = framecnt - pkthdr->framecnt; state_netxruns += 1; //printf ("Frame %d \tPacket missed or incomplete (expected: %d bytes, got: %d bytes)\n", framecnt, rx_bufsize, size); //printf ("Frame %d \tPacket missed or incomplete\n", framecnt); cont_miss += 1; chn = 0; node = capture_ports; while (node != NULL) { port = (jack_port_t *) node->data; buf = jack_port_get_buffer (port, nframes); porttype = jack_port_type (port); if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size ()) == 0) for (i = 0; i < nframes; i++) buf[i] = 0.0; else if (strncmp (porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size ()) == 0) jack_midi_clear_buffer (buf); node = jack_slist_next (node); chn++; } } if (latency != 0) { /* reset packet_bufX... */ packet_bufX = packet_buf_tx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t); /* ---------- Send ---------- */ render_jack_ports_to_payload (bitdepth, playback_ports, playback_srcs, nframes, packet_bufX, net_period, dont_htonl_floats); /* fill in packet hdr */ pkthdr_tx->transport_state = jack_transport_query (client, &local_trans_pos); pkthdr_tx->transport_frame = local_trans_pos.frame; pkthdr_tx->framecnt = framecnt; pkthdr_tx->latency = latency; pkthdr_tx->reply_port = reply_port; pkthdr_tx->sample_rate = jack_get_sample_rate (client); pkthdr_tx->period_size = nframes; /* playback for us is capture on the other side */ pkthdr_tx->capture_channels_audio = playback_channels_audio; pkthdr_tx->playback_channels_audio = capture_channels_audio; pkthdr_tx->capture_channels_midi = playback_channels_midi; pkthdr_tx->playback_channels_midi = capture_channels_midi; pkthdr_tx->mtu = mtu; if( freewheeling != 0 ) pkthdr_tx->sync_state = (jack_nframes_t)MASTER_FREEWHEELS; else pkthdr_tx->sync_state = (jack_nframes_t)deadline_goodness; //printf("goodness=%d\n", deadline_goodness ); packet_header_hton (pkthdr_tx); if (cont_miss < 3 * latency + 5) { int r; for( r = 0; r < redundancy; r++ ) netjack_sendto (outsockfd, (char *) packet_buf_tx, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu); } else if (cont_miss > 50 + 5 * latency) { state_connected = 0; packet_cache_reset_master_address( packcache ); //printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss); cont_miss = 0; } } framecnt++; return 0; } /** * This is the shutdown callback for this JACK application. * It is called by JACK if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit (1); } void init_sockaddr_in (struct sockaddr_in *name , const char *hostname , uint16_t port) { name->sin_family = AF_INET ; name->sin_port = htons (port); if (hostname) { struct hostent *hostinfo = gethostbyname (hostname); if (hostinfo == NULL) { fprintf (stderr, "init_sockaddr_in: unknown host: %s.\n", hostname); fflush( stderr ); } #ifdef WIN32 name->sin_addr.s_addr = inet_addr( hostname ); #else name->sin_addr = *(struct in_addr *) hostinfo->h_addr ; #endif } else name->sin_addr.s_addr = htonl (INADDR_ANY) ; } void printUsage () { fprintf (stderr, "usage: jack_netsource [options]\n" "\n" " -h this help text\n" " -H <slave host> - Host name of the slave JACK\n" " -o <num channels> - Number of audio playback channels\n" " -i <num channels> - Number of audio capture channels\n" " -O <num channels> - Number of midi playback channels\n" " -I <num channels> - Number of midi capture channels\n" " -n <periods> - Network latency in JACK periods\n" " -p <port> - UDP port that the slave is listening on\n" " -r <reply port> - UDP port that we are listening on\n" " -B <bind port> - reply port, for use in NAT environments\n" " -b <bitdepth> - Set transport to use 16bit or 8bit\n" " -P <kbits> - Use Opus encoding with <kbits> kbits per channel\n" " -m <mtu> - Assume this mtu for the link\n" " -R <N> - Redundancy: send out packets N times.\n" " -e - skip host-to-network endianness conversion\n" " -N <jack name> - Reports a different name to jack\n" " -s <server name> - The name of the local jack server\n" "\n"); } void sigterm_handler( int signal ) { quit = 1; } int main (int argc, char *argv[]) { /* Some startup related basics */ char *client_name, *server_name = NULL, *peer_ip; int peer_port = 3000; jack_options_t options = JackNullOption; jack_status_t status; #ifdef WIN32 WSADATA wsa; int rc = WSAStartup(MAKEWORD(2, 0), &wsa); #endif /* Torben's famous state variables, aka "the reporting API" ! */ /* heh ? these are only the copies of them ;) */ int statecopy_connected, statecopy_latency, statecopy_netxruns; jack_nframes_t net_period; /* Argument parsing stuff */ extern char *optarg; extern int optind, optopt; int errflg = 0, c; if (argc < 3) { printUsage (); return 1; } client_name = (char *) malloc (sizeof (char) * 10); peer_ip = (char *) malloc (sizeof (char) * 10); sprintf(client_name, "netjack"); sprintf(peer_ip, "localhost"); while ((c = getopt (argc, argv, ":h:H:o:i:O:I:n:p:r:B:b:c:m:R:e:N:s:P:")) != -1) { switch (c) { case 'h': printUsage(); exit (0); break; case 'H': free(peer_ip); peer_ip = (char *) malloc (sizeof (char) * strlen (optarg) + 1); strcpy (peer_ip, optarg); break; case 'o': playback_channels_audio = atoi (optarg); break; case 'i': capture_channels_audio = atoi (optarg); break; case 'O': playback_channels_midi = atoi (optarg); break; case 'I': capture_channels_midi = atoi (optarg); break; case 'n': latency = atoi (optarg); break; case 'p': peer_port = atoi (optarg); break; case 'r': reply_port = atoi (optarg); break; case 'B': bind_port = atoi (optarg); break; case 'b': bitdepth = atoi (optarg); break; case 'P': #if HAVE_OPUS bitdepth = 999; kbps = atoi (optarg); #else printf( "not built with opus support\n" ); exit(10); #endif break; case 'm': mtu = atoi (optarg); break; case 'R': redundancy = atoi (optarg); break; case 'e': dont_htonl_floats = 1; break; case 'N': free(client_name); client_name = (char *) malloc (sizeof (char) * strlen (optarg) + 1); strcpy (client_name, optarg); break; case 's': server_name = (char *) malloc (sizeof (char) * strlen (optarg) + 1); strcpy (server_name, optarg); options |= JackServerName; break; case ':': fprintf (stderr, "Option -%c requires an operand\n", optopt); errflg++; break; case '?': fprintf (stderr, "Unrecognized option: -%c\n", optopt); errflg++; } } if (errflg) { printUsage (); exit (2); } capture_channels = capture_channels_audio + capture_channels_midi; playback_channels = playback_channels_audio + playback_channels_midi; outsockfd = socket (AF_INET, SOCK_DGRAM, 0); insockfd = socket (AF_INET, SOCK_DGRAM, 0); if ((outsockfd == -1) || (insockfd == -1)) { fprintf (stderr, "can not open sockets\n" ); return 1; } init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port); if (bind_port) { init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, bind_port); if( bind (outsockfd, &bindaddr, sizeof (bindaddr)) ) { fprintf (stderr, "bind failure\n" ); } } if (reply_port) { init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port); if( bind (insockfd, &bindaddr, sizeof (bindaddr)) ) { fprintf (stderr, "bind failure\n" ); } } /* try to become a client of the JACK server */ client = jack_client_open (client_name, options, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, status = 0x%2.0x\n" "Is the JACK server running ?\n", status); return 1; } /* Set up jack callbacks */ jack_set_process_callback (client, process, 0); jack_set_sync_callback (client, sync_cb, 0); jack_set_freewheel_callback (client, freewheel_cb, 0); jack_on_shutdown (client, jack_shutdown, 0); alloc_ports (capture_channels_audio, playback_channels_audio, capture_channels_midi, playback_channels_midi); if( bitdepth == 999) net_period = (kbps * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8) & (~1) ; else net_period = ceilf((float) jack_get_buffer_size (client)); int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header); packcache = packet_cache_new (latency + 50, rx_bufsize, mtu); /* tell the JACK server that we are ready to roll */ if (jack_activate (client)) { fprintf (stderr, "Cannot activate client"); return 1; } /* Now sleep forever... and evaluate the state_ vars */ signal( SIGTERM, sigterm_handler ); signal( SIGINT, sigterm_handler ); statecopy_connected = 2; // make it report unconnected on start. statecopy_latency = state_latency; statecopy_netxruns = state_netxruns; while ( !quit ) { #ifdef WIN32 Sleep (1000); #else sleep(1); #endif if (statecopy_connected != state_connected) { statecopy_connected = state_connected; if (statecopy_connected) { state_netxruns = 1; // We want to reset the netxrun count on each new connection printf ("Connected :-)\n"); } else printf ("Not Connected\n"); fflush(stdout); } if (statecopy_connected) { if (statecopy_netxruns != state_netxruns) { statecopy_netxruns = state_netxruns; printf ("%s: at frame %06d -> total netxruns %d (%d%%) queue time= %d\n", client_name, state_currentframe, statecopy_netxruns, 100 * statecopy_netxruns / state_currentframe, state_recv_packet_queue_time); fflush(stdout); } } else { if (statecopy_latency != state_latency) { statecopy_latency = state_latency; if (statecopy_latency > 1) printf ("current latency %d\n", statecopy_latency); fflush(stdout); } } } jack_client_close (client); packet_cache_free (packcache); exit (0); } 07070100000055000081A400000000000000000000000161E2F7EE00001C0C000000000000000000000000000000000000002600000000jack-example-tools-1/tools/property.c#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <getopt.h> #include <jack/jack.h> #include <jack/metadata.h> #include <jack/uuid.h> #include <jack/session.h> static int subject_is_client = 0; static int subject_is_port = 0; static jack_uuid_t uuid = JACK_UUID_EMPTY_INITIALIZER; static char* subject = NULL; static void show_usage (void) { fprintf (stderr, "\nUsage: jack_property [options] UUID [ key [ value [ type ] ] ]\n"); fprintf (stderr, "Set/Display JACK properties (metadata).\n\n"); fprintf (stderr, "Set options:\n"); fprintf (stderr, " -s, --set Set property \"key\" to \"value\" for \"UUID\" with optional MIME type \"type\"\n"); fprintf (stderr, " -d, --delete Remove/delete property \"key\" for \"UUID\"\n"); fprintf (stderr, " -d, --delete UUID Remove/delete all properties for \"UUID\"\n"); fprintf (stderr, " -D, --delete-all Remove/delete all properties\n"); fprintf (stderr, " --client Interpret UUID as a client name, not a UUID\n"); fprintf (stderr, " --port Interpret UUID as a port name, not a UUID\n"); fprintf (stderr, "\nDisplay options:\n"); fprintf (stderr, " -l Show all properties\n"); fprintf (stderr, " -l, --list UUID Show value for all properties of UUID\n"); fprintf (stderr, " -l, --list UUID key Show value for key of UUID\n"); fprintf (stderr, "\nFor more information see https://jackaudio.org/\n"); } static int get_subject (jack_client_t* client, char* argv[], int* optind) { if (subject_is_client) { char* cstr = argv[(*optind)++]; char* ustr; if ((ustr = jack_get_uuid_for_client_name (client, cstr)) == NULL) { fprintf (stderr, "cannot get UUID for client named %s\n", cstr); return -1; } if (jack_uuid_parse (ustr, &uuid)) { fprintf (stderr, "cannot parse client UUID as UUID '%s' '%s'\n", cstr, ustr); return -1; } subject = cstr; } else if (subject_is_port) { char* pstr = argv[(*optind)++]; jack_port_t* port; if ((port = jack_port_by_name (client, pstr)) == NULL) { fprintf (stderr, "cannot find port name %s\n", pstr); return -1; } uuid = jack_port_uuid (port); subject = pstr; } else { char* str = argv[(*optind)++]; if (jack_uuid_parse (str, &uuid)) { fprintf (stderr, "cannot parse subject as UUID\n"); return -1; } subject = str; } return 0; } int main (int argc, char* argv[]) { jack_client_t* client = NULL; jack_options_t options = JackNoStartServer; char* key = NULL; char* value = NULL; char* type = NULL; int set = 1; int delete = 0; int delete_all = 0; int c; int option_index; extern int optind; struct option long_options[] = { { "set", 0, 0, 's' }, { "delete", 0, 0, 'd' }, { "delete-all", 0, 0, 'D' }, { "list", 0, 0, 'l' }, { "client", 0, 0, 'c' }, { "port", 0, 0, 'p' }, { 0, 0, 0, 0 } }; if (argc < 2) { show_usage (); exit (1); } while ((c = getopt_long (argc, argv, "sdDlApc", long_options, &option_index)) >= 0) { switch (c) { case 's': if (argc < 5) { show_usage (); exit (1); } set = 1; break; case 'd': if (argc < 3) { show_usage (); return 1; } set = 0; delete = 1; break; case 'D': delete = 0; set = 0; delete_all = 1; break; case 'l': set = 0; delete = 0; delete_all = 0; break; case 'p': subject_is_port = 1; break; case 'c': subject_is_client = 1; break; case '?': default: show_usage (); exit (1); } } if ((client = jack_client_open ("jack-property", options, NULL)) == 0) { fprintf (stderr, "Cannot connect to JACK server\n"); exit (1); } if (delete_all) { if (jack_remove_all_properties (client) == 0) { printf ("JACK metadata successfully delete\n"); exit (0); } exit (1); } if (delete) { int args_left = argc - optind; if (args_left < 1) { show_usage (); exit (1); } /* argc == 3: delete all properties for a subject argc == 4: delete value of key for subject */ if (args_left >= 2) { if (get_subject (client, argv, &optind)) { return 1; } key = argv[optind++]; if (jack_remove_property (client, uuid, key)) { fprintf (stderr, "\"%s\" property not removed for %s\n", key, subject); exit (1); } } else { if (get_subject (client, argv, &optind)) { return 1; } if (jack_remove_properties (client, uuid) < 0) { fprintf (stderr, "cannot remove properties for UUID %s\n", subject); exit (1); } } } else if (set) { int args_left = argc - optind; if (get_subject (client, argv, &optind)) { return -1; } key = argv[optind++]; value = argv[optind++]; if (args_left >= 3) { type = argv[optind++]; } else { type = ""; } if (jack_set_property (client, uuid, key, value, type)) { fprintf (stderr, "cannot set value for key %s of %s\n", key, subject); exit (1); } } else { /* list properties */ int args_left = argc - optind; if (args_left >= 2) { /* list properties for a UUID/key pair */ if (get_subject (client, argv, &optind)) { return -1; } key = argv[optind++]; if (jack_get_property (uuid, key, &value, &type) == 0) { printf ("%s\n", value); free (value); if (type) { free (type); } } else { fprintf (stderr, "Value not found for %s of %s\n", key, subject); exit (1); } } else if (args_left == 1) { /* list all properties for a given UUID */ jack_description_t description; int cnt, n; if (get_subject (client, argv, &optind)) { return -1; } if ((cnt = jack_get_properties (uuid, &description)) < 0) { fprintf (stderr, "could not retrieve properties for %s\n", subject); exit (1); } for (n = 0; n < cnt; ++n) { if (description.properties[n].type) { printf ("key: %s value: %s type: %s\n", description.properties[n].key, description.properties[n].data, description.properties[n].type); } else { printf ("key: %s value: %s\n", description.properties[n].key, description.properties[n].data); } } jack_free_description (&description, 0); } else { /* list all properties */ jack_description_t* description; int cnt, n; size_t p; char buf[JACK_UUID_STRING_SIZE]; if ((cnt = jack_get_all_properties (&description)) < 0) { fprintf (stderr, "could not retrieve all properties\n"); exit (1); } for (n = 0; n < cnt; ++n) { jack_uuid_unparse (description[n].subject, buf); printf ("%s\n", buf); for (p = 0; p < description[n].property_cnt; ++p) { if (description[n].properties[p].type) { printf ("key: %s value: %s type: %s\n", description[n].properties[p].key, description[n].properties[p].data, description[n].properties[p].type); } else { printf ("key: %s value: %s\n", description[n].properties[p].key, description[n].properties[p].data); } } jack_free_description (&description[n], 0); } free (description); } } jack_client_close (client); return 0; } 07070100000056000081A400000000000000000000000161E2F7EE00000806000000000000000000000000000000000000002800000000jack-example-tools-1/tools/samplerate.c/* * smaplerate.c -- get current samplerate * * Copyright (C) 2003 Jack O'Quin. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <errno.h> #ifndef WIN32 #include <unistd.h> #endif #include <signal.h> #include <stdlib.h> #include <string.h> #include <jack/jack.h> #include <jack/transport.h> char *package; /* program name */ jack_client_t *client; void jack_shutdown(void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } void parse_arguments(int argc, char *argv[]) { /* basename $0 */ package = strrchr(argv[0], '/'); if (package == 0) package = argv[0]; else package++; if (argc==1) { return; } fprintf(stderr, "usage: %s\n", package); exit(9); } int main(int argc, char *argv[]) { parse_arguments(argc, argv); /* become a JACK client */ if ((client = jack_client_open(package, JackNullOption, NULL)) == 0) { fprintf(stderr, "JACK server not running?\n"); exit(1); } #ifndef WIN32 signal(SIGQUIT, signal_handler); signal(SIGHUP, signal_handler); #endif signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); jack_on_shutdown(client, jack_shutdown, 0); fprintf(stdout, "%d\n", jack_get_sample_rate( client ) ); jack_client_close(client); return 0; } 07070100000057000081A400000000000000000000000161E2F7EE0000125E000000000000000000000000000000000000002C00000000jack-example-tools-1/tools/session_notify.c/* * session_notify.c -- ultra minimal session manager * * Copyright (C) 2018 Karl Linden <karl.j.linden@gmail.com> * Copyright (C) 2010 Torben Hohn. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <alloca.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <jack/jack.h> #include <jack/jslist.h> #include <jack/transport.h> #include <jack/session.h> char *package; /* program name */ jack_client_t *client; jack_session_event_type_t notify_type; char *save_path = NULL; void jack_shutdown(void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } void parse_arguments(int argc, char *argv[]) { /* basename $0 */ package = strrchr(argv[0], '/'); if (package == 0) package = argv[0]; else package++; if (argc==2) { if( !strcmp( argv[1], "quit" ) ) { notify_type = JackSessionSaveAndQuit; return; } } if (argc==3) { if( !strcmp( argv[1], "save" ) ) { notify_type = JackSessionSave; save_path = argv[2]; return; } } fprintf(stderr, "usage: %s quit|save [path]\n", package); exit(9); } typedef struct { char name[32]; char uuid[16]; } uuid_map_t; JSList *uuid_map = NULL; void add_uuid_mapping( const char *uuid ) { char *clientname = jack_get_client_name_by_uuid( client, uuid ); if( !clientname ) { printf( "error... can not find client for uuid" ); return; } uuid_map_t *mapping = malloc( sizeof(uuid_map_t) ); snprintf( mapping->uuid, sizeof(mapping->uuid), "%s", uuid ); snprintf( mapping->name, sizeof(mapping->name), "%s", clientname ); uuid_map = jack_slist_append( uuid_map, mapping ); } char *map_port_name_to_uuid_port( const char *port_name ) { JSList *node; char retval[300]; char *port_component = strchr( port_name,':' ); char *client_component = strdup( port_name ); strchr( client_component, ':' )[0] = '\0'; sprintf( retval, "%s", port_name ); for( node=uuid_map; node; node=jack_slist_next(node) ) { uuid_map_t *mapping = node->data; if( !strcmp( mapping->name, client_component ) ) { sprintf( retval, "%s%s", mapping->uuid, port_component ); break; } } return strdup(retval); } int main(int argc, char *argv[]) { parse_arguments(argc, argv); jack_session_command_t *retval; int k,i,j; /* become a JACK client */ if ((client = jack_client_open(package, JackNullOption, NULL)) == 0) { fprintf(stderr, "JACK server not running?\n"); exit(1); } #ifndef WIN32 signal(SIGQUIT, signal_handler); signal(SIGHUP, signal_handler); #endif signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); jack_on_shutdown(client, jack_shutdown, 0); jack_activate(client); retval = jack_session_notify( client, NULL, notify_type, save_path ); for (i = 0; retval[i].uuid; i++) { printf( "export SESSION_DIR=\"%s%s/\"\n", save_path, retval[i].client_name ); printf( "%s &\n", retval[i].command ); add_uuid_mapping(retval[i].uuid); } printf( "sleep 10\n" ); for (k = 0; retval[k].uuid; k++) { char* port_regexp = alloca( jack_client_name_size()+3 ); char* client_name = jack_get_client_name_by_uuid( client, retval[k].uuid ); snprintf( port_regexp, jack_client_name_size()+3, "%s:.*", client_name ); jack_free(client_name); const char **ports = jack_get_ports( client, port_regexp, NULL, 0 ); if( !ports ) { continue; } for (i = 0; ports[i]; ++i) { const char **connections; if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) { for (j = 0; connections[j]; j++) { char *src = map_port_name_to_uuid_port( ports[i] ); char *dst = map_port_name_to_uuid_port( connections[j] ); printf( "jack_connect -u \"%s\" \"%s\"\n", src, dst ); } jack_free (connections); } } jack_free(ports); } jack_session_commands_free(retval); jack_client_close(client); return 0; } 07070100000058000081A400000000000000000000000161E2F7EE00003133000000000000000000000000000000000000002700000000jack-example-tools-1/tools/transport.c/* * transport.c -- JACK transport master example client. * * Copyright (C) 2003 Jack O'Quin. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <errno.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <string.h> #if HAVE_READLINE #include <readline/readline.h> #include <readline/history.h> #endif #include <jack/jack.h> #include <jack/transport.h> /* Use a copy of the readline macro whitespace if it does not exist. * Not all readline compatible libraries supply the whitespace macro * (libedit for example), so pull in the copy in those cases too. */ #if !HAVE_READLINE || !defined(whitespace) #define whitespace(c) (((c) == ' ') || ((c) == '\t')) #endif char *package; /* program name */ int done = 0; jack_client_t *client; double last_tick; /* Time and tempo variables. These are global to the entire, * transport timeline. There is no attempt to keep a true tempo map. * The default time signature is: "march time", 4/4, 120bpm */ float time_beats_per_bar = 4.0; float time_beat_type = 4.0; double time_ticks_per_beat = 1920.0; double time_beats_per_minute = 120.0; volatile int time_reset = 1; /* true when time values change */ volatile int avr_set = 0; float audio_frames_per_video_frame; /* JACK timebase callback. * * Runs in the process thread. Realtime, must not wait. */ static void timebase(jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void *arg) { double min; /* minutes since frame 0 */ long abs_tick; /* ticks since frame 0 */ long abs_beat; /* beats since frame 0 */ if (new_pos || time_reset) { pos->valid = JackPositionBBT; pos->beats_per_bar = time_beats_per_bar; pos->beat_type = time_beat_type; pos->ticks_per_beat = time_ticks_per_beat; pos->beats_per_minute = time_beats_per_minute; time_reset = 0; /* time change complete */ /* Compute BBT info from frame number. This is relatively * simple here, but would become complex if we supported tempo * or time signature changes at specific locations in the * transport timeline. */ min = pos->frame / ((double) pos->frame_rate * 60.0); abs_tick = min * pos->beats_per_minute * pos->ticks_per_beat; abs_beat = abs_tick / pos->ticks_per_beat; pos->bar = abs_beat / pos->beats_per_bar; pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1; last_tick = abs_tick - (abs_beat * pos->ticks_per_beat); pos->bar_start_tick = pos->bar * pos->beats_per_bar * pos->ticks_per_beat; pos->bar++; /* adjust start to bar 1 */ #if 0 /* some debug code... */ fprintf(stderr, "\nnew position: %" PRIu32 "\tBBT: %3" PRIi32 "|%" PRIi32 "|%04" PRIi32 "\n", pos->frame, pos->bar, pos->beat, last_tick); #endif } else { /* Compute BBT info based on previous period. */ last_tick += nframes * pos->ticks_per_beat * pos->beats_per_minute / (pos->frame_rate * 60); while (last_tick >= pos->ticks_per_beat) { last_tick -= pos->ticks_per_beat; if (++pos->beat > pos->beats_per_bar) { pos->beat = 1; ++pos->bar; pos->bar_start_tick += pos->beats_per_bar * pos->ticks_per_beat; } } } pos->tick = (int)(last_tick + 0.5); #ifdef JACK_TICK_DOUBLE pos->valid |= JackTickDouble; pos->tick_double = last_tick; #endif if (avr_set) { pos->valid |= JackAudioVideoRatio; pos->audio_frames_per_video_frame = audio_frames_per_video_frame; } } static int jack_process(jack_nframes_t nframes, void *arg) { return 0; } static void jack_shutdown(void *arg) { #if defined(RL_READLINE_VERSION) && RL_READLINE_VERSION >= 0x0400 rl_cleanup_after_signal(); #endif fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } static void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } /* Command functions: see commands[] table following. */ static void com_activate(char *arg) { if (jack_activate(client)) { fprintf(stderr, "cannot activate client"); } } static void com_deactivate(char *arg) { if (jack_deactivate(client)) { fprintf(stderr, "cannot deactivate client"); } } static void com_exit(char *arg) { done = 1; } static void com_help(char *); /* forward declaration */ static void com_locate(char *arg) { jack_nframes_t frame = 0; if (*arg != '\0') frame = atoi(arg); jack_transport_locate(client, frame); } static void com_master(char *arg) { int cond = (*arg != '\0'); if (jack_set_timebase_callback(client, cond, timebase, NULL) != 0) fprintf(stderr, "Unable to take over timebase.\n"); } static void com_play(char *arg) { jack_transport_start(client); } static void com_release(char *arg) { jack_release_timebase(client); } static void com_stop(char *arg) { jack_transport_stop(client); } /* Change the tempo for the entire timeline, not just from the current * location. */ static void com_tempo(char *arg) { float tempo = 120.0; if (*arg != '\0') tempo = atof(arg); time_beats_per_minute = tempo; time_reset = 1; } /* Set sync timeout in seconds. */ static void com_timeout(char *arg) { double timeout = 2.0; if (*arg != '\0') timeout = atof(arg); jack_set_sync_timeout(client, (jack_time_t) (timeout*1000000)); } /* Toggle between play and stop state */ static void com_toggle(char *arg) { jack_position_t current; jack_transport_state_t transport_state; transport_state = jack_transport_query (client, ¤t); switch (transport_state) { case JackTransportStopped: com_play( arg ); break; case JackTransportRolling: com_stop( arg ); break; case JackTransportStarting: fprintf(stderr, "state: Starting - no transport toggling"); break; default: fprintf(stderr, "unexpected state: no transport toggling"); } } /* Change the tempo for the entire timeline, not just from the current * location. */ void com_av_ratio(char *arg) { float avr = 0; if (*arg != '\0') avr = atof(arg); audio_frames_per_video_frame = avr; avr_set = 1; } /* Command parsing based on GNU readline info examples. */ typedef void cmd_function_t(char *); /* command function type */ /* Transport command table. */ typedef struct { char *name; /* user printable name */ cmd_function_t *func; /* function to call */ char *doc; /* documentation */ } command_t; /* command table must be in alphabetical order */ command_t commands[] = { {"activate", com_activate, "Call jack_activate()"}, {"avr", com_av_ratio, "Set audio/video frame ratio <audio frames per video frame>"}, {"exit", com_exit, "Exit transport program"}, {"deactivate", com_deactivate, "Call jack_deactivate()"}, {"help", com_help, "Display help text [<command>]"}, {"locate", com_locate, "Locate to frame <position>"}, {"master", com_master, "Become timebase master " "[<conditionally>]"}, {"play", com_play, "Start transport rolling"}, {"quit", com_exit, "Synonym for `exit'"}, {"release", com_release, "Release timebase"}, {"stop", com_stop, "Stop transport"}, {"tempo", com_tempo, "Set beat tempo <beats_per_min>"}, {"timeout", com_timeout, "Set sync timeout in <seconds>"}, {"toggle", com_toggle, "Toggle transport rolling"}, {"?", com_help, "Synonym for `help'" }, {(char *)NULL, (cmd_function_t *)NULL, (char *)NULL } }; static command_t *find_command(char *name) { register int i; size_t namelen; if ((name == NULL) || (*name == '\0')) return ((command_t *)NULL); namelen = strlen(name); for (i = 0; commands[i].name; i++) if (strncmp(name, commands[i].name, namelen) == 0) { /* make sure the match is unique */ if ((commands[i+1].name) && (strncmp(name, commands[i+1].name, namelen) == 0)) return ((command_t *)NULL); else return (&commands[i]); } return ((command_t *)NULL); } static void com_help(char *arg) { register int i; command_t *cmd; if (!*arg) { /* print help for all commands */ for (i = 0; commands[i].name; i++) { printf("%s\t\t%s.\n", commands[i].name, commands[i].doc); } } else if ((cmd = find_command(arg))) { printf("%s\t\t%s.\n", cmd->name, cmd->doc); } else { int printed = 0; printf("No `%s' command. Valid command names are:\n", arg); for (i = 0; commands[i].name; i++) { /* Print in six columns. */ if (printed == 6) { printed = 0; printf ("\n"); } printf ("%s\t", commands[i].name); printed++; } printf("\n\nTry `help [command]\' for more information.\n"); } } static void execute_command(char *line) { register int i; command_t *command; char *word; /* Isolate the command word. */ i = 0; while (line[i] && whitespace(line[i])) i++; word = line + i; while (line[i] && !whitespace(line[i])) i++; if (line[i]) line[i++] = '\0'; command = find_command(word); if (!command) { fprintf(stderr, "%s: No such command. There is `help\'.\n", word); return; } /* Get argument to command, if any. */ while (whitespace(line[i])) i++; word = line + i; /* invoke the command function. */ (*command->func)(word); } /* Strip whitespace from the start and end of string. */ static char *stripwhite(char *string) { register char *s, *t; s = string; while (whitespace(*s)) s++; if (*s == '\0') return s; t = s + strlen (s) - 1; while (t > s && whitespace(*t)) t--; *++t = '\0'; return s; } static char *dupstr(char *s) { char *r = malloc(strlen(s) + 1); strcpy(r, s); return r; } /* Readline generator function for command completion. */ static char *command_generator (const char *text, int state) { static int list_index, len; char *name; /* If this is a new word to complete, initialize now. This includes saving the length of TEXT for efficiency, and initializing the index variable to 0. */ if (!state) { list_index = 0; len = strlen (text); } /* Return the next name which partially matches from the command list. */ while ((name = commands[list_index].name)) { list_index++; if (strncmp(name, text, len) == 0) return dupstr(name); } return (char *) NULL; /* No names matched. */ } static void command_loop() { #if HAVE_READLINE char *line, *cmd; char prompt[32]; snprintf(prompt, sizeof(prompt), "%s> ", package); /* Allow conditional parsing of the ~/.inputrc file. */ rl_readline_name = package; /* Define a custom completion function. */ rl_completion_entry_function = command_generator; #else char line[64] = {0,}; char *cmd = NULL; #endif /* Read and execute commands until the user quits. */ while (!done) { #if HAVE_READLINE line = readline(prompt); if (line == NULL) { /* EOF? */ printf("\n"); /* close out prompt */ done = 1; break; } #else printf("%s> ", package); fgets(line, sizeof(line), stdin); line[strlen(line)-1] = '\0'; #endif /* Remove leading and trailing whitespace from the line. */ cmd = stripwhite(line); /* If anything left, add to history and execute it. */ if (*cmd) { #if HAVE_READLINE add_history(cmd); #endif execute_command(cmd); } #if HAVE_READLINE free(line); /* realine() called malloc() */ #endif } } int main(int argc, char *argv[]) { jack_status_t status; /* basename $0 */ package = strrchr(argv[0], '/'); if (package == 0) package = argv[0]; else package++; /* open a connection to the JACK server */ client = jack_client_open (package, JackNullOption, &status); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); return 1; } #if !WIN32 signal(SIGQUIT, signal_handler); signal(SIGHUP, signal_handler); #endif signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); jack_set_process_callback(client, jack_process, 0); jack_on_shutdown(client, jack_shutdown, 0); if (jack_activate(client)) { fprintf(stderr, "cannot activate client"); return 1; } /* execute commands until done */ command_loop(); jack_client_close(client); exit(0); } 07070100000059000081A400000000000000000000000161E2F7EE00001838000000000000000000000000000000000000002000000000jack-example-tools-1/tools/tw.c/** @file tw.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. */ #include <stdio.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <jack/jack.h> jack_port_t *input_port; jack_port_t *output_port; jack_client_t *client; /* a simple state machine for this client */ volatile enum { Init, Run, Exit } client_state = Init; static void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } /** * The process callback for this JACK application is called in a * special realtime thread once for each audio cycle. * * This client follows a simple rule: when the JACK transport is * running, copy the input port to the output. When it stops, exit. */ static int _process (jack_nframes_t nframes) { jack_default_audio_sample_t *in, *out; jack_transport_state_t ts = jack_transport_query(client, NULL); if (ts == JackTransportRolling) { if (client_state == Init) client_state = Run; in = jack_port_get_buffer (input_port, nframes); out = jack_port_get_buffer (output_port, nframes); memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); } else if (ts == JackTransportStopped) { if (client_state == Run) { client_state = Exit; return -1; // to stop the thread } } return 0; } static void* jack_thread(void *arg) { jack_client_t* client = (jack_client_t*) arg; while (1) { jack_nframes_t frames = jack_cycle_wait (client); int status = _process(frames); jack_cycle_signal (client, status); /* Possibly do something else after signaling next clients in the graph */ /* End condition */ if (status != 0) return 0; } /* not reached*/ return 0; } /* static void* jack_thread(void *arg) { jack_client_t* client = (jack_client_t*) arg; while (1) { jack_nframes_t frames; int status; // cycle 1 frames = jack_cycle_wait (client); status = _process(frames); jack_cycle_signal (client, status); // cycle 2 frames = jack_cycle_wait (client); status = _process(frames); jack_cycle_signal (client, status); // cycle 3 frames = jack_cycle_wait (client); status = _process(frames); jack_cycle_signal (client, status); // cycle 4 frames = jack_cycle_wait (client); status = _process(frames); jack_cycle_signal (client, status); } return 0; } */ /** * JACK calls this shutdown_callback if the server ever shuts down or * decides to disconnect the client. */ static void jack_shutdown (void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit (1); } int main (int argc, char *argv[]) { const char **ports; const char *client_name; const char *server_name = NULL; jack_options_t options = JackNullOption; jack_status_t status; if (argc >= 2) { /* client name specified? */ client_name = argv[1]; if (argc >= 3) { /* server name specified? */ server_name = argv[2]; options |= JackServerName; } } else { /* use basename of argv[0] */ client_name = strrchr(argv[0], '/'); if (client_name == 0) { client_name = argv[0]; } else { client_name++; } } /* open a client connection to the JACK server */ client = jack_client_open (client_name, options, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } exit (1); } if (status & JackServerStarted) { fprintf (stderr, "JACK server started\n"); } if (status & JackNameNotUnique) { client_name = jack_get_client_name(client); fprintf (stderr, "unique name `%s' assigned\n", client_name); } /* tell the JACK server to call `process()' whenever there is work to be done. */ if (jack_set_process_thread(client, jack_thread, client) < 0) exit(1); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* display the current sample rate. */ printf ("engine sample rate: %" PRIu32 "\n", jack_get_sample_rate (client)); /* create two ports */ input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if ((input_port == NULL) || (output_port == NULL)) { fprintf(stderr, "no more JACK ports available\n"); exit (1); } /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); exit (1); } /* Connect the ports. You can't do this before the client is * activated, because we can't make connections to clients * that aren't running. Note the confusing (but necessary) * orientation of the driver backend ports: playback ports are * "input" to the backend, and capture ports are "output" from * it. */ ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); if (ports == NULL) { fprintf(stderr, "no physical capture ports\n"); exit (1); } if (jack_connect (client, ports[0], jack_port_name (input_port))) { fprintf (stderr, "cannot connect input ports\n"); } jack_free (ports); ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); if (ports == NULL) { fprintf(stderr, "no physical playback ports\n"); exit (1); } if (jack_connect (client, jack_port_name (output_port), ports[0])) { fprintf (stderr, "cannot connect output ports\n"); } jack_free (ports); /* install a signal handler to properly quits jack client */ signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); /* keep running until the transport stops */ while (client_state != Exit) { sleep (1); } jack_client_close (client); exit (0); } 0707010000005A000081A400000000000000000000000161E2F7EE00000E03000000000000000000000000000000000000002200000000jack-example-tools-1/tools/wait.c#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <getopt.h> #include <time.h> #include <jack/jack.h> char * my_name; void silent_function( const char *ignore ) { } void show_usage(void) { fprintf(stderr, "\nUsage: %s [options]\n", my_name); fprintf(stderr, "Check for jack existence, or wait, until it either quits, or gets started\n"); fprintf(stderr, "options:\n"); fprintf(stderr, " -s, --server <name> Connect to the jack server named <name>\n"); fprintf(stderr, " -n, --name <name> Set client name to <name>\n"); fprintf(stderr, " -w, --wait Wait for server to become available\n"); fprintf(stderr, " -q, --quit Wait until server is quit\n"); fprintf(stderr, " -c, --check Check whether server is running\n"); fprintf(stderr, " -t, --timeout Wait timeout in seconds\n"); fprintf(stderr, " -h, --help Display this help message\n"); fprintf(stderr, "For more information see http://jackaudio.org/\n"); } int main(int argc, char *argv[]) { jack_client_t *client; jack_status_t status; jack_options_t options = JackNoStartServer; int c; int option_index; char *server_name = NULL; char *client_name = NULL; int wait_for_start = 0; int wait_for_quit = 0; int just_check = 0; int wait_timeout = 0; time_t start_timestamp; struct option long_options[] = { { "server", 1, 0, 's' }, { "wait", 0, 0, 'w' }, { "name", 1, 0, 'n'}, { "quit", 0, 0, 'q' }, { "check", 0, 0, 'c' }, { "timeout", 1, 0, 't' }, { "help", 0, 0, 'h' }, { 0, 0, 0, 0 } }; my_name = strrchr(argv[0], '/'); if (my_name == 0) { my_name = argv[0]; } else { my_name ++; } while ((c = getopt_long (argc, argv, "s:n:wqct:h", long_options, &option_index)) >= 0) { switch (c) { case 's': server_name = (char *) malloc (sizeof (char) * (strlen(optarg) + 1)); strcpy (server_name, optarg); options |= JackServerName; break; case 'n': client_name = (char *) malloc (sizeof (char) * (strlen(optarg) + 1)); strcpy (client_name, optarg); break; case 'w': wait_for_start = 1; break; case 'q': wait_for_quit = 1; break; case 'c': just_check = 1; break; case 't': wait_timeout = atoi(optarg); break; case 'h': show_usage(); return 1; default: show_usage(); return 1; } } jack_set_info_function(silent_function); /* try to open server in a loop. breaking under certein conditions */ start_timestamp = time(NULL); while (1) { if (client_name) { client = jack_client_open (client_name, options, &status, server_name); } else { client = jack_client_open ("wait", options, &status, server_name); } /* check for some real error and bail out */ if ((client == NULL) && !(status & JackServerFailed)) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); return 1; } if (client == NULL) { if (wait_for_quit) { fprintf(stdout, "server is gone\n"); break; } if (just_check) { fprintf(stdout, "not running\n"); break; } } else { jack_client_close(client); if (wait_for_start) { fprintf(stdout, "server is available\n"); break; } if (just_check) { fprintf(stdout, "running\n"); break; } } if (wait_timeout) { if ((time(NULL) - start_timestamp) > wait_timeout) { fprintf(stdout, "timeout\n"); exit(EXIT_FAILURE); } } // Wait a second, and repeat #ifdef WIN32 Sleep(1*1000); #else sleep(1); #endif } exit(0); } 0707010000005B000041ED00000000000000000000000161E2F7EE00000000000000000000000000000000000000000000002100000000jack-example-tools-1/tools/zalsa0707010000005C000081A400000000000000000000000161E2F7EE0000894D000000000000000000000000000000000000002900000000jack-example-tools-1/tools/zalsa/LICENSE GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 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 state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: <program> Copyright (C) <year> <name of author> This program 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, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <https://www.gnu.org/licenses/>. The GNU 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 Lesser General Public License instead of this License. But first, please read <https://www.gnu.org/licenses/why-not-lgpl.html>. 0707010000005D000081A400000000000000000000000161E2F7EE0000179C000000000000000000000000000000000000002F00000000jack-example-tools-1/tools/zalsa/alsathread.cc// ---------------------------------------------------------------------------- // // Copyright (C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // ---------------------------------------------------------------------------- #include <stdlib.h> #include <string.h> #include <stdio.h> #include <math.h> #include "alsathread.h" #include "timers.h" Alsathread::Alsathread (Alsa_pcmi *alsadev, int mode) : _alsadev (alsadev ), _mode (mode), _state (INIT), _fsize (alsadev->fsize ()), _audioq (0), _commq (0), _alsaq (0) { // Compute DLL filter coefficients. _dt = (double) _fsize / _alsadev->fsamp (); _w1 = 2 * M_PI * 0.1 * _dt; _w2 = _w1 * _w1; _w1 *= 1.6; } Alsathread::~Alsathread (void) { if (_state != INIT) { _state = TERM; thr_wait (); } else { _alsadev->pcm_stop (); } } int Alsathread::start (Lfq_audio *audioq, Lfq_int32 *commq, Lfq_adata *alsaq, int rtprio) { // Start the ALSA thread. _audioq = audioq; _commq = commq; _alsaq = alsaq; _state = WAIT; if (thr_start (SCHED_FIFO, rtprio, 0x10000)) return 1; return 0; } void Alsathread::send (int k, double t) { Adata *D; // Send (state, frame count, timestamp) to Jack thread. if (_alsaq->wr_avail ()) { D = _alsaq->wr_datap (); D->_state = _state; D->_nsamp = k; D->_timer = t; _alsaq->wr_commit (); } } // The following two functions transfer data between the audio queue // and the ALSA device. Note that we do *not* check the queue's fill // state, and it may overrun or underrun. It actually will in the first // few iterations and in error conditions. This is entirely intentional. // The queue keeps correct read and write counters even in that case, // and the main control loop and error recovery depend on it working // and being used in this way. int Alsathread::capture (void) { int c, n, k; float *p; // Start reading from ALSA device. _alsadev->capt_init (_fsize); if (_state == PROC) { // Input frames from the ALSA device to the audio queue. // The outer loop takes care of wraparound. for (n = _fsize; n; n -= k) { p = _audioq->wr_datap (); // Audio queue write pointer. k = _audioq->wr_linav (); // Number of frames that can be if (k > n) k = n; // written without wraparound. for (c = 0; c < _audioq->nchan (); c++) { // Copy and interleave one channel. _alsadev->capt_chan (c, p + c, k, _audioq->nchan ()); } _audioq->wr_commit (k); // Update audio queue state. } } // Finish reading from ALSA device. _alsadev->capt_done (_fsize); return _fsize; } int Alsathread::playback (void) { int c, n, k; float *p; // Start writing to ALSA device. _alsadev->play_init (_fsize); c = 0; if (_state == PROC) { // Output frames from the audio queue to the ALSA device. // The outer loop takes care of wraparound. for (n = _fsize; n; n -= k) { p = _audioq->rd_datap (); // Audio queue read pointer. k = _audioq->rd_linav (); // Number of frames that can if (k > n) k = n; // be read without wraparound. for (c = 0; c < _audioq->nchan (); c++) { // De-interleave and copy one channel. _alsadev->play_chan (c, p + c, k, _audioq->nchan ()); } _audioq->rd_commit (k); // Update audio queue state. } } // Clear all or remaining channels. while (c < _alsadev->nplay ()) _alsadev->clear_chan (c++, _fsize); // Finish writing to ALSA device. _alsadev->play_done (_fsize); return _fsize; } void Alsathread::thr_main (void) { int na, nu; double tw, er; _alsadev->pcm_start (); while (_state != TERM) { // Wait for next cycle, then take timestamp. na = _alsadev->pcm_wait (); tw = tjack (jack_get_time ()); // Check for errors - requires restart. if (_alsadev->state () && (na == 0)) { _state = WAIT; send (0, 0); usleep (10000); continue; } // Check for commands from the Jack thread. if (_commq->rd_avail ()) { _state = _commq->rd_int32 (); if (_state == PROC) _first = true; if (_state == TERM) send (0, 0); } // We could have more than one period. nu = 0; while (na >= _fsize) { // Transfer frames. if (_mode == PLAY) nu += playback (); else nu += capture (); // Update loop condition. na -= _fsize; // Run the DLL if in PROC state. if (_state == PROC) { if (_first) { // Init DLL in first iteration. _first = false; _dt = (double) _fsize / _alsadev->fsamp (); _t0 = tw; _t1 = tw + _dt; } else { // Update the DLL. // If we have more than one period, use // the time error only for the last one. if (na >= _fsize) er = 0; else er = tjack_diff (tw, _t1); _t0 = _t1; _t1 = tjack_diff (_t1 + _dt + _w1 * er, 0.0); _dt += _w2 * er; } } } // Send number of frames used and timestamp to Jack thread. if (_state == PROC) send (nu, _t1); } _alsadev->pcm_stop (); } 0707010000005E000081A400000000000000000000000161E2F7EE0000072D000000000000000000000000000000000000002E00000000jack-example-tools-1/tools/zalsa/alsathread.h// ---------------------------------------------------------------------------- // // Copyright (C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // ---------------------------------------------------------------------------- #ifndef __ALSATHREAD_H #define __ALSATHREAD_H #include <zita-alsa-pcmi.h> #include "jack/jack.h" #include "pxthread.h" #include "lfqueue.h" class Alsathread : public Pxthread { public: enum { INIT, WAIT, PROC, TERM }; enum { PLAY, CAPT }; Alsathread (Alsa_pcmi *alsadev, int mode); virtual ~Alsathread (void); virtual void thr_main (void); int start (Lfq_audio *audioq, Lfq_int32 *commq, Lfq_adata *alsaq, int rtprio); private: void send (int k, double t); int capture (void); int playback (void); Alsa_pcmi *_alsadev; int _mode; int _state; int _nfail; int _fsize; Lfq_audio *_audioq; Lfq_int32 *_commq; Lfq_adata *_alsaq; bool _first; // double _jtmod; double _t0; double _t1; double _dt; double _w1; double _w2; }; #endif 0707010000005F000081A400000000000000000000000161E2F7EE00003572000000000000000000000000000000000000002F00000000jack-example-tools-1/tools/zalsa/jackclient.cc// ---------------------------------------------------------------------------- // // Copyright (C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // ---------------------------------------------------------------------------- #include <stdio.h> #include <math.h> #include "jackclient.h" #include "alsathread.h" #include "timers.h" Jackclient::Jackclient (jack_client_t* cl, const char *jserv, int mode, int nchan, bool sync, void *arg) : _client (cl), _arg (arg), _mode (mode), _nchan (nchan), _state (INIT), _freew (false), _resamp (0) { init (jserv); if (!sync) _resamp = new VResampler (); } Jackclient::~Jackclient (void) { fini (); } bool Jackclient::init (const char *jserv) { int i, spol, flags; char s [64]; struct sched_param spar; if (_client == 0) { fprintf (stderr, "Can't connect to Jack, is the server running ?\n"); return false; } jack_set_process_callback (_client, jack_static_process, (void *) this); jack_set_latency_callback (_client, jack_static_latency, (void *) this); jack_set_freewheel_callback (_client, jack_static_freewheel, (void *) this); jack_set_buffer_size_callback (_client, jack_static_buffsize, (void *) this); jack_on_shutdown (_client, jack_static_shutdown, (void *) this); _bsize = 0; _fsamp = 0; if (jack_activate (_client)) { fprintf(stderr, "Can't activate Jack"); return false; } _jname = jack_get_client_name (_client); _bsize = jack_get_buffer_size (_client); _fsamp = jack_get_sample_rate (_client); flags = JackPortIsTerminal | JackPortIsPhysical; for (i = 0; i < _nchan; i++) { if (_mode == PLAY) { sprintf (s, "playback_%d", i + 1); _ports [i] = jack_port_register (_client, s, JACK_DEFAULT_AUDIO_TYPE, flags | JackPortIsInput, 0); } else { sprintf (s, "capture_%d", i + 1); _ports [i] = jack_port_register (_client, s, JACK_DEFAULT_AUDIO_TYPE, flags | JackPortIsOutput, 0); } } pthread_getschedparam (jack_client_thread_id (_client), &spol, &spar); _rprio = spar.sched_priority - sched_get_priority_max (spol); _buff = new float [_bsize * _nchan]; return true; } void Jackclient::fini (void) { delete[] _buff; delete _resamp; } void Jackclient::jack_static_shutdown (void *arg) { ((Jackclient *) arg)->sendinfo (TERM, 0, 0); } int Jackclient::jack_static_buffsize (jack_nframes_t nframes, void *arg) { Jackclient *J = (Jackclient *) arg; if (J->_bsize == 0) J->_bsize = nframes; else if (J->_bsize != (int) nframes) J->_state = Jackclient::TERM; return 0; } void Jackclient::jack_static_freewheel (int state, void *arg) { ((Jackclient *) arg)->jack_freewheel (state); } void Jackclient::jack_static_latency (jack_latency_callback_mode_t jlcm, void *arg) { ((Jackclient *) arg)->jack_latency (jlcm); } int Jackclient::jack_static_process (jack_nframes_t nframes, void *arg) { return ((Jackclient *) arg)->jack_process (nframes); } void Jackclient::start (Lfq_audio *audioq, Lfq_int32 *commq, Lfq_adata *alsaq, Lfq_jdata *infoq, double ratio, int delay, int ltcor, int rqual) { double d; _audioq = audioq; _commq = commq; _alsaq = alsaq; _infoq = infoq; _ratio = ratio; _delay = delay; _rcorr = 1.0; if (_resamp) { _resamp->setup (_ratio, _nchan, rqual); _resamp->set_rrfilt (100); d = _resamp->inpsize () / 2.0; if (_mode == PLAY) d *= _ratio; _delay += d; } _ltcor = ltcor; _ppsec = (_fsamp + _bsize / 2) / _bsize; initwait (_ppsec / 2); jack_recompute_total_latencies (_client); } void Jackclient::initwait (int nwait) { _count = -nwait; _commq->wr_int32 (Alsathread::WAIT); _state = WAIT; if (nwait > _ppsec) sendinfo (WAIT, 0, 0); } void Jackclient::initsync (void) { // Reset all lock-free queues. _commq->reset (); _alsaq->reset (); _audioq->reset (); if (_resamp) { // Reset and prefill the resampler. _resamp->reset (); _resamp->inp_count = _resamp->inpsize () / 2 - 1; _resamp->out_count = 99999; _resamp->process (); } // Initialise state variables. _t_a0 = _t_a1 = 0; _k_a0 = _k_a1 = 0; // Initialise loop filter state. _z1 = _z2 = _z3 = 0; // Activate the ALSA thread, _commq->wr_int32 (Alsathread::PROC); _state = SYNC0; sendinfo (SYNC0, 0, 0); } void Jackclient::setloop (double bw) { double w; // Set the loop bandwidth to bw Hz. w = 6.28 * bw * _bsize / _fsamp; _w0 = 1.0 - exp (-20.0 * w); _w1 = w * 2 / _bsize; _w2 = w / 2; if (_mode == PLAY) _w1 /= _ratio; else _w1 *= _ratio; } void Jackclient::playback (int nframes) { int i, j, n; float *p, *q; float *inp [MAXCHAN]; _bstat = _audioq->rd_avail (); for (i = 0; i < _nchan; i++) { inp [i] = (float *)(jack_port_get_buffer (_ports [i], nframes)); } if (_resamp) { // Interleave inputs into _buff. for (i = 0; i < _nchan; i++) { p = inp [i]; q = _buff + i; for (j = 0; j < _bsize; j++) q [j * _nchan] = p [j]; } // Resample _buff and write to audio queue. // The while loop takes care of wraparound. _resamp->inp_count = _bsize; _resamp->inp_data = _buff; while (_resamp->inp_count) { _resamp->out_count = _audioq->wr_linav (); _resamp->out_data = _audioq->wr_datap (); n = _resamp->out_count; _resamp->process (); n -= _resamp->out_count; _audioq->wr_commit (n); } } else { // Interleave inputs into audio queue. // The while loop takes care of wraparound. while (nframes) { q = _audioq->wr_datap (); n = _audioq->wr_linav (); if (n > nframes) n = nframes; for (i = 0; i < _nchan; i++) { p = inp [i]; for (j = 0; j < n; j++) q [j * _nchan] = p [j]; inp [i] += n; q += 1; } _audioq->wr_commit (n); nframes -= n; } } } void Jackclient::capture (int nframes) { int i, j, n; float *p, *q; float *out [MAXCHAN]; for (i = 0; i < _nchan; i++) { out [i] = (float *)(jack_port_get_buffer (_ports [i], nframes)); } if (_resamp) { // Read from audio queue and resample. // The while loop takes care of wraparound. _resamp->out_count = _bsize; _resamp->out_data = _buff; while (_resamp->out_count) { _resamp->inp_count = _audioq->rd_linav (); _resamp->inp_data = _audioq->rd_datap (); n = _resamp->inp_count; _resamp->process (); n -= _resamp->inp_count; _audioq->rd_commit (n); } // Deinterleave _buff to outputs. for (i = 0; i < _nchan; i++) { p = _buff + i; q = out [i]; for (j = 0; j < _bsize; j++) q [j] = p [j * _nchan]; } } else { // Deinterleave audio queue to outputs. // The while loop takes care of wraparound. while (nframes) { p = _audioq->rd_datap (); n = _audioq->rd_linav (); if (n > nframes) n = nframes; for (i = 0; i < _nchan; i++) { q = out [i]; for (j = 0; j < n; j++) q [j] = p [j * _nchan]; out [i] += n; p += 1; } _audioq->rd_commit (n); nframes -= n; } } _bstat = _audioq->rd_avail (); } void Jackclient::silence (int nframes) { int i; float *q; // Write silence to all jack ports. for (i = 0; i < _nchan; i++) { q = (float *)(jack_port_get_buffer (_ports [i], nframes)); memset (q, 0, nframes * sizeof (float)); } } void Jackclient::sendinfo (int state, double error, double ratio) { Jdata *J; if (_infoq->wr_avail ()) { J = _infoq->wr_datap (); J->_state = state; J->_error = error; J->_ratio = ratio; J->_bstat = _bstat; _infoq->wr_commit (); } } void Jackclient::jack_freewheel (int state) { _freew = state ? true : false; if (_freew) initwait (_ppsec / 4); } void Jackclient::jack_latency (jack_latency_callback_mode_t jlcm) { jack_latency_range_t R; int i; if (_state < WAIT) return; if (_mode == PLAY) { if (jlcm != JackPlaybackLatency) return; R.min = R.max = (int)(_delay / _ratio) + _ltcor; } else { if (jlcm != JackCaptureLatency) return; R.min = R.max = (int)(_delay * _ratio) + _ltcor; } for (i = 0; i < _nchan; i++) { jack_port_set_latency_range (_ports [i], jlcm, &R); } } int Jackclient::jack_process (int nframes) { int dk, n; Adata *D; jack_time_t t0, t1; jack_nframes_t ft; float us; double tj, err, d1, d2, rd; // Buffer size change or other evil. if (_state == TERM) { sendinfo (TERM, 0, 0); return 0; } // Skip cylce if ports may not yet exist. if (_state < WAIT) return 0; // Start synchronisation 1/2 second after entering // the WAIT state. This delay allows the ALSA thread // to restart cleanly if necessary. Disabled while // freewheeling. if (_state == WAIT) { if (_freew) return 0; if (_mode == CAPT) silence (nframes); if (++_count == 0) initsync (); else return 0; } // Get the start time of the current cycle. jack_get_cycle_times (_client, &ft, &t0, &t1, &us); tj = tjack (t0); // Check for any skipped cycles. if (_state >= SYNC1) { dk = ft - _ft - _bsize; if (_mode == PLAY) { dk = (int)(dk * _ratio + 0.5); _audioq->wr_commit (dk); } else { dk = (int)(dk / _ratio + 0.5); _audioq->rd_commit (dk); } } _ft = ft; // Check if we have timing data from the ALSA thread. n = _alsaq->rd_avail (); // If the data queue is full restart synchronisation. // This can happen e.g. on a jack engine timeout, or // when too many cycles have been skipped. if (n == _alsaq->size ()) { initwait (_ppsec / 2); return 0; } if (n) { // Else move interval end to start, and update the // interval end keeping only the most recent data. if (_state < SYNC2) _state++; _t_a0 = _t_a1; _k_a0 = _k_a1; while (_alsaq->rd_avail ()) { D = _alsaq->rd_datap (); // Restart synchronisation in case of // an error in the ALSA interface. if (D->_state == Alsathread::WAIT) { initwait (_ppsec / 2); return 0; } _t_a1 = D->_timer; _k_a1 += D->_nsamp; _alsaq->rd_commit (); } } err = 0; if (_state >= SYNC2) { // Compute the delay error. d1 = tjack_diff (tj, _t_a0); d2 = tjack_diff (_t_a1, _t_a0); rd = _resamp ? _resamp->inpdist () : 0.0; if (_mode == PLAY) { n = _audioq->nwr () - _k_a0; // Must be done as integer as both terms will overflow. err = n - (_k_a1 - _k_a0) * d1 / d2 + rd * _ratio - _delay; } else { n = _k_a0 - _audioq->nrd (); // Must be done as integer as both terms will overflow. err = n + (_k_a1 - _k_a0) * d1 / d2 + rd - _delay ; } n = (int)(floor (err + 0.5)); if (_state == SYNC2) { // We have the first delay error value. Adjust the audio // queue to obtain the actually wanted delay, and start // tracking. if (_mode == PLAY) _audioq->wr_commit (-n); else _audioq->rd_commit (n); err -= n; setloop (1.0); _state = PROC1; } } // Switch to lower bandwidth after 4 seconds. if ((_state == PROC1) && (++_count == 4 * _ppsec)) { _state = PROC2; setloop (0.05); } if (_state >= PROC1) { _z1 += _w0 * (_w1 * err - _z1); _z2 += _w0 * (_z1 - _z2); _z3 += _w2 * _z2; // Check error conditions. if (fabs (_z3) > 0.05) { // Something is really wrong, wait 10 seconds then restart. initwait (10 * _ppsec); return 0; } // Run loop filter and set resample ratio. if (_resamp) { _rcorr = 1 - (_z2 + _z3); if (_rcorr > 1.05) _rcorr = 1.05; if (_rcorr < 0.95) _rcorr = 0.95; _resamp->set_rratio (_rcorr); } sendinfo (_state, err, _rcorr); // Resample and transfer between audio // queue and jack ports. if (_mode == PLAY) playback (nframes); else capture (nframes); } else if (_mode == CAPT) silence (nframes); return 0; } 07070100000060000081A400000000000000000000000161E2F7EE00000E0A000000000000000000000000000000000000002E00000000jack-example-tools-1/tools/zalsa/jackclient.h// ---------------------------------------------------------------------------- // // Copyright (C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // ---------------------------------------------------------------------------- #ifndef __JACKCLIENT_H #define __JACKCLIENT_H #include <zita-resampler/vresampler.h> #include "jack/jack.h" #include "lfqueue.h" class Jackclient { public: Jackclient (jack_client_t*, const char *jserv, int mode, int nchan, bool sync, void *arg); virtual ~Jackclient (void); enum { PLAY, CAPT, MAXCHAN = 64 }; enum { INIT, TERM, WAIT, SYNC0, SYNC1, SYNC2, PROC1, PROC2 }; void start (Lfq_audio *audioq, Lfq_int32 *commq, Lfq_adata *alsaq, Lfq_jdata *infoq, double ratio, int delay, int ltcor, int rqual); const char *jname (void) const { return _jname; } int fsamp (void) const { return _fsamp; } int bsize (void) const { return _bsize; } int rprio (void) const { return _rprio; } void *getarg(void) const { return _arg; } private: bool init (const char *jserv); void fini (void); void initwait (int nwait); void initsync (void); void setloop (double bw); void silence (int nframes); void playback (int nframes); void capture (int nframes); void sendinfo (int state, double error, double ratio); virtual void thr_main (void) {} void jack_freewheel (int state); void jack_latency (jack_latency_callback_mode_t jlcm); int jack_process (int nframes); jack_client_t *_client; jack_port_t *_ports [MAXCHAN]; void *_arg; const char *_jname; int _mode; int _nchan; int _state; int _count; int _fsamp; int _bsize; int _rprio; bool _freew; float *_buff; Lfq_audio *_audioq; Lfq_int32 *_commq; Lfq_adata *_alsaq; Lfq_jdata *_infoq; double _ratio; int _ppsec; int _bstat; jack_nframes_t _ft; double _t_a0; double _t_a1; int _k_a0; int _k_a1; double _delay; int _ltcor; double _w0; double _w1; double _w2; double _z1; double _z2; double _z3; double _rcorr; VResampler *_resamp; static void jack_static_shutdown (void *arg); static int jack_static_buffsize (jack_nframes_t nframes, void *arg); static void jack_static_freewheel (int state, void *arg); static void jack_static_latency (jack_latency_callback_mode_t jlcm, void *arg); static int jack_static_process (jack_nframes_t nframes, void *arg); }; #endif 07070100000061000081A400000000000000000000000161E2F7EE00000750000000000000000000000000000000000000002C00000000jack-example-tools-1/tools/zalsa/lfqueue.cc// ---------------------------------------------------------------------------- // // Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // ---------------------------------------------------------------------------- #include <assert.h> #include "lfqueue.h" Lfq_adata::Lfq_adata (int size) : _size (size), _mask (size - 1), _nwr (0), _nrd (0) { assert (!(_size & _mask)); _data = new Adata [_size]; } Lfq_adata::~Lfq_adata (void) { delete[] _data; } Lfq_jdata::Lfq_jdata (int size) : _size (size), _mask (size - 1), _nwr (0), _nrd (0) { assert (!(_size & _mask)); _data = new Jdata [_size]; } Lfq_jdata::~Lfq_jdata (void) { delete[] _data; } Lfq_int32::Lfq_int32 (int size) : _size (size), _mask (size - 1), _nwr (0), _nrd (0) { assert (!(_size & _mask)); _data = new int32_t [_size]; } Lfq_int32::~Lfq_int32 (void) { delete[] _data; } Lfq_audio::Lfq_audio (int nsamp, int nchan) : _size (nsamp), _mask (nsamp - 1), _nch (nchan), _nwr (0), _nrd (0) { assert (!(_size & _mask)); _data = new float [_nch * _size]; } Lfq_audio::~Lfq_audio (void) { delete[] _data; } 07070100000062000081A400000000000000000000000161E2F7EE000011AE000000000000000000000000000000000000002B00000000jack-example-tools-1/tools/zalsa/lfqueue.h// ---------------------------------------------------------------------------- // // Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // ---------------------------------------------------------------------------- #ifndef __LFQUEUE_H #define __LFQUEUE_H #include <stdint.h> #include <string.h> class Adata { public: int32_t _state; int32_t _nsamp; double _timer; }; class Lfq_adata { public: Lfq_adata (int size); ~Lfq_adata (void); void reset (void) { _nwr = _nrd = 0; } int size (void) const { return _size; } int wr_avail (void) const { return _size - _nwr + _nrd; } Adata *wr_datap (void) { return _data + (_nwr & _mask); } void wr_commit (void) { _nwr++; } int rd_avail (void) const { return _nwr - _nrd; } Adata *rd_datap (void) { return _data + (_nrd & _mask); } void rd_commit (void) { _nrd++; } private: Adata *_data; int _size; int _mask; int _nwr; int _nrd; }; class Jdata { public: int32_t _state; double _error; double _ratio; int _bstat; }; class Lfq_jdata { public: Lfq_jdata (int size); ~Lfq_jdata (void); void reset (void) { _nwr = _nrd = 0; } int size (void) const { return _size; } int wr_avail (void) const { return _size - _nwr + _nrd; } Jdata *wr_datap (void) { return _data + (_nwr & _mask); } void wr_commit (void) { _nwr++; } int rd_avail (void) const { return _nwr - _nrd; } Jdata *rd_datap (void) { return _data + (_nrd & _mask); } void rd_commit (void) { _nrd++; } private: Jdata *_data; int _size; int _mask; int _nwr; int _nrd; }; class Lfq_int32 { public: Lfq_int32 (int size); ~Lfq_int32 (void); int size (void) const { return _size; } void reset (void) { _nwr = _nrd = 0; } int wr_avail (void) const { return _size - _nwr + _nrd; } int32_t *wr_datap (void) { return _data + (_nwr & _mask); } void wr_commit (void) { _nwr++; } int rd_avail (void) const { return _nwr - _nrd; } int32_t *rd_datap (void) { return _data + (_nrd & _mask); } void rd_commit (void) { _nrd++; } void wr_int32 (int32_t v) { _data [_nwr++ & _mask] = v; } void wr_uint32 (uint32_t v) { _data [_nwr++ & _mask] = v; } void wr_float (float v) { *(float *)(_data + (_nwr++ & _mask)) = v; } int32_t rd_int32 (void) { return _data [_nrd++ & _mask]; } int32_t rd_uint32 (void) { return _data [_nrd++ & _mask]; } float rd_float (void) { return *(float *)(_data + (_nrd++ & _mask)); } private: int32_t *_data; int _size; int _mask; int _nwr; int _nrd; }; class Lfq_audio { public: Lfq_audio (int nsamp, int nchan); ~Lfq_audio (void); int size (void) const { return _size; } void reset (void) { _nwr = _nrd = 0; memset (_data, 0, _size * _nch * sizeof (float)); } int nchan (void) const { return _nch; } int nwr (void) const { return _nwr; }; int nrd (void) const { return _nrd; }; int wr_avail (void) const { return _size - _nwr + _nrd; } int wr_linav (void) const { return _size - (_nwr & _mask); } float *wr_datap (void) { return _data + _nch * (_nwr & _mask); } void wr_commit (int k) { _nwr += k; } int rd_avail (void) const { return _nwr - _nrd; } int rd_linav (void) const { return _size - (_nrd & _mask); } float *rd_datap (void) { return _data + _nch * (_nrd & _mask); } void rd_commit (int k) { _nrd += k; } private: float *_data; int _size; int _mask; int _nch; int _nwr; int _nrd; }; #endif 07070100000063000081A400000000000000000000000161E2F7EE000003C0000000000000000000000000000000000000002D00000000jack-example-tools-1/tools/zalsa/meson.build zalsa_version = '0.8.4' zalsa_in_c_args = c_args_common + ['-DAPPNAME="zalsa_in"', '-DVERSION="@0@"'.format(zalsa_version)] lib_zalsa_in = library( 'zalsa_in', cpp_args: zalsa_in_c_args, name_prefix: '', sources: ['zita-a2j.cc', 'alsathread.cc', 'jackclient.cc', 'pxthread.cc', 'lfqueue.cc'], dependencies: [dep_alsa, dep_jack, dep_threads, lib_jackserver, lib_m, lib_rt, lib_zita_alsa_pcmi, lib_zita_resampler], install: true, install_dir: get_option('libdir') / 'jack', ) zalsa_out_c_args = c_args_common + ['-DAPPNAME="zalsa_out"', '-DVERSION="@0@"'.format(zalsa_version)] lib_zalsa_out = library( 'zalsa_out', cpp_args: zalsa_out_c_args, name_prefix: '', sources: ['zita-j2a.cc', 'alsathread.cc', 'jackclient.cc', 'pxthread.cc', 'lfqueue.cc'], dependencies: [dep_alsa, dep_jack, dep_threads, lib_jackserver, lib_m, lib_rt, lib_zita_alsa_pcmi, lib_zita_resampler], install: true, install_dir: get_option('libdir') / 'jack', ) 07070100000064000081A400000000000000000000000161E2F7EE00000893000000000000000000000000000000000000002D00000000jack-example-tools-1/tools/zalsa/pxthread.cc// ---------------------------------------------------------------------------- // // Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // ---------------------------------------------------------------------------- #include "pxthread.h" Pxthread::Pxthread (void) : _thrid (0) { } Pxthread::~Pxthread (void) { } extern "C" void *Pxthread_entry_point (void *arg) { Pxthread *T = (Pxthread *) arg; T->thr_main (); return NULL; } int Pxthread::thr_start (int policy, int priority, size_t stacksize) { int min, max, rc; pthread_attr_t attr; struct sched_param parm; min = sched_get_priority_min (policy); max = sched_get_priority_max (policy); priority += max; if (priority > max) priority = max; if (priority < min) priority = min; parm.sched_priority = priority; pthread_attr_init (&attr); pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); pthread_attr_setschedpolicy (&attr, policy); pthread_attr_setschedparam (&attr, &parm); pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setstacksize (&attr, stacksize); _thrid = 0; rc = pthread_create (&_thrid, &attr, Pxthread_entry_point, this); pthread_attr_destroy (&attr); return rc; } void Pxthread::thr_main (void) { } void Pxthread::thr_wait (void) { if (_thrid == 0) return; pthread_join (_thrid, NULL); _thrid = 0; } 07070100000065000081A400000000000000000000000161E2F7EE00000595000000000000000000000000000000000000002C00000000jack-example-tools-1/tools/zalsa/pxthread.h// ---------------------------------------------------------------------------- // // Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // ---------------------------------------------------------------------------- #ifndef __PXTHREAD_H #define __PXTHREAD_H #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <assert.h> #include <errno.h> #include <pthread.h> class Pxthread { public: Pxthread (void); virtual ~Pxthread (void); Pxthread (const Pxthread&); Pxthread& operator=(const Pxthread&); virtual void thr_main (void) = 0; virtual int thr_start (int policy, int priority, size_t stacksize = 0); virtual void thr_wait (void); private: pthread_t _thrid; }; #endif 07070100000066000081A400000000000000000000000161E2F7EE0000054B000000000000000000000000000000000000002A00000000jack-example-tools-1/tools/zalsa/timers.h// ---------------------------------------------------------------------------- // // Copyright (C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // ---------------------------------------------------------------------------- #ifndef __TIMERS_H #define __TIMERS_H #include <math.h> #include <sys/time.h> #include <jack/jack.h> #define tjack_mod ldexp (1e-6f, 32) inline double tjack_diff (double a, double b) { double d, m; d = a - b; m = tjack_mod; while (d < -m / 2) d += m; while (d >= m / 2) d -= m; return d; } inline double tjack (jack_time_t t, double dt = 0) { int32_t u = (int32_t)(t & 0xFFFFFFFFLL); return 1e-6 * u; } #endif 07070100000067000081A400000000000000000000000161E2F7EE00002CF0000000000000000000000000000000000000002D00000000jack-example-tools-1/tools/zalsa/zita-a2j.cc// ---------------------------------------------------------------------------- // // Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // ---------------------------------------------------------------------------- #include <stdlib.h> #include <string.h> #include <ctype.h> #include <stdio.h> #include <signal.h> #include "alsathread.h" #include "jackclient.h" #include "lfqueue.h" #include "jack/control.h" static const char *clopt = "hvLSwj:d:r:p:n:c:Q:I:"; static void help (void) { jack_info ("%s-%s", APPNAME, VERSION); jack_info ("(C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org>"); jack_info ("Use ALSA capture device as a Jack client."); jack_info ("Options:"); jack_info (" -h Display this text"); jack_info (" -j <jackname> Name as Jack client [%s]", APPNAME); jack_info (" -d <device> ALSA capture device [none]"); jack_info (" -r <rate> Sample rate [48000]"); jack_info (" -p <period> Period size [256]"); jack_info (" -n <nfrags> Number of fragments [2]"); jack_info (" -c <nchannels> Number of channels [2]"); jack_info (" -S Word clock sync, no resampling"); jack_info (" -Q <quality> Resampling quality, 16..96 [auto]"); jack_info (" -I <samples> Latency adjustment [0]"); jack_info (" -L Force 16-bit and 2 channels [off]"); jack_info (" -w Wait until soundcard is available [off]"); jack_info (" -v Print tracing information [off]"); } class zita_a2j { Lfq_int32 *commq; Lfq_adata *alsaq; Lfq_jdata *infoq; Lfq_audio *audioq; bool stop; bool v_opt; bool L_opt; bool S_opt; bool w_opt; char *jname; char *device; int fsamp; int bsize; int nfrag; int nchan; int rqual; int ltcor; public: zita_a2j() { commq = new Lfq_int32(16); alsaq = new Lfq_adata(256); infoq = new Lfq_jdata(256); audioq = 0; stop = false; v_opt = false; L_opt = false; S_opt = false; w_opt = false; jname = strdup(APPNAME); device = 0; fsamp = 48000; bsize = 128; nfrag = 2; nchan = 2; rqual = 0; ltcor = 0; A = 0; C = 0; J = 0; t = 0; } private: int procoptions (int ac, const char *av []) { int k; optind = 1; opterr = 0; while ((k = getopt (ac, (char **) av, (char *) clopt)) != -1) { if (optarg && (*optarg == '-')) { jack_error (APPNAME ": Missing argument for '-%c' option.", k); jack_error (APPNAME ": Use '-h' to see all options."); return 1; } switch (k) { case 'h' : help (); return 1; case 'v' : v_opt = true; break; case 'L' : L_opt = true; break; case 'S' : S_opt = true; break; case 'w' : w_opt = true; break; case 'j' : jname = optarg; break; case 'd' : device = optarg; break; case 'r' : fsamp = atoi (optarg); break; case 'p' : bsize = atoi (optarg); break; case 'n' : nfrag = atoi (optarg); break; case 'c' : nchan = atoi (optarg); break; case 'Q' : rqual = atoi (optarg); break; case 'I' : ltcor = atoi (optarg); break; case '?': if (optopt != ':' && strchr (clopt, optopt)) { jack_error (APPNAME ": Missing argument for '-%c' option.", optopt); } else if (isprint (optopt)) { jack_error (APPNAME ": Unknown option '-%c'.", optopt); } else { jack_error (APPNAME ": Unknown option character '0x%02x'.", optopt & 255); } jack_error (APPNAME ": Use '-h' to see all options."); return 1; default: return 1; } } return 0; } int parse_options (const char* load_init) { int argsz; int argc = 0; const char** argv; char* args = strdup (load_init); char* token; char* ptr = args; char* savep; if (!load_init) { return 0; } argsz = 8; /* random guess at "maxargs" */ argv = (const char **) malloc (sizeof (char *) * argsz); argv[argc++] = APPNAME; while (1) { if ((token = strtok_r (ptr, " ", &savep)) == NULL) { break; } if (argc == argsz) { argsz *= 2; argv = (const char **) realloc (argv, sizeof (char *) * argsz); } argv[argc++] = token; ptr = NULL; } return procoptions (argc, argv); } void printinfo (void) { int n, k; double e, r; Jdata *J; n = 0; k = 99999; e = r = 0; while (infoq->rd_avail ()) { J = infoq->rd_datap (); if (J->_state == Jackclient::TERM) { jack_error (APPNAME ": Fatal error condition, terminating."); stop = true; return; } else if (J->_state == Jackclient::WAIT) { jack_info (APPNAME ": Detected excessive timing errors, waiting 10 seconds."); n = 0; } else if (J->_state == Jackclient::SYNC0) { jack_info (APPNAME ": Starting synchronisation."); } else if (v_opt) { n++; e += J->_error; r += J->_ratio; if (J->_bstat < k) k = J->_bstat; } infoq->rd_commit (); } if (n) jack_info (APPNAME ": %8.3lf %10.6lf %5d", e / n, r / n, k); } Alsa_pcmi *A; Alsathread *C; Jackclient *J; pthread_t t; int topts; static void* _retry_alsa_pcmi (void *arg) { ((zita_a2j*)arg)->retry_alsa_pcmi (); return NULL; } void retry_alsa_pcmi () { Alsa_pcmi *a; while (! stop) { sleep(1); a = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, topts); if (a->state ()) { delete a; continue; } A = a; if (v_opt) A->printinfo (); C = new Alsathread (A, Alsathread::CAPT); usleep (100*1000); jack_initialize_part2 (); jack_info (APPNAME ": Device is now available and has been activated"); break; } t = 0; } public: int jack_initialize (jack_client_t* client, const char* load_init) { int opts; if (parse_options (load_init)) { jack_error (APPNAME ": parse options failed"); delete this; return 1; } if (device == 0) { help (); delete this; return 1; } if (rqual < 16) rqual = 16; if (rqual > 96) rqual = 96; if ((fsamp < 8000) || (bsize < 16) || (nfrag < 2) || (nchan < 1)) { jack_error (APPNAME ": Illegal parameter value(s)."); delete this; return 1; } opts = 0; if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH; if (w_opt) { J = new Jackclient (client, 0, Jackclient::CAPT, nchan, S_opt, this); A = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, opts); // if device is not available, spawn thread to keep trying if (A->state ()) { delete A; A = NULL; topts = opts; pthread_create (&t, NULL, _retry_alsa_pcmi, this); jack_info (APPNAME ": Could not open device, will keep trying in new thread..."); return 0; } // otherwise continue as normal if (v_opt) A->printinfo (); C = new Alsathread (A, Alsathread::CAPT); } else { A = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, opts); if (A->state ()) { jack_error (APPNAME ": Can't open ALSA capture device '%s'.", device); delete this; return 1; } if (v_opt) A->printinfo (); if (nchan > A->ncapt ()) { nchan = A->ncapt (); jack_error (APPNAME ": Warning: only %d channels are available.", nchan); } C = new Alsathread (A, Alsathread::CAPT); J = new Jackclient (client, 0, Jackclient::CAPT, nchan, S_opt, this); } usleep (100*1000); jack_initialize_part2 (); return 0; } void jack_initialize_part2 () { int k, k_del; double t_alsa; double t_jack; double t_del; t_alsa = (double) bsize / fsamp; if (t_alsa < 1e-3) t_alsa = 1e-3; t_jack = (double) J->bsize () / J->fsamp (); t_del = t_alsa + t_jack; k_del = (int)(t_del * fsamp); for (k = 256; k < 2 * k_del; k *= 2); audioq = new Lfq_audio (k, nchan); if (rqual == 0) { k = (fsamp < J->fsamp ()) ? fsamp : J->fsamp (); if (k < 44100) k = 44100; rqual = (int)((6.7 * k) / (k - 38000)); } if (rqual < 16) rqual = 16; if (rqual > 96) rqual = 96; C->start (audioq, commq, alsaq, J->rprio () + 10); J->start (audioq, commq, alsaq, infoq, J->fsamp () / (double) fsamp, k_del, ltcor, rqual); } void jack_finish (void* arg) { if (t != 0) { stop = true; pthread_join(t, NULL); } commq->wr_int32 (Alsathread::TERM); usleep (100000); delete C; delete A; delete J; delete audioq; } }; extern "C" { int jack_initialize (jack_client_t* client, const char* load_init) { zita_a2j *c = new zita_a2j(); return c->jack_initialize(client, load_init); } void jack_finish (void* arg) { if (!arg) return; Jackclient *J = (Jackclient *)arg; zita_a2j *c = (zita_a2j *)J->getarg(); c->jack_finish(arg); delete c; } } /* extern "C" */ 07070100000068000081A400000000000000000000000161E2F7EE00002CBA000000000000000000000000000000000000002D00000000jack-example-tools-1/tools/zalsa/zita-j2a.cc// ---------------------------------------------------------------------------- // // Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // ---------------------------------------------------------------------------- #include <stdlib.h> #include <string.h> #include <ctype.h> #include <stdio.h> #include <signal.h> #include "alsathread.h" #include "jackclient.h" #include "lfqueue.h" #include "jack/control.h" static const char *clopt = "hvLSwj:d:r:p:n:c:Q:O:"; static void help (void) { jack_info ("%s-%s", APPNAME, VERSION); jack_info ("(C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org>"); jack_info ("Use ALSA playback device as a Jack client."); jack_info ("Options:"); jack_info (" -h Display this text"); jack_info (" -j <jackname> Name as Jack client [%s]", APPNAME); jack_info (" -d <device> ALSA playback device [none]"); jack_info (" -r <rate> Sample rate [48000]"); jack_info (" -p <period> Period size [256]"); jack_info (" -n <nfrags> Number of fragments [2]"); jack_info (" -c <nchannels> Number of channels [2]"); jack_info (" -S Word clock sync, no resampling"); jack_info (" -Q <quality> Resampling quality, 16..96 [auto]"); jack_info (" -O <samples> Latency adjustment [0]"); jack_info (" -L Force 16-bit and 2 channels [off]"); jack_info (" -w Wait until soundcard is available [off]"); jack_info (" -v Print tracing information [off]"); } class zita_j2a { Lfq_int32 *commq; Lfq_adata *alsaq; Lfq_jdata *infoq; Lfq_audio *audioq; bool stop; bool v_opt; bool L_opt; bool S_opt; bool w_opt; char *jname; char *device; int fsamp; int bsize; int nfrag; int nchan; int rqual; int ltcor; public: zita_j2a() { commq = new Lfq_int32(16); alsaq = new Lfq_adata(256); infoq = new Lfq_jdata(256); audioq = 0; stop = false; v_opt = false; L_opt = false; S_opt = false; w_opt = false; jname = strdup(APPNAME); device = 0; fsamp = 48000; bsize = 128; nfrag = 2; nchan = 2; rqual = 0; ltcor = 0; A = 0; P = 0; J = 0; t = 0; } private: int procoptions (int ac, const char *av []) { int k; optind = 1; opterr = 0; while ((k = getopt (ac, (char **) av, (char *) clopt)) != -1) { if (optarg && (*optarg == '-')) { jack_error (APPNAME ": Missing argument for '-%c' option.", k); jack_error (APPNAME ": Use '-h' to see all options."); return 1; } switch (k) { case 'h' : help (); return 1; case 'v' : v_opt = true; break; case 'L' : L_opt = true; break; case 'S' : S_opt = true; break; case 'w' : w_opt = true; break; case 'j' : jname = optarg; break; case 'd' : device = optarg; break; case 'r' : fsamp = atoi (optarg); break; case 'p' : bsize = atoi (optarg); break; case 'n' : nfrag = atoi (optarg); break; case 'c' : nchan = atoi (optarg); break; case 'Q' : rqual = atoi (optarg); break; case 'O' : ltcor = atoi (optarg); break; case '?': if (optopt != ':' && strchr (clopt, optopt)) { jack_error (APPNAME ": Missing argument for '-%c' option.", optopt); } else if (isprint (optopt)) { jack_error (APPNAME ": Unknown option '-%c'.", optopt); } else { jack_error (APPNAME ": Unknown option character '0x%02x'.", optopt & 255); } jack_error (APPNAME ": Use '-h' to see all options."); return 1; default: return 1; } } return 0; } int parse_options (const char* load_init) { int argsz; int argc = 0; const char** argv; char* args = strdup (load_init); char* token; char* ptr = args; char* savep; if (!load_init) { return 0; } argsz = 8; /* random guess at "maxargs" */ argv = (const char **) malloc (sizeof (char *) * argsz); argv[argc++] = APPNAME; while (1) { if ((token = strtok_r (ptr, " ", &savep)) == NULL) { break; } if (argc == argsz) { argsz *= 2; argv = (const char **) realloc (argv, sizeof (char *) * argsz); } argv[argc++] = token; ptr = NULL; } return procoptions (argc, argv); } void printinfo (void) { int n, k; double e, r; Jdata *J; n = 0; k = 99999; e = r = 0; while (infoq->rd_avail ()) { J = infoq->rd_datap (); if (J->_state == Jackclient::TERM) { jack_info (APPNAME ": Fatal error condition, terminating."); stop = true; return; } else if (J->_state == Jackclient::WAIT) { jack_info (APPNAME ": Detected excessive timing errors, waiting 10 seconds."); n = 0; } else if (J->_state == Jackclient::SYNC0) { jack_info (APPNAME ": Starting synchronisation."); } else if (v_opt) { n++; e += J->_error; r += J->_ratio; if (J->_bstat < k) k = J->_bstat; } infoq->rd_commit (); } if (n) jack_info ("%8.3lf %10.6lf %5d", e / n, r / n, k); } Alsa_pcmi *A; Alsathread *P; Jackclient *J; pthread_t t; int topts; static void* _retry_alsa_pcmi (void *arg) { ((zita_j2a*)arg)->retry_alsa_pcmi (); return NULL; } void retry_alsa_pcmi () { Alsa_pcmi *a; while (! stop) { sleep(1); a = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, topts); if (a->state ()) { delete a; continue; } A = a; if (v_opt) A->printinfo (); P = new Alsathread (A, Alsathread::PLAY); usleep (100*1000); jack_initialize_part2 (); jack_info (APPNAME ": Device is now available and has been activated"); break; } t = 0; } public: int jack_initialize (jack_client_t* client, const char* load_init) { int opts; if (parse_options (load_init)) { delete this; return 1; } if (device == 0) { help (); delete this; return 1; } if (rqual < 16) rqual = 16; if (rqual > 96) rqual = 96; if ((fsamp < 8000) || (bsize < 16) || (nfrag < 2) || (nchan < 1)) { jack_error (APPNAME ": Illegal parameter value(s)."); delete this; return 1; } opts = 0; if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH; if (w_opt) { J = new Jackclient (client, 0, Jackclient::PLAY, nchan, S_opt, this); // if device is not available, spawn thread to keep trying A = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, opts); if (A->state ()) { delete A; A = NULL; topts = opts; pthread_create (&t, NULL, _retry_alsa_pcmi, this); jack_info (APPNAME ": Could not open device, will keep trying in new thread..."); return 0; } // otherwise continue as normal if (v_opt) A->printinfo (); P = new Alsathread (A, Alsathread::PLAY); } else { A = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, opts); if (A->state ()) { jack_error (APPNAME ": Can't open ALSA playback device '%s'.", device); delete this; return 1; } if (v_opt) A->printinfo (); if (nchan > A->nplay ()) { nchan = A->nplay (); jack_error (APPNAME ": Warning: only %d channels are available.", nchan); } P = new Alsathread (A, Alsathread::PLAY); J = new Jackclient (client, 0, Jackclient::PLAY, nchan, S_opt, this); } usleep (100*1000); jack_initialize_part2 (); return 0; } void jack_initialize_part2 () { int k, k_del; double t_jack; double t_alsa; double t_del; t_alsa = (double) bsize / fsamp; if (t_alsa < 1e-3) t_alsa = 1e-3; t_jack = (double) J->bsize () / J->fsamp (); t_del = t_alsa + t_jack; k_del = (int)(t_del * fsamp); for (k = 256; k < 2 * k_del; k *= 2); audioq = new Lfq_audio (k, nchan); if (rqual == 0) { k = (fsamp < J->fsamp ()) ? fsamp : J->fsamp (); if (k < 44100) k = 44100; rqual = (int)((6.7 * k) / (k - 38000)); } if (rqual < 16) rqual = 16; if (rqual > 96) rqual = 96; P->start (audioq, commq, alsaq, J->rprio () + 10); J->start (audioq, commq, alsaq, infoq, (double) fsamp / J->fsamp (), k_del, ltcor, rqual); } void jack_finish (void* arg) { if (t != 0) { stop = true; pthread_join(t, NULL); t = 0; } commq->wr_int32 (Alsathread::TERM); usleep (100*1000); delete P; delete A; delete J; delete audioq; } }; extern "C" { int jack_initialize (jack_client_t* client, const char* load_init) { zita_j2a *c = new zita_j2a(); return c->jack_initialize(client, load_init); } void jack_finish (void* arg) { if (!arg) return; Jackclient *J = (Jackclient *)arg; zita_j2a *c = (zita_j2a *)J->getarg(); c->jack_finish(arg); delete c; } } /* extern "C" */ 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!1128 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor