summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Zerrer <him@jakezerrer.com>2025-10-15 13:35:07 -0400
committerJake Zerrer <him@jakezerrer.com>2025-10-16 08:54:11 -0400
commit3454235122b8208af7a30e6fdd374ebe15e9b777 (patch)
treef5e9b4f04e4fde1d303bd554fd81484079fbcaae
parentaedd0df6c2c61b6ef42d610017f066e3d10233dd (diff)
Improve portal window opening / closing
-rw-r--r--src/notation.clj66
1 files changed, 61 insertions, 5 deletions
diff --git a/src/notation.clj b/src/notation.clj
index aff26e3..6ec09f8 100644
--- a/src/notation.clj
+++ b/src/notation.clj
@@ -1,5 +1,7 @@
(ns notation
- "Experimental notation")
+ "Experimental notation"
+ (:require [missionary.core :as m]
+ [clojure.set :refer [union]]))
(comment
;; Parallel groups
@@ -7,6 +9,7 @@
;; = 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)
@@ -41,8 +44,7 @@
[= 1 2 3]
[= 1 2 3]]
-
- ;; Note 1, followed by a rest, followed by note 3
+;; Note 1, followed by a rest, followed by note 3
[1 (r) 3]
;; Unlike notes, rests are at most 2-tuples
@@ -59,8 +61,7 @@
;; Middle arguments are variable names
(=loop2 dur ([1 2 3] dur))
-
- ;; TODO:
+;; TODO:
;; - Note literals turn into numbers
;; - Represent keyboard as byte array of shorts
;; - play a note increments, stop a note decrements
@@ -71,3 +72,58 @@
;; - Notion of scenes that change mapping of inputs to vars
;; - Loops
)
+
+(def ctr (atom nil))
+(def pulse (m/signal (m/watch ctr)))
+
+(defn note [value duration]
+ #_
+ (m/eduction (take-while #(not= ::done %)))
+ (m/ap
+ (m/amb #{value}
+ (let [c (atom 0)
+ dxfn (case (m/?< pulse) :inc inc :dec dec)]
+ (println "AT" (swap! c dxfn))
+ (if (< 0 @c duration)
+ (m/amb #{value})
+ (m/amb #{})
+ )))))
+
+(defmacro chord
+ [& notes]
+ (let [atoms (repeatedly (count notes) gensym)
+ let-bindings (vec (mapcat (fn [atom] [atom `(atom #{})]) atoms))
+ reset-forms (map (fn [atom note] `(m/amb (reset! ~atom (m/?< ~note)))) atoms notes)
+ union-form (cons `union (map (fn [atom] `(deref ~atom)) atoms))]
+ `(m/ap
+ (m/amb
+ (let ~let-bindings
+ (m/amb= ~@reset-forms)
+ ~union-form)))))
+
+;; We have something pretty cool going. I think chord is actually correct.
+;; Line isn't working quite corectly, though.
+;; The idea of note storing its internal state is clever, but isn't behaving
+;; quite corectly when you try to sequence two chords back to back. Think through
+;; how this will work with pulses. You are close!
+;;
+(defmacro line
+ [& notes]
+ `(m/ap (m/amb ~@(map (fn [note] `(m/?< ~note)) notes))))
+
+(def melody
+ (line
+ (chord (note 1 2)
+ (note 3 2)
+ (note 5 2))
+ (chord (note 2 2)
+ (note 4 2)
+ (note 6 2))))
+
+(def cancel
+ ((m/reduce prn #{} melody) {} {}))
+
+(cancel)
+
+(reset! ctr :dec)
+(reset! ctr :inc)