   (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)))))))


(defn touches
  [canvas-id type]
  (map< touch-data->touches (util/listen (dom/getElement canvas-id) type)))

(defn create-touch-input-channel
  [canvas-id]
  (async/merge [(touches canvas-id :touchstart)
                (touches canvas-id :touchend)
                (touches canvas-id :touchmove)]))

(defn step-time
  [instrument delta]

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

(defn touch->note
  [{playhead :playhead :as instrument} touch]
  (let [freq (touch->freq instrument touch)]
    (if (not (get-in instrument [:piano-keys freq :on?]))
      {:freq freq
       :on playhead
       :off nil
       :touch-id (touch :touch-id)})))

(defn start-note
  [touch {notes :notes :as instrument}]
  (if-let [new-note (touch->note instrument touch)]
    (-> instrument
        (maybe-init-synths)
        (play-piano-key (new-note :freq))
        (assoc :notes (conj notes new-note)))
    instrument))

(defn end-notes
  [touch {notes :notes playhead :playhead :as instrument}]
  (let [note-off? (fn [n] (= (touch :touch-id) (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
  [{x1 :x y1 :y} {x2 :x y2 :y}]
  (.sqrt js/Math (+ (.pow js/Math (- x2 x1) 2) (.pow js/Math (- y2 y1) 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
  [touch {playhead :playhead px-per-ms :px-per-ms :as instrument}]
  ;; #_(-> instrument
  ;;     ;; (assoc :scrolling? true)
  ;;   (assoc :playhead (+ playhead (/ (touch :y-distance) px-per-ms))))
  ;; (assoc instrument :scrolling? false)
  (assoc instrument :playhead (+ playhead (/ (touch :y-distance) px-per-ms))))

;; (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-touch-on-instrument
  [touch instrument]
  (condp = (touch :type)
    "touchstart" (start-note touch instrument)
    "touchmove" (scroll touch instrument)
    "touchend" (end-notes touch instrument)))

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