blob: 513b090db43abdd9037cafc6329ed7f21a65bb65 (
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
(ns unheard.cycles)
(defn l
"List combinator: subdivides time evenly among children, advancing in lockstep.
Each child receives an equal portion of the parent's time duration.
All children advance synchronously through their patterns.
Equivalent to TidalCycles/Strudel 'fastcat' operator.
Example:
(l :a :b :c) with cycle-length 1
=> [[0 1/3 :a] [1/3 2/3 :b] [2/3 1 :c]]"
[& args]
{:v (vec args) :type :l})
(defn f
"Fork combinator: cycles through children sequentially across iterations.
Each iteration selects one child in round-robin fashion.
The selected child gets the full time duration for that iteration.
Forks extend the total pattern duration by (num-children × child-cycles).
Equivalent to TidalCycles/Strudel 'slowcat' operator.
Example:
(f :a :b :c) with cycle-length 1
=> [[0 1 :a] [1 2 :b] [2 3 :c]]"
[& args]
{:v (vec args) :type :f})
(defn scalar? [x]
(not (and (map? x) (:type x))))
(defn gcd [a b]
(if (zero? b) a (recur b (mod a b))))
(defn lcm [a b]
(/ (* a b) (gcd a b)))
(defn compute-cycle [node]
(cond
(scalar? node) 1
(= :f (:type node))
(let [children (:v node)
n (count children)]
(* n (reduce lcm 1 (map compute-cycle children))))
(= :l (:type node))
(let [children (:v node)]
(reduce lcm 1 (map compute-cycle children)))))
(defn unfold-node [node start end iteration]
(let [duration (- end start)]
(cond
(scalar? node)
[[start end node]]
(= :l (:type node))
(let [children (:v node)
n (count children)
slice-size (/ duration n)]
(mapcat (fn [i child]
(let [child-start (+ start (* i slice-size))
child-end (+ start (* (inc i) slice-size))]
(unfold-node child child-start child-end iteration)))
(range n)
children))
(= :f (:type node))
(let [children (:v node)
n (count children)
child-idx (mod iteration n)]
(unfold-node (nth children child-idx) start end (quot iteration n))))))
(defn unfold
"Unfolds a pattern tree into concrete time intervals.
Takes a cycle-length and a pattern node (scalar, list, or fork),
and returns a vector of [start end value] intervals representing
when each scalar value is active.
Args:
cycle-length - Duration of each iteration (can be any number)
node - Pattern tree built from scalars, (l ...), and (f ...)
Returns:
Vector of [start end value] tuples, where start and end are rational
numbers representing time positions.
The total duration of the result is (* cycle-length (compute-cycle node)).
Examples:
(unfold 1 :a)
=> [[0 1 :a]]
(unfold 1 (l :a :b))
=> [[0 1/2 :a] [1/2 1 :b]]
(unfold 1 (f :a :b))
=> [[0 1 :a] [1 2 :b]]"
[cycle-length node]
(let [cycle-count (compute-cycle node)]
(vec (mapcat (fn [i]
(unfold-node node
(* i cycle-length)
(* (inc i) cycle-length)
i))
(range cycle-count)))))
|