   (go
    (loop [instrument (update-size (create-instrument (scales/c-minor)) canvas-id)]
      (>! c-instrument instrument)
-     (let [[data c] (alts! [c-touch c-orientation-change (timeout frame-delay)])]
+     (let [[data c] (alts! [c-orientation-change c-touch (timeout frame-delay)])]
        (condp = c
          c-orientation-change (recur (update-size instrument canvas-id))
-         c-touch (recur (fire-touches-on-instrument instrument data))
+         c-touch (recur (fire-touch-on-instrument data instrument))
          (recur (tick instrument frame-delay)))))))

  [f coll val]
  (reduce f val coll))

(defn touches->notes
  [{playhead :playhead :as instrument} touches]
  (->> touches
       (map (fn [t] (assoc t :freq (touch->freq instrument t))))
       (remove (fn [t] (get-in instrument [:piano-keys (t :freq) :on?])))
       (map (fn [t] {:freq (t :freq)
                     :on playhead
                     :off nil
                     :touch-id (t :touch-id)}))))

(defn start-notes
  [touches {notes :notes :as instrument}]
  (let [new-notes (touches->notes instrument (filter-type "touchstart" touches))]
    (reduce play-piano-key
            (assoc instrument :notes (concat new-notes notes))
            (map :freq new-notes))))

(defn end-notes
  [touches {notes :notes playhead :playhead :as instrument}]
  (let [off-touch-ids (->> (filter-type "touchend" touches)
                           (map :touch-id)
                           set)
        note-off? (fn [n] (contains? off-touch-ids (n :touch-id)))]
    (-> instrument
        (assoc :notes (map (fn [n] (if (note-off? n) (assoc n :off playhead) n)) notes))
        (->> (reduce-val->> stop-piano-key (->> notes (filter note-off?) (map :freq)))))))

(defn x-distance
  [{{end-x :x} :position :as t} instrument]
  (- (get-in instrument [:cur-touches (t :touch-id) :position :x]) end-x))

(defn y-distance
  [{{end-y :y} :position :as t} instrument]
  (- (get-in instrument [:cur-touches (t :touch-id) :position :y]) end-y))

(defn distance
  [t instrument]
  (.sqrt js/Math (+ (.pow js/Math (x-distance t instrument) 2)
                    (.pow js/Math (y-distance t instrument) 2))))

(defn filter-scroll-touches
  [touches instrument]
  (filter (fn [t] (> (.abs js/Math (distance t instrument)) 10))
          (filter-type "touchmove" touches)))

(defn record-touches
  [touches instrument]
  (let [starts (filter-type "touchstart" touches)
        moves (filter-type "touchmove" touches)
        ends (filter-type "touchend" touches)]
    (-> instrument
        (update-in [:cur-touches] into (map vector (map :touch-id starts) starts))
        (update-in [:cur-touches] into (map vector (map :touch-id moves) moves))
        (update-in [:cur-touches] (fn [c] (apply dissoc c (map :touch-id ends)))))))

(defn scroll
  [scroll-touches {playhead :playhead px-per-ms :px-per-ms :as instrument}]
  (if-let [scroll-touch (first (sort (fn [a b] (max (.abs js/Math (y-distance a instrument))
                                                    (.abs js/Math (y-distance b instrument))))
                                     scroll-touches))]
    (-> instrument
        (assoc :scrolling? true)
        (assoc :playhead (+ playhead (/ (y-distance scroll-touch instrument) px-per-ms))))
    (assoc instrument :scrolling? false)))

(defn delete-scrolled-notes
  [scroll-touches {notes :notes :as instrument}]
  (let [scroll-touch-ids (set (map :touch-id scroll-touches))
        delete-notes (group-by (fn [t] (and (nil? (t :off))
                                            (contains? scroll-touch-ids (t :touch-id))))
                               notes)]
    (-> instrument
        (assoc :notes (get delete-notes false))
        (->> (reduce-val->> stop-piano-key (map :freq (get delete-notes true)))))))

(defn handle-scrolling
  [touches instrument]
  (let [scroll-touches (filter-scroll-touches touches instrument)]
    (->> instrument
         (scroll scroll-touches)
         (delete-scrolled-notes scroll-touches)
         (record-touches touches))))

(defn fire-touches-on-instrument
  [instrument touches]
  (->> instrument
       maybe-init-synths
       (start-notes touches)
       (end-notes touches)
       (handle-scrolling touches)))

(defn update-size [instrument canvas-id]
  (let [{w :w h :h :as window-size} (util/get-window-size)]

  (draw-notes draw-ctx instrument)
  (.restore draw-ctx))

(defn touch->piano-key
  [x instrument]
  (let [note-index (.floor js/Math (/ x (piano-key-width instrument)))]
    (nth (-> instrument :piano-keys keys) note-index)))
