blob: c10161c700eb4abfd4149d702b52849cff0877f2 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
(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
;; HACK: coerce start to long to work around
;; class clojure.lang.BigInt cannot be cast to class java.lang.Comparable
(getNormStart [_] (if (instance? clojure.lang.BigInt start)
(long start)
start))
;; HACK: coerce start to long to work around
;; class clojure.lang.BigInt cannot be cast to class java.lang.Comparable
(getNormEnd [_] (if (instance? clojure.lang.BigInt end)
(long end)
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.))
|