 
 ;; A simple object which holds the values necessary to establish a link between an external
 ;; source of MIDI clock messages and the metronome driving the timing of a light show.
-(defrecord ClockSync [metronome midi-clock-source buffer traktor-info] 
+(defrecord ClockSync [metronome midi-clock-source timestamps means traktor-info] 
     IClockSync
     (sync-start [this]
-      (add-synced-metronome midi-clock-source metronome (fn [msg] (sync-handler msg buffer metronome traktor-info))))
+      (add-synced-metronome midi-clock-source metronome
+                            (fn [msg] (sync-handler msg timestamps means metronome traktor-info))))
     (sync-stop [this]
       (remove-synced-metronome midi-clock-source metronome))
     (sync-status [this]
       (dosync
-       (ensure buffer)
+       (ensure timestamps)
        (ensure traktor-info)
-       (let [n (count @buffer)
-             lag (when (pos? n) (- (now) (last @buffer)))
+       (let [n (count @timestamps)
+             lag (when (pos? n) (- (now) (last @timestamps)))
              current (and (= n max-clock-intervals)
                           (< lag 100))
              traktor-current (traktor-beat-phase-current @traktor-info)]

  "Handles MIDI communication, including syncing a show metronome to MIDI clock pulses."
  (:require [afterglow.rhythm :as rhythm]
            [amalloy.ring-buffer :refer [ring-buffer]]
            [overtone.at-at :refer [now]]
            [overtone.midi :as midi]
            [taoensso.timbre :as timbre])

  If it is a clock pulse, update the ring buffer in which we are
  collecting timestamps, and if we have enough, calculate a BPM value
  and update the associated metronome."
  [msg timestamps means metronome traktor-info]
  (dosync
   (ensure traktor-info)
   (case (:status msg)
     :timing-clock (let [timestamp (now)]  ; Ordinary clock pulse
                     (alter timestamps conj timestamp)
                     (when (> (count @timestamps) 1)
                       (let [passed (- timestamp (peek @timestamps))
                             intervals (dec (count @timestamps))
                             mean (/ passed intervals)]
                         (alter means conj mean)
                         (when (= (count @means) max-clock-intervals)
                           (let [mean-mean (/ (apply + @means) max-clock-intervals)
                                 new-bpm (/ (math/round (double (/ 6000000 (* mean-mean 24)))) 100)]
                             (when (>= (math/abs (- new-bpm (rhythm/metro-bpm metronome))) 0.1)
                               (rhythm/metro-bpm metronome new-bpm)))))))
     (:start :stop) (do (ref-set timestamps (ring-buffer max-clock-intervals)) ; Clock is being reset
                        (ref-set means (ring-buffer max-clock-intervals)))
     :control-change (when (and (some? @traktor-info) (< (:note msg) 5))  ; Traktor beat phase update
                       (when (zero? (:note msg))  ; Switching the current master deck
                         (alter traktor-info assoc :master (:velocity msg)))
