(ns unheard.time-object (:require [missionary.core :as m] [unheard.interval :as i])) ;; TODO: Update description (defn time-object "A time-object takes a start time, and end time, and a value. Value is a flow that will be consumed when the corresponding time tree is consumed at a point in time within the time-object's interval. " [start duration value] {:start start, :duration duration, :value value}) (defn lift "Lift collection of time objects to a phrase" [& children] {:start 0, :time-objects children}) ;; BUG c9be408 (defn phrase ;; TODO: Description [& children] (fn [start] {:start start, :time-objects (for [child children time-object (:time-objects child)] (update time-object :start (partial + start)))})) (comment (def a (phrase (lift (time-object 0 4 :x)) (lift (time-object 0 4 :a)))) (def b (phrase (a 0) (a 1) (lift (time-object 10 2 :x) (time-object 10 2 :b)) (lift (time-object 0 2 :y)))) (def c (phrase (b 0) (b 3))) (c 0)) (defn phrase->spans [phrase] (let [{:keys [time-objects]} (phrase 0)] (map (fn [{:keys [start duration value]}] [start (+ start duration) value]) time-objects))) (comment (phrase->spans c)) (defn timeline "Primary timeline bookkeeping mehanism." [spans] (let [c (i/create-ratio-interval-collection)] (doall (for [[start end value] spans] (.add c (i/ratio-interval start end value)))) c)) (comment (def t (timeline (phrase->spans c))) (i/find-overlaps t (i/ratio-interval 0 1 nil)) (i/find-overlaps t (i/ratio-interval -1 0 nil))) (defn point-query "Query a timeline. Returns a flow of time objects." [timeline >at] (m/stream (m/ap (let [at (m/?< >at)] (into #{} (map #(.value %) (i/find-overlaps timeline (i/ratio-interval at at nil)))))))) (comment (def at (atom 0)) (def >at (m/watch at)) (def cancel ((m/reduce prn nil (point-query t >at)) prn prn)) (reset! at 5) (reset! at 14) (cancel))