summaryrefslogtreecommitdiff
path: root/src/unheard/theory.clj
diff options
context:
space:
mode:
authorJake Zerrer <him@jakezerrer.com>2025-11-05 16:45:22 -0500
committerJake Zerrer <him@jakezerrer.com>2025-11-06 11:08:24 -0500
commit2d956a3a779672ab3acfc1bc542ebba855522d06 (patch)
tree37c5f1eb7e549e2662bfb6abbe932136aa53cdf0 /src/unheard/theory.clj
parentbee77914483da25831093e0475e4a71f1383253b (diff)
Organize namespaces
Diffstat (limited to 'src/unheard/theory.clj')
-rw-r--r--src/unheard/theory.clj34
1 files changed, 34 insertions, 0 deletions
diff --git a/src/unheard/theory.clj b/src/unheard/theory.clj
new file mode 100644
index 0000000..5d5805b
--- /dev/null
+++ b/src/unheard/theory.clj
@@ -0,0 +1,34 @@
+(ns unheard.theory
+ (:require [missionary.core :as m]
+ [clojure.set :refer [union]]))
+
+(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 #{})))))
+
+;; 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