tidal 0.6 → 0.7
raw patch · 18 files changed
+1089/−276 lines, 18 filesdep +PortMididep +serialportdep ~containersdep ~hoscPVP ok
version bump matches the API change (PVP)
Dependencies added: PortMidi, serialport
Dependency ranges changed: containers, hosc
API changes (from Hackage documentation)
- Sound.Tidal.Dirt: dirtstart :: t -> IO (MVar OscPattern)
- Sound.Tidal.Dirt: doubledirt :: IO (OscPattern -> IO ())
- Sound.Tidal.Params: sound_p :: Param
- Sound.Tidal.Stream: BundleStamp :: TimeStamp
- Sound.Tidal.Stream: MessageStamp :: TimeStamp
- Sound.Tidal.Stream: NoStamp :: TimeStamp
- Sound.Tidal.Stream: OscShape :: String -> [Param] -> Bool -> TimeStamp -> Double -> Bool -> [Datum] -> OscShape
- Sound.Tidal.Stream: [namedParams] :: OscShape -> Bool
- Sound.Tidal.Stream: [path] :: OscShape -> String
- Sound.Tidal.Stream: [preamble] :: OscShape -> [Datum]
- Sound.Tidal.Stream: [timestamp] :: OscShape -> TimeStamp
- Sound.Tidal.Stream: data OscShape
- Sound.Tidal.Stream: data TimeStamp
- Sound.Tidal.Stream: defaultDatum :: Param -> Maybe Datum
- Sound.Tidal.Stream: instance GHC.Classes.Eq Sound.Tidal.Stream.TimeStamp
- Sound.Tidal.Stream: nudge :: Pattern Double -> OscPattern
- Sound.Tidal.Stream: toMessage :: UDP -> OscShape -> Tempo -> Int -> (Double, OscMap) -> Maybe (IO ())
- Sound.Tidal.Stream: type OscMap = Map Param (Maybe Datum)
- Sound.Tidal.Stream: type OscPattern = Pattern OscMap
- Sound.Tidal.Transition: anticipate :: Time -> [OscPattern] -> OscPattern
- Sound.Tidal.Transition: anticipateIn :: Time -> Time -> [OscPattern] -> OscPattern
- Sound.Tidal.Transition: dirtSetters :: IO Time -> IO (OscPattern -> IO (), (Time -> [OscPattern] -> OscPattern) -> OscPattern -> IO ())
+ Sound.Tidal.Dirt: anticipate :: Time -> [ParamPattern] -> ParamPattern
+ Sound.Tidal.Dirt: anticipateIn :: Time -> Time -> [ParamPattern] -> ParamPattern
+ Sound.Tidal.Dirt: dirtBackend :: IO (Backend a)
+ Sound.Tidal.Dirt: dirtSetters :: IO Time -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())
+ Sound.Tidal.Dirt: dirtSlang :: OscSlang
+ Sound.Tidal.Dirt: superDirtBackend :: Int -> IO (Backend a)
+ Sound.Tidal.Dirt: superDirtSetters :: IO Time -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())
+ Sound.Tidal.Dirt: superDirtSlang :: OscSlang
+ Sound.Tidal.Dirt: superDirtState :: Int -> IO (MVar (ParamPattern, [ParamPattern]))
+ Sound.Tidal.Dirt: superDirts :: [Int] -> IO [(ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())]
+ Sound.Tidal.MIDI.Control: CC :: Param -> Int -> (Int, Int) -> Double -> RangeMapFunc -> ControlChange
+ Sound.Tidal.MIDI.Control: ControllerShape :: [ControlChange] -> Double -> ControllerShape
+ Sound.Tidal.MIDI.Control: NRPN :: Param -> Int -> (Int, Int) -> Double -> RangeMapFunc -> ControlChange
+ Sound.Tidal.MIDI.Control: SysEx :: Param -> Int -> (Int, Int) -> Double -> RangeMapFunc -> ControlChange
+ Sound.Tidal.MIDI.Control: [controls] :: ControllerShape -> [ControlChange]
+ Sound.Tidal.MIDI.Control: [latency] :: ControllerShape -> Double
+ Sound.Tidal.MIDI.Control: [midi] :: ControlChange -> Int
+ Sound.Tidal.MIDI.Control: [param] :: ControlChange -> Param
+ Sound.Tidal.MIDI.Control: [range] :: ControlChange -> (Int, Int)
+ Sound.Tidal.MIDI.Control: [scalef] :: ControlChange -> RangeMapFunc
+ Sound.Tidal.MIDI.Control: [vdefault] :: ControlChange -> Double
+ Sound.Tidal.MIDI.Control: ctrlN :: Num b => ControllerShape -> Param -> Maybe b
+ Sound.Tidal.MIDI.Control: data ControlChange
+ Sound.Tidal.MIDI.Control: data ControllerShape
+ Sound.Tidal.MIDI.Control: mCC :: Param -> Int -> ControlChange
+ Sound.Tidal.MIDI.Control: mNRPN :: Param -> Int -> ControlChange
+ Sound.Tidal.MIDI.Control: mapRange :: (Int, Int) -> Double -> Int
+ Sound.Tidal.MIDI.Control: mrNRPN :: Param -> Int -> (Int, Int) -> Double -> ControlChange
+ Sound.Tidal.MIDI.Control: paramN :: ControllerShape -> Param -> Maybe ControlChange
+ Sound.Tidal.MIDI.Control: passThru :: (Int, Int) -> Double -> Int
+ Sound.Tidal.MIDI.Control: toParams :: ControllerShape -> [Param]
+ Sound.Tidal.MIDI.Control: toShape :: ControllerShape -> Shape
+ Sound.Tidal.MIDI.Control: type RangeMapFunc = (Int, Int) -> Double -> Int
+ Sound.Tidal.MIDI.Device: displayDevices :: Show a => [(a, DeviceInfo)] -> String
+ Sound.Tidal.MIDI.Device: displayOutputDevices :: IO String
+ Sound.Tidal.MIDI.Device: getDevices :: IO ([DeviceInfo])
+ Sound.Tidal.MIDI.Device: getIDForDeviceName :: Num a => String -> IO (Maybe a)
+ Sound.Tidal.MIDI.Device: getIndexedDevices :: IO [(Integer, DeviceInfo)]
+ Sound.Tidal.MIDI.Device: getOutputDevices :: [(a, DeviceInfo)] -> [(a, DeviceInfo)]
+ Sound.Tidal.MIDI.Params: dur :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Params: dur_p :: Param
+ Sound.Tidal.MIDI.Params: expression :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Params: expression_p :: Param
+ Sound.Tidal.MIDI.Params: modwheel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Params: modwheel_p :: Param
+ Sound.Tidal.MIDI.Params: note :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Params: note_p :: Param
+ Sound.Tidal.MIDI.Params: sustainpedal :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Params: sustainpedal_p :: Param
+ Sound.Tidal.MidiStream: midiBackend :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (Backend a)
+ Sound.Tidal.MidiStream: midiDevices :: IO (MVar (MidiDeviceMap))
+ Sound.Tidal.MidiStream: midiSetters :: MVar (MidiDeviceMap) -> String -> Int -> ControllerShape -> IO Time -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())
+ Sound.Tidal.MidiStream: midiState :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (MVar (ParamPattern, [ParamPattern]))
+ Sound.Tidal.MidiStream: midiStream :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (ParamPattern -> IO ())
+ Sound.Tidal.OscStream: BundleStamp :: TimeStamp
+ Sound.Tidal.OscStream: MessageStamp :: TimeStamp
+ Sound.Tidal.OscStream: NoStamp :: TimeStamp
+ Sound.Tidal.OscStream: OscSlang :: String -> TimeStamp -> Bool -> [Datum] -> OscSlang
+ Sound.Tidal.OscStream: [namedParams] :: OscSlang -> Bool
+ Sound.Tidal.OscStream: [path] :: OscSlang -> String
+ Sound.Tidal.OscStream: [preamble] :: OscSlang -> [Datum]
+ Sound.Tidal.OscStream: [timestamp] :: OscSlang -> TimeStamp
+ Sound.Tidal.OscStream: data OscSlang
+ Sound.Tidal.OscStream: data TimeStamp
+ Sound.Tidal.OscStream: instance GHC.Classes.Eq Sound.Tidal.OscStream.TimeStamp
+ Sound.Tidal.OscStream: makeConnection :: String -> Int -> OscSlang -> IO (ToMessageFunc)
+ Sound.Tidal.OscStream: send :: (Integral a, Transport t) => t -> OscSlang -> Shape -> Tempo -> a -> (Double, Map Param (Maybe Datum)) -> IO ()
+ Sound.Tidal.OscStream: toOscDatum :: Value -> Maybe Datum
+ Sound.Tidal.OscStream: toOscMap :: ParamMap -> OscMap
+ Sound.Tidal.OscStream: type OscMap = Map Param (Maybe Datum)
+ Sound.Tidal.Params: channel :: Pattern Int -> ParamPattern
+ Sound.Tidal.Params: channel_p :: Param
+ Sound.Tidal.Params: dry :: Pattern Double -> ParamPattern
+ Sound.Tidal.Params: dry_p :: Param
+ Sound.Tidal.Params: grp :: [Param] -> Pattern String -> ParamPattern
+ Sound.Tidal.Params: n :: Pattern Int -> ParamPattern
+ Sound.Tidal.Params: n_p :: Param
+ Sound.Tidal.Params: nudge :: Pattern Double -> ParamPattern
+ Sound.Tidal.Params: nudge_p :: Param
+ Sound.Tidal.Params: orbit :: Pattern Int -> ParamPattern
+ Sound.Tidal.Params: orbit_p :: Param
+ Sound.Tidal.Params: room :: Pattern Double -> ParamPattern
+ Sound.Tidal.Params: room_p :: Param
+ Sound.Tidal.Params: s :: Pattern String -> ParamPattern
+ Sound.Tidal.Params: s_p :: Param
+ Sound.Tidal.Params: size :: Pattern Double -> ParamPattern
+ Sound.Tidal.Params: size_p :: Param
+ Sound.Tidal.Parse: midinote :: Parser Integer
+ Sound.Tidal.Pattern: choose :: [a] -> Pattern a
+ Sound.Tidal.Pattern: enclosingArc :: [Arc] -> Arc
+ Sound.Tidal.Pattern: fit' :: Time -> Int -> Pattern Int -> Pattern Int -> Pattern a -> Pattern a
+ Sound.Tidal.Pattern: lindenmayer :: Int -> String -> String -> String
+ Sound.Tidal.Pattern: mask :: Pattern a -> Pattern b -> Pattern b
+ Sound.Tidal.Pattern: parseLMRule :: String -> [(String, String)]
+ Sound.Tidal.Pattern: parseLMRule' :: String -> [(Char, String)]
+ Sound.Tidal.Pattern: permstep :: RealFrac b => Int -> [a] -> Pattern b -> Pattern a
+ Sound.Tidal.Pattern: stretch :: Pattern a -> Pattern a
+ Sound.Tidal.Pattern: struct :: Pattern String -> Pattern a -> Pattern a
+ Sound.Tidal.Pattern: unwrap' :: Pattern (Pattern a) -> Pattern a
+ Sound.Tidal.SerialStream: blinken :: Shape
+ Sound.Tidal.SerialStream: blinkenSetters :: MVar (SerialDeviceMap) -> String -> IO Time -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())
+ Sound.Tidal.SerialStream: blinkenState :: MVar SerialDeviceMap -> String -> IO (MVar (ParamPattern, [ParamPattern]))
+ Sound.Tidal.SerialStream: blinkenStream :: MVar SerialDeviceMap -> String -> IO (ParamPattern -> IO ())
+ Sound.Tidal.SerialStream: light :: Pattern String -> ParamPattern
+ Sound.Tidal.SerialStream: serialBackend :: MVar SerialDeviceMap -> String -> IO (Backend a)
+ Sound.Tidal.SerialStream: serialDevices :: IO (MVar (SerialDeviceMap))
+ Sound.Tidal.Strategies: ghost :: Pattern ParamMap -> Pattern ParamMap
+ Sound.Tidal.Strategies: ghost' :: t -> Pattern ParamMap -> Pattern ParamMap
+ Sound.Tidal.Strategies: ghost'' :: Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
+ Sound.Tidal.Strategies: randslice :: Int -> ParamPattern -> ParamPattern
+ Sound.Tidal.Strategies: slice :: Int -> Int -> ParamPattern -> ParamPattern
+ Sound.Tidal.Strategies: step' :: [String] -> String -> Pattern String
+ Sound.Tidal.Stream: Backend :: ToMessageFunc -> Backend a
+ Sound.Tidal.Stream: Shape :: [Param] -> Double -> Bool -> Shape
+ Sound.Tidal.Stream: VF :: Double -> Value
+ Sound.Tidal.Stream: VI :: Int -> Value
+ Sound.Tidal.Stream: VS :: String -> Value
+ Sound.Tidal.Stream: [fvalue] :: Value -> Double
+ Sound.Tidal.Stream: [ivalue] :: Value -> Int
+ Sound.Tidal.Stream: [svalue] :: Value -> String
+ Sound.Tidal.Stream: [toMessage] :: Backend a -> ToMessageFunc
+ Sound.Tidal.Stream: data Backend a
+ Sound.Tidal.Stream: data Shape
+ Sound.Tidal.Stream: data Value
+ Sound.Tidal.Stream: defaultValue :: Param -> Maybe Value
+ Sound.Tidal.Stream: instance GHC.Classes.Eq Sound.Tidal.Stream.Value
+ Sound.Tidal.Stream: instance GHC.Classes.Ord Sound.Tidal.Stream.Value
+ Sound.Tidal.Stream: instance GHC.Show.Show Sound.Tidal.Stream.Value
+ Sound.Tidal.Stream: logicalOnset' :: Integral a => Tempo -> a -> Double -> Double -> Double
+ Sound.Tidal.Stream: mergeNumWith :: Applicative f => (Int -> Int -> Int) -> (Double -> Double -> Double) -> f (Map Param (Maybe Value)) -> f (Map Param (Maybe Value)) -> f (Map Param (Maybe Value))
+ Sound.Tidal.Stream: mergePlus :: Applicative f => f (Map Param (Maybe Value)) -> f (Map Param (Maybe Value)) -> f (Map Param (Maybe Value))
+ Sound.Tidal.Stream: type ParamMap = Map Param (Maybe Value)
+ Sound.Tidal.Stream: type ParamPattern = Pattern ParamMap
+ Sound.Tidal.Stream: type ToMessageFunc = Shape -> Tempo -> Int -> (Double, ParamMap) -> Maybe (IO ())
+ Sound.Tidal.SuperCollider: scBackend :: String -> IO (Backend a)
+ Sound.Tidal.SuperCollider: scSlang :: String -> OscSlang
+ Sound.Tidal.Synth: synth :: Shape
+ Sound.Tidal.Synth: synthController :: ControllerShape
+ Sound.Tidal.Transition: histpan' :: Double -> Int -> Time -> [ParamPattern] -> ParamPattern
+ Sound.Tidal.Transition: histpan2 :: Int -> Time -> [ParamPattern] -> ParamPattern
- Sound.Tidal.Dirt: datumToColour :: Datum -> ColourD
+ Sound.Tidal.Dirt: datumToColour :: Value -> ColourD
- Sound.Tidal.Dirt: dirt :: OscShape
+ Sound.Tidal.Dirt: dirt :: Shape
- Sound.Tidal.Dirt: dirtState :: IO (MVar (OscPattern, [OscPattern]))
+ Sound.Tidal.Dirt: dirtState :: IO (MVar (ParamPattern, [ParamPattern]))
- Sound.Tidal.Dirt: dirtStream :: IO (OscPattern -> IO ())
+ Sound.Tidal.Dirt: dirtStream :: IO (ParamPattern -> IO ())
- Sound.Tidal.Dirt: dirtToColour :: OscPattern -> Pattern ColourD
+ Sound.Tidal.Dirt: dirtToColour :: ParamPattern -> Pattern ColourD
- Sound.Tidal.Dirt: dirtstream :: t -> IO (OscPattern -> IO ())
+ Sound.Tidal.Dirt: dirtstream :: t -> IO (ParamPattern -> IO ())
- Sound.Tidal.Dirt: metronome :: Pattern OscMap
+ Sound.Tidal.Dirt: metronome :: Pattern ParamMap
- Sound.Tidal.Dirt: striate :: Int -> OscPattern -> OscPattern
+ Sound.Tidal.Dirt: striate :: Int -> ParamPattern -> ParamPattern
- Sound.Tidal.Dirt: striate' :: Int -> Double -> OscPattern -> OscPattern
+ Sound.Tidal.Dirt: striate' :: Int -> Double -> ParamPattern -> ParamPattern
- Sound.Tidal.Dirt: striateL :: Int -> Int -> OscPattern -> OscPattern
+ Sound.Tidal.Dirt: striateL :: Int -> Int -> ParamPattern -> ParamPattern
- Sound.Tidal.Dirt: striateL' :: Integral a => Int -> Double -> a -> OscPattern -> OscPattern
+ Sound.Tidal.Dirt: striateL' :: Integral a => Int -> Double -> a -> ParamPattern -> ParamPattern
- Sound.Tidal.Dirt: striateO :: OscPattern -> Int -> Double -> OscPattern
+ Sound.Tidal.Dirt: striateO :: ParamPattern -> Int -> Double -> ParamPattern
- Sound.Tidal.Dirt: stut :: Integer -> Double -> Rational -> OscPattern -> OscPattern
+ Sound.Tidal.Dirt: stut :: Integer -> Double -> Rational -> ParamPattern -> ParamPattern
- Sound.Tidal.Dirt: stut' :: Integer -> Time -> (OscPattern -> OscPattern) -> OscPattern -> OscPattern
+ Sound.Tidal.Dirt: stut' :: Integer -> Time -> (ParamPattern -> ParamPattern) -> ParamPattern -> ParamPattern
- Sound.Tidal.Dirt: xfade :: Time -> [OscPattern] -> OscPattern
+ Sound.Tidal.Dirt: xfade :: Time -> [ParamPattern] -> ParamPattern
- Sound.Tidal.Dirt: xfadeIn :: Time -> Time -> [OscPattern] -> OscPattern
+ Sound.Tidal.Dirt: xfadeIn :: Time -> Time -> [ParamPattern] -> ParamPattern
- Sound.Tidal.Params: accelerate :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: accelerate :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: bandf :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: bandf :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: bandq :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: bandq :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: begin :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: begin :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: coarse :: Pattern Int -> OscPattern
+ Sound.Tidal.Params: coarse :: Pattern Int -> ParamPattern
- Sound.Tidal.Params: crush :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: crush :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: cut :: Pattern Int -> OscPattern
+ Sound.Tidal.Params: cut :: Pattern Int -> ParamPattern
- Sound.Tidal.Params: cutoff :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: cutoff :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: delay :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: delay :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: delayfeedback :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: delayfeedback :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: delaytime :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: delaytime :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: end :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: end :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: gain :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: gain :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: hcutoff :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: hcutoff :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: hresonance :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: hresonance :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: kriole :: Pattern Int -> OscPattern
+ Sound.Tidal.Params: kriole :: Pattern Int -> ParamPattern
- Sound.Tidal.Params: loop :: Pattern Int -> OscPattern
+ Sound.Tidal.Params: loop :: Pattern Int -> ParamPattern
- Sound.Tidal.Params: make' :: (a -> Datum) -> Param -> Pattern a -> OscPattern
+ Sound.Tidal.Params: make' :: (a -> Value) -> Param -> Pattern a -> ParamPattern
- Sound.Tidal.Params: offset :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: offset :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: pan :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: pan :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: resonance :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: resonance :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: shape :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: shape :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: sound :: Pattern String -> OscPattern
+ Sound.Tidal.Params: sound :: Pattern String -> ParamPattern
- Sound.Tidal.Params: speed :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: speed :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: unit :: Pattern String -> OscPattern
+ Sound.Tidal.Params: unit :: Pattern String -> ParamPattern
- Sound.Tidal.Params: velocity :: Pattern Double -> OscPattern
+ Sound.Tidal.Params: velocity :: Pattern Double -> ParamPattern
- Sound.Tidal.Params: vowel :: Pattern String -> OscPattern
+ Sound.Tidal.Params: vowel :: Pattern String -> ParamPattern
- Sound.Tidal.Pattern: irand :: Double -> Pattern Int
+ Sound.Tidal.Pattern: irand :: Int -> Pattern Int
- Sound.Tidal.Strategies: chop :: Int -> OscPattern -> OscPattern
+ Sound.Tidal.Strategies: chop :: Int -> ParamPattern -> ParamPattern
- Sound.Tidal.Strategies: gap :: Int -> OscPattern -> OscPattern
+ Sound.Tidal.Strategies: gap :: Int -> ParamPattern -> ParamPattern
- Sound.Tidal.Strategies: interlace :: OscPattern -> OscPattern -> OscPattern
+ Sound.Tidal.Strategies: interlace :: ParamPattern -> ParamPattern -> ParamPattern
- Sound.Tidal.Strategies: jux :: (OscPattern -> Pattern OscMap) -> OscPattern -> Pattern OscMap
+ Sound.Tidal.Strategies: jux :: (ParamPattern -> Pattern ParamMap) -> ParamPattern -> Pattern ParamMap
- Sound.Tidal.Strategies: jux' :: [t -> OscPattern] -> t -> Pattern OscMap
+ Sound.Tidal.Strategies: jux' :: [t -> ParamPattern] -> t -> Pattern ParamMap
- Sound.Tidal.Strategies: jux4 :: (OscPattern -> Pattern OscMap) -> OscPattern -> Pattern OscMap
+ Sound.Tidal.Strategies: jux4 :: (ParamPattern -> Pattern ParamMap) -> ParamPattern -> Pattern ParamMap
- Sound.Tidal.Strategies: juxBy :: Double -> (OscPattern -> Pattern OscMap) -> OscPattern -> Pattern OscMap
+ Sound.Tidal.Strategies: juxBy :: Double -> (ParamPattern -> Pattern ParamMap) -> ParamPattern -> Pattern ParamMap
- Sound.Tidal.Strategies: juxcut :: (OscPattern -> Pattern OscMap) -> OscPattern -> Pattern OscMap
+ Sound.Tidal.Strategies: juxcut :: (ParamPattern -> Pattern ParamMap) -> ParamPattern -> Pattern ParamMap
- Sound.Tidal.Strategies: smash :: Int -> [Time] -> OscPattern -> Pattern OscMap
+ Sound.Tidal.Strategies: smash :: Int -> [Time] -> ParamPattern -> Pattern ParamMap
- Sound.Tidal.Strategies: smash' :: Int -> [Time] -> OscPattern -> Pattern OscMap
+ Sound.Tidal.Strategies: smash' :: Int -> [Time] -> ParamPattern -> Pattern ParamMap
- Sound.Tidal.Strategies: spin :: Int -> OscPattern -> OscPattern
+ Sound.Tidal.Strategies: spin :: Int -> ParamPattern -> ParamPattern
- Sound.Tidal.Strategies: stackwith :: Pattern OscMap -> [OscPattern] -> Pattern OscMap
+ Sound.Tidal.Strategies: stackwith :: Pattern ParamMap -> [ParamPattern] -> Pattern ParamMap
- Sound.Tidal.Strategies: up :: Pattern Double -> OscPattern
+ Sound.Tidal.Strategies: up :: Pattern Double -> ParamPattern
- Sound.Tidal.Strategies: weave :: Rational -> OscPattern -> [OscPattern] -> OscPattern
+ Sound.Tidal.Strategies: weave :: Rational -> ParamPattern -> [ParamPattern] -> ParamPattern
- Sound.Tidal.Stream: (#) :: OscPattern -> OscPattern -> OscPattern
+ Sound.Tidal.Stream: (#) :: ParamPattern -> ParamPattern -> ParamPattern
- Sound.Tidal.Stream: (|*|) :: OscPattern -> OscPattern -> OscPattern
+ Sound.Tidal.Stream: (|*|) :: ParamPattern -> ParamPattern -> ParamPattern
- Sound.Tidal.Stream: (|+|) :: OscPattern -> OscPattern -> OscPattern
+ Sound.Tidal.Stream: (|+|) :: ParamPattern -> ParamPattern -> ParamPattern
- Sound.Tidal.Stream: (|-|) :: OscPattern -> OscPattern -> OscPattern
+ Sound.Tidal.Stream: (|-|) :: ParamPattern -> ParamPattern -> ParamPattern
- Sound.Tidal.Stream: (|/|) :: OscPattern -> OscPattern -> OscPattern
+ Sound.Tidal.Stream: (|/|) :: ParamPattern -> ParamPattern -> ParamPattern
- Sound.Tidal.Stream: (|=|) :: OscPattern -> OscPattern -> OscPattern
+ Sound.Tidal.Stream: (|=|) :: ParamPattern -> ParamPattern -> ParamPattern
- Sound.Tidal.Stream: [cpsStamp] :: OscShape -> Bool
+ Sound.Tidal.Stream: [cpsStamp] :: Shape -> Bool
- Sound.Tidal.Stream: [latency] :: OscShape -> Double
+ Sound.Tidal.Stream: [latency] :: Shape -> Double
- Sound.Tidal.Stream: [params] :: OscShape -> [Param]
+ Sound.Tidal.Stream: [params] :: Shape -> [Param]
- Sound.Tidal.Stream: applyShape' :: OscShape -> OscMap -> Maybe OscMap
+ Sound.Tidal.Stream: applyShape' :: Shape -> ParamMap -> Maybe ParamMap
- Sound.Tidal.Stream: defaultMap :: OscShape -> OscMap
+ Sound.Tidal.Stream: defaultMap :: Shape -> ParamMap
- Sound.Tidal.Stream: defaulted :: OscShape -> [Param]
+ Sound.Tidal.Stream: defaulted :: Shape -> [Param]
- Sound.Tidal.Stream: hasRequired :: OscShape -> OscMap -> Bool
+ Sound.Tidal.Stream: hasRequired :: Shape -> ParamMap -> Bool
- Sound.Tidal.Stream: make :: (a -> Datum) -> OscShape -> String -> Pattern a -> OscPattern
+ Sound.Tidal.Stream: make :: (a -> Value) -> Shape -> String -> Pattern a -> ParamPattern
- Sound.Tidal.Stream: makeF :: OscShape -> String -> Pattern Double -> OscPattern
+ Sound.Tidal.Stream: makeF :: Shape -> String -> Pattern Double -> ParamPattern
- Sound.Tidal.Stream: makeI :: OscShape -> String -> Pattern Int -> OscPattern
+ Sound.Tidal.Stream: makeI :: Shape -> String -> Pattern Int -> ParamPattern
- Sound.Tidal.Stream: makeS :: OscShape -> String -> Pattern String -> OscPattern
+ Sound.Tidal.Stream: makeS :: Shape -> String -> Pattern String -> ParamPattern
- Sound.Tidal.Stream: merge :: OscPattern -> OscPattern -> OscPattern
+ Sound.Tidal.Stream: merge :: ParamPattern -> ParamPattern -> ParamPattern
- Sound.Tidal.Stream: mergeWith :: (Real n, Applicative f) => (Float -> Float -> n) -> f (Map Param (Maybe Datum)) -> f (Map Param (Maybe Datum)) -> f (Map Param (Maybe Datum))
+ Sound.Tidal.Stream: mergeWith :: (Ord k, Applicative f) => (k -> a -> a -> a) -> f (Map k a) -> f (Map k a) -> f (Map k a)
- Sound.Tidal.Stream: onTick :: UDP -> OscShape -> MVar (OscPattern) -> Tempo -> Int -> IO ()
+ Sound.Tidal.Stream: onTick :: Backend a -> Shape -> MVar (ParamPattern) -> Tempo -> Int -> IO ()
- Sound.Tidal.Stream: onTick' :: UDP -> OscShape -> MVar (OscPattern, [OscPattern]) -> Tempo -> Int -> IO ()
+ Sound.Tidal.Stream: onTick' :: Backend a -> Shape -> MVar (ParamPattern, [ParamPattern]) -> Tempo -> Int -> IO ()
- Sound.Tidal.Stream: param :: OscShape -> String -> Param
+ Sound.Tidal.Stream: param :: Shape -> String -> Param
- Sound.Tidal.Stream: required :: OscShape -> [Param]
+ Sound.Tidal.Stream: required :: Shape -> [Param]
- Sound.Tidal.Stream: start :: String -> Int -> OscShape -> IO (MVar (OscPattern))
+ Sound.Tidal.Stream: start :: Backend a -> Shape -> IO (MVar (ParamPattern))
- Sound.Tidal.Stream: state :: String -> Int -> OscShape -> IO (MVar (OscPattern, [OscPattern]))
+ Sound.Tidal.Stream: state :: Backend a -> Shape -> IO (MVar (ParamPattern, [ParamPattern]))
- Sound.Tidal.Stream: stream :: String -> Int -> OscShape -> IO (OscPattern -> IO ())
+ Sound.Tidal.Stream: stream :: Backend a -> Shape -> IO (ParamPattern -> IO ())
- Sound.Tidal.Stream: streamcallback :: (OscPattern -> IO ()) -> String -> Int -> OscShape -> IO (OscPattern -> IO ())
+ Sound.Tidal.Stream: streamcallback :: (ParamPattern -> IO ()) -> Backend a -> Shape -> IO (ParamPattern -> IO ())
- Sound.Tidal.SuperCollider: scStream :: String -> [Param] -> Double -> IO (OscPattern -> IO (), OscShape)
+ Sound.Tidal.SuperCollider: scStream :: String -> [Param] -> Double -> IO (ParamPattern -> IO (), Shape)
- Sound.Tidal.SuperCollider: supercollider :: String -> [Param] -> Double -> OscShape
+ Sound.Tidal.SuperCollider: supercollider :: [Param] -> Double -> Shape
- Sound.Tidal.Transition: histpan :: Int -> Time -> [OscPattern] -> OscPattern
+ Sound.Tidal.Transition: histpan :: Int -> Time -> [ParamPattern] -> ParamPattern
- Sound.Tidal.Transition: jump :: Time -> [OscPattern] -> OscPattern
+ Sound.Tidal.Transition: jump :: Time -> [ParamPattern] -> ParamPattern
- Sound.Tidal.Transition: jumpIn :: Int -> Time -> [OscPattern] -> OscPattern
+ Sound.Tidal.Transition: jumpIn :: Int -> Time -> [ParamPattern] -> ParamPattern
- Sound.Tidal.Transition: jumpIn' :: Int -> Time -> [OscPattern] -> OscPattern
+ Sound.Tidal.Transition: jumpIn' :: Int -> Time -> [ParamPattern] -> ParamPattern
- Sound.Tidal.Transition: jumpMod :: Int -> Time -> [OscPattern] -> OscPattern
+ Sound.Tidal.Transition: jumpMod :: Int -> Time -> [ParamPattern] -> ParamPattern
- Sound.Tidal.Transition: mortal :: Time -> Time -> Time -> [OscPattern] -> OscPattern
+ Sound.Tidal.Transition: mortal :: Time -> Time -> Time -> [ParamPattern] -> ParamPattern
- Sound.Tidal.Transition: transition :: (IO Time) -> MVar (OscPattern, [OscPattern]) -> (Time -> [OscPattern] -> OscPattern) -> OscPattern -> IO ()
+ Sound.Tidal.Transition: transition :: (IO Time) -> MVar (ParamPattern, [ParamPattern]) -> (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ()
- Sound.Tidal.Transition: wait :: Time -> Time -> [OscPattern] -> OscPattern
+ Sound.Tidal.Transition: wait :: Time -> Time -> [ParamPattern] -> ParamPattern
Files
- Sound/Tidal/Context.hs +4/−1
- Sound/Tidal/Dirt.hs +80/−35
- Sound/Tidal/MIDI/Control.hs +59/−0
- Sound/Tidal/MIDI/Device.hs +36/−0
- Sound/Tidal/MIDI/Params.hs +25/−0
- Sound/Tidal/MidiStream.hs +277/−0
- Sound/Tidal/OscStream.hs +68/−0
- Sound/Tidal/Params.hs +102/−60
- Sound/Tidal/Parse.hs +22/−2
- Sound/Tidal/Pattern.hs +94/−14
- Sound/Tidal/SerialStream.hs +113/−0
- Sound/Tidal/Strategies.hs +37/−16
- Sound/Tidal/Stream.hs +94/−102
- Sound/Tidal/SuperCollider.hs +18/−10
- Sound/Tidal/Synth.hs +18/−0
- Sound/Tidal/Transition.hs +22/−23
- tidal.cabal +10/−3
- tidal.el +10/−10
Sound/Tidal/Context.hs view
@@ -15,4 +15,7 @@ import Sound.Tidal.SuperCollider as C import Sound.Tidal.Params as C import Sound.Tidal.Transition as C-+import Sound.Tidal.MidiStream as C+import Sound.Tidal.MIDI.Params as C+import Sound.Tidal.Synth as C+import Sound.Tidal.SerialStream as C
Sound/Tidal/Dirt.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE NoMonomorphismRestriction #-}- module Sound.Tidal.Dirt where import Sound.OSC.FD (Datum)@@ -17,15 +16,17 @@ import System.Process import Sound.Tidal.Stream+import Sound.Tidal.OscStream import Sound.Tidal.Pattern import Sound.Tidal.Parse import Sound.Tidal.Params import Sound.Tidal.Time+import Sound.Tidal.Tempo+import Sound.Tidal.Transition (transition, wash) import Sound.Tidal.Utils (enumerate) -dirt :: OscShape-dirt = OscShape {path = "/play",- params = [ sound_p,+dirt :: Shape+dirt = Shape { params = [ s_p, offset_p, begin_p, end_p,@@ -50,37 +51,76 @@ bandf_p, bandq_p, unit_p,- loop_p+ loop_p,+ n_p ], cpsStamp = True,- timestamp = MessageStamp,- latency = 0.04,- namedParams = False,- preamble = []+ latency = 0.04 } -dirtstart name = start "127.0.0.1" 7771 dirt-dirtStream = stream "127.0.0.1" 7771 dirt-dirtState = Sound.Tidal.Stream.state "127.0.0.1" 7771 dirt+dirtSlang = OscSlang {+ path = "/play",+ timestamp = MessageStamp,+ namedParams = False,+ preamble = []+ } --- disused parameter..+superDirtSlang = dirtSlang { timestamp = BundleStamp, path = "/play2", namedParams = True }++superDirtBackend port = do+ s <- makeConnection "127.0.0.1" port superDirtSlang+ return $ Backend s++superDirtState port = do+ backend <- superDirtBackend port+ Sound.Tidal.Stream.state backend dirt++dirtBackend = do+ s <- makeConnection "127.0.0.1" 7771 dirtSlang+ return $ Backend s++-- dirtstart name = start "127.0.0.1" 7771 dirt++dirtStream = do+ backend <- dirtBackend+ stream backend dirt++dirtState = do+ backend <- dirtBackend+ Sound.Tidal.Stream.state backend dirt++dirtSetters :: IO Time -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())+dirtSetters getNow = do ds <- dirtState+ return (setter ds, transition getNow ds)++superDirtSetters :: IO Time -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())+superDirtSetters getNow = do ds <- superDirtState 57120+ return (setter ds, transition getNow ds)+++superDirts :: [Int] -> IO [(ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())]+superDirts ports = do (_, getNow) <- bpsUtils+ states <- mapM (superDirtState) ports+ return $ map (\state -> (setter state, transition getNow state)) states++-- -- disused parameter.. dirtstream _ = dirtStream -doubledirt = do remote <- stream "178.77.72.138" 7777 dirt- local <- stream "192.168.0.102" 7771 dirt- return $ \p -> do remote p- local p- return ()+-- doubledirt = do remote <- stream "178.77.72.138" 7777 dirt+-- local <- stream "192.168.0.102" 7771 dirt+-- return $ \p -> do remote p+-- local p+-- return () -dirtToColour :: OscPattern -> Pattern ColourD+dirtToColour :: ParamPattern -> Pattern ColourD dirtToColour p = s where s = fmap (\x -> maybe black (maybe black datumToColour) (Map.lookup (param dirt "sound") x)) p showToColour :: Show a => a -> ColourD showToColour = stringToColour . show -datumToColour :: Datum -> ColourD+datumToColour :: Value -> ColourD datumToColour = showToColour stringToColour :: String -> ColourD@@ -90,9 +130,8 @@ g = fromIntegral $ (i .&. 0x00FF00) `shiftR` 8; b = fromIntegral $ (i .&. 0x0000FF); - {--visualcallback :: IO (OscPattern -> IO ())+visualcallback :: IO (ParamPattern -> IO ()) visualcallback = do t <- ticker mv <- startVis t let f p = do let p' = dirtToColour p@@ -103,27 +142,26 @@ --dirtyvisualstream name = do cb <- visualcallback -- streamcallback cb "127.0.0.1" "127.0.0.1" name "127.0.0.1" 7771 dirt- pick :: String -> Int -> String pick name n = name ++ ":" ++ (show n) -striate :: Int -> OscPattern -> OscPattern+striate :: Int -> ParamPattern -> ParamPattern striate n p = cat $ map (\x -> off (fromIntegral x) p) [0 .. n-1]- where off i p = p - # begin (atom (fromIntegral i / fromIntegral n)) + where off i p = p+ # begin (atom (fromIntegral i / fromIntegral n)) # end (atom (fromIntegral (i+1) / fromIntegral n)) -striate' :: Int -> Double -> OscPattern -> OscPattern+striate' :: Int -> Double -> ParamPattern -> ParamPattern striate' n f p = cat $ map (\x -> off (fromIntegral x) p) [0 .. n-1] where off i p = p # begin (atom (slot * i) :: Pattern Double) # end (atom ((slot * i) + f) :: Pattern Double) slot = (1 - f) / (fromIntegral n) -striateO :: OscPattern -> Int -> Double -> OscPattern+striateO :: ParamPattern -> Int -> Double -> ParamPattern striateO p n o = cat $ map (\x -> off (fromIntegral x) p) [0 .. n-1] where off i p = p # begin ((atom $ (fromIntegral i / fromIntegral n) + o) :: Pattern Double) # end ((atom $ (fromIntegral (i+1) / fromIntegral n) + o) :: Pattern Double) -striateL :: Int -> Int -> OscPattern -> OscPattern+striateL :: Int -> Int -> ParamPattern -> ParamPattern striateL n l p = striate n p # loop (atom $ fromIntegral l) striateL' n f l p = striate' n f p # loop (atom $ fromIntegral l) @@ -137,19 +175,26 @@ clutch :: Time -> [Pattern a] -> Pattern a clutch = clutchIn 2 -xfadeIn :: Time -> Time -> [OscPattern] -> OscPattern+xfadeIn :: Time -> Time -> [ParamPattern] -> ParamPattern xfadeIn _ _ [] = silence xfadeIn _ _ (p:[]) = p xfadeIn t now (p:p':_) = overlay (p |*| gain (now ~> (slow t envEqR))) (p' |*| gain (now ~> (slow t (envEq)))) -xfade :: Time -> [OscPattern] -> OscPattern+xfade :: Time -> [ParamPattern] -> ParamPattern xfade = xfadeIn 2 -stut :: Integer -> Double -> Rational -> OscPattern -> OscPattern-stut steps feedback time p = stack (p:(map (\x -> (((x%steps)*time) ~> (p |*| gain (pure $ scale (fromIntegral x))))) [1..(steps-1)])) - where scale x +stut :: Integer -> Double -> Rational -> ParamPattern -> ParamPattern+stut steps feedback time p = stack (p:(map (\x -> (((x%steps)*time) ~> (p |*| gain (pure $ scale (fromIntegral x))))) [1..(steps-1)]))+ where scale x = ((+feedback) . (*(1-feedback)) . (/(fromIntegral steps)) . ((fromIntegral steps)-)) x -stut' :: Integer -> Time -> (OscPattern -> OscPattern) -> OscPattern -> OscPattern+stut' :: Integer -> Time -> (ParamPattern -> ParamPattern) -> ParamPattern -> ParamPattern stut' steps steptime f p | steps <= 0 = p | otherwise = overlay (f (steptime ~> stut' (steps-1) steptime f p)) p++-- Increase comb filter to anticipate 'drop' to next pattern+anticipateIn :: Time -> Time -> [ParamPattern] -> ParamPattern+anticipateIn t now = wash (spread' (stut 8 0.2) (now ~> (slow t $ (toRational . (1-)) <$> envL))) t now++anticipate :: Time -> [ParamPattern] -> ParamPattern+anticipate = anticipateIn 8
+ Sound/Tidal/MIDI/Control.hs view
@@ -0,0 +1,59 @@+module Sound.Tidal.MIDI.Control where++import qualified Sound.Tidal.Stream as S++import Sound.Tidal.Params+import Sound.Tidal.MIDI.Params++type RangeMapFunc = (Int, Int) -> Double -> Int++data ControlChange = CC { param :: S.Param, midi :: Int, range :: (Int, Int), vdefault :: Double, scalef :: RangeMapFunc }+ | NRPN { param :: S.Param, midi :: Int, range :: (Int, Int), vdefault :: Double, scalef :: RangeMapFunc }+ | SysEx { param :: S.Param, midi :: Int, range :: (Int, Int), vdefault :: Double, scalef :: RangeMapFunc }++data ControllerShape = ControllerShape {+ controls :: [ControlChange],+ latency :: Double+ }+++toShape :: ControllerShape -> S.Shape+toShape cs =+ let params = [dur_p, note_p, velocity_p] ++ params'+ params' = [param p | p <- (controls cs)]+ in S.Shape { S.params = params,+ S.cpsStamp = False,+ S.latency = latency cs+ }++passThru :: (Int, Int) -> Double -> Int+passThru (_, _) = floor -- no sanitizing of range…++mapRange :: (Int, Int) -> Double -> Int+mapRange (low, high) = floor . (+ (fromIntegral low)) . (* ratio)+ where ratio = fromIntegral $ high - low++mCC :: S.Param -> Int -> ControlChange+mCC p m = CC {param=p, midi=m, range=(0, 127), vdefault=0, scalef=mapRange }++mNRPN :: S.Param -> Int -> ControlChange+mNRPN p m = NRPN {param=p, midi=m, range=(0, 127), vdefault=0, scalef=mapRange }++mrNRPN :: S.Param -> Int -> (Int, Int) -> Double -> ControlChange+mrNRPN p m r d = NRPN {param=p, midi=m, range=r, vdefault=d, scalef=mapRange }++toParams :: ControllerShape -> [S.Param]+toParams shape = map param (controls shape)++ctrlN :: Num b => ControllerShape -> S.Param -> Maybe b+ctrlN shape x = fmap fromIntegral $ fmap midi (paramN shape x)++paramN :: ControllerShape -> S.Param -> Maybe ControlChange+paramN shape x+ | x `elem` names = paramX $ matching p+ | otherwise = Nothing -- error $ "No such Controller param: " ++ show x+ where names = toParams shape+ paramX [] = Nothing+ paramX (h:_) = Just h+ matching = filter ((== x) . param)+ p = controls shape
+ Sound/Tidal/MIDI/Device.hs view
@@ -0,0 +1,36 @@+module Sound.Tidal.MIDI.Device where+import qualified Sound.PortMidi as PM++displayOutputDevices :: IO String+displayOutputDevices = do+ devices <- getIndexedDevices+ return $ displayDevices $ getOutputDevices devices++displayDevices :: Show a => [(a, PM.DeviceInfo)] -> String+displayDevices devices =+ let indices = map (show . fst) devices+ names = map ((":\t"++) . PM.name . snd) devices+ pairs = zipWith (++) indices names+ in unlines (["ID:\tName"]++pairs)++getOutputDevices :: [(a, PM.DeviceInfo)] -> [(a, PM.DeviceInfo)]+getOutputDevices = filter (PM.output . snd)++getIndexedDevices :: IO [(Integer, PM.DeviceInfo)]+getIndexedDevices = do+ rawDevices <- getDevices+ return $ zip [0..] rawDevices++getDevices :: IO ([PM.DeviceInfo])+getDevices = do+ PM.initialize+ count <- PM.countDevices+ mapM PM.getDeviceInfo [0..(count - 1)]++getIDForDeviceName :: Num a => String -> IO (Maybe a)+getIDForDeviceName name = do+ odevs <- fmap getOutputDevices getIndexedDevices+ let res = filter (\n -> (PM.name . snd) n == name) odevs+ case res of+ [] -> return Nothing+ [dev] -> return $ Just $ fromIntegral $ fst dev
+ Sound/Tidal/MIDI/Params.hs view
@@ -0,0 +1,25 @@+module Sound.Tidal.MIDI.Params where++import Sound.Tidal.Pattern+import Sound.Tidal.Stream+import Sound.Tidal.Params++dur :: Pattern Double -> ParamPattern+dur = make' VF dur_p+dur_p = F "dur" (Just 0.05)++note :: Pattern Int -> ParamPattern+note = make' VI note_p+note_p = I "note" Nothing++modwheel :: Pattern Double -> ParamPattern+modwheel = make' VF modwheel_p+modwheel_p = F "modwheel" (Just 0)++expression :: Pattern Double -> ParamPattern+expression = make' VF expression_p+expression_p = F "expression" (Just 1)++sustainpedal :: Pattern Double -> ParamPattern+sustainpedal = make' VF sustainpedal_p+sustainpedal_p = F "sustainpedal_p" (Just 0)
+ Sound/Tidal/MidiStream.hs view
@@ -0,0 +1,277 @@+module Sound.Tidal.MidiStream (midiStream, midiBackend, midiState, midiSetters, midiDevices) where++import Control.Monad.Trans.Maybe+-- generics+import qualified Data.Map as Map+import Data.List (sortBy)+import Data.Maybe+import Data.Ord (comparing)+import Data.Time (getCurrentTime, UTCTime, diffUTCTime)+import Data.Time.Clock.POSIX+import Control.Concurrent+import Control.Concurrent.MVar+import Data.Bits+import Foreign.C+import Control.Applicative++-- Tidal specific+import Sound.Tidal.Tempo (Tempo, cps)+import Sound.Tidal.Stream as S+import Sound.Tidal.Utils+import Sound.Tidal.Time+import Sound.Tidal.Transition (transition)++-- MIDI specific+import Sound.Tidal.MIDI.Device+import Sound.Tidal.MIDI.Control+import Sound.Tidal.MIDI.Params+import qualified Sound.PortMidi as PM++data Output = Output {+ conn :: PM.PMStream,+ lock :: MVar (),+ offset :: Double,+ buffer :: MVar [PM.PMEvent]+ }++type MidiMap = Map.Map S.Param (Maybe Int)+type MidiDeviceMap = Map.Map String Output++toMidiEvent :: ControllerShape -> S.Param -> Value -> Maybe Int+toMidiEvent s p (VF x) = ($) <$> mscale <*> mrange <*> pure x+ where+ mrange = fmap range mcc+ mscale = fmap scalef mcc+ mcc = paramN s p+toMidiEvent s p (VI x) = Just x+toMidiEvent s p (VS x) = Nothing -- ignore strings for now, we might 'read' them later++toMidiMap :: ControllerShape -> S.ParamMap -> MidiMap+toMidiMap s m = Map.mapWithKey (toMidiEvent s) (Map.mapMaybe (id) m)+++send s ch cshape shape change tick o ctrls (tdur:tnote:trest) = midi+ where+ midi = sendmidi s cshape ch' (note, vel, dur) (diff) ctrls+ diff = floor $ (*1000) $ (logicalOnset - (offset s))+ note = fromIntegral $ ivalue $ snd tnote+ dur = realToFrac $ fvalue $ snd tdur+ (vel, nudge) = case length trest of+ 2 -> (mkMidi $ trest !! 1, fvalue $ snd $ trest !! 0)+ 1 -> (mkMidi $ trest !! 0, 0)+ ch' = fromIntegral ch+ mkMidi = fromIntegral . floor . (*127) . fvalue . snd+ logicalOnset = logicalOnset' change tick o nudge++mkSend cshape channel s = return $ (\ shape change tick (o,m) -> do+ let defaulted = (S.applyShape' shape m)+ -- split ParamMap into Properties and Controls+ mpartition = fmap (Map.partitionWithKey (\k _ -> (name k) `elem` ["dur", "note", "velocity", "nudge"])) defaulted+ props = fmap fst mpartition+ ctrls = fmap snd mpartition+ props' = fmap (Map.toAscList) $ fmap (Map.mapMaybe (id)) props+ -- only send explicitly set Control values+ ctrls' = fmap (Map.filterWithKey (\k v -> v /= (defaultValue k))) ctrls+ ctrls'' = fmap (toMidiMap cshape) ctrls'+ send' = fmap (send s channel cshape shape change tick o) ctrls''+ ($) <$> send' <*> props'+ )++connected cshape channel name s = do+ putStrLn ("Successfully initialized Device '" ++ name ++ "'")+ sendevents s+ mkSend cshape channel s++failed di err = do+ error (show err ++ ": " ++ show di)++notfound name = do+ putStrLn "List of Available Device Names"+ putStrLn =<< displayOutputDevices+ error ("Device '" ++ show name ++ "' not found")++useOutput outsM name lat = do+ outs <- readMVar outsM -- maybe+ let outM = Map.lookup name outs -- maybe+ -- if we have a valid output by now, return+ case outM of+ Just o -> do+ putStrLn "Cached Device Output"+ return $ Just o+ Nothing -> do+ -- otherwise open a new output and store the result in the mvar+ devidM <- (>>= maybe (failed name "Failed opening MIDI Output Device ID") return) (getIDForDeviceName name)+ econn <- outputDevice devidM lat -- either+ case econn of+ Left o -> do+ swapMVar outsM $ Map.insert name o outs+ return $ Just o+ Right _ -> return Nothing++++makeConnection :: MVar (MidiDeviceMap) -> String -> Int -> ControllerShape -> IO (S.ToMessageFunc)+makeConnection devicesM deviceName channel cshape = do+ let lat = (floor $ (*100) $ Sound.Tidal.MIDI.Control.latency cshape)+ moutput <- useOutput devicesM deviceName lat+ case moutput of+ Just o ->+ connected cshape channel deviceName o+ Nothing ->+ --failed o+ error "Failed"+-- devidM'' <- devidM' -- maybe++midiDevices :: IO (MVar (MidiDeviceMap))+midiDevices = do+ newMVar $ Map.fromList []++midiBackend d n c cs = do+ s <- makeConnection d n c cs+ return $ Backend s++midiStream d n c s = do+ backend <- midiBackend d n c s+ stream backend (toShape s)++midiState d n c s = do+ backend <- midiBackend d n c s+ S.state backend (toShape s)++midiSetters :: MVar (MidiDeviceMap) -> String -> Int -> ControllerShape -> IO 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)+++-- actual midi interaction+sendevents :: Output -> IO ThreadId+sendevents stream = do+ forkIO $ do loop stream+ where loop stream = do act stream+ delay+ loop stream+ act stream = do+ let buf = buffer stream+ o = conn stream+ buf' <- tryTakeMVar buf+ case buf' of+ Nothing -> do+ return Nothing+ Just [] -> do+ putMVar buf []+ return Nothing+ (Just evts@(x:xs)) -> do+ midiTime <- PM.time+ let evts' = sortBy (comparing PM.timestamp) evts+ nextTick = fromIntegral $ midiTime + 1 -- advance on millisecond, i.e. the next call of this loop+ (evts'',later) = span (\x -> (((PM.timestamp x) < midiTime)) || ((PM.timestamp x) < nextTick)) evts'+ putMVar buf later++ err <- PM.writeEvents o evts''+ case err of+ PM.NoError -> return Nothing+ e -> return $ Just (userError ("Error '" ++ show e ++ "' sending Events: " ++ show evts))++ delay = threadDelay 1000 -- in microseconds, i.e. one millisecond+++sendctrls :: Output -> ControllerShape -> CLong -> CULong -> MidiMap -> IO ()+sendctrls stream shape ch t ctrls = do+ let ctrls' = filter ((>=0) . snd) $ Map.toList $ Map.mapMaybe (id) ctrls+ sequence_ $ map (\(param, ctrl) -> makeCtrl stream ch (fromJust $ paramN shape param) (fromIntegral ctrl) t) ctrls' -- FIXME: we should be sure param has ControlChange+ return ()++sendnote :: RealFrac s => Output -> t -> CLong -> (CLong, CLong, s) -> CULong -> IO ThreadId+sendnote stream shape ch (note,vel, dur) t =+ do forkIO $ do noteOn stream ch note vel t+ noteOff stream ch note (t + (floor $ 1000 * dur))+ return ()++sendmidi :: (Show s, RealFrac s) => Output -> ControllerShape -> CLong -> (CLong, CLong, s) -> CULong -> MidiMap -> IO ()+sendmidi stream shape ch (128,vel,dur) t ctrls = do+ sendctrls stream shape ch t ctrls+ return ()+sendmidi stream shape ch (note,vel,dur) t ctrls = do+ sendnote stream shape ch (note,vel,dur) t+ sendctrls stream shape ch t ctrls+ return ()+++-- MIDI Utils+encodeChannel :: (Bits a, Num a) => a -> a -> a+encodeChannel ch cc = (((-) ch 1) .|. cc)+++-- MIDI Messages+noteOn :: Output -> CLong -> CLong -> CLong -> CULong -> IO (Maybe a)+noteOn o ch val vel t = do+ let evt = makeEvent 0x90 val ch vel t+ sendEvent o evt++noteOff :: Output -> CLong -> CLong -> CULong -> IO (Maybe a)+noteOff o ch val t = do+ let evt = makeEvent 0x80 val ch 60 t+ sendEvent o evt++makeCtrl :: Output -> CLong -> ControlChange -> CLong -> CULong -> IO (Maybe a)+makeCtrl o ch (CC {midi=midi, range=range}) n t = makeCC o ch (fromIntegral midi) n t+makeCtrl o ch (NRPN {midi=midi, range=range}) n t = makeNRPN o ch (fromIntegral midi) n t+-- makeCtrl o ch (C.SysEx {C.midi=midi, C.range=range, C.scalef=f}) n t = makeSysEx o ch (fromIntegral midi) scaledN t+-- where scaledN = fromIntegral $ (f range (n))++-- This is sending CC+makeCC :: Output -> CLong -> CLong -> CLong -> CULong -> IO (Maybe a)+makeCC o ch c n t = do+ let evt = makeEvent 0xB0 c ch n t+ sendEvent o evt++-- This is sending NRPN+makeNRPN :: Output -> CLong -> CLong -> CLong -> CULong -> IO (Maybe a)+makeNRPN o ch c n t = do+ let nrpn = makeEvent 0xB0+ evts = [nrpn 0x63 ch (shift (c .&. 0x3F80) (-7)) t,+ nrpn 0x62 ch (c .&. 0x7F) t,+ nrpn 0x06 ch (shift (n .&. 0x3F80) (-7)) t,+ nrpn 0x26 ch (n .&. 0x7F) t+ ]+ mapM (sendEvent o) evts+ return Nothing+++-- Port Midi Wrapper++outputDevice :: PM.DeviceID -> Int -> IO (Either Output PM.PMError)+outputDevice deviceID latency = do+ PM.initialize+ now <- getCurrentTime+ result <- PM.openOutput deviceID latency+ case result of+ Left dev ->+ do+ info <- PM.getDeviceInfo deviceID+ putStrLn ("Opened: " ++ show (PM.interface info) ++ ": " ++ show (PM.name info))+ sem <- newEmptyMVar+ putMVar sem () -- initially fill MVar to be taken by the first user of this output+ buffer <- newMVar []++ midiOffset <- PM.time++ let posixNow = realToFrac $ utcTimeToPOSIXSeconds now+ syncedNow = posixNow - ((0.001*) $ fromIntegral midiOffset)+ return (Left Output { conn=dev, lock=sem, offset=syncedNow, buffer=buffer })+ Right err -> return (Right err)+++makeEvent :: CLong -> CLong -> CLong -> CLong -> CULong -> PM.PMEvent+makeEvent st n ch v t = PM.PMEvent msg (t)+ where msg = PM.PMMsg (encodeChannel ch st) (n) (v)++-- now with a semaphore since PortMIDI is NOT thread safe+sendEvent :: Output -> PM.PMEvent -> IO (Maybe a)+sendEvent o evt = do+ let sem = lock o+ buf = buffer o+ cbuf <- takeMVar buf+ putMVar buf (cbuf ++ [evt])+ return Nothing
+ Sound/Tidal/OscStream.hs view
@@ -0,0 +1,68 @@+module Sound.Tidal.OscStream where++import qualified Data.Map as Map+import Data.Maybe+import Sound.Tidal.Tempo (Tempo, cps)+import Sound.Tidal.Stream+import Sound.Tidal.Utils+import GHC.Float (float2Double, double2Float)+import Sound.OSC.FD+import Sound.OSC.Datum+import Sound.Tidal.Params++data TimeStamp = BundleStamp | MessageStamp | NoStamp+ deriving Eq++data OscSlang = OscSlang {path :: String,+ timestamp :: TimeStamp,+ namedParams :: Bool,+ preamble :: [Datum]+ }++type OscMap = Map.Map Param (Maybe Datum)++toOscDatum :: Value -> Maybe Datum+toOscDatum (VF x) = Just $ float x+toOscDatum (VI x) = Just $ int32 x+toOscDatum (VS x) = Just $ string x++toOscMap :: ParamMap -> OscMap+toOscMap m = Map.map (toOscDatum) (Map.mapMaybe (id) m)++-- constructs and sends an Osc Message according to the given slang+-- and other params - this is essentially the same as the former+-- toMessage in Stream.hs+send s slang shape change tick (o, m) = osc+ where+ osc | timestamp slang == BundleStamp = sendOSC s $ Bundle (ut_to_ntpr logicalOnset) [Message (path slang) oscdata]+ | timestamp slang == MessageStamp = sendOSC s $ Message (path slang) ((int32 sec):(int32 usec):oscdata)+ | otherwise = doAt logicalOnset $ sendOSC s $ Message (path slang) oscdata+ oscPreamble = cpsPrefix ++ preamble slang+ oscdata | namedParams slang = oscPreamble ++ (concatMap (\(k, Just v) -> [string (name k), v] )+ $ filter (isJust . snd) $ Map.assocs m)+ | otherwise = oscPreamble ++ (catMaybes $ mapMaybe (\x -> Map.lookup x m) (params shape))+ cpsPrefix | cpsStamp shape && namedParams slang = [string "cps", float (cps change)]+ | cpsStamp shape = [float (cps change)]+ | otherwise = []+ parameterise ds = mergelists (map (string . name) (params shape)) ds+ usec = floor $ 1000000 * (logicalOnset - (fromIntegral sec))+ sec = floor logicalOnset+ logicalOnset = logicalOnset' change tick o ((latency shape) + nudge)+ nudge = maybe 0 (toF) (Map.lookup nudge_p m)+ toF (Just (Float f)) = float2Double f+ toF _ = 0++-- type OscMap = Map.Map Param (Maybe Datum)+ +-- Returns a function that will convert a generic ParamMap into a specific Osc message and send it over UDP to the supplied server+-- messages will be built according to the given OscSlang+makeConnection :: String -> Int -> OscSlang -> IO (ToMessageFunc)+makeConnection address port slang = do+ s <- openUDP address port+ return (\ shape change tick (o,m) -> do+ let m' = if (namedParams slang) then (Just m) else (applyShape' shape m)+ -- this might result in Nothing, make sure we do this first+ m'' <- fmap (toOscMap) m'+ -- to allow us to simplify `send` (no `do`)+ return $ send s slang shape change tick (o,m'')+ )
Sound/Tidal/Params.hs view
@@ -2,115 +2,157 @@ import Sound.Tidal.Stream import Sound.Tidal.Pattern-import Sound.OSC.FD-import Sound.OSC.Datum-import Data.Map as Map+import qualified Data.Map as Map+import Sound.Tidal.Utils -make' :: (a -> Datum) -> Param -> Pattern a -> OscPattern-make' toOsc par p = fmap (\x -> Map.singleton par (defaultV x)) p- where defaultV a = Just $ toOsc a+make' :: (a -> Value) -> Param -> Pattern a -> ParamPattern+make' toValue par p = fmap (\x -> Map.singleton par (defaultV x)) p+ where defaultV a = Just $ toValue a -sound :: Pattern String -> OscPattern-sound = make' string sound_p-sound_p = S "sound" Nothing+grp :: [Param] -> Pattern String -> ParamPattern+grp [] _ = silence+grp params p = (fmap lookupPattern p)+ where lookupPattern :: String -> ParamMap+ lookupPattern s = Map.fromList $ map (\(param,s') -> toPV param s') $ zip params $ (split s)+ split s = wordsBy (==':') s+ toPV :: Param -> String -> (Param, Maybe Value)+ toPV param@(S _ _) s = (param, (Just $ VS s))+ toPV param@(F _ _) s = (param, (Just $ VF $ read s))+ toPV param@(I _ _) s = (param, (Just $ VI $ read s)) -offset :: Pattern Double -> OscPattern-offset = make' float offset_p+sound :: Pattern String -> ParamPattern+sound = grp [s_p, n_p]++-- "s" stands for sample, or synth+s :: Pattern String -> ParamPattern+s = make' VS s_p+s_p = S "s" Nothing++-- "n" stands for sample number, or note+n :: Pattern Int -> ParamPattern+n = make' VI n_p+n_p = I "n" (Just 0)++nudge :: Pattern Double -> ParamPattern+nudge = make' VF nudge_p+nudge_p = (F "nudge" (Just 0))++offset :: Pattern Double -> ParamPattern+offset = make' VF offset_p offset_p = F "offset" (Just 0) -begin :: Pattern Double -> OscPattern-begin = make' float begin_p+begin :: Pattern Double -> ParamPattern+begin = make' VF begin_p begin_p = F "begin" (Just 0) -end :: Pattern Double -> OscPattern-end = make' float end_p+end :: Pattern Double -> ParamPattern+end = make' VF end_p end_p = F "end" (Just 1) -speed :: Pattern Double -> OscPattern-speed = make' float speed_p+speed :: Pattern Double -> ParamPattern+speed = make' VF speed_p speed_p = F "speed" (Just 1) -pan :: Pattern Double -> OscPattern-pan = make' float pan_p+pan :: Pattern Double -> ParamPattern+pan = make' VF pan_p pan_p = F "pan" (Just 0.5) -velocity :: Pattern Double -> OscPattern-velocity = make' float velocity_p-velocity_p = F "velocity" (Just 0)+velocity :: Pattern Double -> ParamPattern+velocity = make' VF velocity_p+velocity_p = F "velocity" (Just 0.5) -vowel :: Pattern String -> OscPattern-vowel = make' string vowel_p+vowel :: Pattern String -> ParamPattern+vowel = make' VS vowel_p vowel_p = S "vowel" (Just "") -cutoff :: Pattern Double -> OscPattern-cutoff = make' float cutoff_p+cutoff :: Pattern Double -> ParamPattern+cutoff = make' VF cutoff_p cutoff_p = F "cutoff" (Just 0) -resonance :: Pattern Double -> OscPattern-resonance = make' float resonance_p+resonance :: Pattern Double -> ParamPattern+resonance = make' VF resonance_p resonance_p = F "resonance" (Just 0) -accelerate :: Pattern Double -> OscPattern-accelerate = make' float accelerate_p+accelerate :: Pattern Double -> ParamPattern+accelerate = make' VF accelerate_p accelerate_p = F "accelerate" (Just 0) -shape :: Pattern Double -> OscPattern-shape = make' float shape_p+shape :: Pattern Double -> ParamPattern+shape = make' VF shape_p shape_p = F "shape" (Just 0) -kriole :: Pattern Int -> OscPattern-kriole = make' int32 kriole_p+kriole :: Pattern Int -> ParamPattern+kriole = make' VI kriole_p kriole_p = I "kriole" (Just 0) -gain :: Pattern Double -> OscPattern-gain = make' float gain_p+gain :: Pattern Double -> ParamPattern+gain = make' VF gain_p gain_p = F "gain" (Just 1) -cut :: Pattern Int -> OscPattern-cut = make' int32 cut_p+cut :: Pattern Int -> ParamPattern+cut = make' VI cut_p cut_p = I "cut" (Just (0)) -delay :: Pattern Double -> OscPattern-delay = make' float delay_p+delay :: Pattern Double -> ParamPattern+delay = make' VF delay_p delay_p = F "delay" (Just (0)) -delaytime :: Pattern Double -> OscPattern-delaytime = make' float delaytime_p+delaytime :: Pattern Double -> ParamPattern+delaytime = make' VF delaytime_p delaytime_p = F "delaytime" (Just (-1)) -delayfeedback :: Pattern Double -> OscPattern-delayfeedback = make' float delayfeedback_p+delayfeedback :: Pattern Double -> ParamPattern+delayfeedback = make' VF delayfeedback_p delayfeedback_p = F "delayfeedback" (Just (-1)) -crush :: Pattern Double -> OscPattern-crush = make' float crush_p+crush :: Pattern Double -> ParamPattern+crush = make' VF crush_p crush_p = F "crush" (Just 0) -coarse :: Pattern Int -> OscPattern-coarse = make' int32 coarse_p+coarse :: Pattern Int -> ParamPattern+coarse = make' VI coarse_p coarse_p = I "coarse" (Just 0) -hcutoff :: Pattern Double -> OscPattern-hcutoff = make' float hcutoff_p+hcutoff :: Pattern Double -> ParamPattern+hcutoff = make' VF hcutoff_p hcutoff_p = F "hcutoff" (Just 0) -hresonance :: Pattern Double -> OscPattern-hresonance = make' float hresonance_p+hresonance :: Pattern Double -> ParamPattern+hresonance = make' VF hresonance_p hresonance_p = F "hresonance" (Just 0) -bandf :: Pattern Double -> OscPattern-bandf = make' float bandf_p+bandf :: Pattern Double -> ParamPattern+bandf = make' VF bandf_p bandf_p = F "bandf" (Just 0) -bandq :: Pattern Double -> OscPattern-bandq = make' float bandq_p+bandq :: Pattern Double -> ParamPattern+bandq = make' VF bandq_p bandq_p = F "bandq" (Just 0) -unit :: Pattern String -> OscPattern-unit = make' string unit_p+unit :: Pattern String -> ParamPattern+unit = make' VS unit_p unit_p = S "unit" (Just "rate") -loop :: Pattern Int -> OscPattern-loop = make' int32 loop_p+loop :: Pattern Int -> ParamPattern+loop = make' VI loop_p loop_p = I "loop" (Just 1) +channel :: Pattern Int -> ParamPattern+channel = make' VI channel_p+channel_p = I "channel" Nothing++room :: Pattern Double -> ParamPattern+room = make' VF room_p+room_p = F "room" Nothing++size :: Pattern Double -> ParamPattern+size = make' VF size_p+size_p = F "size" Nothing++dry :: Pattern Double -> ParamPattern+dry = make' VF dry_p+dry_p = F "dry" (Just 0)++orbit :: Pattern Int -> ParamPattern+orbit = make' VI orbit_p+orbit_p = I "orbit" (Just 0)
Sound/Tidal/Parse.hs view
@@ -14,6 +14,7 @@ import Control.Exception as E import Control.Applicative ((<$>), (<*>)) import Data.Maybe+import Data.List import Sound.Tidal.Pattern @@ -132,7 +133,7 @@ scale base (ps@((n,_):_)) = map (\(n',p) -> density (fromIntegral (fromMaybe n base)/ fromIntegral n') p) ps pString :: Parser (String)-pString = many1 (letter <|> oneOf "0123456789:") <?> "string"+pString = many1 (letter <|> oneOf "0123456789:.-_") <?> "string" pVocable :: Parser (Pattern String) pVocable = do v <- pString@@ -152,8 +153,27 @@ pInt :: Parser (Pattern Int) pInt = do s <- sign- i <- integer <?> "integer"+ i <- choice [integer, midinote] return $ atom (applySign s $ fromIntegral i)++midinote :: Parser Integer+midinote = do n <- notenum+ modifiers <- many noteModifier+ octave <- option 5 natural+ let n' = fromIntegral $ foldr (+) n modifiers+ return $ n' + octave*12+ where notenum = choice [char 'c' >> return 0,+ char 'd' >> return 2,+ char 'e' >> return 4,+ char 'f' >> return 5,+ char 'g' >> return 7,+ char 'a' >> return 9,+ char 'b' >> return 11+ ]+ noteModifier = choice [char 's' >> return 1,+ char 'f' >> return (-1),+ char 'n' >> return 0+ ] pColour :: Parser (Pattern ColourD) pColour = do name <- many1 letter <?> "colour name"
Sound/Tidal/Pattern.hs view
@@ -7,11 +7,14 @@ import Data.Fixed import Data.List import Data.Maybe+import Data.Ord import Data.Ratio import Debug.Trace import Data.Typeable import Data.Function import System.Random.Mersenne.Pure64+import Data.Char+import qualified Data.Text as T import Music.Theory.Bjorklund @@ -23,6 +26,7 @@ -- active during that time. For continuous patterns, events with -- values for the midpoint of the given @Arc@ is returned. data Pattern a = Pattern {arc :: Arc -> [Event a]}+ deriving Typeable -- | @show (p :: Pattern)@ returns a text string representing the -- event values active during the first cycle of the given pattern.@@ -73,8 +77,8 @@ -- Pattern a -> (a -> Pattern b) -> Pattern b -- Pattern Char -> (Char -> Pattern String) -> Pattern String - p >>= f = -- unwrap (f <$> p)- Pattern (\a -> concatMap+ p >>= f = unwrap (f <$> p)+{-Pattern (\a -> concatMap (\((s,e), (s',e'), x) -> map (\ev -> ((s,e), (s',e'), thd' ev)) $ filter (\(a', _, _) -> isIn a' s)@@ -82,7 +86,7 @@ ) (arc p a) )-+-} -- join x = x >>= id @@ -289,6 +293,7 @@ -- sinewave with frequency of one cycle, and amplitude from -1 to 1. sinewave :: Pattern Double sinewave = sig $ \t -> sin $ pi * 2 * (fromRational t)+ -- | @sine@ is a synonym for @sinewave. sine = sinewave -- | @sinerat@ is equivalent to @sinewave@ for @Rational@ values,@@ -445,9 +450,12 @@ timeToRand t = fst $ randomDouble $ pureMT $ floor $ (*1000000) t -irand :: Double -> Pattern Int-irand i = (floor . (*i)) <$> rand+irand :: Int -> Pattern Int+irand i = (floor . (* (fromIntegral i))) <$> rand +choose :: [a] -> Pattern a+choose xs = (xs !!) <$> (irand $ length xs)+ degradeBy :: Double -> Pattern a -> Pattern a degradeBy x p = unMaybe $ (\a f -> toMaybe (f > x) a) <$> p <*> rand where toMaybe False _ = Nothing@@ -630,24 +638,96 @@ -- | @randcat ps@: does a @slowcat@ on the list of patterns @ps@ but -- randomises the order in which they are played. randcat :: [Pattern a] -> Pattern a-randcat ps = spread' (<~) (discretise 1 $ ((%1) . fromIntegral) <$> irand (fromIntegral $ length ps)) (slowcat ps)+randcat ps = spread' (<~) (discretise 1 $ ((%1) . fromIntegral) <$> irand (length ps)) (slowcat ps) +-- | @toMIDI p@: converts a pattern of human-readable pitch names into+-- MIDI pitch numbers. For example, @"cs4"@ will be rendered as @"49"@.+-- Omitting the octave number will create a pitch in the fifth octave+-- (@"cf"@ -> @"cf5"@). Pitches can be decorated using:+--+-- * s = Sharp, a half-step above (@"gs4"@)+-- * f = Flat, a half-step below (@"gf4"@)+-- * n = Natural, no decoration (@"g4" and "gn4"@ are equivalent)+-- * ss = Double sharp, a whole step above (@"gss4"@)+-- * ff = Double flat, a whole step below (@"gff4"@)+--+-- This function also has a shorter alias @tom@. toMIDI :: Pattern String -> Pattern Int toMIDI p = fromJust <$> (filterValues (isJust) (noteLookup <$> p)) where+ noteLookup :: String -> Maybe Int noteLookup [] = Nothing- noteLookup s | last s `elem` ['0' .. '9'] = elemIndex s names- | otherwise = noteLookup (s ++ "5")- names = take 128 [(n ++ show o)- | o <- octaves,- n <- notes- ]- notes = ["c","cs","d","ds","e","f","fs","g","gs","a","as","b"]- octaves = [0 .. 10]+ noteLookup s | not (last s `elem` ['0' .. '9']) = noteLookup (s ++ "5")+ | not (isLetter (s !! 1)) = noteLookup((head s):'n':(tail s))+ | otherwise = parse s+ parse x = (\a b c -> a+b+c) <$> pc x <*> sym x <*> Just(12*digitToInt (last x))+ pc x = lookup (head x) [('c',0),('d',2),('e',4),('f',5),('g',7),('a',9),('b',11)]+ sym x = lookup (init (tail x)) [("s",1),("f",-1),("n",0),("ss",2),("ff",-2)] +-- | @tom p@: Alias for @toMIDI@. tom = toMIDI fit :: Int -> [a] -> Pattern Int -> Pattern a fit perCycle xs p = (xs !!!) <$> (Pattern $ \a -> map ((\e -> (mapThd' (+ (cyclePos perCycle e)) e))) (arc p a)) where cyclePos perCycle e = perCycle * (floor $ eventStart e) +permstep :: RealFrac b => Int -> [a] -> Pattern b -> Pattern a+permstep steps things p = unwrap $ (\n -> listToPat $ concatMap (\x -> replicate (fst x) (snd x)) $ zip (ps !! (floor (n * (fromIntegral $ (length ps - 1))))) things) <$> (discretise 1 p)+ where ps = permsort (length things) steps+ deviance avg xs = sum $ map (abs . (avg-) . fromIntegral) xs+ permsort n total = map fst $ sortBy (comparing snd) $ map (\x -> (x,deviance (fromIntegral total/ fromIntegral n) x)) $ perms n total+ perms 0 _ = []+ perms 1 n = [[n]]+ perms n total = concatMap (\x -> map (x:) $ perms (n-1) (total-x)) [1 .. (total-(n-1))]++-- | @struct a b@: structures pattern @b@ in terms of @a@.+struct :: Pattern String -> Pattern a -> Pattern a+struct ps pv = (flip const) <$> ps <*> pv++-- Lindenmayer patterns, these go well with the step sequencer+-- general rule parser (strings map to strings)+parseLMRule :: String -> [(String,String)]+parseLMRule s = map (splitOn ':') (commaSplit s)+ where splitOn sep str = splitAt (fromJust $ elemIndex sep str) + $ filter (/= sep) str+ commaSplit s = map T.unpack $ T.splitOn (T.pack ",") $ T.pack s++-- specific parser for step sequencer (chars map to string)+-- ruleset in form "a:b,b:ab" +parseLMRule' :: String -> [(Char, String)] +parseLMRule' str = map fixer $ parseLMRule str+ where fixer (c,r) = (head c, r)++-- for example, `lindenmayer 1 "a:b,b:ab" "ab" -> "bab"`+lindenmayer :: Int -> String -> String -> String+lindenmayer n r [] = []+lindenmayer 1 r (c:cs) = (fromMaybe [c] $ lookup c $ parseLMRule' r) + ++ (lindenmayer 1 r cs)+lindenmayer n r s = iterate (lindenmayer 1 r) s !! n++-- support for fit'+unwrap' :: Pattern (Pattern a) -> Pattern a+unwrap' pp = Pattern $ \a -> arc (stack $ map scalep (arc pp a)) a+ where scalep ev = compress (fst' ev) $ thd' ev++-- removes events from pattern b that don't start during an event from pattern a+mask :: Pattern a -> Pattern b -> Pattern b+mask pa pb = Pattern $ \a -> concat [filterOns (subArc a $ eventArc i) (arc pb a) | i <- arc pa a]+ where filterOns Nothing es = []+ filterOns (Just arc) es = filter (onsetIn arc) es++enclosingArc :: [Arc] -> Arc+enclosingArc [] = (0,1)+enclosingArc as = (minimum (map fst as), maximum (map snd as))++stretch :: Pattern a -> Pattern a+stretch p = splitQueries $ Pattern $ \a@(s,e) -> arc+ (zoom (enclosingArc $ map eventArc $ arc p (sam s,nextSam s)) p)+ a++-- usage example: fit' 2 4 "[0 1 2 3]/2" "[0 3 1 1, 2*4]" "[bd sn:2 cp*2 hh]/2"+fit' cyc n from to p = unwrap' $ fit n (mapMasks n from' p') to+ where mapMasks n from p = [stretch $ mask (filterValues (== i) from) p + | i <- [0..n-1]]+ p' = density cyc $ p+ from' = density cyc $ from
+ Sound/Tidal/SerialStream.hs view
@@ -0,0 +1,113 @@+module Sound.Tidal.SerialStream (+ serialDevices,+ serialBackend,+ blinken,+ blinkenStream,+ blinkenState,+ blinkenSetters,+ light) where++import Data.List+import Data.Maybe+import qualified Data.Map.Strict as Map+import qualified Data.ByteString.Char8 as B++import Control.Exception+import Control.Concurrent.MVar+import qualified System.Hardware.Serialport as Serial++import Sound.Tidal.Time+import Sound.Tidal.Stream+import Sound.Tidal.Transition+import Sound.Tidal.Pattern+import Sound.Tidal.Params++type SerialMap = Map.Map Param (Maybe String)+type SerialDeviceMap = Map.Map String Serial.SerialPort++toSerialString :: Value -> Maybe String+toSerialString (VF x) = Just $ show x+toSerialString (VI x) = Just $ show x+toSerialString (VS x) = Just $ x++toSerialMap :: ParamMap -> SerialMap+toSerialMap m = Map.map (toSerialString) (Map.mapMaybe (id) m)++send' s content = do+ Serial.send s $ B.pack $ content ++ "\n"+ return ()+++send s shape change tick (o, m) = msg+ where+ msg = doAt logicalOnset $ send' s params''+ -- get the first value of the first param for now+ params'' = case length params' of+ 0 -> ""+ _ -> head $ params'+ params' = catMaybes $ map snd $ Map.toList m+ logicalOnset = logicalOnset' change tick o ((latency shape) + nudge)+ nudge = maybe 0 (toF) (Map.lookup (F "nudge" (Just 0)) m)+ toF (Just s) = read s+ toF _ = 0+++useOutput outsM name = do+ outs <- readMVar outsM+ let outM = Map.lookup name outs+ case outM of+ Just o -> do+ putStrLn "Cached Serial Device output"+ return $ Just o+ Nothing -> do+ o <- Serial.openSerial name Serial.defaultSerialSettings { Serial.commSpeed = Serial.CS115200 }+ swapMVar outsM $ Map.insert name o outs+ return $ Just o++makeConnection :: MVar (SerialDeviceMap) -> String -> IO (ToMessageFunc)+makeConnection devices device = do+ moutput <- useOutput devices device+ case moutput of+ Just s ->+ return $ (\ shape change tick (o, m) -> do+ m' <- fmap (toSerialMap) (applyShape' shape m)+ return $ send s shape change tick (o, m')+ )++ Nothing ->+ error ("Failed connecting to serial device: '" ++ device ++ "'")+++serialDevices :: IO (MVar (SerialDeviceMap))+serialDevices = do+ d <- newMVar $ Map.fromList []+ return d++serialBackend d n = do+ s <- makeConnection d n+ return $ Backend s++blinkenStream d n = do+ backend <- serialBackend d n+ stream backend blinken++blinkenState d n = do+ backend <- serialBackend d n+ state backend blinken++blinkenSetters :: MVar (SerialDeviceMap) -> String -> IO Time -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())+blinkenSetters d n getNow = do+ ds <- blinkenState d n+ return (setter ds, transition getNow ds)++light :: Pattern String -> ParamPattern+light = make' VS light_p+light_p = S "light" Nothing++blinken = Shape {+ params = [+ light_p+ ],+ cpsStamp = True,+ latency = 0.01+ }
Sound/Tidal/Strategies.hs view
@@ -5,6 +5,7 @@ import Data.Ratio import Control.Applicative import qualified Data.Map as Map+import qualified Data.Char as Char import Data.Maybe import Sound.Tidal.Dirt@@ -13,7 +14,7 @@ import Sound.Tidal.Time import Sound.Tidal.Utils import Sound.Tidal.Params-import qualified Sound.OSC.FD as OSC.FD+import Sound.Tidal.Parse stutter n t p = stack $ map (\i -> (t * (fromIntegral i)) ~> p) [0 .. (n-1)] @@ -23,7 +24,7 @@ double = echo jux f p = stack [p # pan (pure 0), f $ p # pan (pure 1)]-juxcut f p = stack [p # pan (pure 0) # cut (pure (-1)), +juxcut f p = stack [p # pan (pure 0) # cut (pure (-1)), f $ p # pan (pure 1) # cut (pure (-2)) ] @@ -54,7 +55,7 @@ {- scrumple :: Time -> Pattern a -> Pattern a -> Pattern a scrumple o p p' = p'' -- overlay p (o ~> p'')- where p'' = Pattern $ \a -> concatMap + where p'' = Pattern $ \a -> concatMap (\((s,d), vs) -> map (\x -> ((s,d), snd x )@@ -64,15 +65,15 @@ -} --rev :: Pattern a -> Pattern a---rev p = Pattern $ \a -> concatMap --- (\a' -> mapFsts mirrorArc $ +--rev p = Pattern $ \a -> concatMap+-- (\a' -> mapFsts mirrorArc $ -- (arc p (mirrorArc a'))) -- (arcCycles a) --spreadf :: [Pattern a -> Pattern b] -> Pattern a -> Pattern b spreadf ts p = spread ($) -spin :: Int -> OscPattern -> OscPattern+spin :: Int -> ParamPattern -> ParamPattern spin copies p = stack $ map (\n -> let offset = toInteger n % toInteger copies in offset <~ p@@ -107,19 +108,19 @@ scale :: (Functor f, Num b) => b -> b -> f b -> f b scale from to p = ((+ from) . (* (to-from))) <$> p -chop :: Int -> OscPattern -> OscPattern+chop :: Int -> ParamPattern -> ParamPattern chop n p = Pattern $ \queryA -> concatMap (f queryA) $ arcCycles queryA where f queryA a = concatMap (chopEvent queryA) (arc p a) chopEvent (queryS, queryE) (a,a',v) = map (newEvent v) $ filter (\(_, (s,e)) -> not $ or [e < queryS, s >= queryE]) (enumerate $ chopArc a n)- newEvent :: OscMap -> (Int, Arc) -> Event OscMap- newEvent v (i, a) = (a,a,Map.insert (param dirt "end") (Just $ OSC.FD.float ((fromIntegral $ i+1)/(fromIntegral n))) $ Map.insert (param dirt "begin") (Just $ OSC.FD.float ((fromIntegral i)/(fromIntegral n))) v)+ newEvent :: ParamMap -> (Int, Arc) -> Event ParamMap+ newEvent v (i, a) = (a,a,Map.insert (param dirt "end") (Just $ VF ((fromIntegral $ i+1)/(fromIntegral n))) $ Map.insert (param dirt "begin") (Just $ VF ((fromIntegral i)/(fromIntegral n))) v) -gap :: Int -> OscPattern -> OscPattern+gap :: Int -> ParamPattern -> ParamPattern gap n p = Pattern $ \queryA -> concatMap (f queryA) $ arcCycles queryA where f queryA a = concatMap (chopEvent queryA) (arc p a) chopEvent (queryS, queryE) (a,a',v) = map (newEvent v) $ filter (\(_, (s,e)) -> not $ or [e < queryS, s >= queryE]) (enumerate $ everyOther $ chopArc a n)- newEvent :: OscMap -> (Int, Arc) -> Event OscMap- newEvent v (i, a) = (a,a,Map.insert (param dirt "end") (Just $ OSC.FD.float ((fromIntegral $ i+1)/(fromIntegral n))) $ Map.insert (param dirt "begin") (Just $ OSC.FD.float ((fromIntegral i)/(fromIntegral n))) v)+ newEvent :: ParamMap -> (Int, Arc) -> Event ParamMap+ newEvent v (i, a) = (a,a,Map.insert (param dirt "end") (Just $ VF ((fromIntegral $ i+1)/(fromIntegral n))) $ Map.insert (param dirt "begin") (Just $ VF ((fromIntegral i)/(fromIntegral n))) v) everyOther (x:(y:xs)) = x:(everyOther xs) everyOther xs = xs @@ -127,7 +128,7 @@ chopArc (s, e) n = map (\i -> ((s + (e-s)*(fromIntegral i/fromIntegral n)), s + (e-s)*((fromIntegral $ i+1)/fromIntegral n))) [0 .. n-1] {- normEv :: Event a -> Event a -> Event a-normEv ev@(_, (s,e), _) ev'@(_, (s',e'), _) +normEv ev@(_, (s,e), _) ev'@(_, (s',e'), _) | not on && not off = [] -- shouldn't happen | on && off = splitEv ev' | not on && s' > sam s = []@@ -148,7 +149,7 @@ en :: [(Int, Int)] -> Pattern String -> Pattern String en ns p = stack $ map (\(i, (k, n)) -> e k n (samples p (pure i))) $ enumerate ns -weave :: Rational -> OscPattern -> [OscPattern] -> OscPattern+weave :: Rational -> ParamPattern -> [ParamPattern] -> ParamPattern weave t p ps = weave' t p (map (\x -> (x #)) ps) weave' :: Rational -> Pattern a -> [Pattern a -> Pattern a] -> Pattern a@@ -156,7 +157,7 @@ | otherwise = slow t $ stack $ map (\(i, f) -> (fromIntegral i % l) <~ (density t $ f (slow t p))) (zip [0 ..] fs) where l = fromIntegral $ length fs -interlace :: OscPattern -> OscPattern -> OscPattern+interlace :: ParamPattern -> ParamPattern -> ParamPattern interlace a b = weave 16 (shape $ ((* 0.9) <$> sinewave1)) [a, b] -- Step sequencing@@ -169,11 +170,31 @@ steps :: [(String, String)] -> Pattern String steps = stack . map (\(a,b) -> step a b) +-- like step, but allows you to specify an array of strings to use for 0,1,2...+step' :: [String] -> String -> Pattern String+step' ss steps = cat $ map f steps+ where f c | c == 'x' = atom $ ss!!0+ | c >= '0' && c <= '9' = atom $ ss!!(Char.digitToInt c)+ | otherwise = silence+ off :: Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a off t f p = superimpose (f . (t ~>)) p offadd :: Num a => Time -> a -> Pattern a -> Pattern a offadd t n p = off t ((+n) <$>) p -up :: Pattern Double -> OscPattern+up :: Pattern Double -> ParamPattern up = speed . ((1.059466**) <$>)++ghost'' a f p = superimpose (((a*2.5) ~>) . f) $ superimpose (((a*1.5) ~>) . f) $ p+ghost' a p = ghost'' 0.125 ((|*| gain (pure 0.7)) . (|=| end (pure 0.2)) . (|*| speed (pure 1.25))) p+ghost p = ghost' 0.125 p ++slice :: Int -> Int -> ParamPattern -> ParamPattern+slice i n p = + p+ # begin (pure $ fromIntegral i / fromIntegral n)+ # end (pure $ fromIntegral (i+1) / fromIntegral n)++randslice :: Int -> ParamPattern -> ParamPattern+randslice n p = unwrap $ (\i -> slice i n p) <$> irand n
Sound/Tidal/Stream.hs view
@@ -3,8 +3,6 @@ module Sound.Tidal.Stream where import Data.Maybe-import Sound.OSC.FD-import Sound.OSC.Datum import Control.Applicative import Control.Concurrent import Control.Concurrent.MVar@@ -12,7 +10,6 @@ import Data.Time (getCurrentTime) import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds) import Data.Ratio-import GHC.Float (float2Double, double2Float) import Sound.Tidal.Pattern import qualified Sound.Tidal.Parse as P import Sound.Tidal.Tempo (Tempo, logicalTime, clocked,clockedTick,cps)@@ -21,6 +18,12 @@ import qualified Data.Map as Map +type ToMessageFunc = Shape -> Tempo -> Int -> (Double, ParamMap) -> Maybe (IO ())++data Backend a = Backend {+ toMessage :: ToMessageFunc+ }+ data Param = S {name :: String, sDefault :: Maybe String} | F {name :: String, fDefault :: Maybe Double} | I {name :: String, iDefault :: Maybe Int}@@ -33,28 +36,24 @@ instance Show Param where show p = name p -data TimeStamp = BundleStamp | MessageStamp | NoStamp- deriving Eq+data Shape = Shape {params :: [Param],+ latency :: Double,+ cpsStamp :: Bool} -data OscShape = OscShape {path :: String,- params :: [Param],- cpsStamp :: Bool,- timestamp :: TimeStamp,- latency :: Double,- namedParams :: Bool,- preamble :: [Datum]- }-type OscMap = Map.Map Param (Maybe Datum) -type OscPattern = Pattern OscMap+data Value = VS { svalue :: String } | VF { fvalue :: Double } | VI { ivalue :: Int } deriving (Show,Eq,Ord) +type ParamMap = Map.Map Param (Maybe Value)++type ParamPattern = Pattern ParamMap+ ticksPerCycle = 8 -defaultDatum :: Param -> Maybe Datum-defaultDatum (S _ (Just x)) = Just $ string x-defaultDatum (I _ (Just x)) = Just $ int32 x-defaultDatum (F _ (Just x)) = Just $ float x-defaultDatum _ = Nothing+defaultValue :: Param -> Maybe Value+defaultValue (S _ (Just x)) = Just $ VS x+defaultValue (I _ (Just x)) = Just $ VI x+defaultValue (F _ (Just x)) = Just $ VF x+defaultValue _ = Nothing hasDefault :: Param -> Bool hasDefault (S _ Nothing) = False@@ -62,165 +61,158 @@ hasDefault (F _ Nothing) = False hasDefault _ = True -defaulted :: OscShape -> [Param]+defaulted :: Shape -> [Param] defaulted = filter hasDefault . params -defaultMap :: OscShape -> OscMap+defaultMap :: Shape -> ParamMap defaultMap s- = Map.fromList $ map (\x -> (x, defaultDatum x)) (defaulted s)+ = Map.fromList $ map (\x -> (x, defaultValue x)) (defaulted s) -required :: OscShape -> [Param]+required :: Shape -> [Param] required = filter (not . hasDefault) . params -hasRequired :: OscShape -> OscMap -> Bool+hasRequired :: Shape -> ParamMap -> Bool hasRequired s m = isSubset (required s) (Map.keys (Map.filter (\x -> x /= Nothing) m)) isSubset :: (Eq a) => [a] -> [a] -> Bool isSubset xs ys = all (\x -> elem x ys) xs -toMessage :: UDP -> OscShape -> Tempo -> Int -> (Double, OscMap) -> Maybe (IO ())-toMessage s shape change tick (o, m) =- do m' <- applyShape' shape m- let cycleD = ((fromIntegral tick) / (fromIntegral ticksPerCycle)) :: Double- logicalNow = (logicalTime change cycleD)- logicalPeriod = (logicalTime change (cycleD + (1/(fromIntegral ticksPerCycle)))) - logicalNow- logicalOnset = logicalNow + (logicalPeriod * o) + (latency shape) + nudge- sec = floor logicalOnset- usec = floor $ 1000000 * (logicalOnset - (fromIntegral sec))- oscdata = cpsPrefix ++ preamble shape ++ (parameterise $ catMaybes $ mapMaybe (\x -> Map.lookup x m') (params shape))- oscdata' = ((int32 sec):(int32 usec):oscdata)- osc | timestamp shape == BundleStamp = sendOSC s $ Bundle (ut_to_ntpr logicalOnset) [Message (path shape) oscdata]- | timestamp shape == MessageStamp = sendOSC s $ Message (path shape) oscdata'- | otherwise = doAt logicalOnset $ sendOSC s $ Message (path shape) oscdata- return osc- where- parameterise :: [Datum] -> [Datum]- parameterise ds | namedParams shape =- mergelists (map (string . name) (params shape)) ds- | otherwise = ds- cpsPrefix | cpsStamp shape = [float (cps change)]- | otherwise = []- nudge = maybe 0 (toF) (Map.lookup (F "nudge" (Just 0)) m)- toF (Just (Float f)) = float2Double f- toF _ = 0 doAt t action = do forkIO $ do now <- getCurrentTime let nowf = realToFrac $ utcTimeToPOSIXSeconds now threadDelay $ floor $ (t - nowf) * 1000000 action return ()- -applyShape' :: OscShape -> OscMap -> Maybe OscMap++logicalOnset' change tick o offset = logicalNow + (logicalPeriod * o) + offset+ where+ tpc = fromIntegral ticksPerCycle+ cycleD = ((fromIntegral tick) / tpc) :: Double+ logicalNow = logicalTime change cycleD+ logicalPeriod = (logicalTime change (cycleD + (1/tpc))) - logicalNow+++applyShape' :: Shape -> ParamMap -> Maybe ParamMap applyShape' s m | hasRequired s m = Just $ Map.union m (defaultMap s) | otherwise = Nothing -start :: String -> Int -> OscShape -> IO (MVar (OscPattern))-start address port shape+start :: Backend a -> Shape -> IO (MVar (ParamPattern))+start backend shape = do patternM <- newMVar silence- s <- openUDP address port- let ot = (onTick s shape patternM) :: Tempo -> Int -> IO ()+ let ot = (onTick backend shape patternM) :: Tempo -> Int -> IO () forkIO $ clockedTick ticksPerCycle ot return patternM -- variant of start where history of patterns is available-state :: String -> Int -> OscShape -> IO (MVar (OscPattern, [OscPattern]))-state address port shape+state :: Backend a -> Shape -> IO (MVar (ParamPattern, [ParamPattern]))+state backend shape = do patternsM <- newMVar (silence, [])- s <- openUDP address port- let ot = (onTick' s shape patternsM) :: Tempo -> Int -> IO ()+ let ot = (onTick' backend shape patternsM) :: Tempo -> Int -> IO () forkIO $ clockedTick ticksPerCycle ot return patternsM -stream :: String -> Int -> OscShape -> IO (OscPattern -> IO ())-stream address port shape - = do patternM <- start address port shape+stream :: Backend a -> Shape -> IO (ParamPattern -> IO ())+stream backend shape+ = do patternM <- start backend shape return $ \p -> do swapMVar patternM p return () -streamcallback :: (OscPattern -> IO ()) -> String -> Int -> OscShape -> IO (OscPattern -> IO ())-streamcallback callback server port shape - = do f <- stream server port shape+streamcallback :: (ParamPattern -> IO ()) -> Backend a -> Shape -> IO (ParamPattern -> IO ())+streamcallback callback backend shape+ = do f <- stream backend shape let f' p = do callback p f p return f' -onTick :: UDP -> OscShape -> MVar (OscPattern) -> Tempo -> Int -> IO ()-onTick s shape patternM change ticks+onTick :: Backend a -> Shape -> MVar (ParamPattern) -> Tempo -> Int -> IO ()+onTick backend shape patternM change ticks = do p <- readMVar patternM let ticks' = (fromIntegral ticks) :: Integer a = ticks' % ticksPerCycle b = (ticks' + 1) % ticksPerCycle- messages = mapMaybe - (toMessage s shape change ticks) + messages = mapMaybe+ (toMessage backend shape change ticks) (seqToRelOnsets (a, b) p) E.catch (sequence_ messages) (\msg -> putStrLn $ "oops " ++ show (msg :: E.SomeException)) return () -- Variant where mutable variable contains list as history of the patterns-onTick' :: UDP -> OscShape -> MVar (OscPattern, [OscPattern]) -> Tempo -> Int -> IO ()-onTick' s shape patternsM change ticks+onTick' :: Backend a -> Shape -> MVar (ParamPattern, [ParamPattern]) -> Tempo -> Int -> IO ()+onTick' backend shape patternsM change ticks = do ps <- readMVar patternsM let ticks' = (fromIntegral ticks) :: Integer+ toM = (toMessage backend) a = ticks' % ticksPerCycle b = (ticks' + 1) % ticksPerCycle- messages = mapMaybe - (toMessage s shape change ticks) + messages = mapMaybe+ (toM shape change ticks) (seqToRelOnsets (a, b) $ fst ps) E.catch (sequence_ messages) (\msg -> putStrLn $ "oops " ++ show (msg :: E.SomeException)) return () -make :: (a -> Datum) -> OscShape -> String -> Pattern a -> OscPattern-make toOsc s nm p = fmap (\x -> Map.singleton nParam (defaultV x)) p+make :: (a -> Value) -> Shape -> String -> Pattern a -> ParamPattern+make toValue s nm p = fmap (\x -> Map.singleton nParam (defaultV x)) p where nParam = param s nm- defaultV a = Just $ toOsc a- --defaultV Nothing = defaultDatum nParam+ defaultV a = Just $ toValue a+ --defaultV Nothing = defaultValue nParam -nudge :: Pattern Double -> OscPattern-nudge p = fmap (\x -> Map.singleton (F "nudge" (Just 0)) (Just $ float x)) p- -makeS = make string+makeS = make VS -makeF :: OscShape -> String -> Pattern Double -> OscPattern-makeF = make float+makeF :: Shape -> String -> Pattern Double -> ParamPattern+makeF = make VF -makeI :: OscShape -> String -> Pattern Int -> OscPattern-makeI = make int32+makeI :: Shape -> String -> Pattern Int -> ParamPattern+makeI = make VI -param :: OscShape -> String -> Param+param :: Shape -> String -> Param param shape n = head $ filter (\x -> name x == n) (params shape) -merge :: OscPattern -> OscPattern -> OscPattern+merge :: ParamPattern -> ParamPattern -> ParamPattern merge x y = (flip Map.union) <$> x <*> y infixl 1 |=|-(|=|) :: OscPattern -> OscPattern -> OscPattern+(|=|) :: ParamPattern -> ParamPattern -> ParamPattern (|=|) = merge (#) = (|=|) -mergeWith op x y = (Map.unionWithKey f) <$> x <*> y- where f (F _ _) (Just a) (Just b) = do a' <- datum_float a- b' <- datum_float b- return $ float (op a' b')- f _ a b = b+mergeWith op x y = (Map.unionWithKey op) <$> x <*> y +mergeWith+ :: (Ord k, Applicative f) =>+ (k -> a -> a -> a)+ -> f (Map.Map k a) -> f (Map.Map k a) -> f (Map.Map k a)++mergeNumWith intOp floatOp = mergeWith f+ where f (F _ _) (Just (VF a)) (Just (VF b)) = Just (VF $ floatOp a b)+ f (I _ _) (Just (VI a)) (Just (VI b)) = Just (VI $ intOp a b)+ f _ _ b = b++mergePlus = mergeWith f+ where f (F _ _) (Just (VF a)) (Just (VF b)) = Just (VF $ a + b)+ f (I _ _) (Just (VI a)) (Just (VI b)) = Just (VI $ a + b)+ f (S _ _) (Just (VS a)) (Just (VS b)) = Just (VS $ a ++ b)+ f _ _ b = b++ infixl 1 |*|-(|*|) :: OscPattern -> OscPattern -> OscPattern-(|*|) = mergeWith (*)+(|*|) :: ParamPattern -> ParamPattern -> ParamPattern+(|*|) = mergeNumWith (*) (*) infixl 1 |+|-(|+|) :: OscPattern -> OscPattern -> OscPattern-(|+|) = mergeWith (+)+(|+|) :: ParamPattern -> ParamPattern -> ParamPattern+(|+|) = mergePlus infixl 1 |-|-(|-|) :: OscPattern -> OscPattern -> OscPattern-(|-|) = mergeWith (-)+(|-|) :: ParamPattern -> ParamPattern -> ParamPattern+(|-|) = mergeNumWith (-) (-) infixl 1 |/|-(|/|) :: OscPattern -> OscPattern -> OscPattern-(|/|) = mergeWith (/)+(|/|) :: ParamPattern -> ParamPattern -> ParamPattern+(|/|) = mergeNumWith (div) (/) setter :: MVar (a, [a]) -> a -> IO () setter ds p = do ps <- takeMVar ds putMVar ds $ (p, p:snd ps) return ()+
Sound/Tidal/SuperCollider.hs view
@@ -6,20 +6,28 @@ import Sound.Tidal.Pattern import Sound.Tidal.Parse import Sound.OSC.FD+import Sound.Tidal.OscStream -supercollider :: String -> [Param] -> Double -> OscShape-supercollider n ps l = OscShape { - -- The OSC path- path = "/s_new",-preamble = [string n, int32 (-1), int32 1, int32 1],- namedParams = True,+supercollider :: [Param] -> Double -> Shape+supercollider ps l = Shape { params = ps, cpsStamp = False,- timestamp = BundleStamp, latency = l } -scStream n ps l = do let shape = (supercollider n ps l)- sc <- stream "127.0.0.1" 57110 shape- return (sc, shape)+scSlang n = OscSlang {+ -- The OSC path+ path = "/s_new",+ preamble = [string n, int32 (-1), int32 1, int32 1],+ namedParams = True,+ timestamp = BundleStamp+ } +scBackend n = do+ s <- makeConnection "127.0.0.1" 57110 (scSlang n)+ return $ Backend s++scStream n ps l = do let shape = (supercollider ps l)+ backend <- scBackend n+ sc <- stream backend shape+ return (sc, shape)
+ Sound/Tidal/Synth.hs view
@@ -0,0 +1,18 @@+module Sound.Tidal.Synth where++import Sound.Tidal.Params+import Sound.Tidal.MIDI.Control+import Sound.Tidal.MIDI.Params++synthController :: ControllerShape+synthController = ControllerShape {+ controls = [+ mCC modwheel_p 1,+ mCC pan_p 10,+ mCC expression_p 11,+ mCC sustainpedal_p 64+ ],+ latency = 0.01+ }++synth = toShape synthController
Sound/Tidal/Transition.hs view
@@ -1,6 +1,5 @@ module Sound.Tidal.Transition where -import Sound.Tidal.Dirt import Sound.Tidal.Stream import Sound.Tidal.Pattern import Sound.Tidal.Time@@ -12,7 +11,7 @@ import Data.Monoid -transition :: (IO Time) -> MVar (OscPattern, [OscPattern]) -> (Time -> [OscPattern] -> OscPattern) -> OscPattern -> IO ()+transition :: (IO Time) -> MVar (ParamPattern, [ParamPattern]) -> (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO () transition getNow mv f p = do now <- getNow ps <- takeMVar mv@@ -24,19 +23,29 @@ return () -- Pans the last n versions of the pattern across the field-histpan :: Int -> Time -> [OscPattern] -> OscPattern-histpan _ _ [] = silence-histpan 0 _ _ = silence-histpan n _ ps = stack $ map (\(i,p) -> p # pan (atom $ (fromIntegral i) / (fromIntegral n'))) (enumerate ps')+histpan' :: Double -> Int -> Time -> [ParamPattern] -> ParamPattern+histpan' _ _ _ [] = silence+histpan' _ 0 _ _ = silence+histpan' scalepan n _ ps = stack $ map (\(i,p) -> p # pan (atom $ ((fromIntegral i) / (fromIntegral n'))*scalepan)) (enumerate ps') where ps' = take n ps n' = length ps' -- in case there's fewer patterns than requested +-- Pans the last n versions of the pattern across the field, where pan+-- goes from 0 to 1+histpan :: Int -> Time -> [ParamPattern] -> ParamPattern+histpan = histpan' 1++-- Pans the last n versions of the pattern across the field, where pan+-- goes from 0 to 2+histpan2 :: Int -> Time -> [ParamPattern] -> ParamPattern+histpan2 = histpan' 2+ -- generalizing wash to use pattern transformers on fadeout, fadein, and delay -- to start of transition superwash :: (Pattern a -> Pattern a) -> (Pattern a -> Pattern a) -> Time -> Time -> Time -> [Pattern a] -> Pattern a superwash _ _ _ _ _ [] = silence superwash _ _ _ _ _ (p:[]) = p-superwash fout fin delay dur now (p:p':_) = +superwash fout fin delay dur now (p:p':_) = (playWhen (< (now + delay)) p') <> (playWhen (between (now + delay) (now + delay + dur)) $ fout p') <> (playWhen (>= (now + delay + dur)) $ fin p)@@ -48,38 +57,28 @@ wash _ _ _ (p:[]) = p wash f t now (p:p':_) = overlay (playWhen (< (now + t)) $ f p') (playWhen (>= (now + t)) p) --- Increase comb filter to anticipate 'drop' to next pattern-anticipateIn :: Time -> Time -> [OscPattern] -> OscPattern-anticipateIn t now = wash (spread' (stut 8 0.2) (now ~> (slow t $ (toRational . (1-)) <$> envL))) t now -anticipate :: Time -> [OscPattern] -> OscPattern-anticipate = anticipateIn 8- -- Just stop for a bit before playing new pattern-wait :: Time -> Time -> [OscPattern] -> OscPattern+wait :: Time -> Time -> [ParamPattern] -> ParamPattern wait t _ [] = silence wait t now (p:_) = playWhen (>= (nextSam (now+t-1))) p -- transition at cycle boundary after n cycles-jumpIn' :: Int -> Time -> [OscPattern] -> OscPattern+jumpIn' :: Int -> Time -> [ParamPattern] -> ParamPattern jumpIn' n now = superwash id id ((nextSam now) - now + (fromIntegral n)) 0 now -- sharp transition a certain number of cycles in the future-jumpIn :: Int -> Time -> [OscPattern] -> OscPattern+jumpIn :: Int -> Time -> [ParamPattern] -> ParamPattern jumpIn n = superwash id id (fromIntegral n) 0 -jump :: Time -> [OscPattern] -> OscPattern+jump :: Time -> [ParamPattern] -> ParamPattern jump = jumpIn 0 -- transition at next cycle boundary where cycle mod n == 0-jumpMod :: Int -> Time -> [OscPattern] -> OscPattern+jumpMod :: Int -> Time -> [ParamPattern] -> ParamPattern jumpMod n now = jumpIn ((n-1) - ((floor now) `mod` n)) now -- Degrade the new pattern over time until it goes to nothing-mortal :: Time -> Time -> Time -> [OscPattern] -> OscPattern+mortal :: Time -> Time -> Time -> [ParamPattern] -> ParamPattern mortal _ _ _ [] = silence mortal lifespan release now (p:_) = overlay (playWhen (<(now+lifespan)) p) (playWhen (>= (now+lifespan)) (fadeOut' (now + lifespan) release p))--dirtSetters :: IO Time -> IO (OscPattern -> IO (), (Time -> [OscPattern] -> OscPattern) -> OscPattern -> IO ())-dirtSetters getNow = do ds <- dirtState- return (setter ds, transition getNow ds)
tidal.cabal view
@@ -1,7 +1,7 @@ name: tidal-version: 0.6+version: 0.7 synopsis: Pattern language for improvised music--- description: +-- description: homepage: http://tidal.lurk.org/ license: GPL-3 license-file: LICENSE@@ -22,6 +22,13 @@ Sound.Tidal.Dirt Sound.Tidal.Pattern Sound.Tidal.Stream+ Sound.Tidal.OscStream+ Sound.Tidal.MidiStream+ Sound.Tidal.MIDI.Device+ Sound.Tidal.MIDI.Params+ Sound.Tidal.MIDI.Control+ Sound.Tidal.Synth+ Sound.Tidal.SerialStream Sound.Tidal.Parse Sound.Tidal.Tempo Sound.Tidal.Time@@ -31,4 +38,4 @@ Sound.Tidal.Params Sound.Tidal.Transition - Build-depends: base < 5, process, parsec, hosc > 0.13, hashable, colour, containers, time, websockets > 0.8, text, mtl >=2.1, transformers, mersenne-random-pure64,binary, bytestring, hmt+ Build-depends: base < 5, process, parsec, hosc > 0.13, hashable, colour, containers, time, websockets > 0.8, text, mtl >=2.1, transformers, mersenne-random-pure64,binary, bytestring, hmt, PortMidi >= 0.1.5, serialport >= 0.4.7
tidal.el view
@@ -57,16 +57,16 @@ (tidal-send-string ":set prompt \"\"") (tidal-send-string ":module Sound.Tidal.Context") (tidal-send-string "(cps, getNow) <- bpsUtils")- (tidal-send-string "(d1,t1) <- dirtSetters getNow")- (tidal-send-string "(d2,t2) <- dirtSetters getNow")- (tidal-send-string "(d3,t3) <- dirtSetters getNow")- (tidal-send-string "(d4,t4) <- dirtSetters getNow")- (tidal-send-string "(d5,t5) <- dirtSetters getNow")- (tidal-send-string "(d6,t6) <- dirtSetters getNow")- (tidal-send-string "(d7,t7) <- dirtSetters getNow")- (tidal-send-string "(d8,t8) <- dirtSetters getNow")- (tidal-send-string "(d9,t9) <- dirtSetters getNow")- (tidal-send-string "(d10,t10) <- dirtSetters getNow")+ (tidal-send-string "(d1,t1) <- superDirtSetters getNow")+ (tidal-send-string "(d2,t2) <- superDirtSetters getNow")+ (tidal-send-string "(d3,t3) <- superDirtSetters getNow")+ (tidal-send-string "(d4,t4) <- superDirtSetters getNow")+ (tidal-send-string "(d5,t5) <- superDirtSetters getNow")+ (tidal-send-string "(d6,t6) <- superDirtSetters getNow")+ (tidal-send-string "(d7,t7) <- superDirtSetters getNow")+ (tidal-send-string "(d8,t8) <- superDirtSetters getNow")+ (tidal-send-string "(d9,t9) <- superDirtSetters getNow")+ (tidal-send-string "(d10,t10) <- superDirtSetters getNow") (tidal-send-string "let bps x = cps (x/2)") (tidal-send-string "let hush = mapM_ ($ silence) [d1,d2,d3,d4,d5,d6,d7,d8,d9,d10]") (tidal-send-string "let solo = (>>) hush")