Compare commits

..

1 Commits

Author SHA1 Message Date
3967d72e72 feat: add zoom2transport example
Signed-off-by: Christopher Arndt <chris@chrisarndt.de>
2024-10-17 16:57:22 +02:00
19 changed files with 482 additions and 384 deletions

View File

@ -1,58 +0,0 @@
name: Run tests and build examples
on: [push, pull_request]
env:
nim_version: "2.2.0"
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
#os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Check out sources
uses: actions/checkout@v4
- name: Nim Runtime Cache
id: cache-nim
uses: actions/cache@v4
with:
path: ".nim_runtime"
key: ${{ runner.os }}-nim-${{ env.nim_version }}
- name: Install Nim
id: install-nim
if: ${{ hashFiles('.nim_runtime/bin/nim*') == '' }}
uses: jiro4989/setup-nim-action@v2
with:
nim-version: ${{ env.nim_version }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Set PATH for Unix
if: ${{ runner.os != 'Windows' && steps.install-nim.outcome == 'skipped' }}
shell: bash
run: |
echo "$(pwd)/.nim_runtime/bin" >> "$GITHUB_PATH"
echo "$HOME/.nimble/bin" >> "$GITHUB_PATH"
- name: Set PATH for Windows
if: ${{ runner.os == 'Windows' && steps.install-nim.outcome == 'skipped' }}
shell: pwsh
run: |
echo "$(Get-Location)\.nim_runtime\bin" >> $Env:GITHUB_PATH
mkdir -Force ~\.nimble\bin
(Resolve-Path ~\.nimble\bin).Path >> $Env:GITHUB_PATH
- name: Install dependency packages (jack)
uses: ConorMacBride/install-package@v1
with:
brew: jack pcre
apt: libjack-jackd2-dev libpcre3-dev
choco: jack
- name: Update PATH (Windows)
if: runner.os == 'Windows'
run: Add-Content $env:GITHUB_PATH "C:\Program Files\jack\bin"
- name: Run tests
run: nimble test -y
- name: Build examples (debug)
run: nimble examples_debug
- name: Build examples (release)
run: nimble examples

View File

@ -1,26 +0,0 @@
name: Build and publish API docs
on:
push:
branches:
- master
env:
nim-version: "stable"
nim-src: src/jacket.nim
deploy-dir: .gh-pages
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: jiro4989/setup-nim-action@v2
with:
nim-version: ${{ env.nim-version }}
- run: nimble install -y
- run: nimble doc --index:on --project --git.url:https://github.com/${{ github.repository }} --git.commit:master --out:${{ env.deploy-dir }} ${{ env.nim-src }}
- name: "Copy to index.html"
run: cp ${{ env.deploy-dir }}/jacket.html ${{ env.deploy-dir }}/index.html
- name: Deploy documents
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ${{ env.deploy-dir }}

View File

@ -1,19 +1,17 @@
# jacket
A [Nim] wrapper for the JACK Audio Connection Kit ([JACK]) client side [C API]
aka **libjack**.
A [Nim] wrapper for the [JACK] client side [C API] aka *libjack*.
## Project status
This software is in *beta status*.
The majority of JACK client API functions have been wrapped and are functional
(see [examples]), but some API parts (e.g. threading) still need wrapping.
Others, like the server control or the deprecated session API, will probably
not be covered by these bindings. While this project is in beta stage, symbol
names may still be changed and things moved around before the first stable
release.
The majority of JACK client APIs have been wrapped and are functional (see
[examples]), but some APIs (e.g. threading) still need wrapping. Others, like
the server control or the deprecated session API, will probably not be covered
by these bindings. While this project is in beta stage, symbol names may still
be changed and things moved around before the first stable release.
## Installation
@ -21,7 +19,7 @@ release.
* Clone this repository.
* Change into the `jacket` directory.
* Run [`nimble install`] (or `nimble develop`).
* Build the [examples] with `nimble examples`.
* Run the [examples] with `nim compile --run examples/<example>.nim`.
(Some examples need `--threads:on` with Nim < 2.0).
@ -29,9 +27,10 @@ release.
## Usage
Here is a very minimal JACK client application, which just passes audio through
from its single input port to its output port. Any error checking and handling
has been omitted for brevity's sake. See the files in the [examples] directory
for more robust example code.
from its single input port to its output port.
Any error checking and handling has been omitted for brevity's sake. See the
files in the [examples] directory for more robust example code.
```nim
import std/os
@ -39,11 +38,11 @@ import system/ansi_c
import jacket
var
jackClient: ClientP
status: cint
exitSignalled = false
inpPort, outPort: Port
type SampleBuffer = ptr UncheckedArray[DefaultAudioSample]
exitSignalled: bool = false
inpPort, outPort: PortP
type JackBufferP = ptr UncheckedArray[DefaultAudioSample]
proc signalCb(sig: cint) {.noconv.} =
exitSignalled = true
@ -52,41 +51,41 @@ proc shutdownCb(arg: pointer = nil) {.cdecl.} =
exitSignalled = true
proc processCb(nFrames: NFrames, arg: pointer): cint {.cdecl.} =
let inpbuf = cast[SampleBuffer](portGetBuffer(inpPort, nFrames))
let outbuf = cast[SampleBuffer](portGetBuffer(outPort, nFrames))
var inpbuf = cast[JackBufferP](portGetBuffer(inpPort, nFrames))
var outbuf = cast[JackBufferP](portGetBuffer(outPort, nFrames))
# copy samples from input to output buffer
for i in 0 ..< nFrames:
outbuf[i] = inpbuf[i]
# Create JACK Client ptr
var jackClient = clientOpen("passthru", NullOption, status.addr)
jackClient = clientOpen("passthru", NullOption, status.addr)
# Register audio input and output ports
inpPort = jackClient.portRegister("in_1", JackDefaultAudioType, PortIsInput, 0)
outPort = jackClient.portRegister("out_1", JackDefaultAudioType, PortIsOutput, 0)
inpPort = jackClient.portRegister("in_1", JACK_DEFAULT_AUDIO_TYPE, PortIsInput, 0)
outPort = jackClient.portRegister("out_1", JACK_DEFAULT_AUDIO_TYPE, PortIsOutput, 0)
# Set JACK callbacks
jackClient.onShutdown(shutdownCb)
jackClient.setProcessCallback(processCb, nil)
discard jackClient.setProcessCallback(processCb, nil)
# Handle POSIX signals
c_signal(SIGINT, signalCb)
c_signal(SIGTERM, signalCb)
# Activate JACK client ...
jackClient.activate()
discard jackClient.activate()
while not exitSignalled:
sleep(50)
jackClient.clientClose()
discard jackClient.clientClose()
```
## License
This software is released under the **MIT License**. See the file
This software is released under the *MIT License*. See the file
[LICENSE.md](./LICENSE.md) for more information.
Please note that the JACK client library (libjack), which this project wraps,
is licensed under the [LGPL-2.1]. This wrapper does not statically or
dynamically link to libjack at build time, but only loads it via [dynlib] at
dynamically link to libjack, but only loads it via the dynamic linker at
run-time.
Software using this wrapper is, in the opinion of its author, not considered a
@ -97,12 +96,11 @@ professional legal counsel when in doubt.
## Author
**jacket** is written by [Christopher Arndt].
*jacket* is written by [Christopher Arndt].
[C API]: https://jackaudio.org/api/
[Christopher Arndt]: mailto:info@chrisarndt.de
[dynlib]: https://nim-lang.org/docs/manual.html#foreign-function-interface-dynlib-pragma-for-import
[examples]: ./examples
[JACK]: https://jackaudio.org/
[LGPL-2.1]: https://spdx.org/licenses/LGPL-2.1-or-later.html

View File

@ -5,7 +5,7 @@ var status: cint
var log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug)
proc errorCb(msg: cstring) {.cdecl.} =
# Suppress verbose JACK error messages when server is not available by
# Suppress verbose JACK error messages when server is not available by
# default. Pass ``lvlAll`` when creating the logger to enable them.
debug "JACK error: " & $msg
@ -26,4 +26,4 @@ echo("DSP load: ", jclient.cpuLoad, "%")
echo("Server time: ", getTime())
echo("Client name: ", jclient.getClientName)
jclient.clientClose()
discard jclient.clientClose

View File

@ -3,12 +3,12 @@ import jacket
var
status: cint
descs: ptr UncheckedArray[DescriptionT]
descs: ptr UncheckedArray[Description]
var log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug)
proc errorCb(msg: cstring) {.cdecl.} =
# Suppress verbose JACK error messages when server is not available by
# Suppress verbose JACK error messages when server is not available by
# default. Pass ``lvlAll`` when creating the logger to enable them.
debug "JACK error: " & $msg
@ -40,4 +40,4 @@ if numDescs != -1:
else:
error "Could not get properties!"
jclient.clientClose()
discard jclient.clientClose

View File

