## ## 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()