pax_global_header00006660000000000000000000000064143667167530014534gustar00rootroot0000000000000052 comment=33de8b4285fa5054af1b37fe0496c110604ed564 jack-example-tools-4/000077500000000000000000000000001436671675300147405ustar00rootroot00000000000000jack-example-tools-4/.cirrus.yml000066400000000000000000000020051436671675300170450ustar00rootroot00000000000000task: freebsd_instance: matrix: - image_family: freebsd-12-3 - image_family: freebsd-13-1 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 jack2_dependencies_script: - pkg install -y jackit pkgconf python3 libsndfile libsamplerate libsysinfo readline alsa-lib dbus expat opus git 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 jack-example-tools-4/.github/000077500000000000000000000000001436671675300163005ustar00rootroot00000000000000jack-example-tools-4/.github/workflows/000077500000000000000000000000001436671675300203355ustar00rootroot00000000000000jack-example-tools-4/.github/workflows/build.yml000066400000000000000000000216461436671675300221700ustar00rootroot00000000000000--- name: Build on various Operating Systems on: push: branches: [main] pull_request: branches: [main] env: JACK2_VERSION: v1.9.21 PAWPAW_CACHE_VERSION: 1 PAWPAW_JACK2_NO_CUSTOM_PREFIX: 1 PAWPAW_SKIP_LTO: 1 PAWPAW_VERSION: 01d07086586818e427b2898d2d446d30b68f3139 jobs: build_arch_linux_jack1: runs-on: ubuntu-latest container: image: archlinux:latest steps: - uses: actions/checkout@v3 - name: Add pro-audio-legacy repository run: | printf "[pro-audio-legacy]\nServer = https://pkgbuild.com/~dvzrv/repos/pro-audio-legacy/\$arch\n" >> /etc/pacman.conf pacman -Syy - name: Install dependencies run: pacman --noconfirm -Syu alsa-lib base-devel jack meson opus readline libsamplerate libsndfile zita-alsa-pcmi zita-resampler - 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@v3 - name: Install dependencies run: pacman --noconfirm -Syu alsa-lib base-devel jack2 meson opus readline libsamplerate libsndfile zita-alsa-pcmi zita-resampler - name: Build jack-example-tools run: meson build && ninja -C build - name: Install jack-example-tools run: ninja -C build install build_arch_linux_pipewire_jack: runs-on: ubuntu-latest container: image: archlinux:latest steps: - uses: actions/checkout@v3 - name: Install dependencies run: pacman --noconfirm -Syu alsa-lib base-devel meson opus pipewire-jack readline libsamplerate libsndfile zita-alsa-pcmi zita-resampler - name: Build jack-example-tools run: meson build && ninja -C build - name: Install jack-example-tools run: ninja -C build install build_alpine_linux: runs-on: ubuntu-latest container: image: alpine:latest steps: - uses: actions/checkout@v3 - name: Install dependencies run: apk add g++ meson pkgconf alsa-lib-dev jack-dev opus-dev readline-dev libsamplerate-dev libsndfile-dev - name: Build jack-example-tools run: meson build && ninja -C build - name: Install jack-example-tools run: ninja -C build install build_macos_latest: runs-on: macos-latest steps: - uses: actions/checkout@v3 - name: Install dependencies run: brew install jack meson opus pkg-config readline - name: Build jack-example-tools run: meson build && ninja -C build - name: Install jack-example-tools run: ninja -C build install build_pawpaw_macos_intel: runs-on: macos-10.15 steps: - uses: actions/checkout@v3 - name: Set up cache uses: actions/cache@v3 with: path: ~/PawPawBuilds key: macos-intel-v${{ env.PAWPAW_CACHE_VERSION }} - name: Set up dependencies run: brew install cmake jq meson - name: Bootstrap macOS intel shell: bash run: | if [ ! -d PawPaw ]; then git clone https://github.com/DISTRHO/PawPaw.git git -C PawPaw checkout ${{ env.PAWPAW_VERSION}} fi ./PawPaw/bootstrap-jack2.sh macos && ./PawPaw/.cleanup.sh macos - name: Build jack2 shell: bash run: | ./PawPaw/build-jack2.sh macos && ./PawPaw/.cleanup.sh macos - name: Build jack-example-tools shell: bash run: | pushd PawPaw && source local.env macos && popd meson build --prefix ${PAWPAW_PREFIX} || cat build/meson-logs/meson-log.txt ninja -C build - name: Install jack-example-tools run: | pushd PawPaw && source local.env macos && popd ninja -C build install build_pawpaw_macos_universal: runs-on: macos-10.15 steps: - uses: actions/checkout@v3 - name: Set up cache uses: actions/cache@v3 with: path: ~/PawPawBuilds key: macos-universal-v${{ env.PAWPAW_CACHE_VERSION }} - name: Set up dependencies run: brew install cmake jq meson - name: Fix up Xcode run: | sudo rm -Rf /Library/Developer/CommandLineTools/SDKs/* sudo xcode-select -s /Applications/Xcode_12.3.app - name: Bootstrap macOS intel shell: bash run: | if [ ! -d PawPaw ]; then git clone https://github.com/DISTRHO/PawPaw.git git -C PawPaw checkout ${{ env.PAWPAW_VERSION}} fi ./PawPaw/bootstrap-jack2.sh macos-universal && ./PawPaw/.cleanup.sh macos-universal - name: Build jack2 shell: bash run: | ./PawPaw/build-jack2.sh macos-universal && ./PawPaw/.cleanup.sh macos-universal - name: Build jack-example-tools shell: bash run: | pushd PawPaw && source local.env macos-universal && popd meson build --prefix ${PAWPAW_PREFIX} || cat build/meson-logs/meson-log.txt ninja -C build - name: Install jack-example-tools run: | pushd PawPaw && source local.env macos-universal && popd ninja -C build install build_pawpaw_win32: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - name: Set up cache uses: actions/cache@v3 with: path: ~/PawPawBuilds key: win32-v${{ env.PAWPAW_CACHE_VERSION }} - name: Fix GitHub's mess run: | sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list sudo apt-get update -qq sudo apt-get install -yqq --allow-downgrades libgd3/focal libpcre2-8-0/focal libpcre2-16-0/focal libpcre2-32-0/focal libpcre2-posix2/focal sudo apt-get purge -yqq libclang* libgbm* libllvm* libmono* moby* mono* php* libgdiplus libpcre2-posix3 libzip4 - name: Set up dependencies run: | sudo dpkg --add-architecture i386 sudo apt-get update -qq sudo apt-get install -y autopoint build-essential curl cmake jq llvm meson mingw-w64 python3-pip \ binutils-mingw-w64-i686 g++-mingw-w64-i686 mingw-w64 wine-stable:i386 pip3 install 'meson>=0.58.0' - name: Bootstrap win32 cross-compiled shell: bash run: | if [ ! -d PawPaw ]; then git clone https://github.com/DISTRHO/PawPaw.git git -C PawPaw checkout ${{ env.PAWPAW_VERSION}} fi ./PawPaw/bootstrap-jack2.sh win32 && ./PawPaw/.cleanup.sh win32 - name: Build jack2 shell: bash run: | ./PawPaw/build-jack2.sh win32 && ./PawPaw/.cleanup.sh win32 - name: Build jack-example-tools shell: bash run: | pushd PawPaw && source local.env win32 && popd meson build --prefix ${PAWPAW_PREFIX} --cross-file PawPaw/setup/meson/win32.ini || cat build/meson-logs/meson-log.txt ninja -C build - name: Install jack-example-tools run: | pushd PawPaw && source local.env win32 && popd ninja -C build install build_pawpaw_win64: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - name: Set up cache uses: actions/cache@v3 with: path: ~/PawPawBuilds key: win64-v${{ env.PAWPAW_CACHE_VERSION }} - name: Fix GitHub's mess run: | sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list sudo apt-get update -qq sudo apt-get install -yqq --allow-downgrades libgd3/focal libpcre2-8-0/focal libpcre2-16-0/focal libpcre2-32-0/focal libpcre2-posix2/focal sudo apt-get purge -yqq libclang* libgbm* libllvm* libmono* moby* mono* php* libgdiplus libpcre2-posix3 libzip4 - name: Set up dependencies run: | sudo dpkg --add-architecture i386 sudo apt-get update -qq sudo apt-get install -y autopoint build-essential curl cmake jq llvm meson mingw-w64 python3-pip \ binutils-mingw-w64-x86-64 g++-mingw-w64-x86-64 mingw-w64 wine-stable pip3 install 'meson>=0.58.0' - name: Bootstrap win64 cross-compiled shell: bash run: | if [ ! -d PawPaw ]; then git clone https://github.com/DISTRHO/PawPaw.git git -C PawPaw checkout ${{ env.PAWPAW_VERSION}} fi ./PawPaw/bootstrap-jack2.sh win64 && ./PawPaw/.cleanup.sh win64 - name: Build jack2 shell: bash run: | ./PawPaw/build-jack2.sh win64 && ./PawPaw/.cleanup.sh win64 - name: Build jack-example-tools shell: bash run: | pushd PawPaw && source local.env win64 && popd meson build --prefix ${PAWPAW_PREFIX} --cross-file PawPaw/setup/meson/win64.ini || cat build/meson-logs/meson-log.txt ninja -C build - name: Install jack-example-tools run: | pushd PawPaw && source local.env win64 && popd ninja -C build install jack-example-tools-4/.github/workflows/irc.yml000066400000000000000000000011011436671675300216260ustar00rootroot00000000000000name: 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 }} jack-example-tools-4/.gitignore000066400000000000000000000000101436671675300167170ustar00rootroot00000000000000/build/ jack-example-tools-4/CHANGELOG.md000066400000000000000000000027571436671675300165640ustar00rootroot00000000000000# Changelog ## [4] ### Fixes - Fix a typo in `alsa_in` manpage - Fix source-code comments and manpage for `jack_simple_client` - Remove includes of non-standard `alloca.h` header ## [3] ### Fixes - Ensure internal clients export their function entry points - Fix macOS and Windows builds ## [2] ### Fixes - Fix crashes in `midi_latency_test` - Fix regression in `alsa_in` that broke resampling (reverted code to known good state) - Fix usage help string in `midiseq` ## [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) jack-example-tools-4/CONTRIBUTING.md000066400000000000000000000033411436671675300171720ustar00rootroot00000000000000# 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 `) according to the new project version ### Versioning The project's version is defined as `` (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. jack-example-tools-4/LICENSE000066400000000000000000000355641436671675300157620ustar00rootroot00000000000000 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 jack-example-tools-4/README.md000066400000000000000000000057641436671675300162330ustar00rootroot00000000000000# 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 ``` ## 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)). jack-example-tools-4/common/000077500000000000000000000000001436671675300162305ustar00rootroot00000000000000jack-example-tools-4/common/memops.c000066400000000000000000001256551436671675300177120ustar00rootroot00000000000000/* 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 #include #include #include #include #include #include #ifdef __linux__ #include #endif #include "memops.h" #if defined (__SSE2__) && !defined (__sun__) #include #ifdef __SSE4_1__ #include #endif #endif #if defined (__ARM_NEON__) || defined (__ARM_NEON) #include #endif /* Notes about these *_SCALING values. the MAX_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_s the "d" component defines the destination type for the operation the "s" 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; } } jack-example-tools-4/common/memops.h000066400000000000000000000222331436671675300177030ustar00rootroot00000000000000/* 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 #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__ */ jack-example-tools-4/common/netjack_packet.c000066400000000000000000001247121436671675300213510ustar00rootroot00000000000000 /* * NetJack - Packet Handling functions * * used by the driver and the jacknet_client * * Copyright (C) 2019 Karl Linden * Copyright (C) 2008 Marc-Olivier Barre * Copyright (C) 2008 Pieter Palmers * Copyright (C) 2006 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. * * $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 #include #include #include #include #include #include #include #include #ifdef WIN32 #include #include #define socklen_t int #else #include #include #include #endif #include #include #include #if HAVE_OPUS #include #include #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); } jack-example-tools-4/common/netjack_packet.h000066400000000000000000000127221436671675300213530ustar00rootroot00000000000000 /* * NetJack - Packet Handling functions * * used by the driver and the jacknet_client * * Copyright (C) 2006 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. * * $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 #include #include #include // 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 jack-example-tools-4/example-clients/000077500000000000000000000000001436671675300200325ustar00rootroot00000000000000jack-example-tools-4/example-clients/capture_client.c000066400000000000000000000221111436671675300231740ustar00rootroot00000000000000/* 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 * 2003/05/26 - use ringbuffers - joq */ #include #include #include #include #include #include #include #include #include #include #include #include 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); } jack-example-tools-4/example-clients/control.c000066400000000000000000000031161436671675300216570ustar00rootroot00000000000000/** @file control.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. */ #include #include #include #include #include #include #include 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); } jack-example-tools-4/example-clients/cpu_load.c000066400000000000000000000034771436671675300217770ustar00rootroot00000000000000/** @file cpu_load.c * */ #include #include #include #include #include #include #ifndef WIN32 #include #endif #include 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 ); } jack-example-tools-4/example-clients/impulse_grabber.c000066400000000000000000000143051436671675300233430ustar00rootroot00000000000000/* * 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 #include #ifndef WIN32 #include #endif #include #include #include #include #include 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= response_duration) { grab_finished = 1; } for (i=0; i peak) { peak = fabs(response[i]); peak_sample = i; } } printf("\n};\n"); } else { for (i=0; i peak) { peak = fabs(response[i]); peak_sample = i; } } } fprintf(stderr, "Peak value was %f at sample %lu\n", peak, peak_sample); exit (0); } jack-example-tools-4/example-clients/inprocess.c000066400000000000000000000065271436671675300222150ustar00rootroot00000000000000/** @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 #include #include #include /** * 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); } jack-example-tools-4/example-clients/internal_metro.cpp000066400000000000000000000100451436671675300235600ustar00rootroot00000000000000/* 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); } jack-example-tools-4/example-clients/internal_metro.h000066400000000000000000000031301436671675300232220ustar00rootroot00000000000000/* 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 #include #include #include #include #include #include #include #include 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 jack-example-tools-4/example-clients/intime.c000066400000000000000000000116171436671675300214710ustar00rootroot00000000000000/* * 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 #include #include #include /* 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 */ JACK_LIB_EXPORT 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 */ JACK_LIB_EXPORT void jack_finish (void *arg) { fprintf (stderr, "Internal timebase client exiting.\n"); } jack-example-tools-4/example-clients/latent_client.c000066400000000000000000000123651436671675300230320ustar00rootroot00000000000000/** @file latent_client.c * * @brief This simple client demonstrates the most basic features of JACK * as they would be used by many applications. */ #include #include #ifndef WIN32 #include #endif #include #include #include #include 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 #include #include #ifndef WIN32 #include #endif #include #include #include #include #include #include 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); } jack-example-tools-4/example-clients/midi_latency_test.c000066400000000000000000000726671436671675300237200ustar00rootroot00000000000000/* 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 #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #include #else #include #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(sem_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[] = {'\'', '-', c, '\'', '\0'}; 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; } jack-example-tools-4/example-clients/midiseq.c000066400000000000000000000075741436671675300216460ustar00rootroot00000000000000/* 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 #include #include #include #include #include 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 8000 samples, then a d4# that starts at 1/4 sec that lasts for 8000 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); } jack-example-tools-4/example-clients/midisine.c000066400000000000000000000103011436671675300217720ustar00rootroot00000000000000/* 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 #include #include #include #include #include #include #include #include #include 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 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); } jack-example-tools-4/example-clients/netmaster.c000066400000000000000000000130141436671675300221770ustar00rootroot00000000000000/* 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 #include #include #include #ifndef WIN32 #include #endif #include #include #include #include #include #include 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); } jack-example-tools-4/example-clients/netslave.c000066400000000000000000000100751436671675300220220ustar00rootroot00000000000000/* 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 #include #include #ifndef WIN32 #include #endif #include #include #include #include #include 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); } jack-example-tools-4/example-clients/server_control.c000066400000000000000000000174151436671675300232540ustar00rootroot00000000000000/* 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 #include #include #include #include #include #include #include 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; } jack-example-tools-4/example-clients/showtime.c000066400000000000000000000062611436671675300220420ustar00rootroot00000000000000/* 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 #include #include #include #include #include #include #include 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); } jack-example-tools-4/example-clients/simdtests.cpp000066400000000000000000000267201436671675300225640ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #include #ifdef __linux__ #include #endif #include "memops.h" #if defined (__SSE2__) && !defined (__sun__) #include #ifdef __SSE4_1__ #include #endif #endif #if defined (__ARM_NEON__) || defined (__ARM_NEON) #include #endif // our additional headers #include /* 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 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; repetitionInteger @%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; sampleintval_orig+1 || intval_orig>intval_accel+1) { if(int_error_count 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; repetitionJackFloat @%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 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_countJackFloat @%7.7s/%u: Errors: %u Max deviation %f\n", test_cases[testcase].name, channels, float_error_count, float_deviation_max); printf("\n"); } } return 0; } jack-example-tools-4/example-clients/simple_client.c000066400000000000000000000124631436671675300230330ustar00rootroot00000000000000/** @file simple_client.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. */ #include #include #include #include #include #include #ifndef WIN32 #include #endif #include 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, write nframes sine wave samples to the two outputs ports. * 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; isine[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 #include #include #include #include #include #include #include #include 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); } jack-example-tools-4/example-clients/thru_client.c000066400000000000000000000134701436671675300225230ustar00rootroot00000000000000/** @file thru_client.c * * @brief This simple through client demonstrates the basic features of JACK * as they would be used by many applications. */ #include #include #include #include #include #include #ifndef WIN32 #include #endif #include 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 ); } jack-example-tools-4/example-clients/transport_client.c000066400000000000000000000114731436671675300235760ustar00rootroot00000000000000/** @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 #include #include #include #include #ifndef WIN32 #include #endif #include 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) { #ifdef WIN32 Sleep (1000); #else sleep (1); #endif } jack_client_close (client); exit (0); } jack-example-tools-4/example-clients/zombie.c000066400000000000000000000043261436671675300214700ustar00rootroot00000000000000/* 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 #include #include #include #include #include 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; } jack-example-tools-4/man/000077500000000000000000000000001436671675300155135ustar00rootroot00000000000000jack-example-tools-4/man/alsa_in.0000066400000000000000000000071301436671675300172030ustar00rootroot00000000000000.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 significantly 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 jack-example-tools-4/man/alsa_out.0000066400000000000000000000000231436671675300173760ustar00rootroot00000000000000.so man1/alsa_in.1 jack-example-tools-4/man/jack_bufsize.0000066400000000000000000000006631436671675300202400ustar00rootroot00000000000000.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. jack-example-tools-4/man/jack_connect.0000066400000000000000000000010521436671675300202130ustar00rootroot00000000000000.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 jack-example-tools-4/man/jack_disconnect.0000066400000000000000000000000301436671675300207060ustar00rootroot00000000000000.so man1/jack_connect.1 jack-example-tools-4/man/jack_freewheel.0000066400000000000000000000012001436671675300205230ustar00rootroot00000000000000.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. jack-example-tools-4/man/jack_impulse_grabber.0000066400000000000000000000005271436671675300217320ustar00rootroot00000000000000.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. jack-example-tools-4/man/jack_iodelay.0000066400000000000000000000056031436671675300202160ustar00rootroot00000000000000.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. jack-example-tools-4/man/jack_load.0000066400000000000000000000016221436671675300175040ustar00rootroot00000000000000.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 jack-example-tools-4/man/jack_lsp.0000066400000000000000000000020541436671675300173630ustar00rootroot00000000000000.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 jack-example-tools-4/man/jack_metro.0000066400000000000000000000021051436671675300177100ustar00rootroot00000000000000.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 jack-example-tools-4/man/jack_monitor_client.0000066400000000000000000000007771436671675300216240ustar00rootroot00000000000000.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 for Debian. jack-example-tools-4/man/jack_netsource.0000066400000000000000000000044741436671675300206040ustar00rootroot00000000000000.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 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 jack-example-tools-4/man/jack_property.0000066400000000000000000000045451436671675300204600ustar00rootroot00000000000000.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 jack-example-tools-4/man/jack_rec.0000066400000000000000000000020241436671675300173330ustar00rootroot00000000000000.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. jack-example-tools-4/man/jack_samplerate.0000066400000000000000000000003501436671675300207170ustar00rootroot00000000000000.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. jack-example-tools-4/man/jack_showtime.0000066400000000000000000000004761436671675300204320ustar00rootroot00000000000000.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 jack-example-tools-4/man/jack_simple_client.0000066400000000000000000000011001436671675300214030ustar00rootroot00000000000000.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 output ports (client-name:output1 and client-name:output2) and plays a sine wave to these ports. .SH EXAMPLE jack_simple_client in_process_test .SH AUTHOR Jeremy Hall .PP This manpage was written by Robert Jordens for Debian. jack-example-tools-4/man/jack_transport.0000066400000000000000000000006161436671675300206230ustar00rootroot00000000000000.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 jack-example-tools-4/man/jack_unload.0000066400000000000000000000007341436671675300200520ustar00rootroot00000000000000.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 for Debian. jack-example-tools-4/man/jack_wait.0000066400000000000000000000020001436671675300175200ustar00rootroot00000000000000.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 jack-example-tools-4/man/meson.build000066400000000000000000000014211436671675300176530ustar00rootroot00000000000000man_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 jack-example-tools-4/meson.build000066400000000000000000000133401436671675300171030ustar00rootroot00000000000000project( 'jack-example-tools', ['c', 'cpp'], meson_version: '>=0.58.0', license: ['GPL2+'], version: '4', ) os = build_machine.system() cc = meson.get_compiler('c') alsa_required = false if get_option('alsa_in_out').enabled() or get_option('zalsa').enabled() alsa_required = true endif lib_rt_required = false if get_option('zalsa').enabled() lib_rt_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 #include #include 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 #include 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()) if host_machine.system() == 'windows' and host_machine.cpu_family() == 'x86_64' lib_jackserver_suffix = '64' else lib_jackserver_suffix = '' endif # we must link to jackserver as shared library, which is hard if `-Wl,-Bstatic` is used in `LDFLAGS` # do a little dance to support such builds here # FIXME find a way to do something like `if link_args.contains('-Bstatic')` if host_machine.system() == 'windows' lib_jackserver = declare_dependency(link_args: ['-Wl,-Bshared', '-ljackserver' + lib_jackserver_suffix, '-Wl,-Bstatic']) else lib_jackserver = cc.find_library('jackserver' + lib_jackserver_suffix, required: true) endif has_jackctl_server_create2 = cc.has_function('jackctl_server_create2', dependencies: lib_jackserver, prefix: '#include ') 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')) header_opus_custom = cc.check_header('opus/opus_custom.h') 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_m = cc.find_library('m') lib_rt = cc.find_library('rt', required: lib_rt_required) 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 ') 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 # FIXME jacknet tools fail to build on windows if get_option('jack_net').enabled() or (get_option('jack_net').auto() and lib_jacknet.found() and host_machine.system() != 'windows') build_jack_net = true endif build_jack_netsource = false # FIXME jacknet tools fail to build on windows if get_option('jack_netsource').enabled() or (get_option('jack_netsource').auto() and dep_samplerate.found() and host_machine.system() != 'windows') build_jack_netsource = true endif opus_support = false if get_option('opus_support').enabled() or (get_option('opus_support').auto() and dep_opus.found() and header_opus_custom) 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_rt.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') jack-example-tools-4/meson_options.txt000066400000000000000000000016151436671675300204000ustar00rootroot00000000000000option('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)') jack-example-tools-4/scripts/000077500000000000000000000000001436671675300164275ustar00rootroot00000000000000jack-example-tools-4/scripts/meson_create_symlink000077500000000000000000000005061436671675300225700ustar00rootroot00000000000000#!/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 -fsv "$2" "$MESON_INSTALL_DESTDIR_PREFIX/$1/$3" jack-example-tools-4/tools/000077500000000000000000000000001436671675300161005ustar00rootroot00000000000000jack-example-tools-4/tools/alias.c000066400000000000000000000046551436671675300173470ustar00rootroot00000000000000#include #include #include #include #include #include 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; } jack-example-tools-4/tools/alsa_in.c000066400000000000000000000562101436671675300176560ustar00rootroot00000000000000/** @file simple_client.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. */ #include #include #include #include #include #include #include #include #include #include "memops.h" #include "alsa/asoundlib.h" #include // 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; idata; 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 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 - client name\n" " -S - server to connect\n" " -d \n" " -c \n" " -p \n" " -n \n" " -r \n" " -q \n" " -t \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) jack_sample_rate / (double) 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 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); } jack-example-tools-4/tools/alsa_out.c000066400000000000000000000564751436671675300200740ustar00rootroot00000000000000/** @file simple_client.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. */ #include #include #include #include #include #include #include #include #include #include "memops.h" #include "alsa/asoundlib.h" #include // 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; idata; 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 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 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 - client name\n" " -S - server to connect\n" " -d \n" " -c \n" " -p \n" " -n \n" " -r \n" " -q \n" " -t \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 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); } jack-example-tools-4/tools/bufsize.c000066400000000000000000000055041436671675300177170ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #include #include 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 \n", package); exit(9); } if (strspn (argv[1], "0123456789") != strlen (argv[1])) { fprintf(stderr, "usage: %s \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; } jack-example-tools-4/tools/connect.c000066400000000000000000000137661436671675300177120ustar00rootroot00000000000000/* 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 #include #ifndef WIN32 #include #endif #include #include #include #include #include #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 Connect to the jack server named \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); } jack-example-tools-4/tools/evmon.c000066400000000000000000000100031436671675300173620ustar00rootroot00000000000000/* 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 #include #ifndef WIN32 #include #endif #include #include #include #include #include #include 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); } jack-example-tools-4/tools/freewheel.c000066400000000000000000000041321436671675300202120ustar00rootroot00000000000000/* * 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 #include #ifndef WIN32 #include #endif #include #include #include #include #include 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; } jack-example-tools-4/tools/iodelay.cpp000066400000000000000000000161661436671675300202440ustar00rootroot00000000000000/* Copyright (C) 2003-2008 Fons Adriaensen 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 #include #define __STDC_LIMIT_MACROS #include #include #include #include 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; } // -------------------------------------------------------------------------------- jack-example-tools-4/tools/ipload.c000066400000000000000000000132451436671675300175210ustar00rootroot00000000000000/* 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 #include #include #include #ifndef WIN32 #include #endif #include #include #include 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; } jack-example-tools-4/tools/ipunload.c000066400000000000000000000054451436671675300200670ustar00rootroot00000000000000/* 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 #include #include #include #include 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; } jack-example-tools-4/tools/load_test.c000066400000000000000000000047701436671675300202320ustar00rootroot00000000000000#include #include #include #include #include #include #include #include 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 ); #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 jack_on_shutdown(client, jack_shutdown, 0); jack_set_process_callback( client, process_cb, NULL ); jack_activate (client); #ifdef WIN32 Sleep (INFINITE); #else sleep (-1); #endif exit (0); } jack-example-tools-4/tools/lsp.c000066400000000000000000000172621436671675300170520ustar00rootroot00000000000000/* 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 #include #ifndef WIN32 #include #endif #include #include #include #include #include #include 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 Connect to the jack server named \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); } jack-example-tools-4/tools/meson.build000066400000000000000000000103751436671675300202500ustar00rootroot00000000000000exe_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 if has_jack1_internal_client or has_jack2_internal_client exe_jack_unload = executable( 'jack_unload', c_args: c_args_jack_unload, sources: ['ipunload.c'], dependencies: [dep_jack], install: true ) endif 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 ) # FIXME deal with alloca on windows if host_machine.system() != 'windows' # 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 ) endif 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 jack-example-tools-4/tools/midi_dump.c000066400000000000000000000133221436671675300202140ustar00rootroot00000000000000// gcc -o jack_midi_dump -Wall midi_dump.c -ljack -pthread #include #include #include #include #include #include #include #include #ifdef __MINGW32__ #include #endif #ifndef WIN32 #include #include #include #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); } #ifdef WIN32 signal(SIGINT, wearedone); signal(SIGABRT, wearedone); signal(SIGTERM, wearedone); #else signal(SIGQUIT, wearedone); signal(SIGTERM, wearedone); 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; } jack-example-tools-4/tools/monitor_client.c000066400000000000000000000032121436671675300212670ustar00rootroot00000000000000/* 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 #include #include #include #include #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); } jack-example-tools-4/tools/netsource.c000066400000000000000000000623761436671675300202710ustar00rootroot00000000000000/* NetJack Client Copyright (C) 2008 Marc-Olivier Barre Copyright (C) 2008 Pieter Palmers Copyright (C) 2006 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. */ /** @file netsource.c * * @brief This client connects a remote slave JACK to a local JACK server assumed to be the master */ #include #include #include #include #include #include #ifdef WIN32 #include #define socklen_t int #include #else #include #include #include #endif /* These two required by FreeBSD. */ #include #include #include #include #ifndef CUSTOM_MODES #define CUSTOM_MODES // for opus_custom_decoder_init #endif #if HAVE_OPUS #include #include #endif #include 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 - Host name of the slave JACK\n" " -o - Number of audio playback channels\n" " -i - Number of audio capture channels\n" " -O - Number of midi playback channels\n" " -I - Number of midi capture channels\n" " -n - Network latency in JACK periods\n" " -p - UDP port that the slave is listening on\n" " -r - UDP port that we are listening on\n" " -B - reply port, for use in NAT environments\n" " -b - Set transport to use 16bit or 8bit\n" " -P - Use Opus encoding with kbits per channel\n" " -m - Assume this mtu for the link\n" " -R - Redundancy: send out packets N times.\n" " -e - skip host-to-network endianness conversion\n" " -N - Reports a different name to jack\n" " -s - 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); } jack-example-tools-4/tools/property.c000066400000000000000000000160141436671675300201320ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include 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; } jack-example-tools-4/tools/samplerate.c000066400000000000000000000040061436671675300204010ustar00rootroot00000000000000/* * 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 #include #ifndef WIN32 #include #endif #include #include #include #include #include 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; } jack-example-tools-4/tools/session_notify.c000066400000000000000000000111121436671675300213130ustar00rootroot00000000000000/* * session_notify.c -- ultra minimal session manager * * Copyright (C) 2018 Karl Linden * 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 #include #include #include #include #include #include #include #include #include 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; } jack-example-tools-4/tools/transport.c000066400000000000000000000305141436671675300203030ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #if HAVE_READLINE #include #include #endif #include #include /* 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