Project icon

com.io7m.jjacob

Build status Maven Central Codacy Codecov

The jjacob package implements a Java binding to the JACK API.

Contents

Features

  • High-performance platform-independent JNR (unsafe) thin binding to the JACK API.
  • Type and memory-safe Java API built on top of the JNR bindings.
  • High coverage test suite.
  • OSGi-ready
  • ISC license

Releases

The current release is 0.0.1-SNAPSHOT.

Source code and binaries are available from the repository.

Documentation

Documentation for the 0.0.1-SNAPSHOT release is available for reading online.

Documentation for current and older releases is archived in the repository.

User documentation

See the JavaDoc comments and the original JACK API documentation.

Usage

Add the com.io7m.jjacob.api and com.io7m.jjacob.vanilla modules as dependencies to your application (or just com.io7m.jjacob.api if you're only writing library code). The com.io7m.jjacob.api module is the API specification and the com.io7m.jjacob.vanilla module is the default implementation that uses the JNR bindings to libjack internally.

The following is a simple example client that produces a sine wave tone forever:

 output_ports =
      client.portsList(
        Optional.empty(),
        Optional.empty(),
        EnumSet.of(JACK_PORT_IS_OUTPUT));

    output_ports.forEach(name -> LOG.debug("output: {}", name));

    final List input_ports =
      client.portsList(
        Optional.empty(),
        Optional.empty(),
        EnumSet.of(JACK_PORT_IS_INPUT));

    input_ports.forEach(name -> LOG.debug("input:  {}", name));

    /*
     * Searching for nonexistent ports returns no ports.
     */

    {
      final List empty_ports =
        client.portsList(
          Optional.of("DOES NOT EXIST!"),
          Optional.empty(),
          EnumSet.noneOf(JackPortFlag.class));
      LOG.debug("empty_ports: {}", empty_ports);
    }

    /*
     * Register two new output ports.
     */

    final JackPortType port_L =
      client.portRegister("out_L", EnumSet.of(JACK_PORT_IS_OUTPUT));
    final JackPortType port_R =
      client.portRegister("out_R", EnumSet.of(JACK_PORT_IS_OUTPUT));

    LOG.debug("owned: {}", Boolean.valueOf(port_L.belongsTo(client)));
    LOG.debug("owned: {}", Boolean.valueOf(port_R.belongsTo(client)));

    /*
     * Set a processing callback that will write a sine wave tone to the
     * outputs.
     */

    client.setProcessCallback(context -> {
      final JackBufferType buf0 = context.portBuffer(port_L);
      final JackBufferType buf1 = context.portBuffer(port_R);
      final int frames = context.bufferFrameCount();

      for (int index = 0; index < frames; index++) {
        final double position = (double) index / (double) frames;
        final double x = 0.2 * Math.sin(position * Math.PI * 4.0);
        buf0.putF(index, (float) x);
        buf1.putF(index, (float) x);
      }
    });

    /*
     * Activate the client.
     */

    client.activate();

    LOG.debug(
      "port_L: {} ({}) (typeName: '{}') (flags: {})",
      port_L.name(),
      port_L.shortName(),
      port_L.typeName(),
      port_L.flags());
    LOG.debug(
      "port_R: {} ({}) (typeName: '{}') (flags: {})",
      port_R.name(),
      port_R.shortName(),
      port_R.typeName(),
      port_R.flags());

    /*
     * Try and find the system's output ports and connect the client
     * to them.
     */

    final Optional system_L_opt =
      client.portByName("system:playback_1");
    final Optional system_R_opt =
      client.portByName("system:playback_2");

    system_L_opt.ifPresent(out_L -> {
      try {
        client.portsConnect(port_L.name(), out_L.name());
      } catch (final JackException e) {
        LOG.error("could not connect output port: ", e);
      }
    });

    system_R_opt.ifPresent(out_R -> {
      try {
        client.portsConnect(port_R.name(), out_R.name());
      } catch (final JackException e) {
        LOG.error("could not connect output port: ", e);
      }
    });

    /*
     * Sleep forever whilst JACK calls the client repeatedly to produce
     * audio.
     */

    try {
      while (true) {
        Thread.sleep(1000L);
      }
    } catch (final InterruptedException e) {
      Thread.currentThread().interrupt();
    }

    client.deactivate();
  } catch (final JackException e) {
    LOG.error("jack error: ", e);
  }
}
]]>

Maven

The following is a complete list of the project's modules expressed as Maven dependencies:

<dependency>
  <groupId>com.io7m.jjacob</groupId>
  <artifactId>com.io7m.jjacob</artifactId>
  <version>0.0.1-SNAPSHOT</version>
</dependency>

<dependency>
  <groupId>com.io7m.jjacob</groupId>
  <artifactId>com.io7m.jjacob.jnr</artifactId>
  <version>0.0.1-SNAPSHOT</version>
</dependency>

<dependency>
  <groupId>com.io7m.jjacob</groupId>
  <artifactId>com.io7m.jjacob.tests</artifactId>
  <version>0.0.1-SNAPSHOT</version>
</dependency>

<dependency>
  <groupId>com.io7m.jjacob</groupId>
  <artifactId>com.io7m.jjacob.api</artifactId>
  <version>0.0.1-SNAPSHOT</version>
</dependency>

<dependency>
  <groupId>com.io7m.jjacob</groupId>
  <artifactId>com.io7m.jjacob.vanilla</artifactId>
  <version>0.0.1-SNAPSHOT</version>
</dependency>

<dependency>
  <groupId>com.io7m.jjacob</groupId>
  <artifactId>com.io7m.jjacob.porttype.api</artifactId>
  <version>0.0.1-SNAPSHOT</version>
</dependency>

Each release of the project is made available on Maven Central within ten minutes of the release announcement.

Changes

Subscribe to the releases atom feed.

No formal releases have been made.

Sources

This project uses Git to manage source code.

Repository: https://github.com/io7m/jjacob

$ git clone https://github.com/io7m/jjacob

License

Copyright ⓒ 2018 Mark Raynsford <code@io7m.com> http://io7m.com

Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

Bug Tracker

The project uses GitHub Issues to track issues.