diff options
| author | Jake Zerrer <him@jakezerrer.com> | 2025-10-23 17:08:36 -0400 |
|---|---|---|
| committer | Jake Zerrer <him@jakezerrer.com> | 2025-10-23 17:18:40 -0400 |
| commit | a504e10d4ae2b37d998f5c7e4cafac5b7cb1d1ae (patch) | |
| tree | a446fed8f21f3516e5856e01eb9fc64c4d5c3591 /src/midi.clj | |
| parent | 2fdb7ce022b521b93ed314c1d33369bfa5d2bd0e (diff) | |
I think >device opens and closes correctly now
Playing with cancellation semantics
Make progress
Diffstat (limited to 'src/midi.clj')
| -rw-r--r-- | src/midi.clj | 79 |
1 files changed, 44 insertions, 35 deletions
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) {} {})) |
