(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)