summaryrefslogtreecommitdiff
path: root/src/unheard/interval.clj
diff options
context:
space:
mode:
Diffstat (limited to 'src/unheard/interval.clj')
-rw-r--r--src/unheard/interval.clj88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/unheard/interval.clj b/src/unheard/interval.clj
new file mode 100644
index 0000000..2ec5645
--- /dev/null
+++ b/src/unheard/interval.clj
@@ -0,0 +1,88 @@
+(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<Ratio>
+
+ 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.))