diff --git a/tl/src/tl/scene.cljs b/tl/src/tl/scene.cljs index 62ac014..0a7842a 100644 --- a/tl/src/tl/scene.cljs +++ b/tl/src/tl/scene.cljs @@ -170,15 +170,19 @@ "The clip-segments that make up context `ctx` — what you draw and select against. An annotation's marks reference clips, so that's just `resolve`. The root timeline doesn't enumerate its clips (they're a parentless pool), so - there it's the pool laid in root's identity coordinate (local = source)." + there it's the pool laid at each clip's TIMELINE position (:start) with :src = + its source range — so the assembled program tiles contiguously even though + the underlying source frames are scattered (and fractional)." [scene ctx] (if (= :timeline (:type (grp scene ctx))) (->> (:groups scene) (keep (fn [[gid g]] (when (= :clip (:type g)) - (let [seg (first (resolve scene gid))] - (assoc seg :mark gid :local (:src seg)))))) ; ref clip by group id - (sort-by (comp first :src)) + (let [seg (first (resolve scene gid)) + [sa sb] (:src seg) + st (:start g 0)] + (assoc seg :mark gid :local [st (+ st (- sb sa))]))))) + (sort-by (comp first :local)) vec) (resolve scene ctx))) @@ -278,6 +282,7 @@ clips (into {} (for [t vtracks c (:clips t)] [(keyword (:id c)) {:type :clip :parent nil :name (:name c) + :start (:start c) ; timeline position (frames) :marks [{:id (keyword (str (:id c) "-m")) :start (:media-in c) :end (+ (:media-in c) (:duration c)) diff --git a/tl/test/tl/scene_test.cljs b/tl/test/tl/scene_test.cljs index 9f3b95c..2b70d0b 100644 --- a/tl/test/tl/scene_test.cljs +++ b/tl/test/tl/scene_test.cljs @@ -8,9 +8,10 @@ (def base {:tracks {:t0 {:name "A-roll"} :t1 {:name "B-roll"} :t2 {:name "C-roll"}} :groups {:root {:type :timeline :parent nil :marks [{:id :m/root :start 0 :end 300}]} - :clip-a {:type :clip :parent nil :marks [{:id :m/a :start 0 :end 100 :track :t0}]} - :clip-b {:type :clip :parent nil :marks [{:id :m/b :start 100 :end 200 :track :t1}]} - :clip-c {:type :clip :parent nil :marks [{:id :m/c :start 200 :end 300 :track :t2}]}}}) + ;; :start = timeline position; here it equals source so root is identity + :clip-a {:type :clip :parent nil :start 0 :marks [{:id :m/a :start 0 :end 100 :track :t0}]} + :clip-b {:type :clip :parent nil :start 100 :marks [{:id :m/b :start 100 :end 200 :track :t1}]} + :clip-c {:type :clip :parent nil :start 200 :marks [{:id :m/c :start 200 :end 300 :track :t2}]}}}) (defn with-group [scene gid g] (assoc-in scene [:groups gid] g)) (defn refm [id clip a b] {:id id :start {:ref clip :at a} :end {:ref clip :at b}}) @@ -177,10 +178,12 @@ (deftest seed-from-otio (testing "from-otio seeds tracks + clip mark-groups + root; content-segments at root tiles the clips" + ;; two clips cut back to back on the timeline (:start 0 then 100), like a + ;; multicam program, even though their source frames aren't contiguous (let [parsed {:fps 24 :duration 200 - :tracks [{:index 0 :kind :video :name "Wide" :clips [{:id "t0-c0" :name "a" :media-in 0 :duration 100}]} - {:index 1 :kind :video :name "CU" :clips [{:id "t1-c0" :name "b" :media-in 100 :duration 100}]} - {:index 2 :kind :audio :name "Aud" :clips [{:id "t2-c0" :name "x" :media-in 0 :duration 50}]}]} + :tracks [{:index 0 :kind :video :name "Wide" :clips [{:id "t0-c0" :name "a" :start 0 :media-in 0 :duration 100}]} + {:index 1 :kind :video :name "CU" :clips [{:id "t1-c0" :name "b" :start 100 :media-in 500 :duration 100}]} + {:index 2 :kind :audio :name "Aud" :clips [{:id "t2-c0" :name "x" :start 0 :media-in 0 :duration 50}]}]} scene (s/from-otio parsed)] (is (= 2 (count (:tracks scene)))) ; audio track dropped (is (contains? (:groups scene) :t0-c0))