 (ns afterglow.midi
   "Handles MIDI communication, including syncing a show metronome to MIDI clock pulses."
   (:require [afterglow.rhythm :refer :all]
+            [clojure.core.async :refer [chan go <! >!! thread]]
             [amalloy.ring-buffer :refer [ring-buffer]]
             [overtone.at-at :refer [now]]
             [overtone.midi :as midi]
-            [taoensso.timbre :refer [error]])
+            [taoensso.timbre :refer [info error]])
   (:import [java.util.regex Pattern]))
 
 (def ^:private max-clock-intervals

  (doseq [handler (vals (get-in @control-mappings [(:name (:device msg)) (:channel msg) (:note msg)]))]
    (handler msg)))

(defn- incoming-message-handler
  "Attached to all midi input devices we manage. Fields incoming MIDI
  messages, looks for registered interest in them (metronome sync,
  variable mappings, etc.) and dispatches to the appropriate specific
  handler."
  [msg]

  ;; First call the global message handlers
  (doseq [handler @global-handlers]
    (try
      (handler msg)
      (catch Exception e
        (error e "Problem runing global MIDI event handler"))))

  ;; Then call any registered port listeners for the port on which
  ;; it arrived

  ;; Finally, call specific message handlers
  (case (:status msg)
    (:timing-clock :start :stop) (clock-message-handler msg)
    :control-change (cc-message-handler msg)
    nil))

(defn- connect-midi-in
  "Open a MIDI input device and cause it to send its events to

            (not (mmj-descriptions (:name device))))))
    identity))

(defn- create-channel
  "Creates the core.async channel used to deliver MIDI events when needed."
  [old-channel]
  (or old-channel
      (let [c (chan 32)]
        (info "Created MIDI dispatch channel.")
        (future (delegated-message-handler))
        c)))

;; TODO: This and open-outputs will have to change once hot-plugging works.
(defn open-inputs-if-needed!
  "Make sure the MIDI input ports are open and ready to distribute events.
  Returns the opened inputs."
  []
  (swap! channel create-channel)
  (let [port-filter (create-midi-port-filter)
        result (swap! midi-inputs #(if (empty? %)
                                     (map connect-midi-in
