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.
- Host: GitHub
- URL: https://github.com/ydah/jack-ruby
- Owner: ydah
- License: mit
- Created: 2026-03-06T13:30:20.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-03-07T13:39:51.000Z (4 months ago)
- Last Synced: 2026-03-07T17:56:44.718Z (4 months ago)
- Topics: api, audio, audio-connections, bindings, client, ffi, jack, ruby
- Language: Ruby
- Homepage:
- Size: 54.7 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
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).