diff --git a/LICENSE b/LICENSE.md similarity index 98% rename from LICENSE rename to LICENSE.md index 69b7c1a..c3b25d1 100644 --- a/LICENSE +++ b/LICENSE.md @@ -1,4 +1,4 @@ -MIT License +# MIT License Copyright (c) 2022 - 2023 Christopher Arndt diff --git a/README.md b/README.md index a721668..feb126c 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,17 @@ # jacket -A [Nim] wrapper for the [JACK] [C API] +A [Nim] wrapper for the [JACK] client side [C API] aka *libjack*. ## Project status -This software is in *alpha status* and has no official release yet. +This software is in *beta status*. 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 alpha or beta stage, symbol names -may still be changed and things moved around before the first public release. - -Also, I plan to add a higher-level abstraction on top of the direct mapping -from Nim procs and types to C functions and types, probably in the form of -a JACK client object, which takes care of creating a JACK client instance, -registering ports and setting up all the callbacks necessary for a well-behaved -JACK application. +by these bindings. While this project is in beta stage, symbol names may still +be changed and things moved around before the first public release. ## Installation @@ -25,18 +19,90 @@ JACK application. * Clone this repository. * Change into the `jacket` directory. * Run [`nimble install`] (or `nimble develop`). -* Run the examples with `nim compile --run examples/.nim` (some also - need `--threads:on`). +* Run the [examples] with `nim compile --run examples/.nim`. + + (Some examples need `--threads:on` with Nim < 2.0). + + +## 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. + +```nim +import std/os +import system/ansi_c +import jacket + +var + jackClient: ClientP + status: cint + exitSignalled: bool = false + inpPort, outPort: PortP +type JackBufferP = ptr UncheckedArray[DefaultAudioSample] + +proc signalCb(sig: cint) {.noconv.} = + exitSignalled = true + +proc shutdownCb(arg: pointer = nil) {.cdecl.} = + exitSignalled = true + +proc processCb(nFrames: NFrames, arg: pointer): cint {.cdecl.} = + 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 +jackClient = clientOpen("passthru", NullOption.ord, status.addr) +# Register audio input and output ports +inpPort = jackClient.portRegister("in_1", JACK_DEFAULT_AUDIO_TYPE, PortIsInput.ord, 0) +outPort = jackClient.portRegister("out_1", JACK_DEFAULT_AUDIO_TYPE, PortIsOutput.ord, 0) +# Set JACK callbacks +jackClient.onShutdown(shutdownCb) +discard jackClient.setProcessCallback(processCb, nil) +# Handle POSIX signals +c_signal(SIGINT, signalCb) +c_signal(SIGTERM, signalCb) +# Activate JACK client ... +discard jackClient.activate() + +while not exitSignalled: + sleep(50) + +discard jackClient.clientClose() +``` ## License -This software is released under the *MIT License*. See the [LICENSE](./LICENSE) -file for more information. +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, 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 +derivative work of libjack and not required to be released under the LGPL, but +no guarantees are made in this regard and users are advised to employ +professional legal counsel when in doubt. + + +## Author + +*jacket* is written by [Christopher Arndt]. -[`nimble install`]: https://github.com/nim-lang/nimble#nimble-usage [C API]: https://jackaudio.org/api/ +[Christopher Arndt]: mailto:info@chrisarndt.de [examples]: ./examples [JACK]: https://jackaudio.org/ +[LGPL-2.1]: https://spdx.org/licenses/LGPL-2.1-or-later.html +[`nimble install`]: https://github.com/nim-lang/nimble#nimble-usage [Nim]: https://nim-lang.org/ diff --git a/TODO.md b/TODO.md index 8fe6fcc..e5b8367 100644 --- a/TODO.md +++ b/TODO.md @@ -1,14 +1,24 @@ # TODO + ## Threading API Still needs to be wrapped. How to handle `jack_native_thread_t` type? + ## Internal Clients Jack 1 and JACK 2 are disagreeing on the signatures of the functions for -loading and getting a handles for internal clients: +loading and getting a handle for internal clients: * https://github.com/jackaudio/jack2/blob/develop/common/jack/intclient.h#L66 * https://github.com/jackaudio/headers/blob/2bfa5069718ca4f4dc091e0be845958f2d8a5ba8/intclient.h#L69 * https://jackaudio.org/api/intclient_8h.html#a176a2daf66c8777eb1a845068fd7a822 + + +## Higher level abstraction + +Add a higher-level abstraction on top of the direct mapping from Nim procs and +types to C functions and types, in the form of a JACK client object, which +takes care of creating a JACK client instance, registering ports and setting up +all the callbacks necessary for a well-behaved JACK application. diff --git a/jacket.nimble b/jacket.nimble index e74557a..8d6d682 100644 --- a/jacket.nimble +++ b/jacket.nimble @@ -2,10 +2,10 @@ version = "0.1.0" author = "Christopher Arndt" -description = "A Nim wrapper for the JACK C API" +description = "A Nim wrapper for the JACK client-side C API aka libjack" license = "MIT" -srcDir = "src" +srcDir = "src" # Dependencies