feat: wrap transport API and add transport query example

Signed-off-by: Christopher Arndt <chris@chrisarndt.de>
This commit is contained in:
Christopher Arndt 2023-05-22 19:58:03 +02:00
parent ada9b13857
commit 2d8533d122
3 changed files with 185 additions and 4 deletions

View File

@ -7,10 +7,10 @@ A [Nim] wrapper for the [JACK] [C API]
This software is in *alpha status* and has no official release yet.
The basic JACK APIs (client lifecycle, ports, callbacks) have been wrapped and
are functional (see [examples]), but latency, transport and meta-data APIs still
need wrapping. Also, symbol names may still be changed and things moved around
before the first public release.
The basic JACK APIs (client lifecycle, ports, callbacks, MIDI, transport) have
been wrapped and are functional (see [examples]), but latency, threading and
meta-data APIs still need wrapping. Also, 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

View File

@ -0,0 +1,54 @@
import std/[logging, strformat]
import jacket
var
jclient: ClientP
status: cint
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
# default. Pass ``lvlAll`` when creating the logger to enable them.
debug "JACK error: " & $msg
addHandler(log)
setErrorFunction(errorCb)
jclient = clientOpen("jacket_info", NullOption.ord, status.addr)
debug "JACK server status: " & $status
if jclient == nil:
error getJackStatusErrorString(status)
quit 1
transportState = transportQuery(jclient, pos.addr)
echo fmt"usecs: {pos.usecs}"
echo fmt"frameRate: {pos.frameRate}"
echo fmt"frame: {pos.frame}"
echo fmt"valid: {pos.valid.ord}"
if bool(pos.valid.ord and PositionBBT.ord):
echo fmt"bar: {pos.bar}"
echo fmt"beat: {pos.beat}"
echo fmt"tick: {pos.tick}"
echo fmt"barStartTick: {pos.barStartTick}"
echo fmt"beatsPerBar: {pos.beatsPerBar}"
echo fmt"beatType: {pos.beatType}"
echo fmt"beatsPerMinute: {pos.beatsPerMinute}"
case transportState
of TransportStopped:
echo "JACK transport stopped, starting it now."
transportStart(jclient)
of TransportRolling:
echo "JACK transport rolling, stopping it now."
transportStop(jclient)
of TransportStarting:
echo "JACK transport starting, nothing to do."
else:
echo "Unknown JACK transport state."
discard jclient.clientClose

View File

@ -89,7 +89,86 @@ type
CaptureLatency,
PlaybackLatency
# Transport
type
PositionBits* {.size: sizeof(cint).} = enum
PositionBBT = 0x10,
PositionTimecode = 0x20,
BBTFrameOffset = 0x40,
AudioVideoRatio = 0x80,
VideoFrameOffset = 0x100,
TickDouble = 0x200
TransportState* {.size: sizeof(cint).} = enum
TransportStopped = 0,
TransportRolling = 1,
TransportLooping = 2,
TransportStarting = 3,
TransportNetStarting = 4
type
Position* = object
unique1*: uint64
usecs*: Time
frameRate*: NFrames
frame*: NFrames
valid*: PositionBits
bar*: int32
beat*: int32
tick*: int32
barStartTick*: cdouble
beatsPerBar*: cfloat
beatType*: cfloat
ticksPerBeat*: cdouble
beatsPerMinute*: cdouble
frameTime*: cdouble
nextTime*: cdouble
bbtOffset*: NFrames
audioFramesPerVideoFrame*: cfloat
videoOffset*: NFrames
tickDouble*: cdouble
padding*: array[5, int32]
unique2*: uint64
PositionP* = ptr Position
#[ DEPRECATED
typedef enum {
JackTransportState = 0x1,
JackTransportPosition = 0x2,
JackTransportLoop = 0x4,
JackTransportSMPTE = 0x8,
JackTransportBBT = 0x10
} jack_transport_bits_t;
typedef struct {
jack_nframes_t frame_rate;
jack_time_t usecs;
jack_transport_bits_t valid;
jack_transport_state_t transport_state;
jack_nframes_t frame;
jack_nframes_t loop_start;
jack_nframes_t loop_end;
long smpte_offset
float smpte_frame_rate;
int bar;
int beat;
int tick;
double bar_start_tick;
float beats_per_bar;
float beat_type;
double ticks_per_beat;
double beats_per_minute;
} jack_transport_info_t;
]#
const
JACK_POSITION_MASK* = (PositionBBT.ord or PositionTimecode.ord)
EXTENDED_TIME_INFO* = true
JACK_TICK_DOUBLE* = true
# Callback function types
type
JackProcessCallback* = proc (nframes: NFrames; arg: pointer): cint {.cdecl.}
JackThreadCallback* = proc (arg: pointer): pointer {.cdecl.}
@ -109,6 +188,10 @@ type
JackInfoCallback* = proc (msg: cstring) {.cdecl.}
JackErrorCallback* = proc (msg: cstring) {.cdecl.}
JackSyncCallback* = proc (state: TransportState; pos: ptr Position; arg: pointer): cint {.cdecl.}
JackTimebaseCallback* = proc (state: TransportState; nframes: NFrames; pos: ptr Position; newPos: cint;
arg: pointer) {.cdecl.}
# ----------------------------- Version info ------------------------------
@ -476,6 +559,50 @@ proc timeToFrames*(client: ClientP; time: Time): NFrames {.importc: "jack_time_t
# jack_time_t jack_get_time(void)
proc getTime*(): Time {.importc: "jack_get_time".}
# ------------------------------- Transport -------------------------------
# int jack_release_timebase (jack_client_t *client)
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: ClientP; syncCallback: JackSyncCallback; arg: pointer): cint {.
importc: "jack_set_sync_callback".}
# int jack_set_sync_timeout (jack_client_t *client, jack_time_t timeout)
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: ClientP; conditional: cint; timebaseCallback: JackTimebaseCallback;
arg: pointer): cint {.
importc: "jack_set_timebase_callback".}
# int jack_transport_locate (jack_client_t *client, jack_nframes_t frame)
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: ClientP; pos: PositionP): TransportState {.importc: "jack_transport_query".}
# jack_nframes_t jack_get_current_transport_frame (const jack_client_t *client)
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: ClientP; pos: PositionP): cint {.importc: "jack_transport_reposition".}
# void jack_transport_start (jack_client_t *client)
proc transportStart*(client: ClientP) {.importc: "jack_transport_start".}
# void jack_transport_stop (jack_client_t *client)
proc transportStop*(client: ClientP) {.importc: "jack_transport_stop".}
#[ DEPRECATED
void jack_get_transport_info (jack_client_t *client, jack_transport_info_t *tinfo)
void jack_set_transport_info (jack_client_t *client, jack_transport_info_t *tinfo)
]#
# ---------------------------- Error handling -----------------------------
proc setErrorFunction*(errorCallback: JackErrorCallback) {.importc: "jack_set_error_function".}