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
|
(ns notation
(:require [missionary.core :as m]
[clojure.set :refer [union]]))
(comment
;; Parallel groups
;; Notes 1, 2, and 3 simultaneously
;; = should remind you of amb=
;; implicit duration of 1
[= 1 2 3]
;; Compiles to?
;; Same as above, but with duration 3
([= 1 2 3] 3)
;; Notes 1, 2, and 3 all with different durations
[=
(1 2)
(2 3)
(3 4)]
;; Inner values override outer values
;; In this chord, 1 would have a duration of 3 while 2 and 3 would have a duration of 2
([= (1 3) 2 3] 2)
;; Notes 1, 2, and 3 all with different durations and velocities
[=
(1 2 100)
(2 3 110)
(3 4 123)]
;; Sequential groups
;; Note 1, then note 2, then note 3
[1 2 3]
;; Note 1 duration 1, then note 2 duration 2, then note 3 duration 1
[(1 1)
(2 2)
(3 1)]
;; Three chords played sequentially
[[= 1 2 3]
[= 1 2 3]
[= 1 2 3]]
;; Note 1, followed by a rest, followed by note 3
[1 (r) 3]
;; Unlike notes, rests are at most 2-tuples
;; (Think about it: Rests never have a note value)
;; Assign the note sequence 1 2 3 to the name loop1
;; The first argument is always the name; the last argument is always either
;; a sequential or parallel group
(=loop1 [1 2 3])
;; Use loop1
[1 (loop1) 2 3]
;; Middle arguments are variable names
(=loop2 dur ([1 2 3] dur))
;; TODO:
;; - Note literals turn into numbers
;; - Represent keyboard as byte array of shorts
;; - play a note increments, stop a note decrements
;; - Multiple instruments
;; - Mapping inputs to vars
;; - Inputs get declared at the top of a track
;; - Devices get mapped to declared inputs
;; - Notion of scenes that change mapping of inputs to vars
;; - Loops
)
;; TODO: Move elsewhere
(defn clock []
(let [clock (atom 0)
>clock (m/signal (m/watch clock))]
[>clock (fn [v] (reset! clock v))]
))
(defn note [clock start duration value]
(m/cp
(if (m/?< (m/latest #(<= start % (dec (+ start duration))) clock))
#{value}
#{})))
(defn poly [& notes]
(m/ap
(apply union (m/?< (apply m/latest vector notes)))))
;; TODO: Group could actually wrap note, rather than using explicitly
;; WIll introduce a lot of GC churn, though
(defn group
[clock start end content]
(m/cp
(let [content (m/signal content)]
(if (m/?< (m/latest #(<= start % end) clock))
(m/?< content)
(m/amb #{})))))
#_(reset! clock 0)
#_(swap! clock inc)
#_(swap! clock dec)
|