@ -2,9 +2,9 @@ import std/[logging, os, strutils]
import signal
import jacket
var jclient: Client
var event: MidiEventT
var midiPort: Port
var jclient: ClientP
var event: MidiEvent
var midiPort: PortP
var status: cint
var exitSignalled: bool = false
var log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug)
@ -13,8 +13,8 @@ var log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug)
proc cleanup() =
debug "Cleaning up..."
if jclient != nil:
jclient.deactivate()
jclient.clientClose()
discard jclient.deactivate()
discard jclient.clientClose()
jclient = nil
proc errorCb(msg: cstring) {.cdecl.} =
@ -30,7 +30,7 @@ proc shutdownCb(arg: pointer = nil) {.cdecl.} =
warn "JACK server has shut down."
exitSignalled = true
proc printMidiEvent(event: var MidiEventT) =
proc printMidiEvent(event: var MidiEvent) =
if event.size <= 3:
for i in 0..<event.size:
stdout.write(event.buffer[i].toHex)
@ -74,7 +74,7 @@ proc main() =
jclient.onShutdown(shutdownCb)
# Create output port
midiPort = jclient.portRegister("midi_in", JackDefaultMidiType, PortIsInput, 0)
midiPort = jclient.portRegister("midi_in", JACK_DEFAULT_MIDI_TYPE, PortIsInput, 0)
# Activate JACK client ...
if jclient.activate() == 0:

View File

@ -5,10 +5,10 @@ import signal
import jacket
var
jclient: Client
event: MidiEventT
midiPort: Port
rb: Ringbuffer
jclient: ClientP
event: MidiEvent
midiPort: PortP
rb: RingbufferP
midiEventPrinter: Thread[void]
status: cint
exitSignalled: bool = false
@ -27,7 +27,7 @@ proc cleanup() =
if jclient != nil:
debug "Deactivating JACK client..."
jclient.deactivate()
discard jclient.deactivate()
if midiEventPrinter.running:
debug "Stopping MIDI event printer thread..."
@ -42,7 +42,7 @@ proc cleanup() =
if jclient != nil:
debug "Closing JACK client..."
jclient.clientClose()
discard jclient.clientClose()
jclient = nil
debug fmt"Buffer overruns: {overruns}"
@ -68,7 +68,7 @@ proc midiEventPrinterProc() {.thread.} =
while true:
while not exitLoop and ringbufferReadSpace(rb) >= 4:
discard ringbufferRead(rb, cast[cstring](recvBuf.addr), 4)
var read = cast[int](ringbufferRead(rb, cast[cstring](recvBuf.addr), 4))
if recvBuf[0] <= 3:
for i in 0..<recvBuf[0].int:
@ -138,7 +138,7 @@ proc main() =
jclient.onShutdown(shutdownCb)
# Create output port
midiPort = jclient.portRegister("midi_in", JackDefaultMidiType, PortIsInput, 0)
midiPort = jclient.portRegister("midi_in", JACK_DEFAULT_MIDI_TYPE, PortIsInput, 0)
# Activate JACK client ...
if jclient.activate() == 0:

View File

@ -3,9 +3,10 @@ import signal
import jacket
var
jclient: Client
midiPort: Port
midiEventChan: Channel[MidiEventT]
jclient: ClientP
event: MidiEvent
midiPort: PortP
midiEventChan: Channel[MidiEvent]
midiEventPrinter: Thread[void]
status: cint
exitSignalled: bool = false
@ -18,13 +19,13 @@ proc cleanup() =
if jclient != nil:
debug "Deactivating JACK client..."
jclient.deactivate()
discard jclient.deactivate()
if midiEventPrinter.running:
debug "Stopping MIDI event printer thread..."
# Receiving an invalid event causes receiving thread to wake up and
# break its endless loop
let event = MidiEventT(size: 0)
event.size = 0
midiEventChan.send(event)
midiEventPrinter.joinThread()
@ -34,7 +35,7 @@ proc cleanup() =
if jclient != nil:
debug "Closing JACK client..."
jclient.clientClose()
discard jclient.clientClose()
jclient = nil
debug "Bye."
@ -53,8 +54,10 @@ proc shutdownCb(arg: pointer = nil) {.cdecl.} =
exitSignalled = true
proc midiEventPrinterProc() =
var event: MidiEvent
while true:
let event = midiEventChan.recv()
event = midiEventChan.recv()
if event.size == 0:
break
@ -67,7 +70,6 @@ proc midiEventPrinterProc() =
stdout.flushFile()
proc processCb*(nFrames: NFrames, arg: pointer): cint {.cdecl.} =
var event: MidiEventT
let inbuf = portGetBuffer(midiPort, nFrames)
let count = midiGetEventCount(inbuf)
@ -108,7 +110,7 @@ proc main() =
jclient.onShutdown(shutdownCb)
# Create output port
midiPort = jclient.portRegister("midi_in", JackDefaultMidiType, PortIsInput, 0)
midiPort = jclient.portRegister("midi_in", JACK_DEFAULT_MIDI_TYPE, PortIsInput, 0)
# Activate JACK client ...
if jclient.activate() == 0:

View File

@ -10,9 +10,9 @@ import signal
import jacket
var
jclient: Client
midiPort: Port
midiEventChan: Chan[MidiEventT]
jclient: ClientP
midiPort: PortP
midiEventChan: Chan[MidiEvent]
midiEventPrinter: Thread[void]
status: cint
exitSignalled: bool = false
@ -25,20 +25,20 @@ proc cleanup() =
if jclient != nil:
debug "Deactivating JACK client..."
jclient.deactivate()
discard jclient.deactivate()
if midiEventPrinter.running:
debug "Stopping MIDI event printer thread..."
# Receiving an invalid event causes receiving thread to wake up and
# break its endless loop
let event = MidiEventT(size: 0)
let event = MidiEvent(size: 0)
discard midiEventChan.trySend(event)
midiEventPrinter.joinThread()
if jclient != nil:
debug "Closing JACK client..."
jclient.clientClose()
discard jclient.clientClose()
jclient = nil
debug "Bye."
@ -57,7 +57,7 @@ proc shutdownCb(arg: pointer = nil) {.cdecl.} =
exitSignalled = true
proc midiEventPrinterProc() =
var event: MidiEventT
var event: MidiEvent
while true:
midiEventChan.recv(event)
@ -72,7 +72,7 @@ proc midiEventPrinterProc() =
stdout.flushFile()
proc processCb*(nFrames: NFrames, arg: pointer): cint {.cdecl.} =
var event: MidiEventT
var event: MidiEvent
let inbuf = portGetBuffer(midiPort, nFrames)
let count = midiGetEventCount(inbuf)
@ -101,7 +101,7 @@ proc main() =
# Set up a thread, which receives MIDI events from process callback via a
# Channel and prints them without danger of blocking the process callback
midiEventChan = newChan[MidiEventT]()
midiEventChan = newChan[MidiEvent]()
createThread(midiEventPrinter, midiEventPrinterProc)
# Register JACK callbacks

View File

@ -6,16 +6,16 @@ import signal
import jacket
var
jclient: Client
jclient: ClientP
status: cint
exitSignalled: bool = false
inpPort, outPort: Port
inpPort, outPort: PortP
log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug)
type JackBufferP = ptr UncheckedArray[DefaultAudioSample]
proc errorCb(msg: cstring) {.cdecl.} =
# Suppress verbose JACK error messages when server is not available by
# Suppress verbose JACK error messages when server is not available by
# default. Compile in non-release mode or pass ``lvlDebug`` or lower
# when creating the logger above to enable them.
debug "JACK error: " & $msg
@ -23,8 +23,8 @@ proc errorCb(msg: cstring) {.cdecl.} =
proc cleanup(sig: cint = 0) =
debug "Cleaning up..."
if jclient != nil:
jclient.deactivate()
jclient.clientClose()
discard jclient.deactivate()
discard jclient.clientClose()
jclient = nil
proc signalCb(sig: cint) {.noconv.} =
@ -55,8 +55,8 @@ if jclient == nil:
quit QuitFailure
# Register audio input and output ports
inpPort = jclient.portRegister("in_1", JackDefaultAudioType, PortIsInput, 0)
outPort = jclient.portRegister("out_1", JackDefaultAudioType, PortIsOutput, 0)
inpPort = jclient.portRegister("in_1", JACK_DEFAULT_AUDIO_TYPE, PortIsInput, 0)
outPort = jclient.portRegister("out_1", JACK_DEFAULT_AUDIO_TYPE, PortIsOutput, 0)
# Register JACK callbacks
jclient.onShutdown(shutdownCb)

View File

