summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dev/scratch.clj37
-rw-r--r--dev/user.clj1
-rw-r--r--src/unheard/instrument/minilab3.clj39
-rw-r--r--src/unheard/instrument/omx_27.clj11
-rw-r--r--src/unheard/instrument/util.clj39
-rw-r--r--src/unheard/midi.clj23
6 files changed, 85 insertions, 65 deletions
diff --git a/dev/scratch.clj b/dev/scratch.clj
index 8bfa7af..0115233 100644
--- a/dev/scratch.clj
+++ b/dev/scratch.clj
@@ -1,14 +1,13 @@
(ns scratch
(:require [unheard.midi :as midi]
[unheard.midi.percussion :refer [kick snare hat]]
- [unheard.instrument.minilab3 :refer [minilab3]]
+ [unheard.instrument.minilab3 :as minilab3]
+ [unheard.instrument.omx-27 :as omx-27]
[unheard.theory :refer [note poly]]
[missionary.core :as m]))
#_(print-all-midi-devices)
-(def midi-keyboard "CoreMIDI4J - Minilab3 MIDI")
-
(defn triad [>c >tonic]
(poly
;; This is a major cord,
@@ -22,10 +21,11 @@
[{:keys [clock tonic]}]
(poly
(triad clock tonic)
+
(triad clock (m/latest #(+ % 12) tonic))
;; The rest of the "song" is a drum pattern.
- (note clock 1 1 (m/ap kick))
+ (note clock 1 1 (m/ap kick))
(note clock 9 1 (m/ap kick))
(note clock 17 1 (m/ap kick))
(note clock 25 1 (m/ap kick))
@@ -51,21 +51,20 @@
(m/ap (m/?< f))) prn prn))
(def run
- (midi/<bus midi-keyboard
+ (midi/<bus minilab3/device-name
(fn [v]
- (m/ap
- ;; 2 is the number of message types, e.g. :key
- (let [controls (midi/controller v minilab3)
- song-config {:clock (get-in controls [:knob 1])
- :tonic (get-in controls [:knob 2])}
- p (song song-config)]
- (m/amb=
- [:n (m/?< p)]
- [:c (m/?< (get-in controls [:knob 1]))]))))))
+ (m/signal
+ (m/ap
+ ;; 2 is the number of message types, e.g. :key
+ (let [controls (midi/controller v minilab3/config)
+ clock (get-in controls [:knob 1])
+ tonic (get-in controls [:knob 2])
+ song-config {:clock clock
+ :tonic tonic}
+ p (song song-config)]
+ (m/?< (m/latest vector clock p))))))))
-#_
-(def cancel
- (run prn prn))
+#_(def cancel
+ (run prn prn))
-#_
-(cancel)
+#_(cancel)
diff --git a/dev/user.clj b/dev/user.clj
index 4a42f1d..95ed600 100644
--- a/dev/user.clj
+++ b/dev/user.clj
@@ -4,4 +4,5 @@
"This function is called automatically at repl connection time."
[]
(require '[clojure.repl])
+ #_
(intern 'clojure.core 'doc #'clojure.repl/doc))
diff --git a/src/unheard/instrument/minilab3.clj b/src/unheard/instrument/minilab3.clj
index 4973be2..3a60058 100644
--- a/src/unheard/instrument/minilab3.clj
+++ b/src/unheard/instrument/minilab3.clj
@@ -1,41 +1,10 @@
(ns unheard.instrument.minilab3
- (:require [missionary.core :as m])
- (:import [javax.sound.midi ShortMessage]))
+ (:require [unheard.instrument.util :refer [matching-control]]))
-(def matching-control-change
- (filter (fn [^ShortMessage m] (= (.getCommand m) ShortMessage/CONTROL_CHANGE))))
+(def device-name
+ "CoreMIDI4J - Minilab3 MIDI")
-(defn matching-channel [ch]
- (filter (fn [^ShortMessage m] (= (.getChannel m) ch))))
-
-(defn matching-data-1 [d1]
- (filter (fn [^ShortMessage m] (= (.getData1 m) d1))))
-
-(def get-data-2
- (map (fn [^ShortMessage m] (.getData2 m))))
-
-(defn matching-control
- "Returns a function filtering flow of ShortMessage `f` down to control
- change messages where channel is `ch` and data-1 is `k`, and then returning
- a signal of values for data-2. Initial value of signal will be `init`.
-
- Though a little esoteric sounding, this is actually quite useful.
- The signal returned by this is useful for representing knobs, faders, and
- pads on a midi controller.
- "
- [init ch k]
- (fn [f]
- (m/signal
- (m/reductions {} init
- (m/eduction
- (comp
- matching-control-change
- (matching-channel ch)
- (matching-data-1 k)
- get-data-2)
- f)))))
-
-(def minilab3
+(def config
{:knob
{1 (matching-control 0 0 74)
2 (matching-control 0 0 71)
diff --git a/src/unheard/instrument/omx_27.clj b/src/unheard/instrument/omx_27.clj
new file mode 100644
index 0000000..33c18c8
--- /dev/null
+++ b/src/unheard/instrument/omx_27.clj
@@ -0,0 +1,11 @@
+(ns unheard.instrument.omx-27
+ (:require [unheard.instrument.util :refer [matching-control]]))
+
+(def device-name "CoreMIDI4J - omx-27")
+(def omx-27
+ {:knob
+ {1 (matching-control 0 0 21)
+ 2 (matching-control 0 0 22)
+ 3 (matching-control 0 0 23)
+ 4 (matching-control 0 0 24)
+ 5 (matching-control 0 0 61)}})
diff --git a/src/unheard/instrument/util.clj b/src/unheard/instrument/util.clj
new file mode 100644
index 0000000..0faa5b5
--- /dev/null
+++ b/src/unheard/instrument/util.clj
@@ -0,0 +1,39 @@
+(ns unheard.instrument.util
+ (:require [missionary.core :as m])
+ (:import [javax.sound.midi ShortMessage]))
+
+(def matching-control-change
+ (filter (fn [^ShortMessage m] (= (.getCommand m) ShortMessage/CONTROL_CHANGE))))
+
+(defn matching-channel [ch]
+ (filter (fn [^ShortMessage m] (= (.getChannel m) ch))))
+
+(defn matching-data-1 [d1]
+ (filter (fn [^ShortMessage m] (= (.getData1 m) d1))))
+
+(def get-data-2
+ (map (fn [^ShortMessage m] (.getData2 m))))
+
+(defn matching-control
+ "Returns a function filtering flow of ShortMessage `f` down to control
+ change messages where channel is `ch` and data-1 is `k`, and then returning
+ a signal of values for data-2. Initial value of signal will be `init`.
+
+ Though a little esoteric sounding, this is actually quite useful.
+ The signal returned by this is useful for representing knobs, faders, and
+ pads on a midi controller.
+ "
+ [init ch k]
+ (fn [f]
+ ;; TODO: Should be signal
+ (m/stream
+ (m/reductions {} init
+ (m/eduction
+ (comp
+ matching-control-change
+ (matching-channel ch)
+ (matching-data-1 k)
+ get-data-2
+ ;; TODO git-bug f109911
+ (dedupe))
+ f)))))
diff --git a/src/unheard/midi.clj b/src/unheard/midi.clj
index 174fec2..b9f20c4 100644
--- a/src/unheard/midi.clj
+++ b/src/unheard/midi.clj
@@ -79,16 +79,17 @@
(m/? (m/via m/blk (.setReceiver transmitter receiver)))
(log/log! {:level :debug, :id :midi/receiver-set})
(m/?
- (t (m/ap
- (loop []
- (m/amb
- (do
- (log/log! {:level :debug, :id :midi/tx-awaiting-value})
- (m/amb))
- (let [v (m/? rv)]
- (log/log! {:level :debug, :id :midi/tx-received-value, :data {:value (str v)}})
- v)
- (recur))))))
+ (t (m/stream
+ (m/ap
+ (loop []
+ (m/amb
+ (do
+ (log/log! {:level :debug, :id :midi/tx-awaiting-value})
+ (m/amb))
+ (let [v (m/? rv)]
+ (log/log! {:level :debug, :id :midi/tx-received-value, :data {:value (str v)}})
+ v)
+ (recur)))))))
(finally
(log/log! {:level :info, :id :midi/closing-tx})
(m/? (m/via m/blk (.close transmitter)))
@@ -206,5 +207,5 @@
(into {}
(map (fn [[group instance]]
- {group (into {} (map (fn [[id flow]] {id (flow f)}) instance))})
+ {group (into {} (map (fn [[id flow]] {id (flow f)}) instance))})
config)))