An open API service indexing awesome lists of open source software.

https://github.com/ydah/jack-ruby

Ruby FFI bindings for the core JACK Audio Connection Kit client APIs.
https://github.com/ydah/jack-ruby

api audio audio-connections bindings client ffi jack ruby

Last synced: 8 days ago
JSON representation

Ruby FFI bindings for the core JACK Audio Connection Kit client APIs.

Awesome Lists containing this project

README

          

# Jack

Ruby FFI bindings for the core [JACK Audio Connection Kit](https://jackaudio.org/) client APIs.

This gem targets `libjack` from both JACK1 and JACK2. It covers client lifecycle, audio and MIDI ports, callbacks, transport, session management, metadata, ring buffers, UUID helpers, thread/statistics helpers, and internal client APIs.

`net.h` / NetJACK (`libjacknet`) is a separate library and is not currently bound by this gem.

## Installation

Add the gem with Bundler:

```bash
bundle add jack-ruby
```

Or install it directly:

```bash
gem install jack-ruby
```

JACK itself must already be installed:

- macOS: `brew install jack`
- Ubuntu/Debian: `sudo apt-get install jackd2 libjack-jackd2-dev`
- Fedora: `sudo dnf install jack-audio-connection-kit-devel`

## Quick Start

```ruby
require "jack"

puts "JACK #{Jack.version_string}"

Jack::Client.open("simple") do |client|
puts "Client name: #{client.name}"
puts "Sample rate: #{client.sample_rate}"
puts "Buffer size: #{client.buffer_size}"
puts "Realtime: #{client.realtime?}"

client.activate

client.get_ports.each do |port_name|
puts port_name
end
end
```

## Examples

### Audio Passthrough

```ruby
require "jack"

Jack::Client.open("passthrough") do |client|
input = client.register_audio_input("in")
output = client.register_audio_output("out")

client.on_process do |nframes|
in_buf = input.buffer_pointer(nframes)
out_buf = output.buffer_pointer(nframes)
out_buf.write_bytes(in_buf.read_bytes(nframes * 4))
0
end

client.activate

capture = client.get_ports(flags: Jack::JackPortIsPhysical | Jack::JackPortIsOutput).first
playback = client.get_ports(flags: Jack::JackPortIsPhysical | Jack::JackPortIsInput).first
client.connect(capture, "passthrough:in") if capture
client.connect("passthrough:out", playback) if playback

sleep
end
```

### MIDI Monitor

```ruby
require "jack"

Jack::Client.open("midi_monitor") do |client|
midi_in = client.register_midi_input("in")

client.on_process do |nframes|
midi_in.read_all_events(nframes).each do |event|
puts "Note ON #{event.note}" if event.note_on?
puts "Note OFF #{event.note}" if event.note_off?
end
0
end

client.activate
sleep
end
```

### Transport Control

```ruby
require "jack"

Jack::Client.open("transport_ctl") do |client|
transport = client.transport

client.activate
transport.locate(0)
transport.start

sleep 2

position = transport.query
puts "State: #{transport.state}"
puts "Frame: #{position[:frame]}"

transport.stop
end
```

More runnable examples live in `examples/`:

- `audio_passthrough.rb`
- `meter.rb`
- `midi_generator.rb`
- `midi_monitor.rb`
- `port_connector.rb`
- `ringbuffer_recorder.rb`
- `simple_client.rb`
- `sine_generator.rb`
- `transport_control.rb`

## API Overview

| API | Description |
|---|---|
| `Jack` | Library-wide helpers like `version`, `version_string`, `client_pid`, `on_error`, `on_info` |
| `Jack::Client` | Client open/close, activation, port registration, connection management, callbacks, stats, RT scheduling, internal clients |
| `Jack::Port` | Common port metadata, aliases, monitor control, latency helpers, legacy tie/untie support |
| `Jack::AudioPort` | Raw audio buffer access |
| `Jack::MidiPort` | MIDI event read/write, buffer reset/clear helpers |
| `Jack::Midi::Event` | MIDI message inspection helpers |
| `Jack::Transport` | Transport query/control, sync callback, timebase callback, legacy transport info helpers |
| `Jack::Session` | Session callback, notify/reply, UUID and reservation helpers |
| `Jack::Metadata` | Property set/get/remove and property change callback |
| `Jack::RingBuffer` | Lock-free ring buffer, vectors, mlock, reset/reset_size |
| `Jack::UUID` | UUID generation, parse/unparse, compare/copy/clear helpers |

## Optional APIs and Compatibility

JACK exports some symbols conditionally depending on the server and library version. When a method relies on an optional symbol and that symbol is not present, this gem raises `Jack::NotImplementedError`.

Common examples:

- `Jack::Metadata` methods on JACK installations without metadata support
- `Jack::Port#rename` on older JACK versions
- `Jack::RingBuffer#reset_size`
- Legacy compatibility helpers such as `Jack::Port#latency`, `Jack::Port#total_latency`, and `Jack::Transport#legacy_info`

The gem supports both JACK1 and JACK2 `libjack`, but some helpers are only available on JACK2 or newer JACK releases.

## Top-Level Helpers

```ruby
require "jack"

Jack.on_error { |message| warn "JACK error: #{message}" }
Jack.on_info { |message| puts "JACK info: #{message}" }

p Jack.version
puts Jack.version_string
puts Jack.client_pid("system")

uuid = Jack::UUID.generate_client
puts Jack::UUID.unparse(uuid)
```

## Development

Install dependencies and run the test suite:

```bash
bundle install
bundle exec rspec
```

Integration tests require a running JACK server and are only enabled when `JACK_TEST=1` is set:

```bash
jackd -d dummy &
JACK_TEST=1 bundle exec rspec spec/integration/
```

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/ydah/jack.

## Environment Variables

- `JACK_LIB_PATH`: override the `libjack` path loaded by FFI

## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).