@ -2,7 +2,7 @@ import std/[logging, os]
import jacket
import signal
var jclient: Client
var jclient: ClientP
var status: cint
var exitSignalled: bool = false
var log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug)
@ -10,8 +10,8 @@ var log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug)
proc cleanup(sig: cint = 0) =
debug "Cleaning up..."
if jclient != nil:
jclient.deactivate()
jclient.clientClose()
discard jclient.deactivate()
discard jclient.clientClose()
jclient = nil
proc errorCb(msg: cstring) {.cdecl.} =
@ -30,7 +30,7 @@ proc shutdownCb(arg: pointer = nil) {.cdecl.} =
proc portConnected(portA: PortId; portB: PortId; connect: cint; arg: pointer) {.cdecl.} =
let portAPtr = jclient.portById(portA)
let portBPtr = jclient.portById(portB)
if portAPtr != nil:
echo("Port A: ", portName(portAPtr))
else:
@ -40,7 +40,7 @@ proc portConnected(portA: PortId; portB: PortId; connect: cint; arg: pointer) {.
echo("Port B: ", portName(portBPtr))
else:
echo "Port B: <unknown>"
echo("Action: ", if connect > 0: "connect" else: "disconnect")
addHandler(log)
@ -57,8 +57,8 @@ when defined(windows):
else:
setSignalProc(signalCb, SIGABRT, SIGHUP, SIGINT, SIGQUIT, SIGTERM)
discard jclient.portRegister("in_1", JackDefaultAudioType, PortIsInput, 0)
discard jclient.portRegister("out_1", JackDefaultAudioType, PortIsOutput, 0)
discard jclient.portRegister("in_1", JACK_DEFAULT_AUDIO_TYPE, PortIsInput, 0)
discard jclient.portRegister("out_1", JACK_DEFAULT_AUDIO_TYPE, PortIsOutput, 0)
if jclient.setPortConnectCallback(portConnected) != 0:
error "Error: could not set JACK port connection callback."

View File

@ -2,7 +2,7 @@ import std/[logging, os]
import signal
import jacket
var jclient: Client
var jclient: ClientP
var status: cint
var exitSignalled: bool = false
var log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug)
@ -10,7 +10,7 @@ var log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug)
proc cleanup(sig: cint = 0) =
debug "Cleaning up..."
if jclient != nil:
jclient.clientClose()
discard jclient.clientClose()
jclient = nil
proc errorCb(msg: cstring) {.cdecl.} =
@ -40,8 +40,8 @@ when defined(windows):
else:
setSignalProc(signalCb, SIGABRT, SIGHUP, SIGINT, SIGQUIT, SIGTERM)
discard jclient.portRegister("in_1", JackDefaultAudioType, PortIsInput, 0)
discard jclient.portRegister("out_1", JackDefaultAudioType, PortIsOutput, 0)
discard jclient.portRegister("in_1", JACK_DEFAULT_AUDIO_TYPE, PortIsInput, 0)
discard jclient.portRegister("out_1", JACK_DEFAULT_AUDIO_TYPE, PortIsOutput, 0)
jclient.onShutdown(shutdownCb)

View File

@ -9,35 +9,35 @@ proc main() =
let size = 32
var read, written: int
var data = [0x64.byte, 0x65, 0x61, 0x64, 0x62, 0x65, 0x65, 0x66]
var recvBuf: array[8, byte]
var data = [0x64.uint8, 0x65, 0x61, 0x64, 0x62, 0x65, 0x65, 0x66]
var recvBuf: array[8, uint8]
let rb = ringbufferCreate(size.csize_t)
debug fmt"Created ringbuffer of {size} bytes size."
doAssert ringbufferReadSpace(rb) == 0
written = ringbufferWrite(rb, cast[cstring](data.addr), 4).int
written = cast[int](ringbufferWrite(rb, cast[cstring](data.addr), 4))
doAssert written == 4
debug fmt"Written {written} bytes to ringbuffer."
doAssert ringbufferReadSpace(rb) == 4
written = ringbufferWrite(rb, cast[cstring](data[4].addr), 4).int
written = cast[int](ringbufferWrite(rb, cast[cstring](data[4].addr), 4))
doAssert written == 4
debug fmt"Written {written} bytes to ringbuffer."
doAssert ringbufferReadSpace(rb) == 8
read = ringbufferRead(rb, cast[cstring](recvBuf.addr), 4).int
read = cast[int](ringbufferRead(rb, cast[cstring](recvBuf.addr), 4))
doAssert read == 4
debug fmt"Read {read} bytes from ringbuffer. Receive buffer: {recvBuf}"
debug fmt"Read {read} bytes from ringbuffer into receive buffer: {recvBuf}"
doAssert ringbufferReadSpace(rb) == 4
read = ringbufferRead(rb, cast[cstring](recvBuf[4].addr), 4).int
read = cast[int](ringbufferRead(rb, cast[cstring](recvBuf[4].addr), 4))
doAssert read == 4
debug fmt"Read {read} bytes from ringbuffer. Receive buffer: {recvBuf}"
debug fmt"Read {read} bytes from ringbuffer into receive buffer: {recvBuf}"
doAssert ringbufferReadSpace(rb) == 0

View File

@ -2,8 +2,8 @@ import std/[logging, math, os]
import signal
import jacket
var jclient: Client
var outPort: Port
var jclient: ClientP
var outPort: PortP
var status: cint
var exitSignalled: bool = false
var log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug)
@ -26,7 +26,7 @@ type
proc initSineOsc(sr: float, freq: float): SineOsc =
let phsInc = twoPi / tableSize
var phase = 0.0
for i in 0 ..< tableSize:
result.waveform[i] = sin(phase)
phase += phsInc
@ -37,15 +37,15 @@ proc initSineOsc(sr: float, freq: float): SineOsc =
proc tick(osc: SineOscP): float =
result = osc.waveform[int(osc.phase)]
osc.phase += osc.idxInc;
if osc.phase >= tableSize:
osc.phase -= tableSize
proc cleanup() =
debug "Cleaning up..."
if jclient != nil:
jclient.deactivate()
jclient.clientClose()
discard jclient.deactivate()
discard jclient.clientClose()
jclient = nil
proc errorCb(msg: cstring) {.cdecl.} =
@ -61,7 +61,7 @@ proc shutdownCb(arg: pointer = nil) {.cdecl.} =
warn "JACK server has shut down."
exitSignalled = true
proc processCb(nFrames: NFrames, arg: pointer): cint {.cdecl.} =
proc processCb(nFrames: NFrames, arg: pointer): cint {.cdecl.} =
var outbuf = cast[JackBufferP](portGetBuffer(outPort, nFrames))
let osc = cast[SineOscP](arg)
@ -101,7 +101,7 @@ if jclient.setProcessCallback(processCb, osc.addr) != 0:
jclient.onShutdown(shutdownCb)
# Create output port
outPort = jclient.portRegister("out_1", JackDefaultAudioType, PortIsOutput, 0)
outPort = jclient.portRegister("out_1", JACK_DEFAULT_AUDIO_TYPE, PortIsOutput, 0)
# Activate JACK client ...
if jclient.activate() == 0:

View File

@ -2,15 +2,15 @@ import std/[logging, strformat]
import jacket
var
jclient: Client
jclient: ClientP
status: cint
pos: PositionT
pos: Position
transportState: TransportState
var log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug)
proc errorCb(msg: cstring) {.cdecl.} =
# Suppress verbose JACK error messages when server is not available by
# Suppress verbose JACK error messages when server is not available by
# default. Pass ``lvlAll`` when creating the logger to enable them.
debug "JACK error: " & $msg
@ -51,4 +51,4 @@ of TransportStarting:
else:
echo "Unknown JACK transport state."
jclient.clientClose()
discard jclient.clientClose

View File

@ -1,15 +1,13 @@
import system/ansi_c
export SIG_DFL, SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV
export SIG_DFL, SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM
when not defined(windows):
export SIGPIPE, SIGTERM
export SIGPIPE
var
SIG_IGN* {.importc: "SIG_IGN", header: "<signal.h>".}: cint
SIGHUP* {.importc: "SIGHUP", header: "<signal.h>".}: cint
SIGQUIT* {.importc: "SIGQUIT", header: "<signal.h>".}: cint
else:
const SIGTERM* = cint(15)
type CSighandlerT = proc (a: cint) {.noconv.}

211
examples/zoom2transport.nim Normal file
View File

