# This requires either nim 1.9+ or --threads:on: import std/[locks, logging, os, strformat] import signal import jacket var jclient: ClientP event: MidiEvent midiPort: PortP rb: RingbufferP midiEventPrinter: Thread[void] status: cint exitSignalled: bool = false exitLoop: bool = false overruns: uint = 0 dataReady: Cond dataReadyLock: Lock let rbSize = 128 var log = newConsoleLogger(when defined(release): lvlInfo else: lvlDebug) addHandler(log) proc cleanup() = debug "Cleaning up..." if jclient != nil: debug "Deactivating JACK client..." discard jclient.deactivate() if midiEventPrinter.running: debug "Stopping MIDI event printer thread..." exitLoop = true if dataReadyLock.tryAcquire(): dataReady.signal() dataReadyLock.release() debug "Joining MIDI event printer thread..." midiEventPrinter.joinThread() debug "Joined." if jclient != nil: debug "Closing JACK client..." discard jclient.clientClose() jclient = nil debug fmt"Buffer overruns: {overruns}" debug "Bye." 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.} = info "Received signal: " & $sig exitSignalled = true proc shutdownCb(arg: pointer = nil) {.cdecl.} = info "JACK server has shut down." exitSignalled = true proc midiEventPrinterProc() {.thread.} = var recvBuf: array[4, uint8] dataReadyLock.acquire() while not exitLoop: while not exitLoop and ringbufferReadSpace(rb) >= 4: var read = cast[int](ringbufferRead(rb, cast[cstring](recvBuf.addr), 4)) if recvBuf[0] <= 3: for i in 0..