summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Zerrer <him@jakezerrer.com>2025-10-23 17:08:36 -0400
committerJake Zerrer <him@jakezerrer.com>2025-10-23 17:18:40 -0400
commita504e10d4ae2b37d998f5c7e4cafac5b7cb1d1ae (patch)
treea446fed8f21f3516e5856e01eb9fc64c4d5c3591
parent2fdb7ce022b521b93ed314c1d33369bfa5d2bd0e (diff)
I think >device opens and closes correctly now
Playing with cancellation semantics Make progress
-rw-r--r--.nrepl-port2
-rw-r--r--src/midi.clj79
2 files changed, 45 insertions, 36 deletions
diff --git a/.nrepl-port b/.nrepl-port
index d0b5b26..be0f9d1 100644
--- a/.nrepl-port
+++ b/.nrepl-port
@@ -1 +1 @@
-60206 \ No newline at end of file
+56380 \ No newline at end of file
diff --git a/src/midi.clj b/src/midi.clj
index 4c10de0..41a8740 100644
--- a/src/midi.clj
+++ b/src/midi.clj
@@ -30,50 +30,60 @@
(m/ap (let [device-info (m/?< >midi-device-info)]
(get-in device-info [device-name :device-info]))))
+(defn >device
+ "Returns a device for given device name. Returns nil if device not found."
+ [device-name]
+ (m/stream
+ (m/ap
+ (let [device-info
+ (m/?< (>device-info device-name))
+ ^MidiDevice device (MidiSystem/getMidiDevice ^MidiDevice$Info device-info)]
+ ;; Essential problem: Combining taking element from flow to put in
+ ;; conditional, and cleaning up in catch.
+ ;; NOTE: You need the MidiDevice type hint when you call open and close!
+
+ (m/amb= (do
+ (println "opening device")
+ (m/? (m/via m/blk (.open device)))
+ (println "device opened")
+ (m/amb
+ device))
+ (try
+ (m/? m/never)
+ (finally
+ (println "closing device")
+ (m/compel (m/? (m/via m/blk (.close device))))
+ (println "device closed"))))))))
+
+;; Key insight: Cancelation shouldn't actually start with the device
+
(defn >midi-messages
"A flow of java midi messages"
- [^MidiDevice device]
+ [device-name]
(m/stream
(m/ap
- (let [^Transmitter transmitter (m/? (m/via m/blk (.getTransmitter device)))
+ (let [^MidiDevice device (m/?< (>device device-name))
+ ^Transmitter transmitter (m/? (m/via m/blk (.getTransmitter device)))
transmit (atom nil)
- >transmit (m/eduction (filter some?) (m/watch transmit))
+ >transmit (m/eduction (filter some?) (m/ap (try (m/?< (m/watch transmit)) (catch missionary.Cancelled _ (m/amb)))))
receiver (reify Receiver
(send [_this midi-message _timestamp]
(println "HI")
(reset! transmit midi-message))
;; TODO: Close
(close [this]))]
- (try
- (println "Connecting to transmitter")
- (m/? (m/via m/blk (.setReceiver transmitter receiver)))
- (println "Connected to transmitter")
- (m/?< >transmit)
- (finally
- (println "Disconnecting from transmitter")
- (m/? (m/compel (m/via m/blk (.close receiver))))
- (println "Disconnected from transmitter")))))))
-
-(defn >device
- "Returns a device for given device name. Returns nil if device not found."
- [device-name with-device]
- (m/ap
- (let [device-info
- (m/?< (>device-info device-name))
- ^MidiDevice device (MidiSystem/getMidiDevice ^MidiDevice$Info device-info)]
- ;; Essential problem: Combining taking element from flow to put in
- ;; conditional, and cleaning up in catch.
- ;; NOTE: You need the MidiDevice type hint when you call open and close!
- (try
- (println "Opening device")
- (m/? (m/via m/blk (.open device)))
- (println "Device opened")
- (m/?< (with-device device))
- (finally
- (println "Closing device")
- (m/compel (m/? (m/via m/blk (.close device))))
- (println "Device closed")
- )))))
+ (m/amb=
+ (do
+ (println "Connecting to transmitter")
+ (m/? (m/via m/blk (.setReceiver transmitter receiver)))
+ (println "Connected to transmitter")
+ (m/?< >transmit))
+ (try (m/? m/never)
+ (finally
+ (println "Disconnecting from transmitter")
+ (m/? (m/compel (m/via m/blk (.close receiver))))
+ (println "Disconnected from transmitter")
+ (throw (missionary.Cancelled. "Transmitter cancelled.")))))))))
(defn new-device
"Generate a new midi device.
@@ -111,8 +121,7 @@
(def run
(m/ap
- (prn (m/?< (>device (m/?< >bus-sel)
- >midi-messages)))
+ (prn (m/?< (>device (m/?< >bus-sel))))
))
(def close ((m/reduce prn {} run) {} {}))