   (let [start   (atom (now))
         tick-ms (atom (beat-ms 1 bpm))
         cur-bpm (atom bpm)]
-    (fn
-      ([] (inc (long (/ (- (now) @start) @tick-ms))))
-      ([arg] (cond
-              (number? arg) (+ (* arg @tick-ms) @start)
-              (= :bpm arg) @cur-bpm
-              :else (throw (Exception. (str "Unsupported metronome arg: " arg)))))
-      ([_ bpm]
-       (let [tms (beat-ms 1 bpm)
-             cur-beat (long (/ (- (now) @start) @tick-ms))
-             new-start (- (now) (* tms cur-beat))]
-         (reset! tick-ms tms)
-         (reset! start new-start)
-         (reset! cur-bpm bpm))
-       [:bpm bpm]))))
-
-(comment defprotocol IMetronome
-  (start [this])
-  (stop  [this])
-  (beat  [this])
-  (tick  [this])
-  (bpm   [this] [this bpm]))
+    (Metronome. start cur-bpm tick-ms)))
 
 ;== Grooves
 ;

;  ([] (bar 1))
;  ([b] (* (bar 1) (first @*signature) b)))

; A metronome is a linear function that given a beat count returns the time in milliseconds.
;
; tpb = ticks-per-beat
(defn metronome
  "A metronome is a beat management function.  Tell it what BPM you want,
  and it will output beat timestamps accordingly.  Call the returned function

  to get the timestamp to play a note at that beat.

  (def m (metronome 128))
  (m)          ; => <next beat number>
  (m 200)      ; => <timestamp of beat 200>
  (m :bpm)     ; => return the current bpm val
  (m :bpm 140) ; => set bpm to 140"