@ -0,0 +1,211 @@
##
## Control JACK transport with foot switch connected to Zoom R8 audio interface
##
## Requires: https://github.com/SpotlightKid/jacket
import std/[cmdline, logging, os, re, strformat]
import threading/channels
import signal
import jacket
const MidiNoteOn: byte = 0x90
const McpRewind: byte = 91
const McpForward: byte = 92
const McpStop: byte = 93
const McpPlay: byte = 94
const McpPunchInOut: byte = 95
type
ConnectionInfo = tuple[name: string, pattern: string]
App = object
client: ClientP
logger: ConsoleLogger
midiIn: PortP
var
jclient: ClientP
event: MidiEvent
midiPort: PortP
status: cint
srcPortPtn: string
portChan: Chan[ConnectionInfo]
portConnecter: Thread[App]
exitSignalled: bool = false
var log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug)
proc cleanup() =
debug "Cleaning up..."
if jclient != nil:
discard jclient.deactivate()
if portConnecter.running:
debug "Stopping port connecter thread..."
discard portChan.trySend((name: "", pattern: ""))
portConnecter.joinThread()
discard jclient.clientClose()
jclient = nil
proc errorCb(msg: cstring) {.cdecl.} =
# Suppress verbose JACK error messages when server is not available by
# default. Pass ``lvlAll`` when creating the logger to enable them.
debug "JACK error: " & $msg
proc signalCb(sig: cint) {.noconv.} =
debug "Received signal: " & $sig
exitSignalled = true
proc shutdownCb(arg: pointer = nil) {.cdecl.} =
warn "JACK server has shut down."
exitSignalled = true
proc isStatus(event: MidiEvent, status: byte): bool =
return (event.buffer[0] and 0xF0) == status
proc processCb*(nFrames: NFrames, arg: pointer): cint {.cdecl.} =
let app = cast[ptr App](arg)
let inbuf = portGetBuffer(app.midiIn, nFrames)
let count = midiGetEventCount(inbuf)
for i in 0..<count:
if midiEventGet(event.addr, inbuf, i.uint32) == 0:
if isStatus(event, MidiNoteOn):
var pos: Position
let transportState = transportQuery(jclient, pos.addr)
case event.buffer[1].byte
of McpRewind:
app.logger.log(lvlDebug, "Setting transport position to frame = 0")
discard transportLocate(app.client, 0)
of McpForward:
let new_pos = pos.frame + pos.frame_rate
app.logger.log(lvlDebug, "Setting transport position to frame = " & $new_pos)
discard transportLocate(app.client, new_pos)
of McpStop:
if (transportState == TransportRolling or
transportState == TransportStarting or
transportState == TransportNetStarting):
app.logger.log(lvlDebug, "STOPPING JACK transport")
transportStop(app.client)
of McpPlay:
if transportState == TransportStopped:
app.logger.log(lvlDebug, "STARTING JACK transport")
transportStart(app.client)
of McpPunchInOut:
if transportState == TransportStopped:
app.logger.log(lvlDebug, "STARTING JACK transport")
transportStart(app.client)
else:
app.logger.log(lvlDebug, "STOPPING JACK transport")
transportStop(app.client)
else:
discard
proc findPort(client: ClientP, pattern: string): string =
let ports = getPorts(client, pattern, JACK_DEFAULT_MIDI_TYPE, PortIsOutput)
if not ports.isNil():
result = $ports[0]
free(ports)
proc portRegisterCb(port: PortId; flag: cint; arg: pointer) {.cdecl.} =
if flag == 0:
return
let portP = jclient.portById(port)
if not portP.isNil():
let info: ConnectionInfo = (name: $portName(portP), pattern: srcPortPtn)
if not portChan.trySend(info):
writeLine stderr, "Port connecter channel overflow!"
proc portConnecterProc(app: App) {.thread.} =
var info: ConnectionInfo
addHandler(app.logger)
setLogFilter(when defined(release): lvlInfo else: lvlDebug)
while true:
portChan.recv(info)
if info.name == "":
break
debug &"New port: {info.name}"
if contains(info.name, re(info.pattern)):
if portConnectedTo(midiPort, info.name.cstring) != 1:
if app.client.connect(info.name.cstring, portName(app.midiIn)) != 1:
debug &"Connected input to port {info.name}"
else:
warn &"Failed to connect to port {info.name}"
proc main() =
addHandler(log)
# Create JACK client
setErrorFunction(errorCb)
jclient = clientOpen("zoom2transport", NoStartServer or UseExactName, status.addr)
debug "JACK server status: " & $status
if jclient == nil:
error getJackStatusErrorString(status)
quit QuitFailure
# Set up signal handlers to clean up on exit
when defined(windows):
setSignalProc(signalCb, SIGABRT, SIGINT, SIGTERM)
else:
setSignalProc(signalCb, SIGABRT, SIGHUP, SIGINT, SIGQUIT, SIGTERM)
# Create output port
midiPort = jclient.portRegister("midi_in", JACK_DEFAULT_MIDI_TYPE, PortIsInput, 0)
var app = App(client: jclient, logger: log, midiIn: midiPort)
portChan = newChan[ConnectionInfo]()
createThread(portConnecter, portConnecterProc, app)
# Register JACK callbacks
if jclient.setProcessCallback(processCb, app.addr) != 0:
error "Could not set JACK process callback function."
cleanup()
quit QuitFailure
jclient.onShutdown(shutdownCb)
if paramCount() > 0:
srcPortPtn = paramStr(1)
if jclient.setPortRegistrationCallback(portRegisterCb) != 0:
error "Error: could not set JACK port registration callback."
cleanup()
quit QuitFailure
else:
srcPortPtn = ""
# Activate JACK client ...
if jclient.activate() == 0:
# try to connect input to port given via port pattern on command line
if srcPortPtn != "":
let srcPortName = findPort(jclient, srcPortPtn)
if srcPortName != "" and portConnectedTo(midiPort, srcPortName.cstring) != 1:
if jclient.connect(srcPortName.cstring, portName(midiPort)) != 1:
debug &"Connected input to port {srcPortName}"
else:
warn &"Failed to connect to port {srcPortName}"
# ... and keep running until a signal is received
while not exitSignalled:
sleep(100)
cleanup()
when isMainModule:
main()

View File

@ -1,8 +1,8 @@
# Package
version = "0.2.0"
version = "0.1.0"
author = "Christopher Arndt"
description = "A Nim wrapper for the JACK Audio Connection Kit client-side C API aka libjack"
description = "A Nim wrapper for the JACK client-side C API aka libjack"
license = "MIT"
srcDir = "src"
@ -10,31 +10,3 @@ srcDir = "src"
# Dependencies
requires "nim >= 1.6.0"
taskrequires "examples", "threading"
taskrequires "examples_debug", "threading"
let examples = @[
"info",
"list_all_properties",
"midi_print",
"midi_print_ringbuffer",
"midi_print_thread",
"midi_print_threading",
"passthru",
"port_connect_cb",
"port_register",
"ringbuffer",
"sine",
"transport_query",
]
task examples, "Build examples (release)":
for example in examples:
echo "Building example 'jacket_" & example & "'..."
selfExec("compile -d:release -d:strip examples/jacket_" & example & ".nim")
task examples_debug, "Build examples (debug)":
for example in examples:
echo "Building example 'jacket_" & example & "' (debug)..."
selfExec("compile examples/jacket_" & example & ".nim")

View File

