(ns unheard.interval "Custom IInterval implementation for Clojure ratios with arbitrary values." (:import [com.brein.time.timeintervals.intervals IInterval] [com.brein.time.timeintervals.collections ListIntervalCollection])) (deftype RatioValueInterval [start end value] IInterval (getNormStart [_] start) (getNormEnd [_] end) (getUniqueIdentifier [_] (str "[" start "," end "]")) (compareTo [_ other] (let [start-cmp (compare start (.getNormStart ^RatioValueInterval other))] (if (zero? start-cmp) (compare end (.getNormEnd ^RatioValueInterval other)) start-cmp))) Object (toString [_] (str "[" start ", " end "] -> " value))) ;; Public API (defn ratio-interval "Create a RatioValueInterval with ratio boundaries and arbitrary value. Args: start - Clojure ratio for interval start (inclusive) end - Clojure ratio for interval end (inclusive) value - Arbitrary data to associate with interval Returns: Instance of RatioValueInterval implementing IInterval Example: (ratio-interval 1/4 3/4 {:note :C :velocity 64})" [start end value] (->RatioValueInterval start end value)) (defn interval-value "Get the value associated with a RatioValueInterval. Args: interval - A RatioValueInterval instance Returns: The value stored in the interval" [^RatioValueInterval interval] (.value interval)) (defn overlaps? "Check if two intervals overlap. Two intervals [a,b] and [c,d] overlap if max(a,c) <= min(b,d)" [^RatioValueInterval iv1 ^RatioValueInterval iv2] (let [start1 (.getNormStart iv1) end1 (.getNormEnd iv1) start2 (.getNormStart iv2) end2 (.getNormEnd iv2)] (<= (max (compare start1 start2)) (min (compare end1 end2))))) (defn find-overlaps "Find all intervals in a collection that overlap with the query interval. Args: coll - A collection of intervals (any Iterable) query - The interval to query for overlaps Returns: A sequence of intervals that overlap with the query" [coll ^RatioValueInterval query] (let [q-start (.getNormStart query) q-end (.getNormEnd query)] (filter (fn [^RatioValueInterval iv] (let [start (.getNormStart iv) end (.getNormEnd iv)] ;; Intervals overlap if: start <= q-end AND end >= q-start (and (<= (compare start q-end) 0) (>= (compare end q-start) 0)))) coll))) (defn create-ratio-interval-collection "Create a simple ListIntervalCollection for RatioValueInterval instances. This uses a simple list-based collection. Use find-overlaps to query for overlapping intervals. Returns: Configured IntervalCollection ready to accept ratio-interval instances" [] (ListIntervalCollection.))