            [java.util.regex Pattern]))
 
 (def ^:private max-clock-intervals
-  "How many MIDI clock pulses should be kept around for averaging?"
+  "How many MIDI clock pulses and interval averages should be kept
+  around for BPM calculation?"
   30)
+
+(def ^:private min-clock-intervals
+  "How many MIDI clock pulses are needed in order to start attempting
+  BPM calculation?"
+  12)
+
+(def ^:private max-clock-lag
+  "How many ms is too long to wait between MIDI clock pulses?"
+  150)
 
 (def ^:private max-tempo-taps
   "How many tempo taps should be kept around for averaging?"
   4)
 
-(def ^:private max-tempo-tap-interval
+(def ^:private max-tempo-tap-lag
   "How long is too long for a tap to be considered part of
   establishing a tempo?"
   2000)

                mean (/ passed intervals)]
            (rhythm/metro-bpm metronome (double (/ 60000 mean))))))
      ;; This tap was isolated, but may start a new series.
      (reset! buffer (conj (ring-buffer max-tempo-tap-interval) timestamp))))
  nil)

(defn create-tempo-tap-handler
  "Returns a function which implements a simple tempo-tap algorithm on
  the supplied metronome."
  [metronome]
  (let [buffer (atom (ring-buffer max-tempo-tap-interval))]
    (fn [] (tap-handler buffer metronome))))

(defonce

      mechanism ever offers that), and :status, which is a
      human-oriented summmary of the status."))))

(defn interval-to-bpm
  "Given an interval between MIDI clock pulses in milliseconds,
  calculate the implied beats per minute value, to the nearest
  hundredth of a beat."
  [interval]
  (/ (math/round (double (/ 6000000 (* interval 24)))) 100.0))

(defn bpm-to-interval
  "Given a BPM, calculate the interval between MIDI clock pulses in
  milliseconds."
  [bpm]
  (/ 2500.0 bpm))

(defn std-dev
  "Calculate the standard deviation of a set of samples."
  ([samples]
   (let [n (count samples)
         mean (/ (reduce + samples) n)]
     (std-dev samples n mean)))
  ([samples n mean]
   (let [intermediate (map #(Math/pow (- %1 mean) 2) samples)]
     (Math/sqrt (/ (reduce + intermediate) n))))) 

(def abs-tolerance
  "If we are going to adjust the BPM, the adjustment we are going to
  make needs to represent at least this many milliseconds per MIDI
  clock tick (to reduce jitter)."
  0.005)

(def dev-tolerance
  "If we are going to adjust the BPM, the adjustment must be at least
  this many times the standard deviation in observed clock pulse
  timings, so we can avoid jitter due to unstable timing."
  2.2)

(defn- sync-handler
  "Called whenever a MIDI message is received for a synced metronome.
  If it is a clock pulse, update the ring buffer in which we are