@ -1,26 +1,29 @@
# jacket.nim
# Possible names/install locations of libjack, according to:
# https://github.com/x42/weakjack/blob/master/weak_libjack.c#L108
when defined(windows):
when sizeof(int) == 4:
const soname = "(|lib)jack.dll"
proc getJackLibName: string =
when system.hostOS == "windows":
when sizeof(int) == 4:
result = "libjack.dll"
else:
result = "libjack64.dll"
elif system.hostOS == "macosx":
result = "(|/usr/local/lib/|/opt/homebrew/lib/|/opt/local/lib/)libjack.dylib"
else:
const soname = "(|lib)jack64.dll"
elif defined(macosx):
const soname = "(|/usr/local/lib/|/opt/homebrew/lib/|/opt/homebrew/opt/jack/lib/|/opt/local/lib/)libjack.dylib"
else:
const soname = "libjack.so.0"
result = "libjack.so.0"
{.push dynlib: soname.}
{.push dynlib: getJackLibName().}
# ------------------------------ Constants --------------------------------
const
JackMaxFrames* = (4294967295'i64)
JackLoadInitLimit* = 1024
JackDefaultAudioType* = "32 bit float mono audio"
JackDefaultMidiType* = "8 bit raw midi"
JACK_MAX_FRAMES* = (4294967295'i64)
JACK_LOAD_INIT_LIMIT* = 1024
JACK_DEFAULT_AUDIO_TYPE* = "32 bit float mono audio"
JACK_DEFAULT_MIDI_TYPE* = "8 bit raw midi"
# ----------------------------- Custom Types ------------------------------
@ -34,18 +37,18 @@ type
DefaultAudioSample* = cfloat
type
ClientT = distinct object
Client* = ptr ClientT
PortT = distinct object
Port* = ptr PortT
Client = distinct object
ClientP* = ptr Client
Port = distinct object
PortP* = ptr Port
type
MidiData* = uint8
MidiEventT* = object
MidiEvent* = object
time*: NFrames
size*: csize_t
buffer*: ptr UncheckedArray[MidiData]
MidiEvent* = ptr MidiEventT
MidiEventP* = ptr MidiEvent
type
JackOptions* {.size: sizeof(cint) pure.} = enum
@ -110,7 +113,7 @@ type
TransportNetStarting = 4
type
PositionT* = object
Position* = object
unique1*: uint64
usecs*: Time
frameRate*: NFrames
@ -132,7 +135,7 @@ type
tickDouble*: cdouble
padding*: array[5, int32]
unique2*: uint64
Position* = ptr PositionT
PositionP* = ptr Position
#[ DEPRECATED
typedef enum {
@ -165,20 +168,20 @@ typedef struct {
]#
const
JackPositionMask* = (PositionBBT.ord or PositionTimecode.ord)
ExtendedTimeInfo* = true
JackTickDouble* = true
JACK_POSITION_MASK* = (PositionBBT.ord or PositionTimecode.ord)
EXTENDED_TIME_INFO* = true
JACK_TICK_DOUBLE* = true
# Ringbuffer
type
RingbufferDataT* = object
RingbufferData* = object
buf*: ptr char
len*: csize_t
RingbufferData* = ptr RingbufferDataT
RingbufferDataP* = ptr RingbufferData
RingbufferT = distinct object
Ringbuffer* = ptr RingbufferT
Ringbuffer = distinct object
RingbufferP* = ptr Ringbuffer
# Metadata
@ -193,13 +196,13 @@ type
PropertyChanged,
PropertyDeleted
DescriptionT* = object
Description* = object
subject*: Uuid
property_cnt*: uint32
properties*: ptr UncheckedArray[Property]
property_size*: uint32
Description* = ptr DescriptionT
DescriptionP* = ptr Description
# Callback function types
@ -255,47 +258,47 @@ proc free*(`ptr`: pointer) {.importc: "jack_free".}
# jack_client_t * jack_client_open (char *client_name,
# jack_options_t options,
# jack_status_t *status, ...)
proc clientOpen*(clientName: cstring; options: cint; status: ptr cint): Client {.
proc clientOpen*(clientName: cstring; options: cint; status: ptr cint): ClientP {.
varargs, importc: "jack_client_open".}
# int jack_client_close (jack_client_t *client)
proc clientClose*(client: Client): cint {.importc: "jack_client_close", discardable.}
proc clientClose*(client: ClientP): cint {.importc: "jack_client_close"}
# int jack_client_name_size (void)
proc clientNameSize*(): cint {.importc: "jack_client_name_size"}
# char * jack_get_client_name (jack_client_t *client)
proc getClientName*(client: Client): cstring {.importc: "jack_get_client_name".}
proc getClientName*(client: ClientP): cstring {.importc: "jack_get_client_name".}
# char *jack_get_uuid_for_client_name (jack_client_t *client, const char *client_name)
proc getUuidForClientName*(client: Client; clientName: cstring): cstring {.
proc getUuidForClientName*(client: ClientP; clientName: cstring): cstring {.
importc: "jack_get_uuid_for_client_name".}
# char *jack_get_client_name_by_uuid (jack_client_t *client, const char *client_uuid)
proc getClientNameByUuid*(client: Client; clientUuid: cstring): cstring {.
proc getClientNameByUuid*(client: ClientP; clientUuid: cstring): cstring {.
importc: "jack_get_client_name_by_uuid".}
# int jack_activate (jack_client_t *client)
proc activate*(client: Client): cint {.importc: "jack_activate", discardable.}
proc activate*(client: ClientP): cint {.importc: "jack_activate".}
# int jack_deactivate (jack_client_t *client)
proc deactivate*(client: Client): cint {.importc: "jack_deactivate", discardable.}
proc deactivate*(client: ClientP): cint {.importc: "jack_deactivate".}
# int jack_get_client_pid (const char *name)
proc getClientPid*(name: cstring): cint {.importc: "jack_get_client_pid".}
# FIXME: not implemented yet
# jack_native_thread_t jack_client_thread_id (jack_client_t *client)
# proc clientThreadId*(client: Client): NativeThread {.importc: "jack_client_thread_id".}
# proc clientThreadId*(client: ClientP): NativeThread {.importc: "jack_client_thread_id".}
# int jack_is_realtime (jack_client_t *client)
proc isRealtime*(client: Client): cint {.importc: "jack_is_realtime".}
proc isRealtime*(client: ClientP): cint {.importc: "jack_is_realtime".}
# jack_nframes_t jack_cycle_wait (jack_client_t* client)
proc cycleWait*(client: Client): NFrames {.importc: "jack_cycle_wait".}
proc cycleWait*(client: ClientP): NFrames {.importc: "jack_cycle_wait".}
# void jack_cycle_signal (jack_client_t* client, int status)
proc cycleSignal*(client: Client; status: cint) {.importc: "jack_cycle_signal".}
proc cycleSignal*(client: ClientP; status: cint) {.importc: "jack_cycle_signal".}
#[ DEPRECATED
jack_client_t *jack_client_new (const char *client_name)
@ -305,23 +308,23 @@ jack_nframes_t jack_thread_wait (jack_client_t *client, int status)
# --------------------------- Internal Clients ----------------------------
# char *jack_get_internal_client_name (jack_client_t *client, jack_intclient_t intclient);
proc getInternalClientName*(client: Client; intclient: IntClient): cstring {.
proc getInternalClientName*(client: ClientP; intclient: IntClient): cstring {.
importc: "jack_get_internal_client_name".}
# jack_intclient_t jack_internal_client_handle (jack_client_t *client, const char *client_name,
# jack_status_t *status)
proc internalClientHandle*(client: Client; clientName: cstring; status: ptr cint): IntClient {.
proc internalClientHandle*(client: ClientP; clientName: cstring; status: ptr cint): IntClient {.
importc: "jack_internal_client_handle".}
# jack_intclient_t jack_internal_client_load (jack_client_t *client, const char *client_name,
# jack_options_t options, jack_status_t *status, ...)
proc internalClientLoad*(client: Client; clientName: cstring; options: cint; status: ptr cint): IntClient {.
proc internalClientLoad*(client: ClientP; clientName: cstring; options: cint; status: ptr cint): IntClient {.
varargs, importc: "jack_internal_client_load".}
# jack_status_t jack_internal_client_unload (jack_client_t *client, jack_intclient_t intclient)
proc internalClientUnload*(client: Client; intclient: IntClient): cint {.
importc: "jack_internal_client_unload", discardable.}
proc internalClientUnload*(client: ClientP; intclient: IntClient): cint {.
importc: "jack_internal_client_unload".}
#[ DEPRECATED
int jack_internal_client_new (const char * client_name, const char *load_name, const char *load_init)
@ -331,70 +334,70 @@ void jack_internal_client_close (const char *client_name)
# ------------------------------- Callbacks -------------------------------
proc onShutdown*(client: Client; shutdownCallback: ShutdownCallback; arg: pointer = nil) {.
proc setProcessThread*(client: ClientP; threadCallback: ThreadCallback; arg: pointer = nil): cint {.
importc: "jack_set_process_thread".}
proc setThreadInitCallback*(client: ClientP; threadInitCallback: ThreadInitCallback; arg: pointer = nil): cint {.
importc: "jack_set_thread_init_callback".}
proc onShutdown*(client: ClientP; shutdownCallback: ShutdownCallback; arg: pointer = nil) {.
importc: "jack_on_shutdown".}
proc onInfoShutdown*(client: Client; shutdownCallback: InfoShutdownCallback; arg: pointer = nil) {.
proc onInfoShutdown*(client: ClientP; shutdownCallback: InfoShutdownCallback; arg: pointer = nil) {.
importc: "jack_on_info_shutdown".}
proc setProcessThread*(client: Client; threadCallback: ThreadCallback; arg: pointer = nil): cint {.
importc: "jack_set_process_thread", discardable.}
proc setProcessCallback*(client: ClientP; processCallback: ProcessCallback; arg: pointer = nil): cint {.
importc: "jack_set_process_callback".}
proc setThreadInitCallback*(client: Client; threadInitCallback: ThreadInitCallback; arg: pointer = nil): cint {.
importc: "jack_set_thread_init_callback", discardable.}
proc setFreewheelCallback*(client: ClientP; freewheelCallback: FreewheelCallback; arg: pointer = nil): cint {.
importc: "jack_set_freewheel_callback".}
proc setProcessCallback*(client: Client; processCallback: ProcessCallback; arg: pointer = nil): cint {.
importc: "jack_set_process_callback", discardable.}
proc setBufferSizeCallback*(client: ClientP; bufsizeCallback: BufferSizeCallback; arg: pointer = nil): cint {.
importc: "jack_set_buffer_size_callback".}
proc setFreewheelCallback*(client: Client; freewheelCallback: FreewheelCallback; arg: pointer = nil): cint {.
importc: "jack_set_freewheel_callback", discardable.}
proc setSampleRateCallback*(client: ClientP; srateCallback: SampleRateCallback; arg: pointer = nil): cint {.
importc: "jack_set_sample_rate_callback".}
proc setBufferSizeCallback*(client: Client; bufsizeCallback: BufferSizeCallback; arg: pointer = nil): cint {.
importc: "jack_set_buffer_size_callback", discardable.}
proc setSampleRateCallback*(client: Client; srateCallback: SampleRateCallback; arg: pointer = nil): cint {.
importc: "jack_set_sample_rate_callback", discardable.}
proc setClientRegistrationCallback*(client: Client; registrationCallback: ClientRegistrationCallback;
proc setClientRegistrationCallback*(client: ClientP; registrationCallback: ClientRegistrationCallback;
arg: pointer = nil): cint {.
importc: "jack_set_client_registration_callback", discardable.}
importc: "jack_set_client_registration_callback".}
proc setPortRegistrationCallback*(client: Client; registrationCallback: PortRegistrationCallback;
proc setPortRegistrationCallback*(client: ClientP; registrationCallback: PortRegistrationCallback;
arg: pointer = nil): cint {.
importc: "jack_set_port_registration_callback", discardable.}
importc: "jack_set_port_registration_callback".}
proc setPortConnectCallback*(client: Client; connectCallback: PortConnectCallback; arg: pointer = nil): cint {.
importc: "jack_set_port_connect_callback", discardable.}
proc setPortConnectCallback*(client: ClientP; connectCallback: PortConnectCallback; arg: pointer = nil): cint {.
importc: "jack_set_port_connect_callback".}
proc setPortRenameCallback*(client: Client; renameCallback: PortRenameCallback; arg: pointer = nil): cint {.
importc: "jack_set_port_rename_callback", discardable.}
proc setPortRenameCallback*(client: ClientP; renameCallback: PortRenameCallback; arg: pointer = nil): cint {.
importc: "jack_set_port_rename_callback".}
proc setGraphOrderCallback*(client: Client; graphCallback: GraphOrderCallback; arg: pointer = nil): cint {.
importc: "jack_set_graph_order_callback", discardable.}
proc setGraphOrderCallback*(client: ClientP; graphCallback: GraphOrderCallback; a3: pointer): cint {.
importc: "jack_set_graph_order_callback".}
proc setXrunCallback*(client: Client; xrunCallback: XRunCallback; arg: pointer = nil): cint {.
importc: "jack_set_xrun_callback", discardable.}
proc setXrunCallback*(client: ClientP; xrunCallback: XRunCallback; arg: pointer = nil): cint {.
importc: "jack_set_xrun_callback".}
proc setLatencyCallback*(client: Client; latencyCallback: LatencyCallback; arg: pointer = nil): cint {.
importc: "jack_set_latency_callback", discardable.}
proc setLatencyCallback*(client: ClientP; latencyCallback: LatencyCallback; arg: pointer = nil): cint {.
importc: "jack_set_latency_callback".}
# -------------------------- Server Client Control ------------------------
# int jack_set_freewheel(jack_client_t* client, int onoff)
proc setFreewheel*(client: Client; onoff: cint): cint {.importc: "jack_set_freewheel", discardable.}
proc setFreewheel*(client: ClientP; onoff: cint): cint {.importc: "jack_set_freewheel".}
# int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes)
proc setBufferSize*(client: Client; nframes: NFrames): cint {.importc: "jack_set_buffer_size", discardable.}
proc setBufferSize*(client: ClientP; nframes: NFrames): cint {.importc: "jack_set_buffer_size".}
#jack_nframes_t jack_get_sample_rate (jack_client_t *)
proc getSampleRate*(client: Client): NFrames {.importc: "jack_get_sample_rate"}
proc getSampleRate*(client: ClientP): NFrames {.importc: "jack_get_sample_rate".}
# jack_nframes_t jack_get_buffer_size (jack_client_t *)
proc getBufferSize*(client: Client): NFrames {.importc: "jack_get_buffer_size".}
proc getBufferSize*(client: ClientP): NFrames {.importc: "jack_get_buffer_size".}
# float jack_cpu_load (jack_client_t *client)
proc cpuLoad*(client: Client): cfloat {.importc: "jack_cpu_load".}
proc cpuLoad*(client: ClientP): cfloat {.importc: "jack_cpu_load".}
#[ DEPRECATED
int jack_engine_takeover_timebase (jack_client_t *)
@ -408,82 +411,82 @@ int jack_engine_takeover_timebase (jack_client_t *)
# const char *port_type,
# unsigned long flags,
# unsigned long buffer_size)
proc portRegister*(client: Client; portName: cstring; portType: cstring;
flags: culong; bufferSize: culong): Port {.importc: "jack_port_register".}
proc portRegister*(client: ClientP; portName: cstring; portType: cstring;
flags: culong; bufferSize: culong): PortP {.importc: "jack_port_register".}
# int jack_port_unregister (jack_client_t *client, jack_port_t *port)
proc portUnregister*(client: Client; port: Port): cint {.importc: "jack_port_unregister", discardable.}
proc portUnregister*(client: ClientP; port: PortP): cint {.importc: "jack_port_unregister".}
# void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t)
proc portGetBuffer*(port: Port; nframes: NFrames): pointer {.importc: "jack_port_get_buffer".}
proc portGetBuffer*(port: PortP; nframes: NFrames): pointer {.importc: "jack_port_get_buffer".}
# jack_uuid_t jack_port_uuid (const jack_port_t *port)
proc portUuid*(port: Port): Uuid {.importc: "jack_port_uuid".}
proc portUuid*(port: PortP): Uuid {.importc: "jack_port_uuid".}
# const char * jack_port_name (const jack_port_t *port)
proc portName*(port: Port): cstring {.importc: "jack_port_name".}
proc portName*(port: PortP): cstring {.importc: "jack_port_name".}
# const char * jack_port_short_name (const jack_port_t *port)
proc portShortName*(port: Port): cstring {.importc: "jack_port_short_name".}
proc portShortName*(port: PortP): cstring {.importc: "jack_port_short_name".}
# int jack_port_flags (const jack_port_t *port)
proc portFlags*(port: Port): cint {.importc: "jack_port_flags".}
proc portFlags*(port: PortP): cint {.importc: "jack_port_flags".}
# const char * jack_port_type (const jack_port_t *port)
proc portType*(port: Port): cstring {.importc: "jack_port_type".}
proc portType*(port: PortP): cstring {.importc: "jack_port_type".}
# jack_port_type_id_t jack_port_type_id (const jack_port_t *port)
proc portTypeId*(port: Port): PortTypeId {.importc: "jack_port_type_id".}
proc portTypeId*(port: PortP): PortTypeId {.importc: "jack_port_type_id".}
# int jack_port_is_mine (const jack_client_t *client, const jack_port_t *port)
proc portIsMine*(client: Client; port: Port): cint {.
proc portIsMine*(client: ClientP; port: PortP): cint {.
importc: "jack_port_is_mine".}
# int jack_port_connected (const jack_port_t *port)
proc portConnected*(port: Port): cint {.importc: "jack_port_connected".}
proc portConnected*(port: PortP): cint {.importc: "jack_port_connected".}
# int jack_port_connected_to (const jack_port_t *port,
# const char *port_name)
proc portConnectedTo*(port: Port; portName: cstring): cint {.importc: "jack_port_connected_to".}
proc portConnectedTo*(port: PortP; portName: cstring): cint {.importc: "jack_port_connected_to".}
# const char ** jack_port_get_connections (const jack_port_t *port)
#
# CAVEAT: The caller is responsible for calling jack_free() on any non-NULL returned value.
proc portGetConnections*(port: Port): cstringArray {.importc: "jack_port_get_connections".}
proc portGetConnections*(port: PortP): cstringArray {.importc: "jack_port_get_connections".}
# const char ** jack_port_get_all_connections (const jack_client_t *client,
# const jack_port_t *port)
#
# CAVEAT: The caller is responsible for calling jack_free() on any non-NULL returned value.
proc portGetAllConnections*(client: Client; port: Port): cstringArray {.
proc portGetAllConnections*(client: ClientP; port: PortP): cstringArray {.
importc: "jack_port_get_all_connections".}
# int jack_port_rename (jack_client_t* client, jack_port_t *port, const char *port_name)
proc portRename*(client: Client; port: Port; portName: cstring): cint {.importc: "jack_port_rename", discardable.}
proc portRename*(client: ClientP; port: PortP; portName: cstring): cint {.importc: "jack_port_rename".}
# int jack_port_set_alias (jack_port_t *port, const char *alias)
proc portSetAlias*(port: Port; alias: cstring): cint {.importc: "jack_port_set_alias", discardable.}
proc portSetAlias*(port: PortP; alias: cstring): cint {.importc: "jack_port_set_alias".}
# int jack_port_unset_alias (jack_port_t *port, const char *alias)
proc portUnsetAlias*(port: Port; alias: cstring): cint {.importc: "jack_port_unset_alias", discardable.}
proc portUnsetAlias*(port: PortP; alias: cstring): cint {.importc: "jack_port_unset_alias".}
# int jack_port_get_aliases (const jack_port_t *port, char* const aliases[2])
proc portGetAliases*(port: Port; aliases: array[2, cstring]): cint {.importc: "jack_port_get_aliases".}
proc portGetAliases*(port: PortP; aliases: array[2, cstring]): cint {.importc: "jack_port_get_aliases".}
#int jack_port_request_monitor (jack_port_t *port, int onoff)
proc portRequestMonitor*(port: Port; onoff: cint): cint {.importc: "jack_port_request_monitor", discardable.}
proc portRequestMonitor*(port: PortP; onoff: cint): cint {.importc: "jack_port_request_monitor".}
# int jack_port_request_monitor_by_name (jack_client_t *client,
# const char *port_name, int onoff)
proc portRequestMonitorByName*(client: Client; portName: cstring; onoff: cint): cint {.
importc: "jack_port_request_monitor_by_name", discardable.}
proc portRequestMonitorByName*(client: ClientP; portName: cstring; onoff: cint): cint {.
importc: "jack_port_request_monitor_by_name".}
# int jack_port_ensure_monitor (jack_port_t *port, int onoff)
proc portEnsureMonitor*(port: Port; onoff: cint): cint {.
importc: "jack_port_ensure_monitor", discardable.}
proc portEnsureMonitor*(port: PortP; onoff: cint): cint {.
importc: "jack_port_ensure_monitor".}
# int jack_port_monitoring_input (jack_port_t *port)
proc portMonitoringInput*(port: Port): cint {.importc: "jack_port_monitoring_input".}
proc portMonitoringInput*(port: PortP): cint {.importc: "jack_port_monitoring_input".}
#[ DEPRECATED
int jack_port_tie (jack_port_t *src, jack_port_t *dst)
@ -500,14 +503,14 @@ int jack_port_set_name (jack_port_t *port, const char *port_name)
# unsigned long flags)
#
# CAVEAT: The caller is responsible for calling jack_free() on any non-NULL returned value.
proc getPorts*(client: Client; portNamePattern: cstring;
proc getPorts*(client: ClientP; portNamePattern: cstring;
typeNamePattern: cstring; flags: culong): cstringArray {.importc: "jack_get_ports".}
# jack_port_t * jack_port_by_name (jack_client_t *client, const char *port_name)
proc portByName*(client: Client; portName: cstring): Port {.importc: "jack_port_by_name".}
proc portByName*(client: ClientP; portName: cstring): PortP {.importc: "jack_port_by_name".}
# jack_port_t * jack_port_by_id (jack_client_t *client, jack_port_id_t port_id)
proc portById*(client: Client; portId: PortId): Port {.importc: "jack_port_by_id".}
proc portById*(client: ClientP; portId: PortId): PortP {.importc: "jack_port_by_id".}
# ------------------------------ Connections ------------------------------
@ -515,15 +518,15 @@ proc portById*(client: Client; portId: PortId): Port {.importc: "jack_port_by_id
# int jack_connect (jack_client_t *client,
# const char *source_port,
# const char *destination_port)
proc connect*(client: Client; srcPort: cstring; destPort: cstring): cint {.importc: "jack_connect", discardable.}
proc connect*(client: ClientP; srcPort: cstring; destPort: cstring): cint {.importc: "jack_connect".}
# int jack_disconnect (jack_client_t *client,
# const char *source_port,
# const char *destination_port)
proc disconnect*(client: Client; srcPort: cstring; destPort: cstring): cint {.importc: "jack_disconnect", discardable.}
proc disconnect*(client: ClientP; srcPort: cstring; destPort: cstring): cint {.importc: "jack_disconnect".}
# int jack_port_disconnect (jack_client_t *client, jack_port_t *port)
proc portDisconnect*(client: Client; port: Port): cint {.importc: "jack_port_disconnect", discardable.}
proc portDisconnect*(client: ClientP; port: PortP): cint {.importc: "jack_port_disconnect".}
# int jack_port_name_size(void)
proc portNameSize*(): cint {.importc: "jack_port_name_size".}
@ -532,7 +535,7 @@ proc portNameSize*(): cint {.importc: "jack_port_name_size".}
proc portTypeSize*(): cint {.importc: "jack_port_type_size".}
# size_t jack_port_type_get_buffer_size (jack_client_t *client, const char *port_type)
proc portTypeGetBufferSize*(client: Client; portType: cstring): csize_t {.
proc portTypeGetBufferSize*(client: ClientP; portType: cstring): csize_t {.
importc: "jack_port_type_get_buffer_size".}
@ -542,7 +545,7 @@ proc portTypeGetBufferSize*(client: Client; portType: cstring): csize_t {.
proc midiGetEventCount*(portBuffer: pointer): NFrames {.importc: "jack_midi_get_event_count".}
# int jack_midi_event_get (jack_midi_event_t *event, void *port_buffer, uint32_t event_index)
proc midiEventGet*(event: MidiEvent, portBuffer: pointer, eventIndex: uint32): cint {.
proc midiEventGet*(event: MidiEventP, portBuffer: pointer, eventIndex: uint32): cint {.
importc: "jack_midi_event_get".}
# void jack_midi_clear_buffer (void *port_buffer)
@ -556,8 +559,8 @@ proc midiEventReserve*(portBuffer: pointer, time: NFrames, dataSize: csize_t): p
importc: "jack_midi_event_reserve".}
# int jack_midi_event_write (void *port_buffer, jack_nframes_t time, const jack_midi_data_t *data, size_t data_size)
proc midiEventWrite*(portBuffer: pointer, time: NFrames, data: ptr MidiData, dataSize: csize_t): cint {.
importc: "jack_midi_event_write", discardable.}
proc midiEventWrite*(portBuffer: pointer, time: NFrames, data: ptr MidiData, dataSize: csize_t): int {.
importc: "jack_midi_event_write".}
# uint32_t jack_midi_get_lost_event_count (void *port_buffer)
proc midiGetLostEventCount*(portBuffer: pointer): uint32 {.importc: "jack_midi_get_lost_event_count".}
@ -566,15 +569,15 @@ proc midiGetLostEventCount*(portBuffer: pointer): uint32 {.importc: "jack_midi_g
# -------------------------------- Latency --------------------------------
# void jack_port_get_latency_range (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range)
proc portGetLatencyRange*(port: Port; mode: LatencyCallbackMode; range: ptr LatencyRange) {.
proc portGetLatencyRange*(port: PortP; mode: LatencyCallbackMode; range: ptr LatencyRange) {.
importc: "jack_port_get_latency_range".}
# void jack_port_set_latency_range (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range)
proc portSetLatencyRange*(port: Port; mode: LatencyCallbackMode; range: ptr LatencyRange) {.
proc portSetLatencyRange*(port: PortP; mode: LatencyCallbackMode; range: ptr LatencyRange) {.
importc: "jack_port_set_latency_range".}
# int jack_recompute_total_latencies (jack_client_t *)
proc recomputeTotalLatencies*(client: Client): cint {.importc: "jack_recompute_total_latencies", discardable.}
proc recomputeTotalLatencies*(client: ClientP): cint {.importc: "jack_recompute_total_latencies".}
#[ DEPRECATED
jack_nframes_t jack_port_get_latency (jack_port_t *port)
@ -587,28 +590,28 @@ int jack_recompute_total_latency (jack_client_t *, jack_port_t *port)
# ----------------------------- Time handling -----------------------------
# jack_nframes_t jack_frames_since_cycle_start (const jack_client_t *)
proc framesSinceCycleStart*(client: Client): NFrames {.importc: "jack_frames_since_cycle_start".}
proc framesSinceCycleStart*(client: ClientP): NFrames {.importc: "jack_frames_since_cycle_start".}
# jack_nframes_t jack_frame_time (const jack_client_t *)
proc frameTime*(client: Client): NFrames {.importc: "jack_frame_time".}
proc frameTime*(client: ClientP): NFrames {.importc: "jack_frame_time".}
# jack_nframes_t jack_last_frame_time (const jack_client_t *client)
proc lastFrameTime*(client: Client): NFrames {.importc: "jack_last_frame_time".}
proc lastFrameTime*(client: ClientP): NFrames {.importc: "jack_last_frame_time".}
# int jack_get_cycle_times(const jack_client_t *client,
# jack_nframes_t *current_frames,
# jack_time_t *current_usecs,
# jack_time_t *next_usecs,
# float *period_usecs)
proc getCycleTimes*(client: Client; currentFrames: ptr NFrames;
proc getCycleTimes*(client: ClientP; currentFrames: ptr NFrames;
currentUsecs: ptr Time; nextUsecs: ptr Time;
periodUsecs: ptr cfloat): cint {.importc: "jack_get_cycle_times".}
# jack_time_t jack_frames_to_time(const jack_client_t *client, jack_nframes_t)
proc framesToTime*(client: Client; nframes: NFrames): Time {.importc: "jack_frames_to_time".}
proc framesToTime*(client: ClientP; nframes: NFrames): Time {.importc: "jack_frames_to_time".}
# jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t)
proc timeToFrames*(client: Client; time: Time): NFrames {.importc: "jack_time_to_frames".}
proc timeToFrames*(client: ClientP; time: Time): NFrames {.importc: "jack_time_to_frames".}
# jack_time_t jack_get_time(void)
proc getTime*(): Time {.importc: "jack_get_time".}
@ -617,40 +620,40 @@ proc getTime*(): Time {.importc: "jack_get_time".}
# ------------------------------- Transport -------------------------------
# int jack_release_timebase (jack_client_t *client)
proc releaseTimebase*(client: Client): cint {.importc: "jack_release_timebase", discardable.}
proc releaseTimebase*(client: ClientP): cint {.importc: "jack_release_timebase".}
# int jack_set_sync_callback (jack_client_t *client, JackSyncCallback sync_callback, void *arg)
proc setSyncCallback*(client: Client; syncCallback: SyncCallback; arg: pointer = nil): cint {.
importc: "jack_set_sync_callback", discardable.}
proc setSyncCallback*(client: ClientP; syncCallback: SyncCallback; arg: pointer = nil): cint {.
importc: "jack_set_sync_callback".}
# int jack_set_sync_timeout (jack_client_t *client, jack_time_t timeout)
proc setSyncTimeout*(client: Client; timeout: Time): cint {.importc: "jack_set_sync_timeout", discardable.}
proc setSyncTimeout*(client: ClientP; timeout: Time): cint {.importc: "jack_set_sync_timeout".}
# int jack_set_timebase_callback (jack_client_t *client,
# int conditional,
# JackTimebaseCallback timebase_callback,
# void *arg)
proc setTimebaseCallback*(client: Client; conditional: cint; timebaseCallback: TimebaseCallback;
proc setTimebaseCallback*(client: ClientP; conditional: cint; timebaseCallback: TimebaseCallback;
arg: pointer = nil): cint {.
importc: "jack_set_timebase_callback", discardable.}
importc: "jack_set_timebase_callback".}
# int jack_transport_locate (jack_client_t *client, jack_nframes_t frame)
proc transportLocate*(client: Client; frame: NFrames): cint {.importc: "jack_transport_locate", discardable.}
proc transportLocate*(client: ClientP; frame: NFrames): cint {.importc: "jack_transport_locate".}
# jack_transport_state_t jack_transport_query (const jack_client_t *client, jack_position_t *pos)
proc transportQuery*(client: Client; pos: Position): TransportState {.importc: "jack_transport_query".}
proc transportQuery*(client: ClientP; pos: PositionP): TransportState {.importc: "jack_transport_query".}
# jack_nframes_t jack_get_current_transport_frame (const jack_client_t *client)
proc getCurrentTransportFrame*(client: Client): NFrames {.importc: "jack_get_current_transport_frame".}
proc getCurrentTransportFrame*(client: ClientP): NFrames {.importc: "jack_get_current_transport_frame".}
# int jack_transport_reposition (jack_client_t *client, const jack_position_t *pos)
proc transportReposition*(client: Client; pos: Position): cint {.importc: "jack_transport_reposition".}
proc transportReposition*(client: ClientP; pos: PositionP): cint {.importc: "jack_transport_reposition".}
# void jack_transport_start (jack_client_t *client)
proc transportStart*(client: Client) {.importc: "jack_transport_start".}
proc transportStart*(client: ClientP) {.importc: "jack_transport_start".}
# void jack_transport_stop (jack_client_t *client)
proc transportStop*(client: Client) {.importc: "jack_transport_stop".}
proc transportStop*(client: ClientP) {.importc: "jack_transport_stop".}
#[ DEPRECATED
void jack_get_transport_info (jack_client_t *client, jack_transport_info_t *tinfo)
@ -660,81 +663,79 @@ void jack_set_transport_info (jack_client_t *client, jack_transport_info_t *tinf
# ----------------------------- Ringbuffers -------------------------------
# jack_ringbuffer_t *jack_ringbuffer_create (size_t sz)
proc ringbufferCreate*(sz: csize_t): Ringbuffer {.importc: "jack_ringbuffer_create".}
proc ringbufferCreate*(sz: csize_t): RingbufferP {.importc: "jack_ringbuffer_create".}
# void jack_ringbuffer_free (jack_ringbuffer_t *rb)
proc ringbufferFree*(rb: Ringbuffer) {.importc: "jack_ringbuffer_free".}
proc ringbufferFree*(rb: RingbufferP) {.importc: "jack_ringbuffer_free".}
# void jack_ringbuffer_get_read_vector (const jack_ringbuffer_t *rb, jack_ringbuffer_data_t *vec)
proc ringbufferGetReadVector*(rb: Ringbuffer, vec: var RingbufferData) {.importc: "jack_ringbuffer_get_read_vector".}
proc ringbufferGetReadVector*(rb: RingbufferP, vec: var RingbufferDataP) {.importc: "jack_ringbuffer_get_read_vector".}
# void jack_ringbuffer_get_write_vector (const jack_ringbuffer_t *rb, jack_ringbuffer_data_t *vec)
proc ringbufferGetWriteVector*(rb: Ringbuffer, vec: var RingbufferData) {.importc: "jack_ringbuffer_get_write_vector".}
proc ringbufferGetWriteVector*(rb: RingbufferP, vec: var RingbufferDataP) {.importc: "jack_ringbuffer_get_write_vector".}
# size_t jack_ringbuffer_read (jack_ringbuffer_t *rb, char *dest, size_t cnt)
proc ringbufferRead*(rb: Ringbuffer, dest: cstring, cnt: csize_t): csize_t {.importc: "jack_ringbuffer_read".}
proc ringbufferRead*(rb: RingbufferP, dest: cstring, cnt: csize_t): csize_t {.importc: "jack_ringbuffer_read".}
# size_t jack_ringbuffer_peek (jack_ringbuffer_t *rb, char *dest, size_t cnt)
proc ringbufferPeek*(rb: Ringbuffer, dest: cstring, cnt: csize_t): csize_t {.importc: "jack_ringbuffer_peek".}
proc ringbufferPeek*(rb: RingbufferP, dest: cstring, cnt: csize_t): csize_t {.importc: "jack_ringbuffer_peek".}
# void jack_ringbuffer_read_advance (jack_ringbuffer_t *rb, size_t cnt)
proc ringbufferReadAdvance*(rb: Ringbuffer, cnt: csize_t) {.importc: "jack_ringbuffer_read_advance".}
proc ringbufferReadAdvance*(rb: RingbufferP, cnt: csize_t) {.importc: "jack_ringbuffer_read_advance".}
# size_t jack_ringbuffer_read_space (const jack_ringbuffer_t *rb)
proc ringbufferReadSpace*(rb: Ringbuffer): csize_t {.importc: "jack_ringbuffer_read_space".}
proc ringbufferReadSpace*(rb: RingbufferP): csize_t {.importc: "jack_ringbuffer_read_space".}
# int jack_ringbuffer_mlock (jack_ringbuffer_t *rb)
proc ringbufferMlock*(rb: Ringbuffer): cint {.importc: "jack_ringbuffer_mlock", discardable.}
proc ringbufferMlock*(rb: RingbufferP): int {.importc: "jack_ringbuffer_mlock".}
# void jack_ringbuffer_reset (jack_ringbuffer_t *rb)
proc ringbufferReset*(rb: Ringbuffer) {.importc: "jack_ringbuffer_reset".}
proc ringbufferReset*(rb: RingbufferP) {.importc: "jack_ringbuffer_reset".}
# size_t jack_ringbuffer_write (jack_ringbuffer_t *rb, const char *src, size_t cnt)
proc ringbufferWrite*(rb: Ringbuffer, src: cstring, cnt: csize_t): csize_t {.importc: "jack_ringbuffer_write".}
proc ringbufferWrite*(rb: RingbufferP, src: cstring, cnt: csize_t): csize_t {.importc: "jack_ringbuffer_write".}
# void jack_ringbuffer_write_advance (jack_ringbuffer_t *rb, size_t cnt)
proc ringbufferWriteAdvance*(rb: Ringbuffer, cnt: csize_t) {.importc: "jack_ringbuffer_write_advance".}
proc ringbufferWriteAdvance*(rb: RingbufferP, cnt: csize_t) {.importc: "jack_ringbuffer_write_advance".}
# size_t jack_ringbuffer_write_space (const jack_ringbuffer_t *rb)
proc ringbufferWriteSpace*(rb: Ringbuffer): csize_t {.importc: "jack_ringbuffer_write_space".}
proc ringbufferWriteSpace*(rb: RingbufferP): csize_t {.importc: "jack_ringbuffer_write_space".}
# ------------------------------- Metadata --------------------------------
# int jack_set_property (jack_client_t*, jack_uuid_t subject, const char* key, const char* value, const char* type)
proc setProperty*(client: Client, subject: Uuid, key, value, `type`: cstring): cint {.importc: "jack_set_property", discardable.}
proc setProperty*(client: ClientP, subject: Uuid, key, value, `type`: cstring): cint {.importc: "jack_set_property".}
# int jack_get_property (jack_uuid_t subject, const char* key, char** value, char** type)
proc getProperty*(subject: Uuid, key: cstring, value, `type`: ptr cstring): cint {.importc: "jack_get_property", discardable.}
proc getProperty*(subject: Uuid, key: cstring, value, `type`: ptr cstring): cint {.importc: "jack_get_property".}
# void jack_free_description (jack_description_t* desc, int free_description_itself)
proc freeDescription*(desc: Description, freeDescriptionItself: cint) {.importc: "jack_free_description".}
proc freeDescription*(desc: DescriptionP, freeDescriptionItself: cint) {.importc: "jack_free_description".}
# int jack_get_properties (jack_uuid_t subject, jack_description_t* desc)
proc getProperties*(subject: Uuid, desc: Description): cint {.importc: "jack_get_properties", discardable.}
proc getProperties*(subject: Uuid, desc: DescriptionP): cint {.importc: "jack_get_properties".}
# int jack_get_all_properties (jack_description_t** descs)
proc getAllProperties*(descs: var ptr UncheckedArray[DescriptionT]): cint {.importc: "jack_get_all_properties", discardable.}
proc getAllProperties*(descs: var ptr UncheckedArray[Description]): cint {.importc: "jack_get_all_properties".}
# int jack_remove_property (jack_client_t* client, jack_uuid_t subject, const char* key)
proc removeProperty*(client: Client, subject: Uuid): cint {.importc: "jack_remove_property", discardable.}
proc removeProperty*(client: ClientP, subject: Uuid): cint {.importc: "jack_remove_property".}
# int jack_remove_properties (jack_client_t* client, jack_uuid_t subject)
proc removeProperties*(client: Client, subject: Uuid): cint {.importc: "jack_remove_properties", discardable.}
proc removeProperties*(client: ClientP, subject: Uuid): cint {.importc: "jack_remove_properties".}
# int jack_remove_all_properties (jack_client_t* client)
proc removeAllProperties*(client: Client): cint {.importc: "jack_remove_all_properties", discardable.}
proc removeAllProperties*(client: ClientP): cint {.importc: "jack_remove_all_properties".}
# int jack_set_property_change_callback (jack_client_t* client, JackPropertyChangeCallback callback, void* arg)
proc setPropertyChangeCallback*(client: Client, callback: PropertyChangeCallback, arg: pointer = nil): cint {.
importc: "jack_set_property_change_callback", discardable.}
proc setPropertyChangeCallback*(client: ClientP, callback: PropertyChangeCallback, arg: pointer = nil): cint {.
importc: "jack_set_property_change_callback".}
# ---------------------------- Error handling -----------------------------
# void jack_set_error_function (void(*)(const char *) func)
proc setErrorFunction*(errorCallback: ErrorCallback) {.importc: "jack_set_error_function".}
# void jack_set_info_function (void(*)(const char *) func)
proc setInfoFunction*(infoCallback: InfoCallback) {.importc: "jack_set_info_function".}
{.pop.}