     - there should also be an also-play-note, which does the same thing as play-note, but doesn't stop any currently playing nodes
     - ditto for also-play-chord, also-play-notes 
     - stop-all-oscs (will need to keep track of them in a top-level dynamic var, like *oscillators*)
+    - make time more accurate by not just using setTimeout
+        ref:
+          http://www.html5rocks.com/en/tutorials/audio/scheduling
+          https://github.com/cwilso/metronome/blob/master/js/metronome.js
 ")
 

  [osc-model {:keys [pitch duration volume]}]
  (let [{:keys [osc-node gain-node] :as osc-impl} (osc* osc-model)]
    (.start osc-node 0)

    (when pitch 
      (freq osc-node pitch))


    (if duration
      (do
        ; *** see below ***
        (js/setTimeout #(stop-osc osc-impl) duration)
        osc-model)
      (update osc-model :osc-nodes (fnil conj #{}) osc-impl))))

; this fn now only works for osc-impl
; need a new fn that works for osc-model (which now has a set of osc-impls) 
; or maybe make this a multimethod that works for both
(defn stop-osc
  "Silences and stops a currently playing oscillator."
  [{:keys [osc-node gain-node] :as osc-model-or-impl}]
  (silence-ramp gain-node)
  (js/setTimeout #(do
                    (.stop osc-node)
                    (alter-var-root #'*active-oscs* disj osc-node)) 1000))

(comment "
  TODO: 
