{-| Entry functions for interacting with MIDI devices through Tidal. -} module Sound.Tidal.MIDI.Stream (midiStream, midiBackend, midiState, midiSetters, midiDevices, displayOutputDevices) where -- generics import Control.Concurrent import Control.Concurrent.MVar () import qualified Data.Map as Map -- Tidal specific import Sound.Tidal.Stream as S import Sound.Tidal.Time import Sound.Tidal.Transition (transition) -- MIDI specific import Sound.Tidal.MIDI.Control import Sound.Tidal.MIDI.Output {-| Create a handle for all currently used 'Output's indexed by their device name. We use this to cache once opened devices. This will be passed to _every_ initialization of a virtual stream to a MIDI device and is necessary since, 'PortMidi' only allows a single connection to a device. -} midiDevices :: IO (MVar MidiDeviceMap) midiDevices = newMVar $ Map.fromList [] {-| Connect to a MIDI device with a given name and channel, using a 'ControllerShape' to allow customized interaction with specific MIDI synths. Needs a 'MidiDeviceMap' to operate, create on using 'midiDevices'! Usage: @ (m1, mt1) <- midiSetters devices "My Synth Controller Device name" 1 synthController getNow @ To find the correct name for your device see 'displayOutputDevices' -} midiSetters :: MVar MidiDeviceMap -- ^ A list of MIDI output devices -> String -- ^ The name of the output device to connect -> Int -- ^ The MIDI Channel to use -> ControllerShape -- ^ The definition of params to be usable -> IO Time -- ^ a method to get the current time -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ()) midiSetters d n c s getNow = do ds <- midiState d n c s return (setter ds, transition getNow ds) {-| Creates a single virtual stream to a MIDI device using a specific 'ControllerShape' Needs a 'MidiDeviceMap' to operate, create one using 'midiDevices'! -} midiStream :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (ParamPattern -> IO ()) midiStream d n c s = do backend <- midiBackend d n c s stream backend (toShape s) {-| Creates a single virtual state for a MIDI device using a specific 'ControllerShape' This state can be used to either create a 'Sound.Tidal.Stream.setter' or a 'Sound.Tidal.Transition.transition' from it. Needs a 'MidiDeviceMap' to operate, create one using 'midiDevices'! -} midiState :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (MVar (ParamPattern, [ParamPattern])) midiState d n c s = do backend <- midiBackend d n c s S.state backend (toShape s) {-| Opens a connection to a MIDI device and wraps it in a 'Sound.Tidal.Stream.Backend' implementation. Needs a 'MidiDeviceMap' to operate, create one using 'midiDevices'! -} midiBackend :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (Backend a) midiBackend d n c cs = do (s, o) <- makeConnection d n c cs return $ Backend s (flushBackend o)