From 3967d72e7213479fbdc17bcabb470f9e7ad51e55 Mon Sep 17 00:00:00 2001 From: Christopher Arndt Date: Thu, 17 Oct 2024 16:57:22 +0200 Subject: [PATCH] feat: add zoom2transport example Signed-off-by: Christopher Arndt --- examples/zoom2transport.nim | 211 ++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 examples/zoom2transport.nim diff --git a/examples/zoom2transport.nim b/examples/zoom2transport.nim new file mode 100644 index 0000000..b1b7fbb --- /dev/null +++ b/examples/zoom2transport.nim @@ -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.. 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()