summaryrefslogtreecommitdiff
path: root/src/midi.clj
diff options
context:
space:
mode:
Diffstat (limited to 'src/midi.clj')
-rw-r--r--src/midi.clj58
1 files changed, 40 insertions, 18 deletions
diff --git a/src/midi.clj b/src/midi.clj
index e63f811..330402b 100644
--- a/src/midi.clj
+++ b/src/midi.clj
@@ -233,32 +233,54 @@
[>messages]
(m/group-by #(.getChannel ^ShortMessage %) >messages))
+(defn |group-by-data-1
+ [>messages]
+ (m/group-by #(.getData1 ^ShortMessage %)
+ >messages))
+
+(defn |matching-commands
+ [>messages commands]
+ (m/eduction (filter (fn [^ShortMessage v]
+ (contains? commands (.getCommand v)))) >messages))
+
(def note-commands
#{ShortMessage/NOTE_OFF
ShortMessage/NOTE_ON
ShortMessage/POLY_PRESSURE})
-(defn |notes
- [>messages]
- (m/group-by #(.getData1 ^ShortMessage %)
- (m/ap
- (let [^ShortMessage v (m/?> >messages)]
- (if (contains? note-commands (.getCommand v))
- v
- (m/amb))))))
-
(def control-commands
#{ShortMessage/CONTROL_CHANGE})
-;; TODO: |control-changes and |notes combine grouping and filtering, which isn't great
-(defn |control-changes
- [>messages]
- (m/group-by #(.getData1 ^ShortMessage %)
- (m/ap
- (let [^ShortMessage v (m/?> >messages)]
- (if (contains? control-commands (.getCommand v))
- v
- (m/amb))))))
+(defn keyboard
+ [f]
+ (m/ap
+ (let [[ch ch-messages]
+ (m/?> 128 (midi/|channels (midi/|short-messages (m/stream f))))
+ ch-messages (m/stream ch-messages)]
+ (m/amb=
+ (let [[note note-messages]
+ (m/?> 128 (-> ch-messages
+ (midi/|matching-commands note-commands)
+ (midi/|group-by-data-1)))]
+ [:key ch note
+ (m/?<
+ (m/relieve
+ (m/reductions
+ (fn [_prev curr]
+ (when (some? curr)
+ (let [cmd (.getCommand ^ShortMessage curr)]
+ (cond
+ (= cmd ShortMessage/NOTE_ON)
+ (.getData2 ^ShortMessage curr)
+ (= cmd ShortMessage/POLY_PRESSURE)
+ (.getData2 ^ShortMessage curr)
+ (= cmd ShortMessage/NOTE_OFF)
+ nil)))) nil note-messages)))])
+ (let [[control-number control-messages]
+ (m/?> 128 (-> ch-messages
+ (midi/|matching-commands control-commands)
+ (midi/|group-by-data-1)))]
+ [:control ch control-number (.getData2 ^ShortMessage (m/?< control-messages))])))))
#_(defn >ch-stream [>device ch]
(m/cp (m/?< (second (get >device ch)))))