packages feed

hsc3-lang 0.14 → 0.15

raw patch · 34 files changed

+3490/−2377 lines, 34 filesdep +data-ordlistdep +dlistdep +hashabledep ~hoscdep ~hsc3PVP ok

version bump matches the API change (PVP)

Dependencies added: data-ordlist, dlist, hashable, vector

Dependency ranges changed: hosc, hsc3

API changes (from Hackage documentation)

- Sound.SC3.Lang.Control.Duration: class Durational d where delta = occ fwd = occ
- Sound.SC3.Lang.Control.Duration: instance Durational Dur
- Sound.SC3.Lang.Control.Midi: K :: (Map (a, a) Node_Id) -> Node_Id -> K a
- Sound.SC3.Lang.Control.Midi: data K a
- Sound.SC3.Lang.Control.Midi: k_alloc :: (Int, Int) -> KT Node_Id
- Sound.SC3.Lang.Control.Midi: k_get :: (Int, Int) -> KT Node_Id
- Sound.SC3.Lang.Control.Midi: k_init :: Node_Id -> K a
- Sound.SC3.Lang.Control.Midi: start_midi :: (UDP -> Midi_Receiver IO Int) -> IO ()
- Sound.SC3.Lang.Control.Midi: type KT = StateT (K Int) IO
- Sound.SC3.Lang.Control.Midi: type Midi_Receiver m n = Midi_Message n -> Int -> m ()
- Sound.SC3.Lang.Control.OverlapTexture: overlapTextureP :: OverlapTexture -> UGen -> P Event
- Sound.SC3.Lang.Control.OverlapTexture: overlapTextureP_st :: OverlapTexture -> USTF st -> st -> P Event
- Sound.SC3.Lang.Control.OverlapTexture: overlapTexture_dt :: OverlapTexture -> Texture_DT
- Sound.SC3.Lang.Control.OverlapTexture: post_process_a :: Transport m => P Event -> Int -> (UGen -> UGen) -> m ()
- Sound.SC3.Lang.Control.OverlapTexture: type Texture_DT = (Double, Double)
- Sound.SC3.Lang.Control.OverlapTexture: xfadeTextureP :: XFadeTexture -> UGen -> P Event
- Sound.SC3.Lang.Control.OverlapTexture: xfadeTexture_dt :: XFadeTexture -> Texture_DT
- Sound.SC3.Lang.Pattern.ID: (<|) :: F_Value v => Key -> P v -> P_Bind
- Sound.SC3.Lang.Pattern.ID: P :: Either a [a] -> P a
- Sound.SC3.Lang.Pattern.ID: data P a
- Sound.SC3.Lang.Pattern.ID: inf :: Int
- Sound.SC3.Lang.Pattern.ID: instance Alternative P
- Sound.SC3.Lang.Pattern.ID: instance Applicative P
- Sound.SC3.Lang.Pattern.ID: instance Audible (P Event)
- Sound.SC3.Lang.Pattern.ID: instance Eq a => Eq (P a)
- Sound.SC3.Lang.Pattern.ID: instance Foldable P
- Sound.SC3.Lang.Pattern.ID: instance Fractional a => Fractional (P a)
- Sound.SC3.Lang.Pattern.ID: instance Functor P
- Sound.SC3.Lang.Pattern.ID: instance Monad P
- Sound.SC3.Lang.Pattern.ID: instance MonadPlus P
- Sound.SC3.Lang.Pattern.ID: instance Monoid (P a)
- Sound.SC3.Lang.Pattern.ID: instance Num a => Num (P a)
- Sound.SC3.Lang.Pattern.ID: instance Ord a => Ord (P a)
- Sound.SC3.Lang.Pattern.ID: instance OrdE a => OrdE (P a)
- Sound.SC3.Lang.Pattern.ID: instance Show a => Show (P a)
- Sound.SC3.Lang.Pattern.ID: instance Traversable P
- Sound.SC3.Lang.Pattern.ID: liftP :: ([a] -> [b]) -> P a -> P b
- Sound.SC3.Lang.Pattern.ID: liftP2 :: ([a] -> [b] -> [c]) -> P a -> P b -> P c
- Sound.SC3.Lang.Pattern.ID: liftP2_repeat :: ([a] -> [b] -> [c]) -> P a -> P b -> P c
- Sound.SC3.Lang.Pattern.ID: liftP3 :: ([a] -> [b] -> [c] -> [d]) -> P a -> P b -> P c -> P d
- Sound.SC3.Lang.Pattern.ID: liftP3_repeat :: ([a] -> [b] -> [c] -> [d]) -> P a -> P b -> P c -> P d
- Sound.SC3.Lang.Pattern.ID: nan :: Floating a => a
- Sound.SC3.Lang.Pattern.ID: pNRT :: P Event -> NRT
- Sound.SC3.Lang.Pattern.ID: p_time :: P Event -> P Time
- Sound.SC3.Lang.Pattern.ID: p_un_mce :: P Event -> P Event
- Sound.SC3.Lang.Pattern.ID: p_with :: P_Bind -> P Event -> P Event
- Sound.SC3.Lang.Pattern.ID: padd :: P_Bind -> P Event -> P Event
- Sound.SC3.Lang.Pattern.ID: pappend :: P a -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: pbind :: [P_Bind] -> P Event
- Sound.SC3.Lang.Pattern.ID: pbool :: (Ord a, Num a) => P a -> P Bool
- Sound.SC3.Lang.Pattern.ID: pbrown :: (Enum e, Random n, Num n, Ord n) => e -> n -> n -> n -> Int -> P n
- Sound.SC3.Lang.Pattern.ID: pbrown' :: (Enum e, Random n, Num n, Ord n) => e -> P n -> P n -> P n -> Int -> P n
- Sound.SC3.Lang.Pattern.ID: pbrownM :: (UId m, Num n, Ord n, Random n) => n -> n -> n -> Int -> m (P n)
- Sound.SC3.Lang.Pattern.ID: pclutch :: P a -> P Bool -> P a
- Sound.SC3.Lang.Pattern.ID: pcollect :: (a -> b) -> P a -> P b
- Sound.SC3.Lang.Pattern.ID: pconcat :: [P a] -> P a
- Sound.SC3.Lang.Pattern.ID: pconcatReplicate :: Int -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: pcons :: a -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: pconst :: (Ord a, Num a) => a -> P a -> a -> P a
- Sound.SC3.Lang.Pattern.ID: pcountpost :: P Bool -> P Int
- Sound.SC3.Lang.Pattern.ID: pcountpre :: P Bool -> P Int
- Sound.SC3.Lang.Pattern.ID: pcycle :: P a -> P a
- Sound.SC3.Lang.Pattern.ID: pdegreeToKey :: RealFrac a => P a -> P [a] -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: pdiff :: Num n => P n -> P n
- Sound.SC3.Lang.Pattern.ID: pdrop :: Int -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: pdurStutter :: Fractional a => P Int -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: pedit :: Key -> (Field -> Field) -> P Event -> P Event
- Sound.SC3.Lang.Pattern.ID: pempty :: P a
- Sound.SC3.Lang.Pattern.ID: pexprand :: (Enum e, Random a, Floating a) => e -> a -> a -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pexprandM :: (UId m, Random a, Floating a) => a -> a -> Int -> m (P a)
- Sound.SC3.Lang.Pattern.ID: pfilter :: (a -> Bool) -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: pfinval :: Int -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: pflop :: [P a] -> P (P a)
- Sound.SC3.Lang.Pattern.ID: pflop' :: [P a] -> P [a]
- Sound.SC3.Lang.Pattern.ID: pfold :: RealFrac n => P n -> n -> n -> P n
- Sound.SC3.Lang.Pattern.ID: pfoldr :: (a -> b -> b) -> b -> P a -> b
- Sound.SC3.Lang.Pattern.ID: pfuncn :: Enum e => e -> (StdGen -> (n, StdGen)) -> Int -> P n
- Sound.SC3.Lang.Pattern.ID: pgeom :: Num a => a -> a -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: phold :: P a -> P a
- Sound.SC3.Lang.Pattern.ID: pif :: P Bool -> P a -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: pinstr :: String -> P Field
- Sound.SC3.Lang.Pattern.ID: pinstr' :: Instr -> P Field
- Sound.SC3.Lang.Pattern.ID: pinterleave :: [P a] -> P a
- Sound.SC3.Lang.Pattern.ID: pinterleave2 :: P a -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: pisPrefixOf :: Eq a => P a -> P a -> Bool
- Sound.SC3.Lang.Pattern.ID: pjoin :: P (P a) -> P a
- Sound.SC3.Lang.Pattern.ID: pjoin_repeat :: P (P a) -> P a
- Sound.SC3.Lang.Pattern.ID: pkey :: Key -> P Event -> P Field
- Sound.SC3.Lang.Pattern.ID: pkey_m :: Key -> P Event -> P (Maybe Field)
- Sound.SC3.Lang.Pattern.ID: place :: [[a]] -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pmap :: (a -> b) -> P a -> P b
- Sound.SC3.Lang.Pattern.ID: pmbind :: P a -> (a -> P b) -> P b
- Sound.SC3.Lang.Pattern.ID: pmce2 :: P Field -> P Field -> P Field
- Sound.SC3.Lang.Pattern.ID: pmce3 :: P Field -> P Field -> P Field -> P Field
- Sound.SC3.Lang.Pattern.ID: pmerge :: P Event -> P Event -> P Event
- Sound.SC3.Lang.Pattern.ID: pmono :: [P_Bind] -> P Event
- Sound.SC3.Lang.Pattern.ID: pmul :: P_Bind -> P Event -> P Event
- Sound.SC3.Lang.Pattern.ID: pmul' :: P_Bind -> P Event -> P Event
- Sound.SC3.Lang.Pattern.ID: pn :: P a -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pnormalizeSum :: Fractional n => P n -> P n
- Sound.SC3.Lang.Pattern.ID: pnull :: P a -> Bool
- Sound.SC3.Lang.Pattern.ID: ppar :: [P Event] -> P Event
- Sound.SC3.Lang.Pattern.ID: ppatlace :: [P a] -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: ppure :: a -> P a
- Sound.SC3.Lang.Pattern.ID: prand :: Enum e => e -> [P a] -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: prand' :: Enum e => e -> [P a] -> Int -> P (P a)
- Sound.SC3.Lang.Pattern.ID: prandM :: UId m => [P a] -> Int -> m (P a)
- Sound.SC3.Lang.Pattern.ID: preject :: (a -> Bool) -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: prepeat :: a -> P a
- Sound.SC3.Lang.Pattern.ID: preplicate :: Int -> a -> P a
- Sound.SC3.Lang.Pattern.ID: preturn :: a -> P a
- Sound.SC3.Lang.Pattern.ID: prorate :: Num a => P (Either a [a]) -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: prorate' :: Num a => Either a [a] -> a -> P a
- Sound.SC3.Lang.Pattern.ID: prsd :: Eq a => P a -> P a
- Sound.SC3.Lang.Pattern.ID: pscanl :: (a -> b -> a) -> a -> P b -> P a
- Sound.SC3.Lang.Pattern.ID: pselect :: (a -> Bool) -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: pseq :: [P a] -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pseq1 :: [P a] -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pseqn :: [Int] -> [P a] -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pseqr :: (Int -> [P a]) -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pser :: [P a] -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pser1 :: [P a] -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pseries :: Num a => a -> a -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pshuf :: Enum e => e -> [a] -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pshufM :: UId m => [a] -> Int -> m (P a)
- Sound.SC3.Lang.Pattern.ID: pslide :: [a] -> Int -> Int -> Int -> Int -> Bool -> P a
- Sound.SC3.Lang.Pattern.ID: psplitAt :: Int -> P a -> (P a, P a)
- Sound.SC3.Lang.Pattern.ID: psplitPlaces :: P Int -> P a -> P (P a)
- Sound.SC3.Lang.Pattern.ID: psplitPlaces' :: P Int -> P a -> P [a]
- Sound.SC3.Lang.Pattern.ID: pstretch :: P Field -> P Event -> P Event
- Sound.SC3.Lang.Pattern.ID: pstutter :: P Int -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: pswitch :: [P a] -> P Int -> P a
- Sound.SC3.Lang.Pattern.ID: pswitch1 :: [P a] -> P Int -> P a
- Sound.SC3.Lang.Pattern.ID: psynth :: Synthdef -> P Field
- Sound.SC3.Lang.Pattern.ID: ptail :: P a -> P a
- Sound.SC3.Lang.Pattern.ID: ptake :: Int -> P a -> P a
- Sound.SC3.Lang.Pattern.ID: ptmerge :: (Time, P Event) -> (Time, P Event) -> P Event
- Sound.SC3.Lang.Pattern.ID: ptpar :: [(Time, P Event)] -> P Event
- Sound.SC3.Lang.Pattern.ID: ptranspose :: [P a] -> P [a]
- Sound.SC3.Lang.Pattern.ID: ptranspose_st_repeat :: [P a] -> P [a]
- Sound.SC3.Lang.Pattern.ID: ptraverse :: Applicative f => (a -> f b) -> P a -> f (P b)
- Sound.SC3.Lang.Pattern.ID: ptrigger :: P Bool -> P a -> P (Maybe a)
- Sound.SC3.Lang.Pattern.ID: ptuple :: [P a] -> Int -> P [a]
- Sound.SC3.Lang.Pattern.ID: punion :: P Event -> P Event -> P Event
- Sound.SC3.Lang.Pattern.ID: punzip :: P (a, b) -> (P a, P b)
- Sound.SC3.Lang.Pattern.ID: pwhite :: (Random n, Enum e) => e -> n -> n -> Int -> P n
- Sound.SC3.Lang.Pattern.ID: pwhite' :: (Enum e, Random n) => e -> P n -> P n -> P n
- Sound.SC3.Lang.Pattern.ID: pwhiteM :: (UId m, Random n) => n -> n -> Int -> m (P n)
- Sound.SC3.Lang.Pattern.ID: pwhitei :: (RealFracE n, Random n, Enum e) => e -> n -> n -> Int -> P n
- Sound.SC3.Lang.Pattern.ID: pwhiteiM :: (UId m, RealFracE n, Random n) => n -> n -> Int -> m (P n)
- Sound.SC3.Lang.Pattern.ID: pwrand :: Enum e => e -> [P a] -> [Double] -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pwrandM :: UId m => [P a] -> [Double] -> Int -> m (P a)
- Sound.SC3.Lang.Pattern.ID: pwrap :: (Ord a, Num a) => P a -> a -> a -> P a
- Sound.SC3.Lang.Pattern.ID: pxrand :: Enum e => e -> [P a] -> Int -> P a
- Sound.SC3.Lang.Pattern.ID: pxrandM :: UId m => [P a] -> Int -> m (P a)
- Sound.SC3.Lang.Pattern.ID: pzip :: P a -> P b -> P (a, b)
- Sound.SC3.Lang.Pattern.ID: pzip3 :: P a -> P b -> P c -> P (a, b, c)
- Sound.SC3.Lang.Pattern.ID: pzipWith :: (a -> b -> c) -> P a -> P b -> P c
- Sound.SC3.Lang.Pattern.ID: pzipWith3 :: (a -> b -> c -> d) -> P a -> P b -> P c -> P d
- Sound.SC3.Lang.Pattern.ID: toP :: [a] -> P a
- Sound.SC3.Lang.Pattern.ID: type P_Bind = (Key, P Field)
- Sound.SC3.Lang.Pattern.ID: unP :: P a -> [a]
- Sound.SC3.Lang.Pattern.ID: unP_either :: P a -> Either a [a]
- Sound.SC3.Lang.Pattern.ID: unP_repeat :: P a -> [a]
- Sound.SC3.Lang.Pattern.ID: undecided :: a -> P a
- Sound.SC3.Lang.Pattern.List: all_just :: [Maybe a] -> Maybe [a]
- Sound.SC3.Lang.Pattern.List: brown' :: (Enum e, Random n, Num n, Ord n) => e -> [n] -> [n] -> [n] -> [n]
- Sound.SC3.Lang.Pattern.List: brown_ :: (RandomGen g, Random n, Num n, Ord n) => (n, n, n) -> (n, g) -> (n, g)
- Sound.SC3.Lang.Pattern.List: lindex :: [a] -> Int -> Maybe a
- Sound.SC3.Lang.Pattern.List: mcycle :: Monoid a => a -> a
- Sound.SC3.Lang.Pattern.List: rsd :: Eq a => [a] -> [a]
- Sound.SC3.Lang.Pattern.List: segment :: [a] -> Int -> (Int, Int) -> [a]
- Sound.SC3.Lang.Pattern.List: take_inf :: Int -> [a] -> [a]
- Sound.SC3.Lang.Pattern.List: transpose_fw :: Int -> [[a]] -> [[Maybe a]]
- Sound.SC3.Lang.Pattern.List: transpose_fw_def :: a -> Int -> [[a]] -> [[a]]
- Sound.SC3.Lang.Pattern.List: transpose_fw_def' :: a -> [[a]] -> [[a]]
- Sound.SC3.Lang.Pattern.List: transpose_st :: [[a]] -> [[a]]
- Sound.SC3.Lang.Pattern.List: uncons :: [a] -> (Maybe a, [a])
- Sound.SC3.Lang.Pattern.List: wrand' :: (Enum e, Fractional n, Ord n, Random n) => e -> [[a]] -> [n] -> [[a]]
+ Sound.SC3.Lang.Collection: absdif :: Num a => a -> a -> a
+ Sound.SC3.Lang.Collection: asRandomTable :: (TernaryOp a, Enum a, RealFrac a) => Int -> [a] -> [a]
+ Sound.SC3.Lang.Collection: blend :: Num a => a -> a -> a -> a
+ Sound.SC3.Lang.Collection: blendAt :: RealFrac a => a -> [a] -> a
+ Sound.SC3.Lang.Collection: blendAtBy :: (Integral i, RealFrac n) => (i -> t -> n) -> n -> t -> n
+ Sound.SC3.Lang.Collection: clipAt :: Int -> [a] -> a
+ Sound.SC3.Lang.Collection: normalize :: (TernaryOp b, Fractional b, Ord b) => b -> b -> [b] -> [b]
+ Sound.SC3.Lang.Collection: resamp1 :: (Enum n, RealFrac n) => Int -> [n] -> [n]
+ Sound.SC3.Lang.Collection: resamp1_gen :: (Integral i, RealFrac n) => i -> i -> (i -> t -> n) -> t -> i -> n
+ Sound.SC3.Lang.Collection: sineFill :: (TernaryOp n, Ord n, Floating n, Enum n) => Int -> [n] -> [n] -> [n]
+ Sound.SC3.Lang.Collection: sineGen :: (Floating n, Enum n) => Int -> [n] -> [n] -> [[n]]
+ Sound.SC3.Lang.Collection: slide1 :: Integral i => [i] -> [i] -> [a] -> [[a]]
+ Sound.SC3.Lang.Collection: slide2 :: Integral i => [i] -> [i] -> [a] -> [a]
+ Sound.SC3.Lang.Collection: stutter1 :: Integral i => [i] -> [a] -> [[a]]
+ Sound.SC3.Lang.Collection: stutter2 :: Integral i => [i] -> [a] -> [a]
+ Sound.SC3.Lang.Collection.Array: blendAt :: RealFrac a => a -> Array Int a -> a
+ Sound.SC3.Lang.Collection.Array: clipAt :: Int -> Array Int a -> a
+ Sound.SC3.Lang.Collection.Array: resamp1 :: (Enum n, RealFrac n) => Int -> Array Int n -> Array Int n
+ Sound.SC3.Lang.Collection.Numerical.Extending: instance Enum a => Enum [a]
+ Sound.SC3.Lang.Collection.Numerical.Extending: instance Integral a => Integral [a]
+ Sound.SC3.Lang.Collection.Numerical.Extending: instance Real a => Real [a]
+ Sound.SC3.Lang.Collection.Vector: blendAt :: RealFrac a => a -> Vector a -> a
+ Sound.SC3.Lang.Collection.Vector: clipAt :: Int -> Vector a -> a
+ Sound.SC3.Lang.Collection.Vector: resamp1 :: (Enum n, RealFrac n) => Int -> Vector n -> Vector n
+ Sound.SC3.Lang.Control.Duration: class Duration d where occ = delta fwd = delta
+ Sound.SC3.Lang.Control.Duration: duration :: Duration d => d -> (Double, Double, Double)
+ Sound.SC3.Lang.Control.Duration: instance Duration Double
+ Sound.SC3.Lang.Control.Duration: instance Duration Dur
+ Sound.SC3.Lang.Control.Duration: instance Duration Float
+ Sound.SC3.Lang.Control.Duration: instance Duration Int
+ Sound.SC3.Lang.Control.Duration: instance Duration Integer
+ Sound.SC3.Lang.Control.Duration: instance Integral i => Duration (Ratio i)
+ Sound.SC3.Lang.Control.Midi: KY :: (Map a Node_Id) -> Node_Id -> KY a
+ Sound.SC3.Lang.Control.Midi: data KY a
+ Sound.SC3.Lang.Control.Midi: iterateM_ :: Monad m => st -> (st -> m st) -> m ()
+ Sound.SC3.Lang.Control.Midi: ky_all :: KY a -> [Node_Id]
+ Sound.SC3.Lang.Control.Midi: ky_alloc :: Ord a => KY a -> a -> (KY a, Node_Id)
+ Sound.SC3.Lang.Control.Midi: ky_free :: Ord a => KY a -> a -> (KY a, Node_Id)
+ Sound.SC3.Lang.Control.Midi: ky_get :: Ord a => KY a -> a -> Node_Id
+ Sound.SC3.Lang.Control.Midi: ky_init :: Node_Id -> KY a
+ Sound.SC3.Lang.Control.Midi: run_midi :: Midi_Init_f st -> Midi_Recv_f st -> IO ()
+ Sound.SC3.Lang.Control.Midi: type Midi_Init_f st = UDP -> IO st
+ Sound.SC3.Lang.Control.Midi: type Midi_Recv_f st = UDP -> st -> Midi_Message Int -> IO st
+ Sound.SC3.Lang.Control.Midi.ST: p3_fst :: (t, u, v) -> t
+ Sound.SC3.Lang.Control.Midi.ST: p3_third :: (t, u, v) -> v
+ Sound.SC3.Lang.Control.Midi.ST: st_access_cc :: (Midi_CC_Map -> r) -> Midi_State -> IO r
+ Sound.SC3.Lang.Control.Midi.ST: st_access_km :: (Midi_Key_Map -> r) -> Midi_State -> IO r
+ Sound.SC3.Lang.Control.Midi.ST: st_chord :: Midi_State -> IO [Midi_Note]
+ Sound.SC3.Lang.Control.Midi.ST: st_edit_cc :: Midi_State -> (Midi_CC_Ix, Midi_CC_Value) -> IO Midi_State
+ Sound.SC3.Lang.Control.Midi.ST: st_edit_km :: Midi_State -> (Midi_Note, Midi_Velocity) -> IO Midi_State
+ Sound.SC3.Lang.Control.Midi.ST: st_edit_pc :: Midi_State -> Midi_Program -> IO Midi_State
+ Sound.SC3.Lang.Control.Midi.ST: st_init_f :: Midi_State -> Midi_Init_f Midi_State
+ Sound.SC3.Lang.Control.Midi.ST: st_read_cc :: Midi_State -> Midi_CC_Ix -> IO Midi_CC_Value
+ Sound.SC3.Lang.Control.Midi.ST: st_read_note :: Midi_State -> Midi_Note -> IO (Maybe Midi_Velocity)
+ Sound.SC3.Lang.Control.Midi.ST: st_recv_f :: Midi_Recv_f Midi_State
+ Sound.SC3.Lang.Control.Midi.ST: st_run :: IO (Midi_State, ThreadId)
+ Sound.SC3.Lang.Control.Midi.ST: type Midi_7bit = Int
+ Sound.SC3.Lang.Control.Midi.ST: type Midi_CC_Ix = Midi_7bit
+ Sound.SC3.Lang.Control.Midi.ST: type Midi_CC_Map = Map Midi_CC_Ix Midi_CC_Value
+ Sound.SC3.Lang.Control.Midi.ST: type Midi_CC_Value = Midi_7bit
+ Sound.SC3.Lang.Control.Midi.ST: type Midi_Key_Map = Map Midi_Note Midi_Velocity
+ Sound.SC3.Lang.Control.Midi.ST: type Midi_Note = Midi_7bit
+ Sound.SC3.Lang.Control.Midi.ST: type Midi_Program = Midi_7bit
+ Sound.SC3.Lang.Control.Midi.ST: type Midi_State = MVar (Midi_Key_Map, Midi_Program, Midi_CC_Map)
+ Sound.SC3.Lang.Control.Midi.ST: type Midi_Velocity = Midi_7bit
+ Sound.SC3.Lang.Control.OverlapTexture: gen_nm :: UGen -> String
+ Sound.SC3.Lang.Control.OverlapTexture: gen_synth' :: UGen -> Env_ST Double -> UGen -> Synthdef
+ Sound.SC3.Lang.Control.OverlapTexture: nrt_sy :: Int -> [Synthdef] -> [Time] -> NRT
+ Sound.SC3.Lang.Control.OverlapTexture: nrt_sy1 :: Int -> Synthdef -> [Double] -> NRT
+ Sound.SC3.Lang.Control.OverlapTexture: overlapTexture_iot :: OverlapTexture -> Double
+ Sound.SC3.Lang.Control.OverlapTexture: overlapTexture_nrt :: Loc_GB -> OverlapTexture -> UGen -> NRT
+ Sound.SC3.Lang.Control.OverlapTexture: overlapTexture_nrt_st :: Loc_GB -> OverlapTexture -> USTF st -> st -> NRT
+ Sound.SC3.Lang.Control.OverlapTexture: post_process :: Transport m => Int -> PP_Bus -> Int -> (UGen -> UGen) -> m ()
+ Sound.SC3.Lang.Control.OverlapTexture: post_process_nrt :: Transport m => Loc_GB -> NRT -> Int -> (UGen -> UGen) -> m ()
+ Sound.SC3.Lang.Control.OverlapTexture: spawnTextureU :: Spawn_Texture -> UGen -> IO ()
+ Sound.SC3.Lang.Control.OverlapTexture: spawnTexture_nrt :: Loc_GB -> Spawn_Texture -> UGen -> NRT
+ Sound.SC3.Lang.Control.OverlapTexture: type Env_ST n = (n, n)
+ Sound.SC3.Lang.Control.OverlapTexture: type Loc_GB = (Int, UGen)
+ Sound.SC3.Lang.Control.OverlapTexture: type PP_Bus = Either UGen (UGen, UGen)
+ Sound.SC3.Lang.Control.OverlapTexture: type Spawn_Texture = (Int -> Double, Int)
+ Sound.SC3.Lang.Control.OverlapTexture: xfadeTexture_iot :: XFadeTexture -> Double
+ Sound.SC3.Lang.Control.OverlapTexture: xfadeTexture_nrt :: Loc_GB -> XFadeTexture -> UGen -> NRT
+ Sound.SC3.Lang.Core: (.:) :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
+ Sound.SC3.Lang.Core: (.::) :: (Functor f, Functor g, Functor h) => (a -> b) -> f (g (h a)) -> f (g (h b))
+ Sound.SC3.Lang.Core: (.:::) :: (Functor f, Functor g, Functor h, Functor i) => (a -> b) -> f (g (h (i a))) -> f (g (h (i b)))
+ Sound.SC3.Lang.Core: (.::::) :: (Functor f, Functor g, Functor h, Functor i, Functor j) => (a -> b) -> f (g (h (i (j a)))) -> f (g (h (i (j b))))
+ Sound.SC3.Lang.Core: (.:::::) :: (Functor f, Functor g, Functor h, Functor i, Functor j, Functor k) => (a -> b) -> f (g (h (i (j (k a))))) -> f (g (h (i (j (k b)))))
+ Sound.SC3.Lang.Core: all_just :: [Maybe a] -> Maybe [a]
+ Sound.SC3.Lang.Core: genericTakeMaybe :: Integral i => i -> [a] -> Maybe [a]
+ Sound.SC3.Lang.Core: lindex :: [a] -> Int -> Maybe a
+ Sound.SC3.Lang.Core: mcycle :: Monoid a => a -> a
+ Sound.SC3.Lang.Core: take_inf :: Int -> [a] -> [a]
+ Sound.SC3.Lang.Core: transpose_fw :: Int -> [[a]] -> [[Maybe a]]
+ Sound.SC3.Lang.Core: transpose_fw_def :: a -> Int -> [[a]] -> [[a]]
+ Sound.SC3.Lang.Core: transpose_fw_def' :: a -> [[a]] -> [[a]]
+ Sound.SC3.Lang.Core: transpose_st :: [[a]] -> [[a]]
+ Sound.SC3.Lang.Core: uncons :: [a] -> (Maybe a, [a])
+ Sound.SC3.Lang.Data.CMUdict: AA :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: AE :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: AH :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: AO :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: AW :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: AX :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: AXR :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: AY :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: Affricate :: Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: Aspirate :: Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: B :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: CH :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: D :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: DH :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: DX :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: Diphthong :: Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: EH :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: EL :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: EM :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: EN :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: ENG :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: ER :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: EY :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: F :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: Fricative :: Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: G :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: HH :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: IH :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: IY :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: JH :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: K :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: L :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: Liquid :: Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: M :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: Monophthong :: Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: N :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: NG :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: NX :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: Nasal :: Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: No_stress :: Stress
+ Sound.SC3.Lang.Data.CMUdict: OW :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: OY :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: P :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: Primary_stress :: Stress
+ Sound.SC3.Lang.Data.CMUdict: Q :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: R :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: R_Coloured :: Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: S :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: SH :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: Secondary_stress :: Stress
+ Sound.SC3.Lang.Data.CMUdict: Semivowel :: Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: Stop :: Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: T :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: TH :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: UH :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: UW :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: V :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: W :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: Y :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: Z :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: ZH :: Phoneme
+ Sound.SC3.Lang.Data.CMUdict: arpabet_classification :: Phoneme -> Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: arpabet_classification_table :: [(Phoneme_Class, [Phoneme])]
+ Sound.SC3.Lang.Data.CMUdict: arpabet_ipa :: ARPABET -> String
+ Sound.SC3.Lang.Data.CMUdict: arpabet_ipa_table :: [(Phoneme, Either String [(Stress, String)])]
+ Sound.SC3.Lang.Data.CMUdict: cmudict_load :: FilePath -> IO CMU_Dict
+ Sound.SC3.Lang.Data.CMUdict: cmudict_load_ty :: (String -> (String, a)) -> FilePath -> IO (CMU_Dict_ty a)
+ Sound.SC3.Lang.Data.CMUdict: cmudict_syl_load :: FilePath -> IO CMU_Dict_syl
+ Sound.SC3.Lang.Data.CMUdict: d_lookup :: CMU_Dict_ty a -> String -> Maybe a
+ Sound.SC3.Lang.Data.CMUdict: d_lookup' :: CMU_Dict_ty a -> String -> Either String a
+ Sound.SC3.Lang.Data.CMUdict: data Phoneme
+ Sound.SC3.Lang.Data.CMUdict: data Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: data Stress
+ Sound.SC3.Lang.Data.CMUdict: instance Bounded Phoneme
+ Sound.SC3.Lang.Data.CMUdict: instance Bounded Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: instance Bounded Stress
+ Sound.SC3.Lang.Data.CMUdict: instance Enum Phoneme
+ Sound.SC3.Lang.Data.CMUdict: instance Enum Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: instance Enum Stress
+ Sound.SC3.Lang.Data.CMUdict: instance Eq Phoneme
+ Sound.SC3.Lang.Data.CMUdict: instance Eq Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: instance Eq Stress
+ Sound.SC3.Lang.Data.CMUdict: instance Ord Phoneme
+ Sound.SC3.Lang.Data.CMUdict: instance Ord Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: instance Ord Stress
+ Sound.SC3.Lang.Data.CMUdict: instance Read Phoneme
+ Sound.SC3.Lang.Data.CMUdict: instance Read Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: instance Read Stress
+ Sound.SC3.Lang.Data.CMUdict: instance Show Phoneme
+ Sound.SC3.Lang.Data.CMUdict: instance Show Phoneme_Class
+ Sound.SC3.Lang.Data.CMUdict: instance Show Stress
+ Sound.SC3.Lang.Data.CMUdict: parse_arpabet :: String -> (String, ARPABET)
+ Sound.SC3.Lang.Data.CMUdict: parse_arpabet_syl :: String -> (String, ARPABET_syl)
+ Sound.SC3.Lang.Data.CMUdict: parse_phoneme_str :: String -> Phoneme_str
+ Sound.SC3.Lang.Data.CMUdict: phoneme_ipa :: Maybe Stress -> Phoneme -> String
+ Sound.SC3.Lang.Data.CMUdict: type ARPABET = [Phoneme_str]
+ Sound.SC3.Lang.Data.CMUdict: type ARPABET_syl = [SYLLABLE]
+ Sound.SC3.Lang.Data.CMUdict: type CMU_Dict = CMU_Dict_ty ARPABET
+ Sound.SC3.Lang.Data.CMUdict: type CMU_Dict_syl = CMU_Dict_ty ARPABET_syl
+ Sound.SC3.Lang.Data.CMUdict: type CMU_Dict_ty a = Map String a
+ Sound.SC3.Lang.Data.CMUdict: type Phoneme_str = (Phoneme, Maybe Stress)
+ Sound.SC3.Lang.Data.CMUdict: type SYLLABLE = [Phoneme_str]
+ Sound.SC3.Lang.Math: degree_to_cps :: (Floating a, RealFrac a) => [a] -> a -> a -> a -> a
+ Sound.SC3.Lang.Math: degree_to_cps' :: (Floating a, RealFrac a) => [a] -> a -> [a] -> [a] -> [a]
+ Sound.SC3.Lang.Math: octpc_to_cps :: Floating a => (a, a) -> a
+ Sound.SC3.Lang.Math: octpc_to_midi :: Num a => (a, a) -> a
+ Sound.SC3.Lang.Math.Warp: warpNamed :: (TernaryOp a, Ord a, Eq a, RealFrac a, Floating a) => String -> Maybe (a -> a -> Warp a)
+ Sound.SC3.Lang.Pattern.Bind: nbind :: [(Synthdef, Int, Param)] -> NRT
+ Sound.SC3.Lang.Pattern.Bind: nbind1 :: (Synthdef, Int, Param) -> NRT
+ Sound.SC3.Lang.Pattern.Bind: nbind_deriv :: (Synthdef, Int, Param) -> [Bundle]
+ Sound.SC3.Lang.Pattern.Bind: nbind_init :: Int -> [(Synthdef, Int, Param)] -> [Bundle]
+ Sound.SC3.Lang.Pattern.Bind: nbind_tseq :: (Synthdef, Int, [Time], Param) -> [Bundle]
+ Sound.SC3.Lang.Pattern.Bind: pr_unused :: Synthdef -> Param -> [String]
+ Sound.SC3.Lang.Pattern.Bind: sbind :: [(Synthdef, Param)] -> NRT
+ Sound.SC3.Lang.Pattern.Bind: sbind1 :: (Synthdef, Param) -> NRT
+ Sound.SC3.Lang.Pattern.Bind: sbind_deriv :: Int -> [Int] -> (Synthdef, Param) -> [Bundle]
+ Sound.SC3.Lang.Pattern.Bind: sbind_init :: Int -> [Synthdef] -> [Bundle]
+ Sound.SC3.Lang.Pattern.Bind: sbind_tseq :: Int -> [Int] -> (Synthdef, [Time], Maybe [Time], Param) -> [Bundle]
+ Sound.SC3.Lang.Pattern.Bind: type Param = [(String, [Double])]
+ Sound.SC3.Lang.Pattern.P.Base: inf :: Int
+ Sound.SC3.Lang.Pattern.P.Base: nan :: Floating a => a
+ Sound.SC3.Lang.Pattern.P.Base: pappend :: P a -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: pbool :: (Ord a, Num a) => P a -> P Bool
+ Sound.SC3.Lang.Pattern.P.Base: pconcat :: [P a] -> P a
+ Sound.SC3.Lang.Pattern.P.Base: pconcatReplicate :: Int -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: pcons :: a -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: pcountpost :: P Bool -> P Int
+ Sound.SC3.Lang.Pattern.P.Base: pcountpre :: P Bool -> P Int
+ Sound.SC3.Lang.Pattern.P.Base: pcycle :: P a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: pempty :: P a
+ Sound.SC3.Lang.Pattern.P.Base: pfilter :: (a -> Bool) -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: pfoldr :: (a -> b -> b) -> b -> P a -> b
+ Sound.SC3.Lang.Pattern.P.Base: phold :: P a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: pinterleave :: [P a] -> P a
+ Sound.SC3.Lang.Pattern.P.Base: pinterleave2 :: P a -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: pisPrefixOf :: Eq a => P a -> P a -> Bool
+ Sound.SC3.Lang.Pattern.P.Base: pjoin :: P (P a) -> P a
+ Sound.SC3.Lang.Pattern.P.Base: pjoin_repeat :: P (P a) -> P a
+ Sound.SC3.Lang.Pattern.P.Base: pmap :: (a -> b) -> P a -> P b
+ Sound.SC3.Lang.Pattern.P.Base: pmbind :: P a -> (a -> P b) -> P b
+ Sound.SC3.Lang.Pattern.P.Base: pnull :: P a -> Bool
+ Sound.SC3.Lang.Pattern.P.Base: ppure :: a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: prepeat :: a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: preplicate :: Int -> a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: preturn :: a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: prsd :: Eq a => P a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: pscanl :: (a -> b -> a) -> a -> P b -> P a
+ Sound.SC3.Lang.Pattern.P.Base: psplitAt :: Int -> P a -> (P a, P a)
+ Sound.SC3.Lang.Pattern.P.Base: psplitPlaces :: P Int -> P a -> P (P a)
+ Sound.SC3.Lang.Pattern.P.Base: psplitPlaces' :: P Int -> P a -> P [a]
+ Sound.SC3.Lang.Pattern.P.Base: ptail :: P a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: ptake :: Int -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.Base: ptranspose :: [P a] -> P [a]
+ Sound.SC3.Lang.Pattern.P.Base: ptranspose_st_repeat :: [P a] -> P [a]
+ Sound.SC3.Lang.Pattern.P.Base: ptraverse :: Applicative f => (a -> f b) -> P a -> f (P b)
+ Sound.SC3.Lang.Pattern.P.Base: ptrigger :: P Bool -> P a -> P (Maybe a)
+ Sound.SC3.Lang.Pattern.P.Core: P :: Either a [a] -> P a
+ Sound.SC3.Lang.Pattern.P.Core: data P a
+ Sound.SC3.Lang.Pattern.P.Core: instance Alternative P
+ Sound.SC3.Lang.Pattern.P.Core: instance Applicative P
+ Sound.SC3.Lang.Pattern.P.Core: instance Eq a => Eq (P a)
+ Sound.SC3.Lang.Pattern.P.Core: instance Foldable P
+ Sound.SC3.Lang.Pattern.P.Core: instance Fractional a => Fractional (P a)
+ Sound.SC3.Lang.Pattern.P.Core: instance Functor P
+ Sound.SC3.Lang.Pattern.P.Core: instance Monad P
+ Sound.SC3.Lang.Pattern.P.Core: instance MonadPlus P
+ Sound.SC3.Lang.Pattern.P.Core: instance Monoid (P a)
+ Sound.SC3.Lang.Pattern.P.Core: instance Num a => Num (P a)
+ Sound.SC3.Lang.Pattern.P.Core: instance Ord a => Ord (P a)
+ Sound.SC3.Lang.Pattern.P.Core: instance OrdE a => OrdE (P a)
+ Sound.SC3.Lang.Pattern.P.Core: instance Show a => Show (P a)
+ Sound.SC3.Lang.Pattern.P.Core: instance Traversable P
+ Sound.SC3.Lang.Pattern.P.Core: liftP :: ([a] -> [b]) -> P a -> P b
+ Sound.SC3.Lang.Pattern.P.Core: liftP2 :: ([a] -> [b] -> [c]) -> P a -> P b -> P c
+ Sound.SC3.Lang.Pattern.P.Core: liftP2_repeat :: ([a] -> [b] -> [c]) -> P a -> P b -> P c
+ Sound.SC3.Lang.Pattern.P.Core: liftP3 :: ([a] -> [b] -> [c] -> [d]) -> P a -> P b -> P c -> P d
+ Sound.SC3.Lang.Pattern.P.Core: liftP3_repeat :: ([a] -> [b] -> [c] -> [d]) -> P a -> P b -> P c -> P d
+ Sound.SC3.Lang.Pattern.P.Core: punzip :: P (a, b) -> (P a, P b)
+ Sound.SC3.Lang.Pattern.P.Core: pzip :: P a -> P b -> P (a, b)
+ Sound.SC3.Lang.Pattern.P.Core: pzip3 :: P a -> P b -> P c -> P (a, b, c)
+ Sound.SC3.Lang.Pattern.P.Core: pzipWith :: (a -> b -> c) -> P a -> P b -> P c
+ Sound.SC3.Lang.Pattern.P.Core: pzipWith3 :: (a -> b -> c -> d) -> P a -> P b -> P c -> P d
+ Sound.SC3.Lang.Pattern.P.Core: toP :: [a] -> P a
+ Sound.SC3.Lang.Pattern.P.Core: unP :: P a -> [a]
+ Sound.SC3.Lang.Pattern.P.Core: unP_either :: P a -> Either a [a]
+ Sound.SC3.Lang.Pattern.P.Core: unP_repeat :: P a -> [a]
+ Sound.SC3.Lang.Pattern.P.Core: undecided :: a -> P a
+ Sound.SC3.Lang.Pattern.P.Event: (<|) :: F_Value v => Key -> P v -> P_Bind
+ Sound.SC3.Lang.Pattern.P.Event: P_Event :: P Event -> P_Event
+ Sound.SC3.Lang.Pattern.P.Event: instance Audible P_Event
+ Sound.SC3.Lang.Pattern.P.Event: newtype P_Event
+ Sound.SC3.Lang.Pattern.P.Event: pNRT :: P Event -> NRT
+ Sound.SC3.Lang.Pattern.P.Event: p_Event :: P_Event -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: p_time :: P Event -> P Time
+ Sound.SC3.Lang.Pattern.P.Event: p_un_mce :: P Event -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: p_with :: P_Bind -> P Event -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: padd :: P_Bind -> P Event -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: paudition :: P Event -> IO ()
+ Sound.SC3.Lang.Pattern.P.Event: pbind :: [P_Bind] -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: pedit :: Key -> (Field -> Field) -> P Event -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: pinstr :: String -> P Field
+ Sound.SC3.Lang.Pattern.P.Event: pinstr' :: Instr -> P Field
+ Sound.SC3.Lang.Pattern.P.Event: pkey :: Key -> P Event -> P Field
+ Sound.SC3.Lang.Pattern.P.Event: pkey_m :: Key -> P Event -> P (Maybe Field)
+ Sound.SC3.Lang.Pattern.P.Event: pmce2 :: P Field -> P Field -> P Field
+ Sound.SC3.Lang.Pattern.P.Event: pmce3 :: P Field -> P Field -> P Field -> P Field
+ Sound.SC3.Lang.Pattern.P.Event: pmerge :: P Event -> P Event -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: pmono :: [P_Bind] -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: pmul :: P_Bind -> P Event -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: pmul' :: P_Bind -> P Event -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: ppar :: [P Event] -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: pplay :: Transport m => P Event -> m ()
+ Sound.SC3.Lang.Pattern.P.Event: pstretch :: P Field -> P Event -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: psynth :: Synthdef -> P Field
+ Sound.SC3.Lang.Pattern.P.Event: ptmerge :: (Time, P Event) -> (Time, P Event) -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: ptpar :: [(Time, P Event)] -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: punion :: P Event -> P Event -> P Event
+ Sound.SC3.Lang.Pattern.P.Event: type P_Bind = (Key, P Field)
+ Sound.SC3.Lang.Pattern.P.SC3: pbrown :: (Enum e, Random n, Num n, Ord n) => e -> n -> n -> n -> Int -> P n
+ Sound.SC3.Lang.Pattern.P.SC3: pbrown' :: (Enum e, Random n, Num n, Ord n) => e -> P n -> P n -> P n -> Int -> P n
+ Sound.SC3.Lang.Pattern.P.SC3: pbrownM :: (UId m, Num n, Ord n, Random n) => n -> n -> n -> Int -> m (P n)
+ Sound.SC3.Lang.Pattern.P.SC3: pclutch :: P a -> P Bool -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pcollect :: (a -> b) -> P a -> P b
+ Sound.SC3.Lang.Pattern.P.SC3: pconst :: (Ord a, Num a) => a -> P a -> a -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pdegreeToKey :: RealFrac a => P a -> P [a] -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pdiff :: Num n => P n -> P n
+ Sound.SC3.Lang.Pattern.P.SC3: pdrop :: Int -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pdurStutter :: Fractional a => P Int -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pexprand :: (Enum e, Random a, Floating a) => e -> a -> a -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pexprandM :: (UId m, Random a, Floating a) => a -> a -> Int -> m (P a)
+ Sound.SC3.Lang.Pattern.P.SC3: pfinval :: Int -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pflop :: [P a] -> P (P a)
+ Sound.SC3.Lang.Pattern.P.SC3: pflop' :: [P a] -> P [a]
+ Sound.SC3.Lang.Pattern.P.SC3: pfold :: RealFrac n => P n -> n -> n -> P n
+ Sound.SC3.Lang.Pattern.P.SC3: pfuncn :: Enum e => e -> (StdGen -> (n, StdGen)) -> Int -> P n
+ Sound.SC3.Lang.Pattern.P.SC3: pgeom :: Num a => a -> a -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pif :: P Bool -> P a -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: place :: [[a]] -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pn :: P a -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pnormalizeSum :: Fractional n => P n -> P n
+ Sound.SC3.Lang.Pattern.P.SC3: ppatlace :: [P a] -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: prand :: Enum e => e -> [P a] -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: prand' :: Enum e => e -> [P a] -> Int -> P (P a)
+ Sound.SC3.Lang.Pattern.P.SC3: prandM :: UId m => [P a] -> Int -> m (P a)
+ Sound.SC3.Lang.Pattern.P.SC3: preject :: (a -> Bool) -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: prorate :: Num a => P (Either a [a]) -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: prorate' :: Num a => Either a [a] -> a -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pselect :: (a -> Bool) -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pseq :: [P a] -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pseq1 :: [P a] -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pseqn :: [Int] -> [P a] -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pseqr :: (Int -> [P a]) -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pser :: [P a] -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pser1 :: [P a] -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pseries :: Num a => a -> a -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pshuf :: Enum e => e -> [a] -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pshufM :: UId m => [a] -> Int -> m (P a)
+ Sound.SC3.Lang.Pattern.P.SC3: pslide :: [a] -> Int -> Int -> Int -> Int -> Bool -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pstutter :: P Int -> P a -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pswitch :: [P a] -> P Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pswitch1 :: [P a] -> P Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: ptuple :: [P a] -> Int -> P [a]
+ Sound.SC3.Lang.Pattern.P.SC3: pwhite :: (Random n, Enum e) => e -> n -> n -> Int -> P n
+ Sound.SC3.Lang.Pattern.P.SC3: pwhite' :: (Enum e, Random n) => e -> P n -> P n -> P n
+ Sound.SC3.Lang.Pattern.P.SC3: pwhiteM :: (UId m, Random n) => n -> n -> Int -> m (P n)
+ Sound.SC3.Lang.Pattern.P.SC3: pwhitei :: (RealFracE n, Random n, Enum e) => e -> n -> n -> Int -> P n
+ Sound.SC3.Lang.Pattern.P.SC3: pwhiteiM :: (UId m, RealFracE n, Random n) => n -> n -> Int -> m (P n)
+ Sound.SC3.Lang.Pattern.P.SC3: pwrand :: Enum e => e -> [P a] -> [Double] -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pwrandM :: UId m => [P a] -> [Double] -> Int -> m (P a)
+ Sound.SC3.Lang.Pattern.P.SC3: pwrap :: (Ord a, Num a) => P a -> a -> a -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pxrand :: Enum e => e -> [P a] -> Int -> P a
+ Sound.SC3.Lang.Pattern.P.SC3: pxrandM :: UId m => [P a] -> Int -> m (P a)
+ Sound.SC3.Lang.Pattern.Stream: brown :: (Enum e, Random n, Num n, Ord n) => e -> [n] -> [n] -> [n] -> [n]
+ Sound.SC3.Lang.Pattern.Stream: brown_ :: (RandomGen g, Random n, Num n, Ord n) => (n, n, n) -> (n, g) -> (n, g)
+ Sound.SC3.Lang.Pattern.Stream: exprand :: (Enum e, Random a, Floating a) => e -> a -> a -> [a]
+ Sound.SC3.Lang.Pattern.Stream: geom :: Num a => a -> a -> [a]
+ Sound.SC3.Lang.Pattern.Stream: iEq :: Eq a => [a] -> [a] -> Bool
+ Sound.SC3.Lang.Pattern.Stream: lace :: [[a]] -> [a]
+ Sound.SC3.Lang.Pattern.Stream: rand :: Enum e => e -> [a] -> [a]
+ Sound.SC3.Lang.Pattern.Stream: rsd :: Eq a => [a] -> [a]
+ Sound.SC3.Lang.Pattern.Stream: segment :: [a] -> Int -> (Int, Int) -> [a]
+ Sound.SC3.Lang.Pattern.Stream: slide :: [a] -> Int -> Int -> Int -> Bool -> [[a]]
+ Sound.SC3.Lang.Pattern.Stream: slidec :: [a] -> Int -> Int -> Int -> Bool -> [a]
+ Sound.SC3.Lang.Pattern.Stream: take_until_forms_set :: Eq a => [a] -> [a] -> [a]
+ Sound.SC3.Lang.Pattern.Stream: white :: (Random n, Enum e) => e -> n -> n -> [n]
+ Sound.SC3.Lang.Pattern.Stream: wrand :: Enum e => e -> [a] -> [Double] -> [a]
+ Sound.SC3.Lang.Pattern.Stream: wrand_generic :: (Enum e, Fractional n, Ord n, Random n) => e -> [a] -> [n] -> [a]
+ Sound.SC3.Lang.Pattern.Stream: xrand :: Enum e => e -> [a] -> [a]
+ Sound.SC3.Lang.Random.Gen: kvariant' :: Int -> (g -> (a, g)) -> g -> ([a], g)
+ Sound.SC3.Lang.Random.Gen: mk_kvariant :: r -> (t -> r -> r) -> (r -> r') -> Int -> (g -> (t, g)) -> g -> (r', g)
+ Sound.SC3.Lang.Random.Gen: nwchoose_N :: (Fractional a, Ord a, RandomGen g, Random a) => Int -> [b] -> [a] -> g -> ([b], g)
+ Sound.SC3.Lang.Random.Gen: r_iterate :: (t -> (a, t)) -> t -> [a]
+ Sound.SC3.Lang.Random.Gen: s_rand :: (RandomGen g, Random n, Num n) => n -> g -> [n]
+ Sound.SC3.Lang.Random.Gen: s_rand2 :: (RandomGen g, Random n, Num n) => n -> g -> [n]
+ Sound.SC3.Lang.Random.Gen: wchoose_N :: (Fractional a, Ord a, RandomGen g, Random a) => [b] -> [a] -> g -> (b, g)
+ Sound.SC3.Lang.Random.ID: id_rand :: Enum e => e -> (StdGen -> (a, StdGen)) -> a
+ Sound.SC3.Lang.Random.ID: nchoose :: Enum e => e -> Int -> [a] -> [a]
+ Sound.SC3.Lang.Random.ID: rand :: (Random a, Num a, Enum e) => e -> a -> a
+ Sound.SC3.Lang.Random.ID: rrand :: (Random a, Num a, Enum e) => e -> a -> a -> a
+ Sound.SC3.Lang.Random.Monad: wchoose :: (RandomGen g, Fractional t, Ord t, Random t) => [a] -> [t] -> Rand g a
+ Sound.SC3.Lang.Random.Monad: wchoose_N :: (RandomGen g, Fractional t, Ord t, Random t) => [a] -> [t] -> Rand g a
- Sound.SC3.Lang.Control.Duration: delta :: Durational d => d -> Double
+ Sound.SC3.Lang.Control.Duration: delta :: Duration d => d -> Double
- Sound.SC3.Lang.Control.Duration: fwd :: Durational d => d -> Double
+ Sound.SC3.Lang.Control.Duration: fwd :: Duration d => d -> Double
- Sound.SC3.Lang.Control.Duration: occ :: Durational d => d -> Double
+ Sound.SC3.Lang.Control.Duration: occ :: Duration d => d -> Double
- Sound.SC3.Lang.Control.Midi: midi_act :: Midi_Receiver IO Int -> Message -> StateT (K Int) IO ()
+ Sound.SC3.Lang.Control.Midi: midi_act :: Midi_Recv_f st -> UDP -> st -> Message -> IO st
- Sound.SC3.Lang.Control.OverlapTexture: gen_synth :: (Double, Double) -> UGen -> Synthdef
+ Sound.SC3.Lang.Control.OverlapTexture: gen_synth :: UGen -> Maybe (Env_ST Double) -> UGen -> Synthdef
- Sound.SC3.Lang.Control.OverlapTexture: mk_env :: UGen -> UGen -> UGen
+ Sound.SC3.Lang.Control.OverlapTexture: mk_env :: Env_ST UGen -> UGen
- Sound.SC3.Lang.Control.OverlapTexture: overlapTexture_env :: OverlapTexture -> (Double, Double)
+ Sound.SC3.Lang.Control.OverlapTexture: overlapTexture_env :: OverlapTexture -> Env_ST Double
- Sound.SC3.Lang.Control.OverlapTexture: post_process_s :: Int -> (UGen -> UGen) -> Synthdef
+ Sound.SC3.Lang.Control.OverlapTexture: post_process_s :: Int -> PP_Bus -> (UGen -> UGen) -> Synthdef
- Sound.SC3.Lang.Control.OverlapTexture: with_env :: (Double, Double) -> UGen -> UGen
+ Sound.SC3.Lang.Control.OverlapTexture: with_env :: UGen -> Env_ST Double -> UGen -> UGen
- Sound.SC3.Lang.Control.OverlapTexture: with_env_u :: UGen -> UGen -> UGen -> UGen
+ Sound.SC3.Lang.Control.OverlapTexture: with_env_u :: UGen -> UGen -> Env_ST UGen -> UGen
- Sound.SC3.Lang.Control.OverlapTexture: xfadeTexture_env :: XFadeTexture -> (Double, Double)
+ Sound.SC3.Lang.Control.OverlapTexture: xfadeTexture_env :: XFadeTexture -> Env_ST Double
- Sound.SC3.Lang.Math.Warp: warpDbFader :: (Eq a, Floating a) => Warp a
+ Sound.SC3.Lang.Math.Warp: warpDbFader :: (TernaryOp a, Eq a, Floating a) => a -> a -> Warp a
- Sound.SC3.Lang.Math.Warp: warpFader :: Floating a => Warp a
+ Sound.SC3.Lang.Math.Warp: warpFader :: Floating a => a -> a -> Warp a

Files

README view
@@ -5,7 +5,7 @@ module that defines a subset of functions from the [SuperCollider Language][sc3] class library. -© [rohan drape][rd], 2007-2013, [gpl][gpl].+© [rohan drape][rd], 2007-2014, [gpl][gpl].  [hs]: http://haskell.org/ [sc3]: http://audiosynth.com/
Sound/SC3/Lang/Collection.hs view
@@ -3,10 +3,13 @@ -- becomes @m i j c@. module Sound.SC3.Lang.Collection where -import qualified Data.List.Split as S {- split -}+import qualified Data.List.Split as L {- split -} import Data.List as L {- base -} import Data.Maybe {- base -}+import qualified Sound.SC3 as S {- hsc3 -} +import Sound.SC3.Lang.Core+ -- * Collection  -- | @Collection.*fill@ is 'map' over indices to /n/.@@ -77,21 +80,21 @@ -- -- > any' (\i _ -> even i) [1,2,3,4] == True any' :: Integral i => (a -> i -> Bool) -> [a] -> Bool-any' f = isJust . detect f+any' = isJust .: detect  -- | @Collection.every@ is 'True' if /f/ applies at all elements. -- -- > every (\i _ -> even i) [1,2,3,4] == False every :: Integral i => (a -> i -> Bool) -> [a] -> Bool every f =-    let g e = not . f e+    let g = not .: f     in not . any' g --- | @Collection.count@ is 'length' '.' 'select'.+-- | @Collection.count@ is 'length' of 'select'. -- -- > count (\i _ -> even i) [1,2,3,4] == 2 count :: Integral i => (a -> i -> Bool) -> [a] -> i-count f = genericLength . select f+count = genericLength .: select  -- | @Collection.occurencesOf@ is an '==' variant of 'count'. --@@ -100,23 +103,23 @@ occurencesOf :: (Integral i,Eq a) => a -> [a] -> i occurencesOf k = count (\e _ -> e == k) --- | @Collection.sum@ is 'sum' '.' 'collect'.+-- | @Collection.sum@ is 'sum' of 'collect'. -- -- > sum' (ignoringIndex (* 2)) [1,2,3,4] == 20 sum' :: (Num a,Integral i) => (b -> i -> a) -> [b] -> a-sum' f = sum . collect f+sum' = sum .: collect --- | @Collection.maxItem@ is 'maximum' '.' 'collect'.+-- | @Collection.maxItem@ is 'maximum' of 'collect'. -- -- > maxItem (ignoringIndex (* 2)) [1,2,3,4] == 8 maxItem :: (Ord b,Integral i) => (a -> i -> b) -> [a] -> b-maxItem f = maximum . collect f+maxItem = maximum .: collect  -- | @Collection.minItem@ is 'maximum' '.' 'collect'. -- -- > minItem (ignoringIndex (* 2)) [1,2,3,4] == 2 minItem :: (Integral i,Ord b) => (a -> i -> b) -> [a] -> b-minItem f = minimum . collect f+minItem = minimum .: collect  -- | Variant of 'zipWith' that cycles the shorter input. --@@ -250,7 +253,7 @@  -- | 'fromJust' variant of 'indexOf'. indexOf' :: Eq a => [a] -> a -> Int-indexOf' l = fromJust . indexOf l+indexOf' = fromJust .: indexOf  -- | @SequenceableCollection.indexOfEqual@ is just 'indexOf'. indexOfEqual :: Eq a => [a] -> a -> Maybe Int@@ -276,8 +279,10 @@     in maybe (size l - 1) f (indexOfGreaterThan e l)  -- | @SequenceableCollection.indexInBetween@ is the linearly--- interpolated fractional index.+-- interpolated fractional index.  Collection must be sorted. The+-- inverse operation is 'blendAt'. --+-- > > [2,3,5,6].indexInBetween(5.2) == 2.2 -- > indexInBetween 5.2 [2,3,5,6] == 2.2 indexInBetween :: (Ord a,Fractional a) => a -> [a] -> a indexInBetween e l =@@ -412,7 +417,7 @@ -- > > [1,2,3,4,5,6,7,8].clump(3) == [[1,2,3],[4,5,6],[7,8]] -- > clump 3 [1,2,3,4,5,6,7,8] == [[1,2,3],[4,5,6],[7,8]] clump :: Int -> [a] -> [[a]]-clump = S.chunksOf+clump = L.chunksOf  -- | @SequenceableCollection.clumps@ is a synonym for -- 'Data.List.Split.splitPlaces'.@@ -428,6 +433,47 @@          [] -> []          _ -> f (cycle m) s +-- | 'blendAt' with @clip@ function as argument.+blendAtBy :: (Integral i,RealFrac n) => (i -> t -> n) -> n -> t -> n+blendAtBy f ix c =+    let m = floor ix+        m' = fromIntegral m+    in blend (absdif ix m') (f m c) (f (m + 1) c)++-- | @SequenceableCollection.blendAt@ returns a linearly interpolated+-- value between the two closest indices.  Inverse operation is+-- 'indexInBetween'.+--+-- > > [2,5,6].blendAt(0.4) == 3.2+--+-- > blendAt 0 [2,5,6] == 2+-- > blendAt 0.4 [2,5,6] == 3.2+blendAt :: RealFrac a => a -> [a] -> a+blendAt = blendAtBy clipAt++-- | Resampling function, /n/ is destination length, /r/ is source+-- length, /f/ is the indexing function, /c/ is the collection.+resamp1_gen :: (Integral i,RealFrac n) => i -> i -> (i -> t -> n) -> t -> i -> n+resamp1_gen n r f c =+    let n' = fromIntegral n+        fwd = (fromIntegral r - 1) / (n' - 1)+        gen i = blendAtBy f (fromIntegral i * fwd) c+    in gen++-- | @SequenceableCollection.resamp1@ returns a new collection of the+-- desired length, with values resampled evenly-spaced from the+-- receiver with linear interpolation.+--+-- > > [1,2,3,4].resamp1(12)+-- > > [1,2,3,4].resamp1(3) == [1,2.5,4]+--+-- > resamp1 12 [1,2,3,4]+-- > resamp1 3 [1,2,3,4] == [1,2.5,4]+resamp1 :: (Enum n,RealFrac n) => Int -> [n] -> [n]+resamp1 n c =+    let gen = resamp1_gen n (length c) clipAt c+    in map gen [0 .. n - 1]+ -- * List and Array  -- | @List.lace@ is a concatenated transposition of cycled@@ -490,6 +536,37 @@     let n = sum l     in map (/ n) l +-- | @ArrayedCollection.normalize@ returns a new Array with the receiver+-- items normalized between min and max.+--+-- > > [1,2,3].normalize == [0,0.5,1]+-- > > [1,2,3].normalize(-20,10) == [-20,-5,10]+--+-- > normalize 0 1 [1,2,3] == [0,0.5,1]+-- > normalize (-20) 10 [1,2,3] == [-20,-5,10]+normalize :: (S.TernaryOp b,Fractional b, Ord b) => b -> b -> [b] -> [b]+normalize l r c =+    let cl = minimum c+        cr = maximum c+    in map (\e -> S.linlin e cl cr l r) c++-- | @ArrayedCollection.asRandomTable@ returns an integral table that+-- can be used to generate random numbers with a specified+-- distribution.+--+-- > > [1,0,1,0,1,0,1].asRandomTable(256).plot+-- > > ((0..100) ++ (100..50) / 100).asRandomTable.plot+--+-- > import Sound.SC3.Plot+-- > plotTable [asRandomTable 256 [1,0,1,0,1,0,1]]+-- > plotTable [asRandomTable 256 (map (/ 100) ([0..100] ++ [100,99..50]))]+asRandomTable :: (S.TernaryOp a,Enum a, RealFrac a) => Int -> [a] -> [a]+asRandomTable n c =+    let n' = fromIntegral n+        a = integrate (resamp1 n c)+        b = normalize 0 (n' - 1) a+    in map (\i -> indexInBetween i b / n') [0 .. n' - 1]+ -- | @List.slide@ is an identity window function with subsequences of -- length /w/ and stride of /n/. --@@ -636,3 +713,91 @@ to_wavetable =     let f (e0,e1) = (2 * e0 - e1,e1 - e0)     in t2_concat . map f . t2_overlap . (++ [0])++-- | Variant of 'sineFill' that gives each component table.+--+-- > let t = sineGen 1024 (map recip [1,2,3,5,8,13,21,34,55]) (replicate 9 0)+-- > map length t == replicate 9 1024+--+-- > import Sound.SC3.Plot+-- > plotTable t+sineGen :: (Floating n,Enum n) => Int -> [n] -> [n] -> [[n]]+sineGen n =+    let incr = (2 * pi) / fromIntegral n+        ph partial = take n [0,incr * fromIntegral partial ..]+        f h amp iph = map (\z -> sin (z + iph) * amp) (ph h)+    in zipWith3 f [1..]++-- | @Signal.*sineFill@ is a table generator.  Frequencies are+-- partials, amplitudes and initial phases are as given.  Result is+-- normalised.+--+-- > let t = let a = [[21,5,34,3,2,13,1,8,55]+-- >                 ,[13,8,55,34,5,21,3,1,2]+-- >                 ,[55,34,1,3,2,13,5,8,21]]+-- >         in map (\amp -> sineFill 1024 (map recip amp) (replicate 9 0)) a+--+-- > import Sound.SC3.Plot+-- > plotTable t+sineFill :: (S.TernaryOp n,Ord n,Floating n,Enum n) => Int -> [n] -> [n] -> [n]+sineFill n amp iph =+    let t = sineGen n amp iph+    in normalize (-1) 1 (map sum (transpose t))++-- * Required++-- | /z/ ranges from 0 (for /i/) to 1 (for /j/).+--+-- > > 1.5.blend(2.0,0.50) == 1.75+-- > > 1.5.blend(2.0,0.75) == 1.875+--+-- > blend 0.50 1.5 2 == 1.75+-- > blend 0.75 1.5 2 == 1.875+blend :: Num a => a -> a -> a -> a+blend z i j = i + (z * (j - i))++-- | Variant of '(!!)' but values for index greater than the size of+-- the collection will be clipped to the last index.+clipAt :: Int -> [a] -> a+clipAt ix c =+    if ix > length c - 1+    then L.last c+    else c !! ix++-- | 'abs' of '(-)'.+absdif :: Num a => a -> a -> a+absdif i j = abs (j - i)++-- * Variants++-- | Variant where all inputs are lists and the result is not+-- catentated.  Does not generate partial windows.+--+-- > let r = ["abc","bc","def","ef","ghi","hi"]+-- > in slide1 (cycle [3,2]) (cycle [1,2]) ['a'..'i'] == r+--+-- > let r = ["abc","bc","bcd","cd","cde","de"]+-- > in slide1 (cycle [3,2]) (cycle [1,0]) ['a'..'e'] == r+slide1 :: Integral i => [i] -> [i] -> [a] -> [[a]]+slide1 w n l =+    case (w,n,l) of+      (w0:w',n0:n',_) -> case genericTakeMaybe w0 l of+                           Nothing -> []+                           Just r -> let l' = genericDrop n0 l+                                     in r : slide1 w' n' l'+      _ -> []++-- | 'concat' of 'slide1'.+slide2 :: Integral i => [i] -> [i] -> [a] -> [a]+slide2 = concat .:: slide1++-- | Variant where stutter input is a list and the result is not+-- catentated.+--+-- > stutter1 [2,1,2] [1,2,3] == [[1,1],[2],[3,3]]+stutter1 :: Integral i => [i] -> [a] -> [[a]]+stutter1 = zipWith genericReplicate++-- | 'concat' of 'stutter1'.+stutter2 :: Integral i => [i] -> [a] -> [a]+stutter2 = concat .: stutter1
+ Sound/SC3/Lang/Collection/Array.hs view
@@ -0,0 +1,31 @@+-- | 'A.Array' variants of "Sound.SC3.Lang.Collection".+module Sound.SC3.Lang.Collection.Array where++import qualified Data.Array as A {- array -}++import qualified Sound.SC3.Lang.Collection as C++-- | 'C.clipAt'.+clipAt :: Int -> A.Array Int a -> a+clipAt ix c =+    let (l,r) = A.bounds c+        f = (A.!) c+    in if ix < l then f l else if ix > r then f r else f ix++-- | 'C.blendAtBy' of 'clipAt'.+--+-- > blendAt 0 (A.listArray (0,2) [2,5,6]) == 2+-- > blendAt 0.4 (A.listArray (0,2) [2,5,6]) == 3.2+blendAt :: RealFrac a => a -> A.Array Int a -> a+blendAt = C.blendAtBy clipAt++-- | 'C.resamp1'.+--+-- > resamp1 12 (A.listArray (0,3) [1,2,3,4])+-- > resamp1 3 (A.listArray (0,3) [1,2,3,4]) == A.listArray (0,2) [1,2.5,4]+resamp1 :: (Enum n,RealFrac n) => Int -> A.Array Int n -> A.Array Int n+resamp1 n c =+    let (_,r) = A.bounds c+        gen = C.resamp1_gen n (r + 1) clipAt c+        rs = map gen [0 .. n - 1]+    in A.listArray (0,n - 1) rs
Sound/SC3/Lang/Collection/Numerical/Extending.hs view
@@ -23,6 +23,28 @@     signum = map signum     fromInteger n = [fromInteger n] +instance Real a => Real [a] where+  toRational = error "[Real], toRational"++instance Enum a => Enum [a] where+  succ = map succ+  pred = map pred+  toEnum = return . toEnum+  fromEnum = error "[Enum], fromEnum"+  enumFrom = error "[Enum]"+  enumFromThen = error "[Enum]"+  enumFromTo = error "[Enum]"+  enumFromThenTo = error "[Enum]"++instance Integral a => Integral [a] where+  quot = zipWith_c quot+  rem = zipWith_c rem+  div = zipWith_c div+  mod = zipWith_c mod+  quotRem = error "[Integral] is partial"+  divMod = error "[Integral] is partial"+  toInteger = error "[Integral] is partial"+ instance Fractional a => Fractional [a] where     recip = map recip     (/) = zipWith_c (/)
Sound/SC3/Lang/Collection/Numerical/Truncating.hs view
@@ -45,8 +45,3 @@     asinh = map asinh     acosh = map acosh     atanh = map atanh--{--[1,2,3] * [4,5]-[1,2,3] * 2--}
+ Sound/SC3/Lang/Collection/Vector.hs view
@@ -0,0 +1,30 @@+-- | 'V.Vector' variants of "Sound.SC3.Lang.Collection".+module Sound.SC3.Lang.Collection.Vector where++import qualified Data.Vector as V {- vector -}++import qualified Sound.SC3.Lang.Collection as C++-- | 'C.clipAt'.+clipAt :: Int -> V.Vector a -> a+clipAt ix c =+    let r = V.length c+        f = (V.!) c+    in if ix > r - 1 then f (r - 1) else f ix++-- | 'C.blendAtBy' of 'clipAt'.+--+-- > blendAt 0 (V.fromList [2,5,6]) == 2+-- > blendAt 0.4 (V.fromList [2,5,6]) == 3.2+-- > blendAt 2.1 (V.fromList [2,5,6]) == 6+blendAt :: RealFrac a => a -> V.Vector a -> a+blendAt = C.blendAtBy clipAt++-- | 'C.resamp1'.+--+-- > resamp1 12 (V.fromList [1,2,3,4])+-- > resamp1 3 (V.fromList [1,2,3,4]) == V.fromList [1,2.5,4]+resamp1 :: (Enum n,RealFrac n) => Int -> V.Vector n -> V.Vector n+resamp1 n c =+    let gen = C.resamp1_gen n (V.length c) clipAt c+    in V.generate n gen
Sound/SC3/Lang/Control/Duration.hs view
@@ -2,26 +2,45 @@ module Sound.SC3.Lang.Control.Duration where  import Data.Maybe {- base -}+import Data.Ratio {- base -} --- * Durational+-- * Duration --- | Values that have duration.+-- | There are three parts to a duration: ----- @occ@ is the interval from the start through to the end of the--- current event, ie. the time span the event /occupies/.+-- 'delta' is the /logical/ or /notated/ duration. ----- @delta@ is the interval from the start of the current event to the--- start of the next /sequential/ event.+-- 'occ' is the /sounding/ duration, the interval that a value+-- actually occupies in time.  If 'occ' '<' 'delta' there will be a+-- /hole/, if 'occ' '>' 'delta' there will be an /overlap/. ----- @fwd@ is the interval from the start of the current event to the--- start of the next /parallel/ event.-class Durational d where-    occ :: d -> Double+-- 'fwd' is the /forward/ duration, the interval to the start time of+-- the next value in the sequence, which may be /parallel/ to the+-- current value.  Ordinarily 'fwd' is either 'delta' or @0@.+class Duration d where     delta :: d -> Double-    delta = occ+    occ :: d -> Double+    occ = delta     fwd :: d -> Double-    fwd = occ+    fwd = delta +instance Duration Int where delta = fromIntegral+instance Duration Integer where delta = fromIntegral+instance Duration Float where delta = realToFrac+instance Duration Double where delta = id+instance Integral i => Duration (Ratio i) where delta = realToFrac++{- FlexibleInstances+instance Real i => Duration (i,i,i) where+    delta (i,_,_) = realToFrac i+    occ (_,i,_) = realToFrac i+    fwd (_,_,i) = realToFrac i+-}++-- | Composite of 'delta', 'occ', and 'fwd'.+duration :: Duration d => d -> (Double,Double,Double)+duration d = (delta d,occ d,fwd d)+ -- * Dur  -- | Variant of the @SC3@ 'Duration' model.@@ -41,9 +60,9 @@         }     deriving (Eq,Show) -instance Durational Dur where-    occ d = fromMaybe (delta d * legato d) (sustain' d)+instance Duration Dur where     delta d = fromMaybe (dur d * stretch d * (60 / tempo d)) (delta' d)+    occ d = fromMaybe (delta d * legato d) (sustain' d)     fwd d = maybe (delta d) (* stretch d) (fwd' d)  -- | Default 'Dur' value, equal to one second.
Sound/SC3/Lang/Control/Event.hs view
@@ -11,6 +11,7 @@ import System.Random {- base -}  import qualified Sound.SC3.Lang.Collection as C+import Sound.SC3.Lang.Core import qualified Sound.SC3.Lang.Control.Duration as D import qualified Sound.SC3.Lang.Control.Instrument as I import qualified Sound.SC3.Lang.Control.Pitch as P@@ -228,7 +229,7 @@     floatDigits = f_atf floatDigits     floatRange = f_atf floatRange     decodeFloat = f_atf decodeFloat-    encodeFloat i = F_Double . encodeFloat i+    encodeFloat = F_Double .: encodeFloat     exponent = f_atf exponent     significand = f_uop significand     scaleFloat i = f_uop (scaleFloat i)@@ -248,9 +249,9 @@ instance Enum Field where     fromEnum = f_atf fromEnum     enumFrom = f_atf (map F_Double . enumFrom)-    enumFromThen = f_atf2 (\a -> map F_Double . enumFromThen a)-    enumFromTo = f_atf2 (\a -> map F_Double . enumFromTo a)-    enumFromThenTo = f_atf3 (\a b -> map F_Double . enumFromThenTo a b)+    enumFromThen = f_atf2 (map F_Double .: enumFromThen)+    enumFromTo = f_atf2 (map F_Double .: enumFromTo)+    enumFromThenTo = f_atf3 (map F_Double .:: enumFromThenTo)     toEnum = F_Double . fromIntegral  instance Random Field where@@ -697,7 +698,7 @@ -- | Transform (productively) an 'Event_Seq' into an 'NRT' score. -- -- > let {n1 = nrt_bundles (e_nrt (Event_Seq (replicate 5 mempty)))--- >     ;n2 = take 10 (nrt_bundles (e_nrt (Event_Seq (repeat mempty))))}+-- >     ;n2 = take 11 (nrt_bundles (e_nrt (Event_Seq (repeat mempty))))} -- > in n1 == n2 e_nrt :: Event_Seq -> NRT e_nrt =@@ -706,18 +707,14 @@               [] -> r               (o,c):l' -> let (c',r') = span (<= o) (insert o (insert c r))                           in c' ++ rec r' l'-    in NRT . rec [] . e_bundle_seq 0+        g0 = Bundle 0 [g_new [(1,AddToTail,0)]]+    in NRT . (g0 :) . rec [] . e_bundle_seq 0  -- | Audition 'Event_Seq'. e_play :: Transport m => Event_Seq -> m ()-e_play l = do-  st <- time-  let f (p,q) = pauseThreadUntil (bundleTime p - 0.1) >>-                sendBundle p >>-                sendBundle q-  mapM_ f (e_bundle_seq st l)+e_play = play . e_nrt -instance Audible Event_Seq where play = e_play+instance Audible Event_Seq where play_at _ = e_play  -- * Aliases 
Sound/SC3/Lang/Control/Instrument.hs view
@@ -2,7 +2,7 @@ module Sound.SC3.Lang.Control.Instrument where  import Data.Default {- data-default -}-import Sound.SC3.ID {- hsc3 -}+import Sound.SC3 {- hsc3 -}  -- | An 'Instr' is either a 'Synthdef' or the 'String' naming a -- 'Synthdef'.
Sound/SC3/Lang/Control/Midi.hs view
@@ -1,16 +1,11 @@--- | For a single input controller, key events always arrive in--- sequence (ie. on->off), ie. for any key on message we can allocate--- an ID and associate it with the key, an off message can retrieve--- the ID given the key.+-- | Trivial midi functions. module Sound.SC3.Lang.Control.Midi where -import qualified Control.Exception as E {- base -}-import Control.Monad {- base -}-import Control.Monad.IO.Class {- transformers -}-import Control.Monad.Trans.State {- transformers -}+import Control.Exception {- base -} import Data.Bits {- base -} import qualified Data.ByteString.Lazy as B {- bytestring -} import qualified Data.Map as M {- containers -}+import Data.Maybe {- base -} import Sound.OSC.FD {- hosc -}  -- * Bits@@ -129,58 +124,66 @@ -- | @SC3@ node identifiers are integers. type Node_Id = Int --- | Map of allocated 'Node_Id's.-data K a = K (M.Map (a,a) Node_Id) Node_Id+-- | Map of allocated 'Node_Id's.  For a single input controller, key+-- events always arrive in sequence (ie. on->off), ie. for any key on+-- message we can allocate an ID and associate it with the key, an off+-- message can retrieve the ID given the key.+data KY a = KY (M.Map a Node_Id) Node_Id --- | 'StateT' of 'K' specialised to 'Int'.-type KT = StateT (K Int) IO+-- | Initialise 'KY' with starting 'Node_Id'.+ky_init :: Node_Id -> KY a+ky_init = KY M.empty --- | Initialise 'K' with starting 'Node_Id'.-k_init :: Node_Id -> K a-k_init = K M.empty+-- | 'KY' 'Node_Id' allocator.+ky_alloc :: Ord a => KY a -> a -> (KY a,Node_Id)+ky_alloc (KY m i) n = (KY (M.insert n i m) (i + 1),i) --- | 'K' 'Node_Id' allocator.-k_alloc :: (Int,Int) -> KT Node_Id-k_alloc n = do-  (K m i) <- get-  put (K (M.insert n i m) (i + 1))-  return i+-- | 'KY' 'Node_Id' removal.+ky_free :: Ord a => KY a -> a -> (KY a,Node_Id)+ky_free (KY m i) n =+    let r = m M.! n+    in (KY (M.delete n m) i,r) --- | 'K' 'Node_Id' retrieval.-k_get :: (Int,Int) -> KT Node_Id-k_get n = do-  (K m _) <- get-  return (m M.! n)+-- | Lookup 'Node_Id'.+ky_get :: Ord a => KY a -> a -> Node_Id+ky_get (KY m _) n = m M.! n --- * IO+-- | All 'Node_Id'.+ky_all :: KY a -> [Node_Id]+ky_all (KY m _) = M.foldl (flip (:)) [] m --- | The 'Midi_Receiver' is passed a 'Midi_Message' and a 'Node_Id'.--- For 'Note_On' and 'Note_Off' messages the 'Node_Id' is positive,--- for all other message it is @-1@.-type Midi_Receiver m n = Midi_Message n -> Int -> m ()+-- * IO (midi-osc) --- | Parse incoming midi messages, do 'K' allocation, and run--- 'Midi_Receiver'.-midi_act :: Midi_Receiver IO Int -> Message -> StateT (K Int) IO ()-midi_act f o = do+type Midi_Init_f st = (UDP -> IO st)++-- | 'Midi_Recv_f' is passed the @SC3@ connection, the user state, a+-- 'Midi_Message' and, for 'Note_On' and 'Note_Off' messages, a+-- 'Node_Id'.+type Midi_Recv_f st = UDP -> st -> Midi_Message Int -> IO st++-- | Parse incoming midi messages and run 'Midi_Receiver'.+midi_act :: Midi_Recv_f st -> UDP -> st -> Message -> IO st+midi_act recv_f fd st o = do     let m = parse_m o-    n <- case m of-           Note_Off ch k _ -> k_get (ch,k)-           Note_On ch k _ -> k_alloc (ch,k)-           _ -> return (-1)-    liftIO (f m n)+    st' <- recv_f fd st m+    return st' --- | Run midi system, handles 'E.AsyncException's.-start_midi :: (UDP -> Midi_Receiver IO Int) -> IO ()-start_midi receiver = do-  s_fd <- openUDP "127.0.0.1" 57110 -- midi-osc+-- | Connect to @midi-osc@ and @sc3@, run initialiser, and then+-- receiver for each incoming message.+run_midi :: Midi_Init_f st -> Midi_Recv_f st -> IO ()+run_midi init_f recv_f = do   m_fd <- openUDP "127.0.0.1" 57150 -- midi-osc+  s_fd <- openUDP "127.0.0.1" 57110 -- scsynth   sendMessage m_fd (Message "/receive" [Int32 0xffff])-  let step = liftIO (recvMessages m_fd) >>=-             midi_act (receiver s_fd) . head-      ex e = print ("start_midi",show (e::E.AsyncException)) >>-             close m_fd >>-             close s_fd-      runs = void (runStateT (forever step) (k_init 1000))-  E.catch runs ex-  return ()+  init_st <- init_f s_fd+  finally+    (iterateM_ init_st (\st -> recvMessage m_fd >>=+                               midi_act recv_f s_fd st . fromJust))+    (sendMessage m_fd (Message "/receive" [Int32 (-1)]))++-- * Monad++iterateM_ :: (Monad m) => st -> (st -> m st) -> m ()+iterateM_ st f = do+  st' <- f st+  iterateM_ st' f
+ Sound/SC3/Lang/Control/Midi/ST.hs view
@@ -0,0 +1,82 @@+-- | Maintain midi state, query functions.+module Sound.SC3.Lang.Control.Midi.ST where++import Control.Concurrent {- base -}+import qualified Data.Map as M {- containers -}++import Sound.SC3.Lang.Control.Midi {- hsc3-lang -}++type Midi_7bit = Int+type Midi_Note = Midi_7bit+type Midi_Velocity = Midi_7bit+type Midi_Program = Midi_7bit+type Midi_CC_Ix = Midi_7bit+type Midi_CC_Value = Midi_7bit++type Midi_Key_Map = M.Map Midi_Note Midi_Velocity+type Midi_CC_Map = M.Map Midi_CC_Ix Midi_CC_Value++type Midi_State = MVar (Midi_Key_Map,Midi_Program,Midi_CC_Map)++st_edit_km :: Midi_State -> (Midi_Note,Midi_Velocity) -> IO Midi_State+st_edit_km mv (k,v) =+    let f (m,p,c) = (if v == 0 then M.delete k m else M.insert k v m,p,c)+    in modifyMVar_ mv (return . f) >> return mv++st_edit_cc :: Midi_State -> (Midi_CC_Ix,Midi_CC_Value) -> IO Midi_State+st_edit_cc mv (k,v) =+    let f (m,p,c) = (m,p,M.insert k v c)+    in modifyMVar_ mv (return . f) >> return mv++st_edit_pc :: Midi_State -> Midi_Program -> IO Midi_State+st_edit_pc mv p =+    let f (m,_,c) = (m,p,c)+    in modifyMVar_ mv (return . f) >> return mv++p3_fst :: (t,u,v) -> t+p3_fst (t,_,_) = t++p3_third :: (t,u,v) -> v+p3_third (_,_,v) = v++st_access_km :: (Midi_Key_Map -> r) -> Midi_State -> IO r+st_access_km f mv = withMVar mv (return . f . p3_fst)++st_access_cc :: (Midi_CC_Map -> r) -> Midi_State -> IO r+st_access_cc f mv = withMVar mv (return . f . p3_third)++st_read_note :: Midi_State -> Midi_Note -> IO (Maybe Midi_Velocity)+st_read_note st k = st_access_km (M.lookup k) st++st_read_cc :: Midi_State -> Midi_CC_Ix -> IO Midi_CC_Value+st_read_cc st k = st_access_cc (M.findWithDefault 0 k) st++st_chord :: Midi_State -> IO [Midi_Note]+st_chord = st_access_km (map fst . M.toAscList)++st_init_f :: Midi_State -> Midi_Init_f Midi_State+st_init_f v _ = return v++st_recv_f :: Midi_Recv_f Midi_State+st_recv_f _ st msg =+    case msg of+      Note_Off _ j _ -> st_edit_km st (j,0)+      Note_On _ j k -> st_edit_km st (j,k)+      Control_Change _ j k -> st_edit_cc st (j,k)+      Program_Change _ j -> st_edit_pc st j+      _ -> print msg >> return st++st_run :: IO (Midi_State,ThreadId)+st_run = do+  v <- newMVar (M.empty,0,M.empty)+  th <- forkIO (run_midi (st_init_f v) st_recv_f)+  return (v,th)++{-+(st,th) <- st_run+st_chord st+readMVar st+st_read_note 55 st+st_read_cc 0 st+killThread th+-}
Sound/SC3/Lang/Control/OverlapTexture.hs view
@@ -5,34 +5,75 @@ -- and calculate inter-onset times and durations.  There are variants -- for different graph constructors, and to allow for a -- post-processing stage.+--+-- Here the implementation of texture adds sumOut nodes at bus 0 to+-- the head of group 1, post-processing adds a replaceOut node at bus+-- 0 to the tail of group 1. module Sound.SC3.Lang.Control.OverlapTexture where -import Control.Applicative {- base -} import Data.List {- base -}+import Data.Hashable {- hashable -}+ import Sound.OSC {- hosc -} import Sound.SC3 {- hsc3 -} -import Sound.SC3.Lang.Control.Event-import Sound.SC3.Lang.Control.Instrument-import Sound.SC3.Lang.Pattern.ID+-- * Envelope +-- | Envelope defined by /sustain/ and /transition/ times.+type Env_ST n = (n,n)++-- | Location in node tree, given as (/group/,/bus/).+type Loc_GB = (Int,UGen)+ -- | Make an 'envGen' 'UGen' with 'envLinen'' structure with given--- /sustain/ and /transition/ times.-mk_env :: UGen -> UGen -> UGen-mk_env s t =+-- by 'Env_ST'.+mk_env :: Env_ST UGen -> UGen+mk_env (s,t) =     let c = EnvNum 4         p = envLinen' t s t 1 (c,c,c)     in envGen KR 1 1 0 1 RemoveSynth p --- | Apply 'mk_env' envelope to input signal and write to output bus @0@.-with_env_u :: UGen -> UGen -> UGen -> UGen-with_env_u g a = out 0 . (*) g . mk_env a+-- | Add multiplier stage and 'out' UGen writing to /bus/.+with_env_u :: UGen -> UGen -> Env_ST UGen -> UGen+with_env_u bus sig = out bus . (* sig) . mk_env  -- | Variant of 'with_env_u' where envelope parameters are lifted from -- 'Double' to 'UGen'.-with_env :: (Double,Double) -> UGen -> UGen-with_env (s,t) g = with_env_u g (constant s) (constant t)+with_env :: UGen -> Env_ST Double -> UGen -> UGen+with_env bus (s,t) sig = with_env_u bus sig (constant s,constant t) +gen_nm :: UGen -> String+gen_nm = show . hash . show++-- | Generate 'Synthdef', perhaps with envelope parameters for+-- 'with_env', and a continuous signal.+gen_synth :: UGen -> Maybe (Env_ST Double) -> UGen -> Synthdef+gen_synth bus k g =+  let g' = maybe (out bus g) (flip (with_env bus) g) k+  in synthdef (gen_nm g) g'++-- | Require envelope.+gen_synth' :: UGen -> Env_ST Double -> UGen -> Synthdef+gen_synth' bus k = gen_synth bus (Just k)++-- | Schedule 'Synthdef' at indicated intervals.  Synthdef is sent once at time zero.+nrt_sy1 :: Int -> Synthdef -> [Double] -> NRT+nrt_sy1 grp sy dur =+    let tm = dx_d' dur+        f t = bundle t [s_new0 (synthdefName sy) (-1) AddToHead grp]+    in NRT (bundle 0 [d_recv sy] : map f tm)++-- | Schedule 'Synthdef's at indicated intervals.  Synthdef is sent in+-- activation bundle.+nrt_sy :: Int -> [Synthdef] -> [Time] -> NRT+nrt_sy grp sy dur =+    let tm = dx_d' dur+        f t s = bundle t [d_recv s+                         ,s_new0 (synthdefName s) (-1) AddToHead grp]+    in NRT (zipWith f tm sy)++-- * Overlap texture+ -- | Control parameters for 'overlapTextureU' and related functions. -- Components are: 1. sustain time, 2. transition time, 3. number of -- overlaping (simultaneous) nodes and 4. number of nodes altogether.@@ -47,142 +88,148 @@  -- | Extract envelope parameters (sustain and transition times) for -- 'with_env' from 'OverlapTexture'.-overlapTexture_env :: OverlapTexture -> (Double,Double)+overlapTexture_env :: OverlapTexture -> Env_ST Double overlapTexture_env (s,t,_,_) = (s,t) --- | (/legato/,/duration/) parameters. The /duration/ is the--- inter-offset time, /legato/ is the scalar giving the sounding time--- in relation to the inter-offset time.-type Texture_DT = (Double,Double)+-- | Inter-offset time given 'OverlapTexture'.+--+-- > overlapTexture_iot (3,1,5,maxBound) == 1+overlapTexture_iot :: OverlapTexture -> Double+overlapTexture_iot (s,t,o,_) = (t + s + t) / o --- | Extract /legato/ (duration of sound proportional to inter-offset--- time) and /duration/ (inter-offset time) parameters from--- 'OverlapTexture'.+-- | Generate an 'NRT' score from 'OverlapTexture' control+-- parameters and a continuous signal.+overlapTexture_nrt :: Loc_GB -> OverlapTexture -> UGen -> NRT+overlapTexture_nrt (grp,bus) k g =+    let s = gen_synth' bus (overlapTexture_env k) g+        d = overlapTexture_iot k+        (_,_,_,c) = k+    in nrt_sy1 grp s (replicate c d)++-- | 'audition' of 'overlapTexture_nrt'. ----- > overlapTexture_dt (3,1,5,maxBound) == (5,1)-overlapTexture_dt :: OverlapTexture -> Texture_DT-overlapTexture_dt (s,t,o,_) = (o,(t + s + t) / o)+-- > import Sound.SC3.ID+-- > import Sound.SC3.Lang.Control.OverlapTexture+-- >+-- > let {o = sinOsc AR (rand 'α' 440 880) 0+-- >     ;u = pan2 o (rand 'β' (-1) 1) (rand 'γ' 0.1 0.2)}+-- > in overlapTextureU (3,1,6,9) u+overlapTextureU :: OverlapTexture -> UGen -> IO ()+overlapTextureU t = audition . overlapTexture_nrt (1,0) t +-- * XFade texture+ -- | Control parameters for 'xfadeTextureU' and related functions. -- Components are: 1. sustain time, 2. transition time, 3. number of--- nodes instatiated altogether.+-- nodes instantiated altogether. type XFadeTexture = (Double,Double,Int)  -- | Extract envelope parameters for 'with_env' from 'XFadeTexture'.-xfadeTexture_env :: XFadeTexture -> (Double,Double)+xfadeTexture_env :: XFadeTexture -> Env_ST Double xfadeTexture_env (s,t,_) = (s,t) --- | Extract /legato/ and /duration/ paramaters from 'XFadeTexture'.-xfadeTexture_dt :: XFadeTexture -> Texture_DT-xfadeTexture_dt (s,t,_) = let r = t + s in ((r + t) / r,r)---- | Generate 'Synthdef' from envelope parameters for 'with_env' and--- a continuous signal.-gen_synth :: (Double,Double) -> UGen -> Synthdef-gen_synth k g =-  let n = show (hashUGen g)-      g' = with_env k g-  in synthdef n g'+-- | Inter-offset time from 'XFadeTexture'.+xfadeTexture_iot :: XFadeTexture -> Double+xfadeTexture_iot (s,t,_) = s + t --- | Generate an /event/ pattern from 'OverlapTexture' control--- parameters and a continuous signal.-overlapTextureP :: OverlapTexture -> UGen -> P Event-overlapTextureP k g =-    let s = gen_synth (overlapTexture_env k) g-        (l,d) = overlapTexture_dt k-        (_,_,_,c) = k-    in pbind [(K_instr,pinstr' (Instr_Def s False))-             ,(K_dur,pn (return (F_Double d)) c)-             ,(K_legato,pure (F_Double l))]+-- | Generate an 'NRT' score from 'XFadeTexture' control parameters+-- and a continuous signal.+xfadeTexture_nrt :: Loc_GB -> XFadeTexture -> UGen -> NRT+xfadeTexture_nrt (grp,bus) k g =+    let s = gen_synth' bus (xfadeTexture_env k) g+        d = xfadeTexture_iot k+        (_,_,c) = k+    in nrt_sy1 grp s (replicate c d) --- | Audition pattern given by 'overlapTextureP'.+-- | 'audition' of 'xfadeTexture_nrt'. ----- > import Sound.SC3.ID--- > import Sound.SC3.Lang.Control.OverlapTexture--- > -- > let {o = sinOsc AR (rand 'α' 440 880) 0 -- >     ;u = pan2 o (rand 'β' (-1) 1) (rand 'γ' 0.1 0.2)}--- > in overlapTextureU (3,1,6,9) u-overlapTextureU :: OverlapTexture -> UGen -> IO ()-overlapTextureU k = audition . overlapTextureP k+-- > in xfadeTextureU (1,3,6) u+xfadeTextureU :: XFadeTexture -> UGen -> IO ()+xfadeTextureU t = audition . xfadeTexture_nrt (1,0) t +-- * Spawn texture++-- | Duration  a function of the iteration number.+type Spawn_Texture = (Int -> Double,Int)++-- | Generate an 'NRT' score from 'OverlapTexture' control parameters+-- and a continuous signal.+spawnTexture_nrt :: Loc_GB -> Spawn_Texture -> UGen -> NRT+spawnTexture_nrt (grp,bus) (t,c) g = nrt_sy1 grp (gen_synth bus Nothing g) (map t [0 .. c - 1])++-- | 'audition' 'spawnTexture_nrt'.+spawnTextureU :: Spawn_Texture -> UGen -> IO ()+spawnTextureU sp = audition . spawnTexture_nrt (1,0) sp++-- * Post-process++type PP_Bus = Either UGen (UGen,UGen)+ -- | Generate 'Synthdef' from a signal processing function over the--- indicated number of channels.-post_process_s :: Int -> (UGen -> UGen) -> Synthdef-post_process_s nc f =-    let i = in' nc AR 0-        u = replaceOut 0 (f i)-        nm = show (hashUGen u)-    in synthdef nm u+-- indicated number of channels.  If there is a single bus, writes+-- using 'replaceOut', else using 'out'.+post_process_s :: Int -> PP_Bus -> (UGen -> UGen) -> Synthdef+post_process_s nc b f =+    let (src,dst,wr) = case b of+                         Left b' -> (b',b',replaceOut)+                         Right (b',b'') -> (b',b'',out)+        i = in' nc AR src+        u = wr dst (f i)+    in synthdef (gen_nm u) u --- | Audition /event/ pattern with specified post-processing function.-post_process_a :: (Transport m) => P Event -> Int -> (UGen -> UGen) -> m ()-post_process_a p nc f = do-  let s = post_process_s nc f+-- | Run post-processing function.+post_process :: (Transport m) => Int -> PP_Bus -> Int -> (UGen -> UGen) -> m ()+post_process nc bus grp f = do+  let s = post_process_s nc bus f   _ <- async (d_recv s)-  send (s_new0 (synthdefName s) (-1) AddToTail 2)-  play p+  send (s_new0 (synthdefName s) (-1) AddToTail grp) +-- | Audition 'NRT' with specified post-processing function.+post_process_nrt :: (Transport m) => Loc_GB -> NRT -> Int -> (UGen -> UGen) -> m ()+post_process_nrt (grp,bus) sc nc f = post_process nc (Left bus) grp f >> play sc+ -- | Post processing function. type PPF = (UGen -> UGen)  -- | Variant of 'overlapTextureU' with post-processing stage. overlapTextureU_pp :: OverlapTexture -> UGen -> Int -> PPF -> IO () overlapTextureU_pp k u nc f = do-  let p = overlapTextureP k u-  withSC3 (post_process_a p nc f)---- | Generate an /event/ pattern from 'XFadeTexture' control--- parameters and a continuous signal.-xfadeTextureP :: XFadeTexture -> UGen -> P Event-xfadeTextureP k g =-    let s = gen_synth (xfadeTexture_env k) g-        (l,d) = xfadeTexture_dt k-        (_,_,c) = k-    in pbind [(K_instr,pinstr' (Instr_Def s False))-             ,(K_dur,pn (return (F_Double d)) c)-             ,(K_legato,pure (F_Double l))]---- | Audition pattern given by 'xfadeTextureP'.------ > let {o = sinOsc AR (rand 'α' 440 880) 0--- >     ;u = pan2 o (rand 'β' (-1) 1) (rand 'γ' 0.1 0.2)}--- > in xfadeTextureU (1,3,6) u-xfadeTextureU :: XFadeTexture -> UGen -> IO ()-xfadeTextureU k = audition . xfadeTextureP k+  let p = overlapTexture_nrt (1,0) k u+  withSC3 (post_process_nrt (1,0) p nc f)  -- | Variant of 'xfadeTextureU' with post-processing stage. xfadeTextureU_pp :: XFadeTexture -> UGen -> Int -> PPF -> IO () xfadeTextureU_pp k u nc f = do-  let p = xfadeTextureP k u-  withSC3 (post_process_a p nc f)+  let p = xfadeTexture_nrt (1,0) k u+  withSC3 (post_process_nrt (1,0) p nc f) +-- * State+ -- | UGen generating state transform function. type USTF st = (st -> (UGen,st)) --- | Variant of 'overlapTextureP' where the continuous signal for each+-- | Variant of 'overlapTexture_nrt' where the continuous signal for each -- /event/ is derived from a state transform function seeded with -- given initial state.-overlapTextureP_st :: OverlapTexture -> USTF st -> st -> P Event-overlapTextureP_st k u i_st =-    let (l,d) = overlapTexture_dt k+overlapTexture_nrt_st :: Loc_GB -> OverlapTexture -> USTF st -> st -> NRT+overlapTexture_nrt_st (grp,bus) k u i_st =+    let d = overlapTexture_iot k         (_,_,_,c) = k         g = take c (unfoldr (Just . u) i_st)-        i = flip Instr_Def False-        s = toP (map (i . gen_synth (overlapTexture_env k)) g)-    in pbind [(K_instr,fmap F_Instr s)-             ,(K_dur,pure (F_Double d))-             ,(K_legato,pure (F_Double l))]+        s = map (gen_synth' bus (overlapTexture_env k)) g+    in nrt_sy grp s (replicate c d) --- | Audition pattern given by 'overlapTextureP_st'.+-- | 'audition' of 'overlapTexture_nrt_st'. overlapTextureS :: OverlapTexture -> USTF st -> st -> IO ()-overlapTextureS k u = audition . overlapTextureP_st k u+overlapTextureS t f = audition . overlapTexture_nrt_st (1,0) t f  -- | Variant of 'overlapTextureS' with post-processing stage. overlapTextureS_pp :: OverlapTexture -> USTF st -> st -> Int -> PPF  -> IO () overlapTextureS_pp k u i_st nc f = do-  let p = overlapTextureP_st k u i_st-  withSC3 (post_process_a p nc f)+  let sc = overlapTexture_nrt_st (1,0) k u i_st+  withSC3 (post_process_nrt (1,0) sc nc f)  -- | Monadic state transform function. type MSTF st m = (st -> m (Maybe st))@@ -192,23 +239,23 @@ -- the function. dt_rescheduler_m :: MonadIO m => MSTF (st,Time) m -> (st,Time) -> m () dt_rescheduler_m f =-    let rec (st,t) = do+    let recur (st,t) = do           pauseThreadUntil t           r <- f (st,t)           case r of-            Just (st',dt) -> rec (st',t + dt)+            Just (st',dt) -> recur (st',t + dt)             Nothing -> return ()-    in rec+    in recur  -- | Underlying function of 'overlapTextureM' with explicit 'Transport'. overlapTextureR :: Transport m =>                    OverlapTexture -> IO UGen -> MSTF (Int,Time) m overlapTextureR k uf =   let nm = "ot_" ++ show k-      (_,dt) = overlapTexture_dt k+      dt = overlapTexture_iot k   in \(st,_) -> do         u <- liftIO uf-        let g = with_env (overlapTexture_env k) u+        let g = with_env 0 (overlapTexture_env k) u         _ <- async (d_recv (synthdef nm g))         send (s_new0 nm (-1) AddToTail 1)         case st of
Sound/SC3/Lang/Control/Pitch.hs view
@@ -67,7 +67,7 @@                    ,scale :: [Double]                    ,degree :: Double                    ,stepsPerOctave :: Double-                   ,detune :: Double+                   ,detune :: Double -- Hz                    ,harmonic :: Double                    ,freq' :: Maybe Double                    ,midinote' :: Maybe Double
+ Sound/SC3/Lang/Core.hs view
@@ -0,0 +1,139 @@+-- | Core (shared) functions.+module Sound.SC3.Lang.Core where++import Data.Maybe {- base -}+import Data.Monoid {- base -}++-- * "Data.Function" variants++-- | 'fmap' '.' 'fmap', ie. @(t -> c) -> (a -> b -> t) -> a -> b -> c@.+(.:) :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)+(.:) = fmap . fmap++-- | 'fmap' '.' '.:', ie. @(t -> d) -> (a -> b -> c -> t) -> a -> b -> c -> d@.+(.::) :: (Functor f, Functor g, Functor h) => (a -> b) -> f (g (h a)) -> f (g (h b))+(.::) = fmap . (.:)++-- | 'fmap' '.' '.::'.+(.:::) :: (Functor f, Functor g, Functor h,Functor i) => (a -> b) -> f (g (h (i a))) -> f (g (h (i b)))+(.:::) = fmap . (.::)++-- | 'fmap' '.' '.:::'.+(.::::) :: (Functor f, Functor g, Functor h,Functor i,Functor j) => (a -> b) -> f (g (h (i (j a)))) -> f (g (h (i (j b))))+(.::::) = fmap . (.:::)++-- | 'fmap' '.' '.::::'.+(.:::::) :: (Functor f, Functor g, Functor h,Functor i,Functor j,Functor k) => (a -> b) -> f (g (h (i (j (k a))))) -> f (g (h (i (j (k b)))))+(.:::::) = fmap . (.::::)++-- * "Data.List" variants++-- | Variant that either takes precisely /n/ elements or 'Nothing'.+--+-- > map (genericTake 3) (inits "abc") == inits "abc"+-- > Data.Maybe.mapMaybe (genericTakeMaybe 3) (inits "abc") == ["abc"]+genericTakeMaybe :: Integral i => i -> [a] -> Maybe [a]+genericTakeMaybe n l =+    case compare n 0 of+      LT -> Nothing+      EQ -> Just []+      GT -> case l of+              [] -> Nothing+              e : l' -> fmap (e :) (genericTakeMaybe (n - 1) l')++-- | Inverse of 'Data.List.:'.+--+-- > map uncons [[],1:[]] == [(Nothing,[]),(Just 1,[])]+uncons :: [a] -> (Maybe a,[a])+uncons l =+    case l of+      [] -> (Nothing,[])+      x:l' -> (Just x,l')++-- | 'Maybe' variant of '!!'.+--+-- > map (lindex "str") [2,3] == [Just 'r',Nothing]+lindex :: [a] -> Int -> Maybe a+lindex l n =+    if n < 0+    then Nothing+    else case (l,n) of+           ([],_) -> Nothing+           (x:_,0) -> Just x+           (_:l',_) -> lindex l' (n - 1)++-- | If /n/ is 'maxBound' this is 'id', else it is 'take'.+take_inf :: Int -> [a] -> [a]+take_inf n = if n == maxBound then id else take n++-- | Variant of 'transpose' for /fixed width/ interior lists.  Holes+-- are represented by 'Nothing'.+--+-- > transpose_fw undefined [] == []+--+-- > transpose [[1,3],[2,4]] == [[1,2],[3,4]]+-- > transpose_fw 2 [[1,3],[2,4]] == [[Just 1,Just 2],[Just 3,Just 4]]+--+-- > transpose [[1,5],[2],[3,7]] == [[1,2,3],[5,7]]+--+-- > transpose_fw 2 [[1,4],[2],[3,6]] == [[Just 1,Just 2,Just 3]+-- >                                     ,[Just 4,Nothing,Just 6]]+--+-- This function is more productive than 'transpose' for the case of+-- an infinite list of finite lists.+--+-- > map head (transpose_fw 4 (repeat [1..4])) == map Just [1,2,3,4]+-- > map head (transpose (repeat [1..4])) == _|_+transpose_fw :: Int -> [[a]] -> [[Maybe a]]+transpose_fw w l =+    if null l+    then []+    else let f n = map (`lindex` n) l+         in map f [0 .. w - 1]++-- | Variant of 'transpose_fw' with default value for holes.+transpose_fw_def :: a -> Int -> [[a]] -> [[a]]+transpose_fw_def def w l =+    let f n = map (fromMaybe def . (`lindex` n)) l+    in map f [0 .. w - 1]++-- | Variant of 'transpose_fw_def' deriving /width/ from first element.+transpose_fw_def' :: a -> [[a]] -> [[a]]+transpose_fw_def' def l =+    case l of+      [] -> []+      h:_ -> transpose_fw_def def (length h) l++-- | A 'transpose' variant, halting when first hole appears.+--+-- > transpose_st [[1,2,3],[4,5,6],[7,8]] == [[1,4,7],[2,5,8]]+transpose_st :: [[a]] -> [[a]]+transpose_st l =+    let (h,l') = unzip (map uncons l)+    in case all_just h of+         Just h' -> h' : transpose_st l'+         Nothing -> []++-- * Data.Maybe variants++-- | Variant of 'catMaybes' that returns 'Nothing' unless /all/+-- elements are 'Just'.+--+-- > map all_just [[Nothing,Just 1],[Just 0,Just 1]] == [Nothing,Just [0,1]]+all_just :: [Maybe a] -> Maybe [a]+all_just =+    let rec r l =+            case l of+              [] -> Just (reverse r)+              Nothing:_ -> Nothing+              Just e:l' -> rec (e:r) l'+    in rec []++-- * Data.Monoid variants++-- | 'mconcat' of 'repeat', for lists this is 'cycle'.+--+-- > [1,2,3,1,2] `isPrefixOf` take 5 (mcycle [1,2,3])+mcycle :: Monoid a => a -> a+mcycle = mconcat . repeat+
+ Sound/SC3/Lang/Data/CMUdict.hs view
@@ -0,0 +1,239 @@+-- | Arpabet phoneme definitions and CMU dictionary functions.+--+-- <http://www.speech.cs.cmu.edu/cgi-bin/cmudict>+-- <http://en.wikipedia.org/wiki/Arpabet>+module Sound.SC3.Lang.Data.CMUdict where++import Data.Char {- base -}+import Data.Maybe {- base -}+import Data.List {- base -}+import Data.List.Split {- split -}+import qualified Data.Map as M {- containers -}++-- | Stress indicators, placed at the stressed syllabic vowel.+data Stress = No_stress | Primary_stress | Secondary_stress+            deriving (Eq,Ord,Enum,Bounded,Read,Show)++-- | Arpabet phonemes as used at CMU dictionary.+--+-- > [AO .. NX] == [minBound .. maxBound]+-- > length [AO .. NX] == 48+data Phoneme+    -- Vowels (Monophthongs)+    = AO | AA | IY | UW | EH | IH | UH | AH | AX | AE+    -- Vowels (Diphthongs)+    | EY | AY | OW | AW | OY+    -- Vowels (R-colored)+    | ER | AXR+    -- Semivowels+    | Y | W | Q+    -- Consonants (Stops)+    | P | B | T | D | K | G+    -- Consonants (Affricates)+    | CH | JH+    -- Consonants (Fricatives)+    | F | V | TH | DH | S | Z | SH | ZH+    -- Consonants (Aspirate)+    | HH+    -- Nasals+    | M | EM | N | EN | NG | ENG+    -- Liquids+    | L | EL | R | DX | NX+      deriving (Eq,Ord,Enum,Bounded,Read,Show)++-- | 'Phoneme' with 'Stress', if given.+type Phoneme_str = (Phoneme,Maybe Stress)++-- | There is a variant CMU dictionary with syllable marks.+-- <http://webdocs.cs.ualberta.ca/~kondrak/cmudict.html>+type SYLLABLE = [Phoneme_str]++-- | An ARPABET word.+type ARPABET = [Phoneme_str]++-- | An ARPABET word, with syllables.+type ARPABET_syl = [SYLLABLE]++-- | Parameterised CMU dictionary.+type CMU_Dict_ty a = M.Map String a++-- | The CMU dictionary.+type CMU_Dict = CMU_Dict_ty ARPABET++-- | The syllabic CMU dictionary.+type CMU_Dict_syl = CMU_Dict_ty ARPABET_syl++-- | Parse 'Phoneme_str'+--+-- > parse_phoneme_str "EY1" == (EY,Just Primary_stress)+-- > parse_phoneme_str "R" == (R,Nothing)+parse_phoneme_str :: String -> Phoneme_str+parse_phoneme_str w =+    case reverse w of+      '0':w' -> (read (reverse w'),Just No_stress)+      '1':w' -> (read (reverse w'),Just Primary_stress)+      '2':w' -> (read (reverse w'),Just Secondary_stress)+      _ -> (read w,Nothing)++parse_arpabet :: String -> (String,ARPABET)+parse_arpabet e =+    case words e of+      w:p -> (w,map parse_phoneme_str p)+      _ -> error "parse_arpabet"++parse_arpabet_syl :: String -> (String,ARPABET_syl)+parse_arpabet_syl e =+    case words e of+      w:p -> let p' = wordsBy (== "-") p+             in (w,map (map parse_phoneme_str) p')+      _ -> error "parse_arpabet_syl"++-- | Classification of 'Phoneme's.+data Phoneme_Class = Monophthong | Diphthong | R_Coloured+                   | Semivowel+                   | Stop | Affricate | Fricative | Aspirate+                   | Nasal+                   | Liquid+                     deriving (Eq,Ord,Enum,Bounded,Read,Show)++-- | Classification table for 'Phoneme'.+arpabet_classification_table :: [(Phoneme_Class,[Phoneme])]+arpabet_classification_table =+    [(Monophthong,[AO,AA,IY,UW,EH,IH,UH,AH,AX,AE])+    ,(Diphthong,[EY,AY,OW,AW,OY])+    ,(R_Coloured,[ER,AXR])+    ,(Semivowel,[Y,W,Q])+    ,(Stop,[P,B,T,D,K,G])+    ,(Affricate,[CH,JH])+    ,(Fricative,[F,V,TH,DH,S,Z,SH,ZH])+    ,(Aspirate,[HH])+    ,(Nasal,[M,EM,N,EN,NG,ENG])+    ,(Liquid,[L,EL,R,DX,NX])]++-- | Consult 'arpabet_classification_table'.+--+-- > arpabet_classification HH == Aspirate+-- > map arpabet_classification [minBound .. maxBound]+arpabet_classification :: Phoneme -> Phoneme_Class+arpabet_classification p =+    let f (_,l) = p `elem` l+    in fromMaybe (error "arpabet_classification") $+       fmap fst $+       find f arpabet_classification_table++cmudict_load_ty :: (String -> (String,a)) -> FilePath -> IO (CMU_Dict_ty a)+cmudict_load_ty pf fn = do+  s <- readFile fn+  let is_comment w = case w of {';':_ -> True;_ -> False}+      l = filter (not . is_comment) (lines s)+  return (M.fromList (map pf l))++-- | Load CMU dictionary from file.+--+-- > d <- cmudict_load "/home/rohan/data/cmudict/cmudict.0.7a"+-- > M.size d == 133313+cmudict_load :: FilePath -> IO CMU_Dict+cmudict_load = cmudict_load_ty parse_arpabet++-- | Load syllable CMU dictionary from file.+--+-- > d <- cmudict_syl_load "/home/rohan/data/cmudict/cmudict.0.6d.syl"+-- > M.size d == 129463+cmudict_syl_load :: FilePath -> IO CMU_Dict_syl+cmudict_syl_load = cmudict_load_ty parse_arpabet_syl++-- | Dictionary lookup.+--+-- > let r = [(R,Nothing),(EY,Just Primary_stress)+-- >         ,(N,Nothing),(ER,Just No_stress),(D,Nothing)]+-- > in d_lookup d "reynard" == Just r+d_lookup :: CMU_Dict_ty a -> String -> Maybe a+d_lookup d w = M.lookup (map toUpper w) d++-- | Variant that retains query string if not in dictionary.+d_lookup' :: CMU_Dict_ty a -> String -> Either String a+d_lookup' d w = maybe (Left w) Right (d_lookup d w)++-- * IPA++-- | Table mapping /Arpabet/ phonemes to /IPA/ strings.+--+-- > length arpabet_ipa_table == 48+arpabet_ipa_table :: [(Phoneme,Either String [(Stress,String)])]+arpabet_ipa_table =+    -- Vowels (Monophthongs)+    [(AO,Left "ɔ")+    ,(AA,Left "ɑ")+    ,(IY,Left "i")+    ,(UW,Left "u")+    ,(EH,Left "ɛ")+    ,(IH,Left "ɪ")+    ,(UH,Left "ʊ")+    ,(AH,Right [(Primary_stress,"ʌ"),(No_stress,"ə")])+    ,(AX,Left "ə")+    ,(AE,Left "æ")+    -- Vowels (Diphthongs)+    ,(EY,Left "eɪ")+    ,(AY,Left "aɪ")+    ,(OW,Left "oʊ")+    ,(AW,Left "aʊ")+    ,(OY,Left "ɔɪ")+    -- Vowels (R-colored)+    ,(ER,Left "ɝ")+    ,(AXR,Left "ɚ")+    -- Semivowels+    ,(Y,Left "j")+    ,(W,Left "w")+    ,(Q,Left "ʔ")+    -- Consonants (Stops)+    ,(P,Left "p")+    ,(B,Left "b")+    ,(T,Left "t")+    ,(D,Left "d")+    ,(K,Left "k")+    ,(G,Left "ɡ")+    -- Consonants (Affricates)+    ,(CH,Left "tʃ")+    ,(JH,Left "dʒ")+    -- Consonants (Fricatives)+    ,(F,Left "f")+    ,(V,Left "v")+    ,(TH,Left "θ")+    ,(DH,Left "ð")+    ,(S,Left "s")+    ,(Z,Left "z")+    ,(SH,Left "ʃ")+    ,(ZH,Left "ʒ")+    -- Consonants (Aspirate)+    ,(HH,Left "h")+    -- Nasals+    ,(M,Left "m")+    ,(EM,Left "m̩")+    ,(N,Left "n")+    ,(EN,Left "n̩")+    ,(NG,Left "ŋ")+    ,(ENG,Left "ŋ̍")+    -- Liquids+    ,(L,Left "ɫ")+    ,(EL,Left "ɫ̩")+    ,(R,Left "ɹ")+    ,(DX,Left "ɾ")+    ,(NX,Left "ɾ̃")+    ]++-- | Consult 'arpabet_ipa_table'.+--+-- > map (phoneme_ipa (Just Primary_stress)) [minBound .. maxBound]+phoneme_ipa :: Maybe Stress -> Phoneme -> String+phoneme_ipa s =+    either id (fromMaybe (error (show ("phoneme_ipa: no stressed phoneme",s))) .+               lookup (fromMaybe (error "phoneme_ipa: no stress") s)) .+    fromMaybe (error "phoneme_ipa: no phoneme") .+    flip lookup arpabet_ipa_table++-- | Consult 'arpabet_ipa_table'.+--+-- > let r = map parse_phoneme_str (words "R EY1 N ER0 D")+-- > in arpabet_ipa r == "ɹeɪnɝd"+arpabet_ipa :: ARPABET -> String+arpabet_ipa = concatMap (\(p,s) -> phoneme_ipa s p)
Sound/SC3/Lang/Math.hs view
@@ -28,7 +28,7 @@ -- > > (0..5).collect({|i| i.degreeToKey([0,1,5,9,11],12)}) == [0,1,5,9,11,12] -- > map (degreeToKey [0,1,5,9,11] 12) [0..5] == [0,1,5,9,11,12] ----- > degreeToKey [0,2,4,5,7,9,11] 12 5 == 9+-- > map (degreeToKey [0,2,4,5,7,9,11] 12) [5,6,7,8] == [9,11,12,14] degreeToKey :: (RealFrac a) => [a] -> a -> a -> a degreeToKey s n d =     let l = length s@@ -64,6 +64,9 @@ log10 :: Floating a => a -> a log10 = logBase 10 +octpc_to_midi :: Num a => (a,a) -> a+octpc_to_midi (o,pc) = 60 + ((o - 4) * 12) + pc+ -- | @SimpleNumber.midicps@ translates from midi note number to cycles -- per second. --@@ -71,6 +74,20 @@ -- > map midicps [57,69] == [220,440] midicps :: (Floating a) => a -> a midicps a = 440.0 * (2.0 ** ((a - 69.0) * (1.0 / 12.0)))++-- | 'midicps' of 'octpc_to_midi'.+octpc_to_cps :: (Floating a) => (a,a) -> a+octpc_to_cps = midicps . octpc_to_midi++-- | 'octpc_to_cps' of 'degreeToKey'.+degree_to_cps :: (Floating a, RealFrac a) => [a] -> a -> a -> a -> a+degree_to_cps sc n d o =+    let pc = degreeToKey sc n d+    in octpc_to_cps (o,pc)++-- | Variant with list inputs for degree and octave, and scalar inputs for scale and steps.+degree_to_cps' :: (Floating a, RealFrac a) => [a] -> a -> [a] -> [a] -> [a]+degree_to_cps' sc n = zipWith (degree_to_cps sc n)  -- * UGen 
Sound/SC3/Lang/Math/Warp.hs view
@@ -2,6 +2,9 @@ -- space /[l,r]/. module Sound.SC3.Lang.Math.Warp where +import Numeric {- base -}+import Sound.SC3.UGen.Math {- hsc3 -}+ import Sound.SC3.Lang.Math  -- | Warp direction.  'W_Map' is forward, 'W_Unmap' is reverse.@@ -39,6 +42,9 @@ -- > > [0,0.5,1].collect{|n| w.map(n)} == [1,pow(2,0.5),2] -- -- > map (warpExponential 1 2 W_Map) [0,0.5,1] == [1,2 ** 0.5,2]+--+-- > import Sound.SC3.Plot+-- > plotTable1 (map (warpExponential 1 2 W_Map) [0,0.01 .. 1]) warpExponential :: (Floating a) => a -> a -> Warp a warpExponential l r d n =     let z = r / l@@ -52,6 +58,8 @@ -- > > [0,0.25,0.5,0.75,1].collect{|n| w.map(n)} -- -- > map (warpCosine 1 2 W_Map) [0,0.25,0.5,0.75,1]+--+-- > plotTable1 (map (warpCosine 1 2 W_Map) [0,0.01 .. 1]) warpCosine :: (Floating a) => a -> a -> Warp a warpCosine l r d n =     let w = warpLinear 0 (r - l) d@@ -62,6 +70,8 @@ -- | Sine warp -- -- > map (warpSine 1 2 W_Map) [0,0.25,0.5,0.75,1]+--+-- > plotTable1 (map (warpSine 1 2 W_Map) [0,0.01 .. 1]) warpSine :: (Floating a) => a -> a -> Warp a warpSine l r d n =     let w = warpLinear 0 (r - l) d@@ -69,26 +79,38 @@        then w (sin (pi * 0.5 * n))        else asin (w n) / (pi / 2) --- | Fader warp.  Left and right values are implicitly zero and one.+-- | Fader warp.  Left and right values are ordinarily zero and one. ----- > map (warpFader W_Map) [0,0.5,1] == [0,0.25,1]-warpFader :: Floating a => Warp a-warpFader d n = if d == W_Map then n * n else sqrt n+-- > map (warpFader 0 1 W_Map) [0,0.5,1] == [0,0.25,1]+--+-- > plotTable1 (map (warpFader 0 1 W_Map) [0,0.01 .. 1])+-- > plotTable1 (map (warpFader 0 2 W_Map) [0,0.01 .. 1])+warpFader :: Floating a => a -> a -> Warp a+warpFader l r d n =+    let n' = if d == W_Map then n * n else sqrt n+    in warpLinear l r d n' --- | DB fader warp. Left and right values are implicitly negative+-- | DB fader warp. Left and right values are ordinarily negative -- infinity and zero.  An input of @0@ gives @-180@. -- -- > map (round . warpDbFader W_Map) [0,0.5,1] == [-180,-12,0]-warpDbFader :: (Eq a,Floating a) => Warp a-warpDbFader d n =+--+-- > plotTable1 (map (warpDbFader (-60) 0 W_Map) [0,0.01 .. 1])+-- > plotTable1 (map (warpDbFader 0 60 W_Unmap) [0 .. 60])+warpDbFader :: (TernaryOp a,Eq a,Floating a) => a -> a -> Warp a+warpDbFader l r d n =     if d == W_Map-    then if n == 0 then -180 else ampdb (n * n)-    else sqrt (dbamp n)+    then let n' = if n == 0 then -180 else ampdb (n * n)+         in linlin n' (-180) 0 l r+    else sqrt (dbamp (linlin n l r (-180) 0))  -- | A curve warp given by a real /n/. -- -- > w_map (warpCurve (-3) 1 2) 0.25 == 1.5552791692202022 -- > w_map (warpCurve (-3) 1 2) 0.50 == 1.8175744761936437+--+-- > plotTable1 (map (warpCurve (-3) 1 2 W_Map) [0,0.01 .. 1])+-- > plotTable1 (map (warpCurve 9 1 2 W_Map) [0,0.01 .. 1]) warpCurve :: (Ord a,Floating a) => a -> a -> a -> Warp a warpCurve k l r d n =     let e = exp k@@ -99,3 +121,25 @@        else if d == W_Map             then b - ((e ** n) * a)             else log ((b - n) / a) / k++-- | Select warp function by name.  Numerical names are interpreted as+-- /curve/ values for 'warpCurve'.+--+-- > let Just w = warpNamed "lin"+-- > let Just w = warpNamed "-3"+-- > let Just w = warpNamed "6"+-- > plotTable1 (map (w 1 2 W_Map) [0,0.01 .. 1])+warpNamed :: (TernaryOp a,Ord a,Eq a,RealFrac a,Floating a) =>+             String -> Maybe (a -> a -> Warp a)+warpNamed nm =+    case nm of+      "lin" -> Just warpLinear+      "exp" -> Just warpExponential+      "sin" -> Just warpSine+      "cos" -> Just warpCosine+      "amp" -> Just warpFader+      "db" -> Just warpDbFader+      _ -> case readSigned readFloat nm of+             [(c,"")] -> Just (warpCurve c)+             _ -> Nothing+
Sound/SC3/Lang/Pattern.hs view
@@ -6,4 +6,6 @@ import Sound.SC3.Lang.Control.Instrument as P import Sound.SC3.Lang.Control.Pitch as P import Sound.SC3.Lang.Control.OverlapTexture as P-import Sound.SC3.Lang.Pattern.ID as P++import Sound.SC3.Lang.Pattern.P as P+import Sound.SC3.Lang.Pattern.P.Event as P
+ Sound/SC3/Lang/Pattern/Bind.hs view
@@ -0,0 +1,94 @@+-- | Minimal functions for binding values to parameter names and sending to scsynth.+module Sound.SC3.Lang.Pattern.Bind where++import Data.List {- base -}+import qualified Data.List.Ordered as O {- data-ordlist -}+import Data.Maybe {- base -}++import Sound.OSC {- hosc -}+import Sound.SC3 {- hsc3 -}++import qualified Sound.SC3.Lang.Core as L {- hsc3-lang -}++type Param = [(String,[Double])]++pr_unused :: Synthdef -> Param -> [String]+pr_unused sy pr = (map fst pr \\ synthdefParam sy) \\ ["dur","sustain"]++-- * Synthdef bind++sbind_init :: Int -> [Synthdef] -> [Bundle]+sbind_init grp sy =+    let sy_b = bundle 0 (map d_recv sy)+        grp_b = bundle 0 [g_new [(grp,AddToHead,0)]]+    in [sy_b,grp_b]++sbind_tseq :: Int -> [Int] -> (Synthdef,[Time],Maybe [Time],Param) -> [Bundle]+sbind_tseq grp nid (sy,tm,sus,pr) =+    let sy_pr = synthdefParam sy+        has_gate = "gate" `elem` sy_pr+        nd (t,k,ar) = let nm = synthdefName sy+                      in bundle t [s_new nm k AddToHead grp ar]+        pr' = let f (p,l) = zip (repeat p) l+              in L.transpose_st (map f pr)+        gt = if has_gate+             then let sus' = fromMaybe (d_dx' tm) sus+                      -- pr' may be finite, zipped here to halt if required...+                      f (t,g,k,_) = bundle (t + g) [n_set1 k "gate" 0]+                  in map f (zip4 tm sus' nid pr')+             else if isNothing sus || "sustain" `elem` sy_pr+                  then []+                  else error ("sbind_tseq: sus given but no gate parameter")+    in case pr_unused sy pr of+         [] -> O.merge (map nd (zip3 tm nid pr')) gt+         u -> error (show ("sbind_tseq: unused parameters",u))++sbind_deriv :: Int -> [Int] -> (Synthdef,Param) -> [Bundle]+sbind_deriv grp nid (sy,pr) =+    let dur = fromMaybe (error "sbind_deriv: no dur parameter") (lookup "dur" pr)+        sus = lookup "sustain" pr+        tm = dx_d' dur+    in sbind_tseq grp nid (sy,tm,sus,pr)++sbind :: [(Synthdef,Param)] -> NRT+sbind set =+    let grp = 1+        nid = map (\n -> [n..]) [1000,6000 ..]+    in NRT (sbind_init grp (map fst set) ++ foldl1 O.merge (zipWith (sbind_deriv grp) nid set))++sbind1 :: (Synthdef,Param) -> NRT+sbind1 = sbind . return++-- * Node bind++nbind_init :: Int -> [(Synthdef,Int,Param)] -> [Bundle]+nbind_init grp m =+    let (sy,nid,_) = unzip3 m+        sy_b = bundle 0 (map d_recv sy)+        grp_b = bundle 0 [g_new [(grp,AddToHead,0)]]+        nd_b = bundle 0 (map (\(s,k) -> s_new (synthdefName s) k AddToHead grp []) (zip sy nid))+    in [sy_b,grp_b,nd_b]++nbind_tseq :: (Synthdef,Int,[Time],Param) -> [Bundle]+nbind_tseq (sy,nid,tm,pr) =+    let m (t,k,ar) = bundle t [n_set k ar]+        pr' = let f (p,l) = zip (repeat p) l+              in L.transpose_st (map f pr)+    in case pr_unused sy pr of+         [] -> map m (zip3 tm (repeat nid) pr')+         u -> error (show ("nbind_tseq: unused parameters",u))++nbind_deriv :: (Synthdef,Int,Param) -> [Bundle]+nbind_deriv (sy,k,pr) =+    let dur = fromMaybe (error "nbind_deriv: no dur parameter") (lookup "dur" pr)+        tm = dx_d' dur+    in nbind_tseq (sy,k,tm,pr)++nbind :: [(Synthdef,Int,Param)] -> NRT+nbind set =+    let grp = 1+        set' = map nbind_deriv set+    in NRT (nbind_init grp set ++ foldl1 O.merge set')++nbind1 :: (Synthdef,Int,Param) -> NRT+nbind1 = nbind . return
− Sound/SC3/Lang/Pattern/ID.hs
@@ -1,1960 +0,0 @@-{-# Language FlexibleInstances #-}--- | @sclang@ pattern library functions.--- See <http://rd.slavepianos.org/?t=hsc3-texts> for tutorial.------ SC3 /value/ patterns: `pbrown` (Pbrown), `pclutch` (Pclutch),--- `pcollect` (Pcollect), `pconst` (Pconst), `pdegreeToKey`--- (PdegreeToKey), `pdiff` (Pdiff), `pdrop` (Pdrop), `pdurStutter`--- (PdurStutter), `pexprand` (Pexprand), `pfinval` (Pfinval), `pfuncn`--- (Pfuncn), `pgeom` (Pgeom), `pif` (Pif), `place` (Place), `pn` (Pn),--- `ppatlace` (Ppatlace), `prand` (Prand), `preject` (Preject),--- `prorate` (Prorate), `pselect` (Pselect), `pseq` (Pseq), `pser`--- (Pser), `pseries` (Pseries), `pshuf` (Pshuf), `pslide` (Pslide),--- `pstutter` (Pstutter), `pswitch1` (Pswitch1), `pswitch` (Pswitch),--- `ptuple` (Ptuple), `pwhite` (Pwhite), `pwrand` (Pwrand), `pwrap`--- (Pwrap), `pxrand` (Pxrand).------ SC3 /event/ patterns: `padd` (Padd), `pbind` (Pbind), `pkey`--- (PKey), `pmono` (Pmono), `pmul` (Pmul), `ppar` (Ppar), `pstretch`--- (Pstretch), `ptpar` (Ptpar).  `pedit`, `pinstr`, `pmce2`, `psynth`,--- `punion`.------ SC3 variant patterns: `pbrown`', `prand'`, `prorate'`, `pseq1`,--- `pseqn`, `pser1`, `pseqr`, `pwhite'`, `pwhitei`.------ SC3 collection patterns: `pfold`------ Haskell patterns: `pappend`, `pbool`, `pconcat`, `pcons`,--- `pcountpost`, `pcountpre`, `pcycle`, `pempty`,`pfilter`, `phold`,--- `pinterleave`,`pjoin`, `prepeat`, `preplicate`, `prsd`, `pscanl`,--- `psplitPlaces`, `psplitPlaces'`, `ptail`, `ptake`, `ptrigger`,--- `pzip`, `pzipWith`-module Sound.SC3.Lang.Pattern.ID where--import Control.Applicative hiding ((<*)) {- base -}-import Control.Monad {- base -}-import Data.Bifunctor {- bifunctors -}-import qualified Data.Foldable as F {- base -}-import qualified Data.List as L {- base -}-import qualified Data.List.Split as S {- split -}-import Data.Maybe {- base -}-import Data.Monoid {- base -}-import qualified Data.Traversable as T {- base -}-import Sound.OSC {- hsc3 -}-import Sound.SC3 {- hsc3 -}-import System.Random {- random -}--import qualified Sound.SC3.Lang.Collection as C-import Sound.SC3.Lang.Control.Duration-import Sound.SC3.Lang.Control.Event-import Sound.SC3.Lang.Control.Instrument-import qualified Sound.SC3.Lang.Math as M-import qualified Sound.SC3.Lang.Pattern.List as P-import qualified Sound.SC3.Lang.Random.Gen as R---- * P---- | Patterns are opaque.  @P a@ is a pattern with elements of type--- @a@.  Patterns are constructed, manipulated and destructured using--- the functions provided, ie. the pattern instances for 'return',--- 'pure' and 'F.toList', and the pattern specific functions--- 'undecided' and 'toP'.------ > F.toList (toP [1,2,3] * 2) == [2,4,6]------ Patterns are 'Functor's.  'fmap' applies a function to each element--- of a pattern.------ > fmap (* 2) (toP [1,2,3,4,5]) == toP [2,4,6,8,10]------ Patterns are 'Monoid's.  'mempty' is the empty pattern, and--- 'mappend' ('<>') makes a sequence of two patterns.------ > 1 <> mempty <> 2 == toP [1,2]------ Patterns are 'Applicative'.  The pattern instance is pointwise &--- truncating, unlike the combinatorial instance for ordinary lists.--- 'pure' lifts a value into an infinite pattern of itself, '<*>'--- applies a pattern of functions to a pattern of values.  This is--- distinct from the list instance which is monadic, ie. 'pure' is--- 'return' and '<*>' is 'ap'.------ > liftA2 (+) (toP [1,2]) (toP [3,4,5]) == toP [4,6]--- > liftA2 (+) [1,2] [3,4,5] == [4,5,6,5,6,7]------ Patterns are 'Monad's, and therefore allow /do/ notation.------ > let p = do {x <- toP [1,2]; y <- toP [3,4,5]; return (x,y)}--- > in p == toP [(1,3),(1,4),(1,5),(2,3),(2,4),(2,5)]------ Patterns are 'Num'erical.  The instances can be derived from the--- 'Applicative' instance.------ > 1 + toP [2,3,4] == liftA2 (+) 1 (toP [2,3,4])-data P a = P {unP_either :: Either a [a]}-           deriving (Eq,Show)---- | Lift a value to a pattern deferring deciding if the constructor--- ought to be 'pure' or 'return' to the consuming function.  The--- pattern instances for 'fromInteger' and 'fromRational' make--- 'undecided' patterns.  In general /horizontal/ functions (ie. '<>')--- resolve using 'return' and /vertical/ functions (ie. 'zip') resolve--- using 'pure'.------ > 1 <> toP [2,3] == return 1 <> toP [2,3]--- > toP [1,2] * 3  == toP [1,2] * pure 3-undecided :: a -> P a-undecided a = P (Left a)---- | The basic list to pattern function, inverse is 'unP'.------ > unP (toP "str") == "str"------ > audition (pbind [(K_degree,pxrand 'α' [0,1,5,7] inf)--- >                 ,(K_dur,toP [0.1,0.2,0.1])])------ > > Pbind(\degree,(Pxrand([0,1,5,7],inf))--- > >      ,\dur,Pseq([0.1,0.2,0.1],1)).play------ The pattern above is finite, `toP` can sometimes be replaced with--- `pseq`.------ > audition (pbind [(K_degree,pxrand 'α' [0,1,5,7] inf)--- >                 ,(K_dur,pseq [0.1,0.2,0.1] inf)])-toP :: [a] -> P a-toP = P . Right---- | Type specialised 'F.toList'.  'undecided' values are singular.------ > F.toList (undecided 'a') == ['a']--- > unP (return 'a') == ['a']--- > "aaa" `L.isPrefixOf` unP (pure 'a')-unP :: P a -> [a]-unP = either return id . unP_either---- | Variant of 'unP' where 'undecided' values are 'repeat'ed.------ > unP_repeat (return 'a') == ['a']--- > take 2 (unP_repeat (undecided 'a')) == ['a','a']--- > take 2 (unP_repeat (pure 'a')) == ['a','a']-unP_repeat :: P a -> [a]-unP_repeat = either repeat id . unP_either--instance Functor P where-    fmap f (P p) = P (bimap f (map f) p)--instance Monoid (P a) where-    mappend p q = toP (unP p ++ unP q)-    mempty = toP []--instance Applicative P where-    pure = toP . repeat-    f <*> e = pzipWith ($) f e--instance Alternative P where-    empty = mempty-    (<|>) = mappend--instance F.Foldable P where-    foldr f i p = L.foldr f i (unP p)--instance T.Traversable P where-    traverse f p = pure toP <*> T.traverse f (unP p)--instance Monad P where-    m >>= k =-        case m of-          P (Left e) -> k e-          P (Right l) -> L.foldr (mappend . k) mempty l-    return x = toP [x]--instance MonadPlus P where-    mzero = mempty-    mplus = mappend--instance (Num a) => Num (P a) where-    (+) = pzipWith (+)-    (-) = pzipWith (-)-    (*) = pzipWith (*)-    abs = fmap abs-    signum = fmap signum-    negate = fmap negate-    fromInteger = undecided . fromInteger--instance (Fractional a) => Fractional (P a) where-    (/) = pzipWith (/)-    recip = fmap recip-    fromRational = undecided . fromRational--instance (Ord a) => Ord (P a) where-    (>) = error ("~> Ord>*")-    (>=) = error ("~> Ord>=*")-    (<) = error ("~> Ord<*")-    (<=) = error ("~> Ord<=*")--instance (OrdE a) => OrdE (P a) where-    (>*) = pzipWith (>*)-    (>=*) = pzipWith (>=*)-    (<*) = pzipWith (<*)-    (<=*) = pzipWith (<=*)---- * Lift P---- | Lift unary list function to pattern function.-liftP :: ([a] -> [b]) -> P a -> P b-liftP f = toP . f . unP---- | Lift binary list function to pattern function.------ > liftP2 (zipWith (+)) (toP [1,2]) (toP [3,4,5]) == toP [4,6]--- > liftA2 (+) (toP [1,2]) (toP [3,4,5]) == toP [4,6]-liftP2 :: ([a] -> [b] -> [c]) -> P a -> P b -> P c-liftP2 f p q =-    let p' = unP p-        q' = unP q-    in toP (f p' q')---- | Lift binary list function to /implicitly repeating/ pattern function.-liftP2_repeat :: ([a] -> [b] -> [c]) -> P a -> P b -> P c-liftP2_repeat f p q =-    let p' = unP_repeat p-        q' = unP_repeat q-    in toP (f p' q')---- | Lift ternary list function to pattern function.-liftP3 :: ([a] -> [b] -> [c] -> [d]) -> P a -> P b -> P c -> P d-liftP3 f p q r =-    let p' = unP p-        q' = unP q-        r' = unP r-    in toP (f p' q' r')---- | Lift ternary list function to /implicitly repeating/ pattern function.-liftP3_repeat :: ([a] -> [b] -> [c] -> [d]) -> P a -> P b -> P c -> P d-liftP3_repeat f p q r =-    let p' = unP_repeat p-        q' = unP_repeat q-        r' = unP_repeat r-    in toP (f p' q' r')---- * Zip P---- | An /implicitly repeating/ pattern variant of 'zipWith'.------ > zipWith (*) [1,2,3] [5,6] == [5,12]--- > pzipWith (*) (toP [1,2,3]) (toP [5,6]) == toP [5,12]------ It is the basis for lifting binary operators to patterns.------ > toP [1,2,3] * toP [5,6] == toP [5,12]------ > let p = pzipWith (,) (pseq [1,2] 2) (pseq [3,4] inf)--- > in p == toP [(1,3),(2,4),(1,3),(2,4)]------ > zipWith (,) (return 0) (return 1) == return (0,1)--- > pzipWith (,) 0 1 == undecided (0,1)-pzipWith :: (a -> b -> c) -> P a -> P b -> P c-pzipWith f p q =-    case (p,q) of-      (P (Left m),P (Left n)) -> undecided (f m n)-      _ -> toP (zipWith f (unP_repeat p) (unP_repeat q))---- | An /implicitly repeating/ pattern variant of 'zipWith3'.-pzipWith3 :: (a -> b -> c -> d) -> P a -> P b -> P c -> P d-pzipWith3 f p q r =-    case (p,q,r) of-      (P (Left m),P (Left n),P (Left o)) -> undecided (f m n o)-      _ -> toP (zipWith3 f (unP_repeat p) (unP_repeat q) (unP_repeat r))---- | An /implicitly repeating/ pattern variant of 'zip'.------ > zip (return 0) (return 1) == return (0,1)--- > pzip (undecided 3) (undecided 4) == undecided (3,4)--- > pzip 0 1 == undecided (0,1)------ Note that 'pzip' is otherwise like haskell 'zip', ie. truncating.------ > zip [1,2] [0] == [(1,0)]--- > pzip (toP [1,2]) (return 0) == toP [(1,0)]--- > pzip (toP [1,2]) (pure 0) == toP [(1,0),(2,0)]--- > pzip (toP [1,2]) 0 == toP [(1,0),(2,0)]-pzip :: P a -> P b -> P (a,b)-pzip = pzipWith (,)---- | Pattern variant of 'zip3'.-pzip3 :: P a -> P b -> P c -> P (a,b,c)-pzip3 = pzipWith3 (,,)---- | Pattern variant on 'unzip'.------ > let p = punzip (pzip (toP [1,2,3]) (toP [4,5]))--- > in p == (toP [1,2],toP [4,5])-punzip :: P (a,b) -> (P a,P b)-punzip p = let (i,j) = unzip (unP p) in (toP i,toP j)---- * Math---- | Type specialised 'maxBound', a pseudo-/infinite/ value for use at--- pattern repeat counts.------ > inf == maxBound-inf :: Int-inf = maxBound--{-| Constant /NaN/ (not a number) value.--> isNaN nan == True--A frequency value of NaN indicates a rest. This constant value can be-used as a rest indicator at a frequency model input (not at a @rest@-key).--> audition (pbind [(K_dur,pseq [0.1,0.7] inf)->                 ,(K_legato,0.2)->                 ,(K_degree,pseq [0,2,return nan] inf)])---}-nan :: Floating a => a-nan = sqrt (-1)---- * Data.List Patterns---- | Pattern variant of 'Data.List.:'.------ > pcons 'α' (pn (return 'β') 2) == toP "αββ"-pcons :: a -> P a -> P a-pcons = mappend . return---- | Pattern variant of 'Data.List.null'.------ > pnull mempty == True--- > pnull (undecided 'a') == False--- > pnull (pure 'a') == False--- > pnull (return 'a') == False-pnull :: P a -> Bool-pnull = null . unP---- | Alias for 'pure', pattern variant of 'Data.List.repeat'.------ > ptake 5 (prepeat 3) == toP [3,3,3,3,3]--- > ptake 5 (pure 3) == toP [3,3,3,3,3]--- > take 5 (pure 3) == [3]-prepeat :: a -> P a-prepeat = pure---- | Pattern variant of 'splitAt'.-psplitAt :: Int -> P a -> (P a,P a)-psplitAt n p =-    let (i,j) = splitAt n (unP p)-    in (toP i,toP j)---- | Pattern variant of 'Data.List.Split.splitPlaces'.------ > psplitPlaces' (toP [1,2,3]) (pseries 1 1 6) == toP [[1],[2,3],[4,5,6]]--- > psplitPlaces' (toP [1,2,3]) (toP ['a'..]) == toP ["a","bc","def"]-psplitPlaces' :: P Int -> P a -> P [a]-psplitPlaces' = liftP2 S.splitPlaces---- | 'fmap' 'toP' of 'psplitPlaces''.------ > psplitPlaces (toP [1,2,3]) (toP ['a'..]) == toP (map toP ["a","bc","def"])-psplitPlaces :: P Int -> P a -> P (P a)-psplitPlaces n = fmap toP . psplitPlaces' n---- | Pattern variant of 'P.take_inf', see also 'pfinval'.------ > ptake 5 (pseq [1,2,3] 2) == toP [1,2,3,1,2]--- > ptake 5 (toP [1,2,3]) == toP [1,2,3]--- > ptake 5 (pseq [1,2,3] inf) == toP [1,2,3,1,2]--- > ptake 5 (pwhite 'α' 0 5 inf) == toP [5,2,1,2,0]------ Note that `ptake` does not extend the input pattern, unlike `pser`.------ > ptake 5 (toP [1,2,3]) == toP [1,2,3]--- > pser [1,2,3] 5 == toP [1,2,3,1,2]-ptake :: Int -> P a -> P a-ptake n = liftP (P.take_inf n)---- | Type specialised 'P.mcycle'.------ > ptake 5 (pcycle 1) == preplicate 5 1--- > ptake 5 (pcycle (pure 1)) == preplicate 5 1--- > ptake 5 (pcycle (return 1)) == preplicate 5 1-pcycle :: P a -> P a-pcycle = P.mcycle---- | Type specialised 'mfilter'.  Aliased to `pselect`.  See also--- `preject`.------ > mfilter even (pseq [1,2,3] 2) == toP [2,2]--- > mfilter (< 3) (pseq [1,2,3] 2) == toP [1,2,1,2]-pfilter :: (a -> Bool) -> P a -> P a-pfilter = mfilter---- | Pattern variant of `replicate`.------ > preplicate 4 1 == toP [1,1,1,1]------ Compare to `pn`:------ > pn 1 4 == toP [1,1,1,1]--- > pn (toP [1,2]) 3 == toP [1,2,1,2,1,2]--- > preplicate 4 (toP [1,2]) :: P (P Int)-preplicate :: Int -> a -> P a-preplicate n = toP . (if n == inf then repeat else replicate n)---- | Pattern variant of `scanl`.  `scanl` is similar to `foldl`, but--- returns a list of successive reduced values from the left.  pscanl--- is an accumulator, it provides a mechanism for state to be threaded--- through a pattern. It can be used to write a function to remove--- succesive duplicates from a pattern, to count the distance between--- occurences of an element in a pattern and so on.------ > F.foldl (\x y -> 2 * x + y) 4 (pseq [1,2,3] 1) == 43--- > pscanl (\x y -> 2 * x + y) 4 (pseq [1,2,3] 1) == toP [4,9,20,43]------ > F.foldl (flip (:)) [] (toP [1..3]) == [3,2,1]--- > pscanl (flip (:)) [] (toP [1..3]) == toP [[],[1],[2,1],[3,2,1]]------ > F.foldl (+) 0 (toP [1..5]) == 15--- > pscanl (+) 0 (toP [1..5]) == toP [0,1,3,6,10,15]-pscanl :: (a -> b -> a) -> a -> P b -> P a-pscanl f i = liftP (L.scanl f i)---- | 'pdrop' @1@.  Pattern variant of `Data.List.tail`.  Drops first--- element from pattern.  Note that the haskell `tail` function is--- partial, although `drop` is not.  `ptake` is equal to `pdrop 1`.------ > tail [] == _|_--- > drop 1 [] == []------ > ptail (toP [1,2]) == toP [2]--- > ptail mempty == mempty-ptail :: P a -> P a-ptail = pdrop 1---- | Variant of 'L.transpose'.------ > L.transpose [[1,2],[3,4,5]] == [[1,3],[2,4],[5]]--- > ptranspose [toP [1,2],toP [3,4,5]] == toP [[1,3],[2,4],[5]]------ > let p = ptranspose [pseq [1,2] inf,pseq [4,5] inf]--- > in ptake 2 (pdrop (2^16) p) == toP [[1,4],[2,5]]-ptranspose :: [P a] -> P [a]-ptranspose l = toP (L.transpose (map unP l))---- | An /implicitly repeating/ pattern variant of 'P.transpose_st'.-ptranspose_st_repeat :: [P a] -> P [a]-ptranspose_st_repeat l = toP (P.transpose_st (map unP_repeat l))---- * SC3 Collection Patterns---- | Variant of 'C.flop'.------ > pflop' [toP [1,2],toP [3,4,5]] == toP [[1,3],[2,4],[1,5]]--- > pflop' [toP [1,2],3] == toP [[1,3],[2,3]]--- > pflop' [pseq [1,2] 1,pseq [3,4] inf]-pflop' :: [P a] -> P [a]-pflop' l = toP (C.flop (map unP l))---- | 'fmap' 'toP' of 'pflop''.------ > C.flop [[1,2],[3,4,5]] == [[1,3],[2,4],[1,5]]--- > pflop [toP [1,2],toP [3,4,5]] == toP (map toP [[1,3],[2,4],[1,5]])-pflop :: [P a] -> P (P a)-pflop = fmap toP . pflop'---- | Type specialised 'P.ffold'.------ > pfold (toP [10,11,12,-6,-7,-8]) (-7) 11 == toP [10,11,10,-6,-7,-6]------ > audition (pbind [(K_degree,pfold (pseries 4 1 inf) (-7) 11)--- >                 ,(K_dur,0.0625)])------ The underlying primitive is then `fold_` function.------ > let f = fmap (\n -> fold_ n (-7) 11)--- > in audition (pbind [(K_degree,f (pseries 4 1 inf))--- >                    ,(K_dur,0.0625)])-pfold :: (RealFrac n) => P n -> n -> n -> P n-pfold = P.ffold---- | Pattern variant of 'C.normalizeSum'.-pnormalizeSum :: Fractional n => P n -> P n-pnormalizeSum = liftP C.normalizeSum---- * SC3 Patterns--{-| Pbrown.  Lifted 'P.brown'.  SC3 pattern to generate-psuedo-brownian motion.--> pbrown 'α' 0 9 1 5 == toP [4,4,5,4,3]--> audition (pbind [(K_dur,0.065)->                 ,(K_freq,pbrown 'α' 440 880 20 inf)])---}-pbrown :: (Enum e,Random n,Num n,Ord n) => e -> n -> n -> n -> Int -> P n-pbrown e l r s n = ptake n (toP (P.brown e l r s))--{-| Pclutch.  SC3 sample and hold pattern.  For true values in the-control pattern, step the value pattern, else hold the previous value.--> > c = Pseq([1,0,1,0,0,1,1],inf);-> > p = Pclutch(Pser([1,2,3,4,5],8),c);-> > r = [1,1,2,2,2,3,4,5,5,1,1,1,2,3];-> > p.asStream.all == r--> let {c = pbool (pseq [1,0,1,0,0,1,1] inf)->     ;p = pclutch (pser [1,2,3,4,5] 8) c->     ;r = toP [1,1,2,2,2,3,4,5,5,1,1,1,2,3]}-> in p == toP [1,1,2,2,2,3,4,5,5,1,1,1,2,3]--Note the initialization behavior, nothing is generated until the-first true value.--> let {p = pseq [1,2,3,4,5] 1->     ;q = pbool (pseq [0,0,0,0,0,0,1,0,0,1,0,1] 1)}-> in pclutch p q == toP [1,1,1,2,2,3]--> > Pbind(\degree,Pstutter(Pwhite(3,10,inf),Pwhite(-4,11,inf)),-> >       \dur,Pclutch(Pwhite(0.1,0.4,inf),-> >                    Pdiff(Pkey(\degree)).abs > 0),-> >       \legato,0.3).play;--> let {d = pstutter (pwhite 'α' 3 10 inf) (pwhitei 'β' (-4) 11 inf)->     ;p = [(K_degree,d)->          ,(K_dur,pclutch (pwhite 'γ' 0.1 0.4 inf)->                          (pbool (abs (pdiff d) >* 0)))->          ,(K_legato,0.3)]}-> in audition (pbind p)---}-pclutch :: P a -> P Bool -> P a-pclutch p q =-    let r = fmap (+ 1) (pcountpost q)-    in pstutter r p---- | Pcollect.  SC3 name for 'fmap', ie. patterns are functors.------ > > Pcollect({|i| i * 3},Pseq(#[1,2,3],1)).asStream.all == [3,6,9]--- > pcollect (* 3) (toP [1,2,3]) == toP [3,6,9]------ > > Pseq(#[1,2,3],1).collect({|i| i * 3}).asStream.all == [3,6,9]--- > fmap (* 3) (toP [1,2,3]) == toP [3,6,9]-pcollect :: (a -> b) -> P a -> P b-pcollect = fmap---- | Pconst.  SC3 pattern to constrain the sum of a numerical pattern.--- Is equal to /p/ until the accumulated sum is within /t/ of /n/.  At--- that point, the difference between the specified sum and the--- accumulated sum concludes the pattern.------ > > p = Pconst(10,Pseed(Pn(1000,1),Prand([1,2,0.5,0.1],inf),0.001));--- > > p.asStream.all == [0.5,0.1,0.5,1,2,2,0.5,1,0.5,1,0.9]------ > let p = pconst 10 (prand 'α' [1,2,0.5,0.1] inf) 0.001--- > in (p,Data.Foldable.sum p)------ > > Pbind(\degree,Pseq([-7,Pwhite(0,11,inf)],1),--- > >       \dur,Pconst(4,Pwhite(1,4,inf) * 0.25)).play------ > let p = [(K_degree,pcons (-7) (pwhitei 'α' 0 11 inf))--- >         ,(K_dur,pconst 4 (pwhite 'β' 1 4 inf * 0.25) 0.001)]--- > in audition (pbind p)-pconst :: (Ord a,Num a) => a -> P a -> a -> P a-pconst n p t =-    let f _ [] = []-        f j (i:is) = if i + j < n - t-                     then i : f (j + i) is-                     else [n - j]-    in toP (f 0 (unP p))--{-| PdegreeToKey.  SC3 pattern to derive notes from an index into a-scale.--> let {p = pseq [0,1,2,3,4,3,2,1,0,2,4,7,4,2] 2->     ;q = pure [0,2,4,5,7,9,11]->     ;r = [0,2,4,5,7,5,4,2,0,4,7,12,7,4,0,2,4,5,7,5,4,2,0,4,7,12,7,4]}-> in pdegreeToKey p q (pure 12) == toP r--> let {p = pseq [0,1,2,3,4,3,2,1,0,2,4,7,4,2] 2->     ;q = pseq (map return [[0,2,4,5,7,9,11],[0,2,3,5,7,8,11]]) 1->     ;r = [0,2,4,5,7,5,4,2,0,4,7,12,7,4,0,2,3,5,7,5,3,2,0,3,7,12,7,3]}-> in pdegreeToKey p (pstutter 14 q) (pure 12) == toP r--This is the pattern variant of 'M.degreeToKey'.--> let s = [0,2,4,5,7,9,11]-> in map (M.degreeToKey s 12) [0,2,4,7,4,2,0] == [0,4,7,12,7,4,0]--> > Pbind(\note,PdegreeToKey(Pseq([1,2,3,2,5,4,3,4,2,1],2),-> >                          #[0,2,3,6,7,9],-> >                          12),\dur,0.25).play--> let {n = pdegreeToKey (pseq [1,2,3,2,5,4,3,4,2,1] 2)->                       (pure [0,2,3,6,7,9])->                       12}-> in audition (pbind [(K_note,n),(K_dur,0.25)])--> > s = #[[0,2,3,6,7,9],[0,1,5,6,7,9,11],[0,2,3]];-> > d = [1,2,3,2,5,4,3,4,2,1];-> > Pbind(\note,PdegreeToKey(Pseq(d,4),-> >                          Pstutter(3,Prand(s,inf)),-> >                          12),\dur,0.25).play;--> let {s = map return [[0,2,3,6,7,9],[0,1,5,6,7,9,11],[0,2,3]]->     ;d = [1,2,3,2,5,4,3,4,2,1]->     ;k = pdegreeToKey (pseq d 4)->                       (pstutter 3 (prand 'α' s 14))->                       (pn 12 40)}-> in audition (pbind [(K_note,k),(K_dur,0.25)])---}-pdegreeToKey :: (RealFrac a) => P a -> P [a] -> P a -> P a-pdegreeToKey = pzipWith3 (\i j k -> M.degreeToKey j k i)---- | Pdiff.  SC3 pattern to calculate adjacent element difference.------ > > Pdiff(Pseq([0,2,3,5,6,8,9],1)).asStream.all == [2,1,2,1,2,1]--- > pdiff (pseq [0,2,3,5,6,8,9] 1) == toP [2,1,2,1,2,1]-pdiff :: Num n => P n -> P n-pdiff p = ptail p - p---- | Pdrop.  Lifted 'L.drop'.------ > > p = Pseries(1,1,20).drop(5);--- > > p.asStream.all == [6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]------ > pdrop 5 (pseries 1 1 10) == toP [6,7,8,9,10]--- > pdrop 1 mempty == mempty-pdrop :: Int -> P a -> P a-pdrop n = liftP (drop n)---- | PdurStutter.  Lifted 'P.durStutter'.------ > > s = Pseq(#[1,1,1,1,1,2,2,2,2,2,0,1,3,4,0],inf);--- > > d = Pseq(#[0.5,1,2,0.25,0.25],1);--- > > PdurStutter(s,d).asStream.all == [0.5,1,2,0.25,0.25]------ > let {s = pseq [1,1,1,1,1,2,2,2,2,2,0,1,3,4,0] inf--- >     ;d = pseq [0.5,1,2,0.25,0.25] 1}--- > in pdurStutter s d == toP [0.5,1.0,2.0,0.25,0.25]------ Applied to duration.------ > > d = PdurStutter(Pseq(#[1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4],inf),--- > >                 Pseq(#[0.5,1,2,0.25,0.25],inf));--- > > Pbind(\freq,440,\dur,d).play------ > let {s = pseq [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4] inf--- >     ;d = pseq [0.5,1,2,0.25,0.25] inf}--- > in audition (pbind [(K_freq,440),(K_dur,pdurStutter s d)])------ Applied to frequency.------ > let {s = pseq [1,1,1,1,1,2,2,2,2,2,3,3,3,3,4,4,0,4,4] inf--- >     ;d = pseq [0,2,3,5,7,9,10] inf + 80}--- > in audition (pbind [(K_midinote,pdurStutter s d),(K_dur,0.15)])-pdurStutter :: Fractional a => P Int -> P a -> P a-pdurStutter = liftP2 P.durStutter---- | Pexprand.  Lifted 'P.exprand'.------ > > Pexprand(0.0001,1,10).asStream.all--- > pexprand 'α' 0.0001 1 10------ > > Pbind(\freq,Pexprand(0.0001,1,inf) * 600 + 300,\dur,0.02).play------ > audition (pbind [(K_freq,pexprand 'α' 0.0001 1 inf * 600 + 300)--- >                 ,(K_dur,0.02)])-pexprand :: (Enum e,Random a,Floating a) => e -> a -> a -> Int -> P a-pexprand e l r = toP . P.exprand e l r---- | Pfinval.  Alias for 'ptake'------ > > Pfinval(5,Pseq(#[1,2,3],inf)).asStream.all == [1,2,3,1,2]--- > pfinval 5 (pseq [1,2,3] inf) == toP [1,2,3,1,2]-pfinval :: Int -> P a -> P a-pfinval = ptake--{-|-A variant of the SC3 pattern that evaluates a closure at each-step.  The haskell variant function has a 'StdGen' form.--> > p = Pfuncn({exprand(0.1,0.3) + #[1,2,3,6,7].choose},inf);-> > Pbind(\freq,p * 100 + 300,\dur,0.02).play--> let {exprand = Sound.SC3.Lang.Random.Gen.exprand->     ;choose = Sound.SC3.Lang.Random.Gen.choose->     ;p = pfuncn 'α' (exprand 0.1 0.3) inf->     ;q = pfuncn 'β' (choose [1,2,3,6,7]) inf}-> in audition (pbind [(K_freq,(p + q) * 100 + 300),(K_dur,0.02)])--Of course in this case there is a pattern equivalent.--> let {p = pexprand 'α' 0.1 0.3 inf + prand 'β' [1,2,3,6,7] inf}-> in audition (pbind [(K_freq,p * 100 + 300),(K_dur,0.02)])---}-pfuncn :: Enum e => e -> (StdGen -> (n,StdGen)) -> Int -> P n-pfuncn e f n = toP (P.funcn e f n)---- | Pgeom.  SC3 geometric series pattern.------ > > Pgeom(3,6,5).asStream.all == [3,18,108,648,3888]--- > pgeom 3 6 5 == toP [3,18,108,648,3888]------ > > Pgeom(1,2,10).asStream.all == [1,2,4,8,16,32,64,128,256,512]--- > pgeom 1 2 10 == toP [1,2,4,8,16,32,64,128,256,512]------ Real numbers work as well.------ > > p = Pgeom(1.0,1.1,6).collect({|i| (i * 100).floor});--- > > p.asStream.all == [100,110,121,133,146,161];------ > let p = fmap (floor . (* 100)) (pgeom 1.0 1.1 6)--- > in p == toP [100,110,121,133,146,161]------ > > Pbind(\degree,Pseries(-7,1,15),--- > >       \dur,Pgeom(0.5,0.89140193218427,15)).play;------ > audition (pbind [(K_degree,pseries (-7) 1 15)--- >                 ,(K_dur,pgeom 0.5 0.89140193218427 15)])------ There is a list variant.------ > > 5.geom(3,6)--- > C.geom 5 3 6 == [3,18,108,648,3888]-pgeom :: (Num a) => a -> a -> Int -> P a-pgeom i s n = toP (C.geom n i s)---- | Pif.  SC3 /implicitly repeating/ pattern-based conditional expression.------ > > a = Pfunc({0.3.coin});--- > > b = Pwhite(0,9,3);--- > > c = Pwhite(10,19,3);--- > > Pfin(9,Pif(a,b,c)).asStream.all------ > let {a = fmap (< 0.75) (pwhite 'α' 0.0 1.0 inf)--- >     ;b = pwhite 'β' 0 9 6--- >     ;c = pwhite 'γ' 10 19 6}--- > in pif a b c * (-1) == toP [-7,-3,-11,-17,-18,-6,-3,-4,-5]-pif :: P Bool -> P a -> P a -> P a-pif = liftP3_repeat P.if_demand---- | Place.  SC3 interlaced embedding of subarrays.------ > > Place([0,[1,2],[3,4,5]],3).asStream.all == [0,1,3,0,2,4,0,1,5]--- > C.lace 9 [[0],[1,2],[3,4,5]] == [0,1,3,0,2,4,0,1,5]--- > place [[0],[1,2],[3,4,5]] 3 == toP [0,1,3,0,2,4,0,1,5]------ > > Place(#[1,[2,5],[3,6]],2).asStream.all == [1,2,3,1,5,6]--- > C.lace 6 [[1],[2,5],[3,6]] == [1,2,3,1,5,6]--- > place [[1],[2,5],[3,6]] 2 == toP [1,2,3,1,5,6]------ > C.lace 12 [[1],[2,5],[3,6..]] == [1,2,3,1,5,6,1,2,9,1,5,12]--- > place [[1],[2,5],[3,6..]] 4 == toP [1,2,3,1,5,6,1,2,9,1,5,12]-place :: [[a]] -> Int -> P a-place a n =-    let f = toP . concat . P.take_inf n . L.transpose . map cycle-    in f a---- | Pn.  SC3 pattern to repeat the enclosed pattern a number of--- times.------ > pn 1 4 == toP [1,1,1,1]--- > pn (toP [1,2,3]) 3 == toP [1,2,3,1,2,3,1,2,3]------ This is related to `concat`.`replicate` in standard list processing.------ > concat (replicate 4 [1]) == [1,1,1,1]--- > concat (replicate 3 [1,2,3]) == [1,2,3,1,2,3,1,2,3]------ There is a `pconcatReplicate` near-alias (reversed argument order).------ > pconcatReplicate 4 1 == toP [1,1,1,1]--- > pconcatReplicate 3 (toP [1,2]) == toP [1,2,1,2,1,2]------ This is productive over infinite lists.------ > concat (replicate inf [1])--- > pconcat (replicate inf 1)--- > pconcatReplicate inf 1-pn :: P a -> Int -> P a-pn p n = mconcat (replicate n p)---- | Ppatlace.  SC3 /implicitly repeating/ pattern to lace input patterns.------ > > p = Ppatlace([1,Pseq([2,3],2),4],5);--- > > p.asStream.all == [1,2,4,1,3,4,1,2,4,1,3,4,1,4]------ > ppatlace [1,pseq [2,3] 2,4] 5 == toP [1,2,4,1,3,4,1,2,4,1,3,4,1,4]------ > > p = Ppatlace([1,Pseed(Pn(1000,1),Prand([2,3],inf))],5);--- > > p.asStream.all == [1,3,1,3,1,3,1,2,1,2]------ > ppatlace [1,prand 'α' [2,3] inf] 5 == toP [1,3,1,2,1,3,1,2,1,2]------ > > Pbind(\degree,Ppatlace([Pseries(0,1,8),Pseries(2,1,7)],inf),--- > >       \dur,0.25).play;------ > let p = [(K_degree,ppatlace [pseries 0 1 8,pseries 2 1 7] inf)--- >         ,(K_dur,0.125)]--- > in audition (pbind p)-ppatlace :: [P a] -> Int -> P a-ppatlace a n =-    let a' = L.transpose (map unP_repeat a)-    in toP (L.concat (P.take_inf n a'))--{-| Prand.  SC3 pattern to make n random selections from a list of-patterns, the resulting pattern is flattened (joined).--> > p = Pseed(Pn(1000,1),Prand([1,Pseq([10,20,30]),2,3,4,5],6));-> > p.asStream.all == [3,5,3,10,20,30,2,2]--> prand 'α' [1,toP [10,20],2,3,4,5] 5 == toP [5,2,10,20,2,1]--> > Pbind(\note,Prand([0,1,5,7],inf),\dur,0.25).play--> audition (pbind [(K_note,prand 'α' [0,1,5,7] inf),(K_dur,0.25)])--Nested sequences of pitches:--> > Pbind(\midinote,Prand([Pseq(#[60,61,63,65,67,63]),-> >                        Prand(#[72,73,75,77,79],6),-> >                        Pshuf(#[48,53,55,58],2)],inf),-> >       \dur,0.25).play--> let {n = prand 'α' [pseq [60,61,63,65,67,63] 1->                    ,prand 'β' [72,73,75,77,79] 6->                    ,pshuf 'γ' [48,53,55,58] 2] inf}-> in audition (pbind [(K_midinote,n),(K_dur,0.075)])--The below cannot be written as intended with the list-based pattern library.  This is precisely because the-noise patterns are values, not processes with a state-threaded non-locally.--> do {n0 <- Sound.SC3.Lang.Random.IO.rrand 2 5->    ;n1 <- Sound.SC3.Lang.Random.IO.rrand 3 9->    ;let p = pseq [prand 'α' [pempty,pseq [24,31,36,43,48,55] 1] 1->                  ,pseq [60,prand 'β' [63,65] 1->                        ,67,prand 'γ' [70,72,74] 1] n0->                  ,prand 'δ' [74,75,77,79,81] n1] inf->     in return (ptake 24 p)}---}-prand :: Enum e => e -> [P a] -> Int -> P a-prand e a = join . prand' e a---- | Preject.  SC3 pattern to rejects values for which the predicate--- is true.  reject f is equal to filter (not . f).------ > preject (== 1) (pseq [1,2,3] 2) == toP [2,3,2,3]--- > pfilter (not . (== 1)) (pseq [1,2,3] 2) == toP [2,3,2,3]------ > > p = Pseed(Pn(1000,1),Pwhite(0,255,20).reject({|x| x.odd}));--- > > p.asStream.all == [224,60,88,94,42,32,110,24,122,172]------ > preject odd (pwhite 'α' 0 255 10) == toP [32,158,62,216,240,20]------ > > p = Pseed(Pn(1000,1),Pwhite(0,255,20).select({|x| x.odd}));--- > > p.asStream.all == [151,157,187,129,45,245,101,79,77,243]------ > pselect odd (pwhite 'α' 0 255 10) == toP [241,187,119,127]-preject :: (a -> Bool) -> P a -> P a-preject f = liftP (filter (not . f))---- | Prorate.  SC3 /implicitly repeating/ sub-dividing pattern.------ > > p = Prorate(Pseq([0.35,0.5,0.8]),1);--- > > p.asStream.all == [0.35,0.65,0.5,0.5,0.8,0.2];------ > let p = prorate (fmap Left (pseq [0.35,0.5,0.8] 1)) 1--- > in fmap roundE (p * 100) == toP [35,65,50,50,80,20]------ > > p = Prorate(Pseq([0.35,0.5,0.8]),Pseed(Pn(100,1),Prand([20,1],inf)));--- > > p.asStream.all == [7,13,0.5,0.5,16,4]------ > let p = prorate (fmap Left (pseq [0.35,0.5,0.8] 1))--- >                 (prand 'α' [20,1] 3)--- > in fmap roundE (p * 100) == toP [35,65,1000,1000,80,20]------ > > l = [[1,2],[5,7],[4,8,9]].collect(_.normalizeSum);--- > > Prorate(Pseq(l,1)).asStream.all------ > let l = map (Right . C.normalizeSum) [[1,2],[5,7],[4,8,9]]--- > in prorate (toP l) 1------ > > Pfinval(5,Prorate(0.6,0.5)).asStream.all == [0.3,0.2,0.3,0.2,0.3]------ > pfinval 5 (prorate (fmap Left 0.6) 0.5) == toP [0.3,0.2,0.3,0.2,0.3]------ > > Pbind(\degree,Pseries(4,1,inf).fold(-7,11),--- > >       \dur,Prorate(0.6,0.5)).play------ > audition (pbind [(K_degree,pfold (pseries 4 1 inf) (-7) 11)--- >                 ,(K_dur,prorate (fmap Left 0.6) 0.25)])-prorate :: Num a => P (Either a [a]) -> P a -> P a-prorate p = pjoin_repeat . pzipWith prorate' p---- | Pselect.  See 'pfilter'.------ > pselect (< 3) (pseq [1,2,3] 2) == toP [1,2,1,2]-pselect :: (a -> Bool) -> P a -> P a-pselect f = liftP (filter f)--{-| Pseq.  SC3 pattern to cycle over a list of patterns. The repeats-pattern gives the number of times to repeat the entire list.--> pseq [return 1,return 2,return 3] 2 == toP [1,2,3,1,2,3]-> pseq [1,2,3] 2 == toP [1,2,3,1,2,3]-> pseq [1,pn 2 2,3] 2 == toP [1,2,2,3,1,2,2,3]--There is an 'inf' value for the repeats variable.--> ptake 3 (pdrop (10^5) (pseq [1,2,3] inf)) == toP [2,3,1]--Unlike the SC3 Pseq, `pseq` does not have an offset argument to give a-starting offset into the list.--> pseq (C.rotate 3 [1,2,3,4]) 3 == toP [2,3,4,1,2,3,4,1,2,3,4,1]--As scale degrees.--> > Pbind(\degree,Pseq(#[0,0,4,4,5,5,4],1),-> >       \dur,Pseq(#[0.5,0.5,0.5,0.5,0.5,0.5,1],1)).play--> audition (pbind [(K_degree,pseq [0,0,4,4,5,5,4] 1)->                 ,(K_dur,pseq [0.5,0.5,0.5,0.5,0.5,0.5,1] 1)])--> > Pseq(#[60,62,63,65,67,63],inf) + Pseq(#[0,0,0,0,-12],inf)--> let n = pseq [60,62,63,65,67,63] inf + pser [0,0,0,0,-12] 25-> in audition (pbind [(K_midinote,n),(K_dur,0.2)])--Pattern `b` pattern sequences `a` once normally, once transposed up a-fifth and once transposed up a fourth.--> > a = Pseq(#[60,62,63,65,67,63]);-> > b = Pseq([a,a + 7,a + 5],inf);-> > Pbind(\midinote,b,\dur,0.3).play--> let {a = pseq [60,62,63,65,67,63] 1->     ;b = pseq [a,a + 7,a + 5] inf}-> in audition (pbind [(K_midinote,b),(K_dur,0.13)])--}-pseq :: [P a] -> Int -> P a-pseq a i =-    let a' = mconcat a-    in if i == inf then pcycle a' else pn a' i---- | Pser.  SC3 pattern that is like 'pseq', however the repeats--- variable gives the number of elements in the sequence, not the--- number of cycles of the pattern.------ > pser [1,2,3] 5 == toP [1,2,3,1,2]--- > pser [1,pser [10,20] 3,3] 9 == toP [1,10,20,10,3,1,10,20,10]--- > pser [1,2,3] 5 * 3 == toP [3,6,9,3,6]-pser :: [P a] -> Int -> P a-pser a i = ptake i (pcycle (mconcat a))---- | Pseries.  SC3 arithmetric series pattern, see also 'pgeom'.------ > pseries 0 2 10 == toP [0,2,4,6,8,10,12,14,16,18]--- > pseries 9 (-1) 10 == toP [9,8 .. 0]--- > pseries 1.0 0.2 3 == toP [1.0::Double,1.2,1.4]-pseries :: (Num a) => a -> a -> Int -> P a-pseries i s n = toP (C.series n i s)---- | Pshuf.  SC3 pattern to return @n@ repetitions of a shuffled--- sequence.------ > > Pshuf([1,2,3,4],2).asStream.all--- > pshuf 'α' [1,2,3,4] 2 == toP [2,4,3,1,2,4,3,1]------ > > Pbind(\degree,Pshuf([0,1,2,4,5],inf),\dur,0.25).play------ > audition (pbind [(K_degree,pshuf 'α' [0,1,2,4,5] inf)--- >                 ,(K_dur,0.25)])-pshuf :: Enum e => e -> [a] -> Int -> P a-pshuf e a =-    let (a',_) = R.scramble a (mkStdGen (fromEnum e))-    in pn (toP a')---- | Pslide.  Lifted 'P.slide'.------ > > Pslide([1,2,3,4],inf,3,1,0).asStream.all--- > pslide [1,2,3,4] 4 3 1 0 True == toP [1,2,3,2,3,4,3,4,1,4,1,2]--- > pslide [1,2,3,4,5] 3 3 (-1) 0 True == toP [1,2,3,5,1,2,4,5,1]------ > > Pbind(\degree,Pslide((-6,-4 .. 12),8,3,1,0),--- > >       \dur,Pseq(#[0.1,0.1,0.2],inf),--- > >       \sustain,0.15).play------ > audition (pbind [(K_degree,pslide [-6,-4 .. 12] 8 3 1 0 True)--- >                 ,(K_dur,pseq [0.05,0.05,0.1] inf)--- >                 ,(K_sustain,0.15)])-pslide :: [a] -> Int -> Int -> Int -> Int -> Bool -> P a-pslide a n j s i = toP . P.slide a n j s i---- | Pstutter.  SC3 /implicitly repeating/ pattern to repeat each--- element of a pattern /n/ times.------ > > Pstutter(2,Pseq([1,2,3],1)).asStream.all == [1,1,2,2,3,3]--- > pstutter 2 (pseq [1,2,3] 1) == toP [1,1,2,2,3,3]------ The count input may be a pattern.------ > let {p = pseq [1,2] inf--- >     ;q = pseq [1,2,3] 2}--- > in pstutter p q == toP [1,2,2,3,1,1,2,3,3]------ > pstutter (toP [1,2,3]) (toP [4,5,6]) == toP [4,5,5,6,6,6]--- > pstutter 2 (toP [4,5,6]) == toP [4,4,5,5,6,6]------ Stutter scale degree and duration with the same random sequence.------ > > Pbind(\n,Pwhite(3,10,inf),--- > >       \degree,Pstutter(Pkey(\n),Pwhite(-4,11,inf)),--- > >       \dur,Pstutter(Pkey(\n),Pwhite(0.05,0.4,inf)),--- > >       \legato,0.3).play------ > let {n = pwhite 'α' 3 10 inf--- >     ;p = [(K_degree,pstutter n (pwhitei 'β' (-4) 11 inf))--- >          ,(K_dur,pstutter n (pwhite 'γ' 0.05 0.4 inf))--- >          ,(K_legato,0.3)]}--- > in audition (pbind p)-pstutter :: P Int -> P a -> P a-pstutter = liftP2_repeat P.stutter---- | Pswitch.  Lifted 'P.switch'.------ > let p = pswitch [pseq [1,2,3] 2,pseq [65,76] 1,800] (toP [2,2,0,1])--- > in p == toP [800,800,1,2,3,1,2,3,65,76]-pswitch :: [P a] -> P Int -> P a-pswitch l = liftP (P.switch (map unP l))---- | Pswitch1.  Lifted /implicitly repeating/ 'P.switch1'.------ > > l = [Pseq([1,2,3],inf),Pseq([65,76],inf),8];--- > > p = Pswitch1(l,Pseq([2,2,0,1],3));--- > > p.asStream.all == [8,8,1,65,8,8,2,76,8,8,3,65];------ > let p = pswitch1 [pseq [1,2,3] inf--- >                  ,pseq [65,76] inf--- >                  ,8] (pseq [2,2,0,1] 6)--- > in p == toP [8,8,1,65,8,8,2,76,8,8,3,65,8,8,1,76,8,8,2,65,8,8,3,76]-pswitch1 :: [P a] -> P Int -> P a-pswitch1 l = liftP (P.switch1 (map unP_repeat l))---- | Ptuple.  'pseq' of 'ptranspose_st_repeat'.------ > > l = [Pseries(7,-1,8),3,Pseq([9,7,4,2],1),Pseq([4,2,0,0,-3],1)];--- > > p = Ptuple(l,1);--- > > p.asStream.all == [[7,3,9,4],[6,3,7,2],[5,3,4,0],[4,3,2,0]]------ > let p = ptuple [pseries 7 (-1) 8--- >                ,3--- >                ,pseq [9,7,4,2] 1--- >                ,pseq [4,2,0,0,-3] 1] 1--- > in p == toP [[7,3,9,4],[6,3,7,2],[5,3,4,0],[4,3,2,0]]-ptuple :: [P a] -> Int -> P [a]-ptuple p = pseq [ptranspose_st_repeat p]---- | Pwhite.  Lifted 'P.white'.------ > pwhite 'α' 0 9 5 == toP [3,0,1,6,6]--- > pwhite 'α' 0 9 5 - pwhite 'α' 0 9 5 == toP [0,0,0,0,0]------ The pattern below is alternately lower and higher noise.------ > let {l = pseq [0.0,9.0] inf--- >     ;h = pseq [1.0,12.0] inf}--- > in audition (pbind [(K_freq,pwhite' 'α' l h * 20 + 800)--- >                    ,(K_dur,0.25)])-pwhite :: (Random n,Enum e) => e -> n -> n -> Int -> P n-pwhite e l r = toP . P.white e l r---- | Pwrand.  Lifted 'P.wrand'.------ > let w = C.normalizeSum [12,6,3]--- > in pwrand 'α' [1,2,3] w 6 == toP [2,1,2,3,3,2]------ > > r = Pwrand.new([1,2,Pseq([3,4],1)],[1,3,5].normalizeSum,6);--- > > p = Pseed(Pn(100,1),r);--- > > p.asStream.all == [2,3,4,1,3,4,3,4,2]------ > let w = C.normalizeSum [1,3,5]--- > in pwrand 'ζ' [1,2,pseq [3,4] 1] w 6 == toP [3,4,2,2,3,4,1,3,4]------ > > Pbind(\degree,Pwrand((0..7),[4,1,3,1,3,2,1].normalizeSum,inf),--- > >       \dur,0.25).play;------ > let {w = C.normalizeSum [4,1,3,1,3,2,1]--- >     ;d = pwrand 'α' (C.series 7 0 1) w inf}--- > in audition (pbind [(K_degree,d),(K_dur,0.25)])-pwrand :: (Enum e) => e -> [P a] -> [Double] -> Int -> P a-pwrand e a w = toP . P.wrand e (map unP a) w---- | Pwrap.  Type specialised 'P.fwrap', see also 'pfold'.------ > > p = Pwrap(Pgeom(200,1.25,9),200,1000.0);--- > > r = p.asStream.all.collect({|n| n.round});--- > > r == [200,250,313,391,488,610,763,954,392];------ > let p = fmap roundE (pwrap (pgeom 200 1.25 9) 200 1000)--- > in p == toP [200,250,312,391,488,610,763,954,391]-pwrap :: (Ord a,Num a) => P a -> a -> a -> P a-pwrap = P.fwrap---- | Pxrand.  Lifted 'P.xrand'.------ > let p = pxrand 'α' [1,toP [2,3],toP [4,5,6]] 9--- > in p == toP [4,5,6,2,3,4,5,6,1]------ > > Pbind(\note,Pxrand([0,1,5,7],inf),\dur,0.25).play------ > audition (pbind [(K_note,pxrand 'α' [0,1,5,7] inf),(K_dur,0.25)])-pxrand :: Enum e => e -> [P a] -> Int -> P a-pxrand e a n = toP (P.xrand e (map unP a) n)---- * Variant SC3 Patterns---- | Lifted /implicitly repeating/ 'P.pbrown''.------ > pbrown' 'α' 1 700 (pseq [1,20] inf) 4 == toP [415,419,420,428]-pbrown' :: (Enum e,Random n,Num n,Ord n) =>-           e -> P n -> P n -> P n -> Int -> P n-pbrown' e l r s n =-    let f = liftP3_repeat (P.brown' e)-    in ptake n (f l r s)---- | Un-joined variant of 'prand'.------ > let p = prand' 'α' [1,toP [2,3],toP [4,5,6]] 5--- > in p == toP [toP [4,5,6],toP [4,5,6],toP [2,3],toP [4,5,6],1]-prand' :: Enum e => e -> [P a] -> Int -> P (P a)-prand' e a n = toP (P.rand' e a n)---- | Underlying pattern for 'prorate'.------ > prorate' (Left 0.6) 0.5-prorate' :: Num a => Either a [a] -> a -> P a-prorate' p =-    case p of-      Left p' -> toP . P.rorate_n' p'-      Right p' -> toP . P.rorate_l' p'--{-|-Variant of `pseq` that retrieves only one value from each pattern-on each list traversal.  Compare to `pswitch1`.--> pseq [pseq [1,2] 1,pseq [3,4] 1] 2 == toP [1,2,3,4,1,2,3,4]-> pseq1 [pseq [1,2] 1,pseq [3,4] 1] 2 == toP [1,3,2,4]-> pseq1 [pseq [1,2] inf,pseq [3,4] inf] 3 == toP [1,3,2,4,1,3]--> let {p = prand' 'α' [pempty,toP [24,31,36,43,48,55]] inf->     ;q = pflop [60,prand 'β' [63,65] inf->                ,67,prand 'γ' [70,72,74] inf]->     ;r = psplitPlaces (pwhite 'δ' 3 9 inf)->                       (toP [74,75,77,79,81])->     ;n = pjoin (pseq1 [p,q,r] inf)}-> in audition (pbind [(K_midinote,n),(K_dur,0.13)])--}-pseq1 :: [P a] -> Int -> P a-pseq1 a i = join (ptake i (pflop a))---- | A variant of 'pseq' to aid translating a common SC3 idiom where a--- finite random pattern is included in a @Pseq@ list.  In the SC3--- case, at each iteration a new computation is run.  This idiom does--- not directly translate to the declarative haskell pattern library.------ > > Pseq([1,Prand([2,3],1)],5).asStream.all--- > pseq [1,prand 'α' [2,3] 1] 5 == toP [1,3,1,3,1,3,1,3,1,3]------ Although the intended pattern can usually be expressed using an--- alternate construction:------ > > Pseq([1,Prand([2,3],1)],5).asStream.all--- > ppatlace [1,prand 'α' [2,3] inf] 5 == toP [1,3,1,2,1,3,1,2,1,2]------ the 'pseqn' variant handles many common cases.------ > > Pseq([Pn(8,2),Pwhite(9,16,1)],5).asStream.all------ > let p = pseqn [2,1] [8,pwhite 'α' 9 16 inf] 5--- > in p == toP [8,8,10,8,8,9,8,8,12,8,8,15,8,8,15]-pseqn :: [Int] -> [P a] -> Int -> P a-pseqn n q =-    let rec p c = if c == 0-                  then mempty-                  else let (i,j) = unzip (zipWith psplitAt n p)-                       in mconcat i <> rec j (c - 1)-    in rec (map pcycle q)--{-|--A variant of 'pseq' that passes a new seed at each invocation,-see also 'pfuncn'.--> > pseqr (\e -> [pshuf e [1,2,3,4] 1]) 2 == toP [2,3,4,1,4,1,2,3]--> let {d = pseqr (\e -> [pshuf e [-7,-3,0,2,4,7] 4->                       ,pseq [0,1,2,3,4,5,6,7] 1]) inf}-> in audition (pbind [(K_degree,d),(K_dur,0.15)])--> > Pbind(\dur,0.2,-> >       \midinote,Pseq([Pshuf(#[60,61,62,63,64,65,66,67],3)],inf)).play--> let m = pseqr (\e -> [pshuf e [60,61,62,63,64,65,66,67] 3]) inf-> in audition (pbind [(K_dur,0.2),(K_midinote,m)])---}-pseqr :: (Int -> [P a]) -> Int -> P a-pseqr f n = mconcat (L.concatMap f [1 .. n])---- | Variant of 'pser' that consumes sub-patterns one element per--- iteration.------ > pser1 [1,pser [10,20] 3,3] 9 == toP [1,10,3,1,20,3,1,10,3]-pser1 :: [P a] -> Int -> P a-pser1 a i = ptake i (join (pflop a))---- | Lifted /implicitly repeating/ 'P.pwhite'.------ > pwhite' 'α' 0 (pseq [9,19] 3) == toP [3,0,1,6,6,15]-pwhite' :: (Enum e,Random n) => e -> P n -> P n -> P n-pwhite' e = liftP2_repeat (P.white' e)---- | Lifted 'P.whitei'.------ > pwhitei 'α' 1 9 5 == toP [5,1,7,7,8]------ > audition (pbind [(K_degree,pwhitei 'α' 0 8 inf),(K_dur,0.15)])-pwhitei :: (RealFracE n,Random n,Enum e) => e -> n -> n -> Int -> P n-pwhitei e l r =  toP . P.whitei e l r---- * Non-SC3 Patterns---- | Type specialised 'P.fbool'.-pbool :: (Ord a,Num a) => P a -> P Bool-pbool = P.fbool---- | 'mconcat' of 'replicate'.-pconcatReplicate :: Int -> P a -> P a-pconcatReplicate i = mconcat . replicate i---- | Lifted 'P.countpost'.-pcountpost :: P Bool -> P Int-pcountpost = liftP P.countpost---- | Lifted 'P.countpre'.-pcountpre :: P Bool -> P Int-pcountpre = liftP P.countpre---- | Lifted 'P.hold'.-phold :: P a -> P a-phold = liftP P.hold---- | Lifted 'P.interleave2'.------ > let p = pinterleave2 (pwhite 'α' 1 9 inf) (pseries 10 1 5)--- > in [3,10,9,11,2,12,9,13,4,14] `L.isPrefixOf` unP p-pinterleave2 :: P a -> P a -> P a-pinterleave2 = liftP2 P.interleave2---- | Lifted 'P.interleave'.------ > pinterleave [pwhitei 'α' 0 4 3,pwhitei 'β' 5 9 3] == toP [2,7,0,5,3,6]-pinterleave :: [P a] -> P a-pinterleave = toP . P.interleave . map unP---- | Lifted 'L.isPrefixOf'.-pisPrefixOf :: Eq a => P a -> P a -> Bool-pisPrefixOf p q = L.isPrefixOf (unP p) (unP q)---- | Lifted 'P.rsd'.------ > prsd (pstutter 2 (toP [1,2,3])) == toP [1,2,3]--- > prsd (pseq [1,2,3] 2) == toP [1,2,3,1,2,3]-prsd :: (Eq a) => P a -> P a-prsd = liftP P.rsd---- | Lifted 'P.trigger'.------ > let {tr = pbool (toP [0,1,0,0,1,1])--- >     ;p = ptrigger tr (toP [1,2,3])--- >     ;r = [Nothing,Just 1,Nothing,Nothing,Just 2,Just 3]}--- > in p == toP r-ptrigger :: P Bool -> P a -> P (Maybe a)-ptrigger p q =-    let r = pcountpre p-        f i x = preplicate i Nothing <> return (Just x)-    in join (pzipWith f r q)---- * SC3 Event Patterns--instance Audible (P Event) where-    play = e_play . Event_Seq . unP---- | Synonym for ('Key','P Field').-type P_Bind = (Key,P Field)--{-|-Padd.  Add a value to an existing key, or set the key if it doesn't exist.--> > p = Padd(\freq,801,Pbind(\freq,Pseq([100],1)));-> > p.asStream.all(()) == [('freq':901)]--> let p = padd (K_freq,801) (pbind [(K_freq,return 100)])-> in p == pbind [(K_freq,return 901)]--> > Padd(\freq,Pseq([401,801],2),Pbind(\freq,100)).play--> audition (padd (K_freq,pseq [401,801] 2) (pbind [(K_freq,100)]))--> let {d = pseq [pshuf 'α' [-7,-3,0,2,4,7] 2->               ,pseq [0,1,2,3,4,5,6,7] 1] 1->     ;p = pbind [(K_dur,0.15),(K_degree,d)]->     ;t n = padd (K_mtranspose,n) p}-> in audition (pseq [p,t 1,t 2] inf)--}-padd :: P_Bind -> P Event -> P Event-padd (k,p) = pzipWith (\i j -> e_edit k 0 (+ i) j) p--{-| Pbind.  SC3 pattern to assign keys to a set of 'Field' patterns-making an 'Event' pattern.--Each input pattern is assigned to key in the resulting event pattern.--There are a set of reserved keys that have particular roles in the-pattern library.--> > p = Pbind(\x,Pseq([1,2,3],1),\y,Pseed(Pn(100,1),Prand([4,5,6],inf)));-> > p.asStream.all(()) == [('y':4,'x':1),('y':6,'x':2),('y':4,'x':3)]--> let p = pbind [(K_param "x",prand 'α' [100,300,200] inf)->               ,(K_param "y",pseq [1,2,3] 1)]-> in pkey (K_param "x") p == toP [200,200,300]--'K_param' can be elided if /OverloadedStrings/ are in place.--> :set -XOverloadedStrings--> ptake 2 (pbind [("x",pwhitei 'α' 0 9 inf)->                ,("y",pseq [1,2,3] inf)])--'Event's implement variations on the @SC3@ 'Dur' and-'Sound.SC3.Lang.Control.Pitch.Pitch' models.--> > Pbind(\freq,Prand([300,500,231.2,399.2],inf),-> >       \dur,0.1).play;--> audition (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)->                 ,(K_dur,0.1)])--> > Pbind(\freq, Prand([300,500,231.2,399.2],inf),-> >       \dur,Prand([0.1,0.3],inf)).play;--> audition (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)->                 ,(K_dur,prand 'β' [0.1,0.3] inf)])--> > Pbind(\freq,Prand([1,1.2,2,2.5,3,4],inf) * 200,-> >       \dur,0.1).play;--> audition (pbind [(K_freq,prand 'α' [1,1.2,2,2.5,3,4] inf * 200)->                 ,(K_dur,0.1)])--> audition (pbind [(K_freq,pseq [440,550,660,770] 2)->                 ,(K_dur,pseq [0.1,0.15,0.1] inf)->                 ,(K_amp,pseq [0.1,0.05] inf)->                 ,(K_param "pan",pseq [-1,0,1] inf)])--A finite binding stops the `Event` pattern.--> > Pbind(\freq,Prand([300,500,231.2,399.2],inf),-> >       \dur,Pseq([0.1,0.2],3)).play;--> audition (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)->                 ,(K_dur,pseq [0.1,0.2] 3)])--> > Pbind(\freq,Prand([300,500,231.2,399.2],inf),-> >       \dur,Prand([0.1,0.3],inf)).play--All infinite inputs:--> audition (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)->                 ,(K_dur,prand 'β' [0.1,0.3] inf)])--Implicit /field/ patterns is this context are infinite.--> audition (pbind [(K_freq,prand 'α' [1,1.2,2,2.5,3,4] inf * 200)->                 ,(K_dur,0.1)])--> let test = let {freq = control KR "freq" 440->                ;amp = control KR "amp" 0.1->                ;nharms = control KR "nharms" 10->                ;pan = control KR "pan" 0->                ;gate = control KR "gate" 1->                ;s = blip AR freq nharms * amp->                ;e = linen gate 0.01 0.6 0.4 RemoveSynth->                ;o = offsetOut 0 (pan2 s pan e)}->            in synthdef "test" o--> audition (pbind [(K_instr,psynth test)->                 ,(K_freq,prand 'α' [1,1.2,2,2.5,3,4] inf * 200)->                 ,(K_dur,0.1)])--> audition (pbind [(K_instr,psynth test)->                 ,(K_param "nharms",pseq [4,10,40] inf)->                 ,(K_dur,pseq [1,1,2,1] inf / 10)->                 ,(K_freq,pn (pseries 1 1 16 * 50) 4)->                 ,(K_sustain,pseq [1/10,0.5,1,2] inf)])--> let acid = let {freq = control KR "freq" 1000->                ;gate = control KR "gate" 1->                ;pan = control KR "pan" 0->                ;cut = control KR "cut" 4000->                ;res = control KR "res" 0.8->                ;amp = control KR "amp" 1->                ;s = rlpf (pulse AR freq 0.05) cut res->                ;d = envLinen 0.01 1 0.3 1->                ;e = envGen KR gate amp 0 1 RemoveSynth d->                ;o = out 0 (pan2 s pan e)}->            in synthdef "acid" o--> > Pbind(\instrument,\acid,-> >       \dur,Pseq([0.25,0.5,0.25],4),-> >       \root,-24,-> >       \degree,Pseq([0,3,5,7,9,11,5,1],inf),-> >       \pan,Pfunc({1.0.rand2}),-> >       \cut,Pxrand([1000,500,2000,300],inf),-> >       \rez,Pfunc({0.7.rand +0.3}),-> >       \amp,0.2).play--> audition (pbind [(K_instr,psynth acid)->                 ,(K_dur,pseq [0.25,0.5,0.25] 4)->                 ,(K_root,-24)->                 ,(K_degree,pseq [0,3,5,7,9,11,5,1] inf)->                 ,(K_param "pan",pwhite 'α' (-1.0) 1.0 inf)->                 ,(K_param "cut",pxrand 'β' [1000,500,2000,300] inf)->                 ,(K_param "res",pwhite 'γ' 0.3 1.0 inf)->                 ,(K_amp,0.2)])--> > Pseq([Pbind(\instrument,\acid,-> >             \dur,Pseq([0.25,0.5,0.25],4),-> >             \root,-24,-> >             \degree,Pseq([0,3,5,7,9,11,5,1],inf),-> >             \pan,Pfunc({1.0.rand2}),-> >             \cut,Pxrand([1000,500,2000,300],inf),-> >             \rez,Pfunc({0.7.rand + 0.3}),-> >             \amp,0.2),-> >       Pbind(\instrument,\acid,-> >             \dur,Pseq([0.25],6),-> >             \root,-24,-> >             \degree,Pseq([18,17,11,9],inf),-> >             \pan,Pfunc({1.0.rand2}),-> >             \cut,1500,-> >             \rez,Pfunc({0.7.rand + 0.3}),-> >             \amp,0.16)],inf).play--> audition (pseq [pbind [(K_instr,psynth acid)->                       ,(K_dur,pseq [0.25,0.5,0.25] 4)->                       ,(K_root,-24)->                       ,(K_degree,pseq [0,3,5,7,9,11,5,1] inf)->                       ,(K_param "pan",pwhite 'α' (-1.0) 1.0 inf)->                       ,(K_param "cut",pxrand 'β' [1000,500,2000,300] inf)->                       ,(K_param "res",pwhite 'γ' 0.3 1.0 inf)->                       ,(K_amp,0.2)]->                ,pbind [(K_instr,psynth acid)->                       ,(K_dur,pn 0.25 6)->                       ,(K_root,-24)->                       ,(K_degree,pser [18,17,11,9] inf)->                       ,(K_param "pan",pwhite 'δ' (-1.0) 1.0 inf)->                       ,(K_param "cut",1500)->                       ,(K_param "res",pwhite 'ε' 0.3 1.0 inf)->                       ,(K_amp,0.16)]] inf)--> > Pbind(\instrument, \acid,-> >       \dur, Pseq([0.25,0.5,0.25], inf),-> >       \root, [-24,-17],-> >       \degree, Pseq([0,3,5,7,9,11,5,1], inf),-> >       \pan, Pfunc({1.0.rand2}),-> >       \cut, Pxrand([1000,500,2000,300], inf),-> >       \rez, Pfunc({0.7.rand +0.3}),-> >       \amp, 0.2).play;--> audition (pbind [(K_instr,psynth acid)->                 ,(K_dur,pseq [0.25,0.5,0.25] inf)->                 ,(K_root,pmce2 (-24) (-17))->                 ,(K_degree,pseq [0,3,5,7,9,11,5,1] inf)->                 ,(K_param "pan",pwhite 'α' (-1.0) 1.0 inf)->                 ,(K_param "cut",pxrand 'β' [1000,500,2000,300] inf)->                 ,(K_param "res",pwhite 'γ' 0.3 1.0 inf)->                 ,(K_amp,0.2)])--A persistent synthesis node with /freq/ and /amp/ controls.--> import Sound.SC3.ID--> let {freq = control KR "freq" 440->     ;amp = control KR "amp" 0.6->     ;n = pinkNoise 'α' AR * amp}-> in audition (out 0 (pan2 (moogFF n freq 2 0) 0 1))--A pattern to set /freq/ and /amp/ controls at the most recently-instantiated synthesis node.--> :set -XOverloadedStrings--> audition (pbind [(K_type,prepeat "n_set")->                 ,(K_id,(-1))->                 ,(K_freq,pwhite 'α' 100 1000 inf)->                 ,(K_dur,0.2)->                 ,(K_amp,toP [1,0.99 .. 0.1])])--> let berlinb =->   let {k = control KR->       ;o = k "out" 0->       ;f = k "freq" 80->       ;a = k "amp" 0.01->       ;p = k "pan" 0->       ;g = k "gate" 1->       ;env = decay2 g 0.05 8 * 0.0003->       ;syn = rlpf (lfPulse AR f 0 (sinOsc KR 0.12 (mce2 0 (pi/2)) * 0.48 + 0.5))->                   (f * (sinOsc KR 0.21 0 * 18 + 20))->                   0.07->       ;syn_env = syn * env->       ;kil = detectSilence (mceChannel 0 syn_env) 0.1 0.2 RemoveSynth}->   in mrg2 (out o (a * mix (panAz 4 syn_env (mce2 p (p + 1)) 1 2 0.5))) kil--> audition (ppar [pbind [(K_degree,pseq [0,1,2,4,6,3,4,8] inf)->                       ,(K_dur,0.5)->                       ,(K_octave,3)->                       ,(K_instr,psynth (synthdef "berlinb" berlinb))]->                ,pbind [(K_degree,pseq [0,1,2,4,6,3,4,8] inf)->                       ,(K_dur,0.5)->                       ,(K_octave,pmce2 2 1)->                       ,(K_param "pan",pwhite 'a' (-1) 1 inf)->                       ,(K_instr,psynth (synthdef "berlinb" berlinb))]])---}-pbind :: [P_Bind] -> P Event-pbind xs =-    let xs' = fmap (\(k,v) -> pzip (undecided k) v) xs-        xs'' = ptranspose_st_repeat xs'-    in fmap e_from_list xs''---- | Operator to lift 'F_Value' pattern to 'P_Bind' tuple.------ > let {r = True `pcons` preplicate 3 False :: P Bool}--- > in pbind [K_rest <| r] == pbind [(K_rest,pseq [1,0,0,0] 1)]-(<|) :: F_Value v => Key -> P v -> P_Bind-(<|) k p = (k,fmap toF p)-infixl 3 <|---- | Pkey.  SC3 pattern to read 'Key' at 'Event' pattern.  Note--- however that in haskell is usually more appropriate to name the--- pattern using /let/.------ > pkey K_freq (pbind [(K_freq,return 440)]) == toP [440]--- > pkey K_amp (pbind [(K_amp,toP [0,1])]) == toP [0,1]------ > > Pbind(\degree,Pseq([Pseries(-7,1,14),Pseries(7,-1,14)],inf),--- > >       \dur,0.25,--- > >       \legato,Pkey(\degree).linexp(-7,7,2.0,0.05)).play------ > let {d = pseq [pseries (-7) 1 14,pseries 7 (-1) 14] inf--- >     ;l = fmap (Sound.SC3.Lang.Math.linexp (-7) 7 2 0.05) d}--- > in audition (pbind [(K_degree,d)--- >                    ,(K_dur,0.25)--- >                    ,(K_legato,l)])-pkey :: Key -> P Event -> P Field-pkey k = fmap (fromJust . e_get k)---- | Pmono.  SC3 pattern that is a variant of 'pbind' for controlling--- monophonic (persistent) synthesiser nodes.------ > let p = [(K_instr,pinstr' (Instr_Ref "default" False))--- >         ,(K_id,100)--- >         ,(K_degree,pxrand 'α' [0,2,4,5,7,9,11] inf)--- >         ,(K_amp,pwrand 'β' [0.05,0.2] [0.7,0.3] inf)--- >         ,(K_dur,0.25)]--- > in audition (pmono p)-pmono :: [P_Bind] -> P Event-pmono b =-    let ty = fmap F_String ("s_new" `pcons` prepeat "n_set")-    in pbind ((K_type,ty) : b)---- | Pmul.  SC3 pattern to multiply an existing key by a value, or set--- the key if it doesn't exist.------ > let p = pbind [(K_dur,0.15),(K_freq,prand 'α' [440,550,660] 6)]--- > in audition (pseq [p,pmul (K_freq,2) p,pmul (K_freq,0.5) p] 2)-pmul :: P_Bind -> P Event -> P Event-pmul (k,p) = pzipWith (\i j -> e_edit k 1 (* i) j) p--{-| Ppar.  Variant of 'ptpar' with zero start times.--The result of `pmerge` can be merged again, `ppar` merges a list of-patterns.--> let {a = pbind [(K_param "a",pseq [1,2,3] inf)]->     ;b = pbind [(K_param "b",pseq [4,5,6] inf)]->     ;r = toP [e_from_list [(K_param "a",1),(K_fwd',0)]->              ,e_from_list [(K_param "b",4),(K_fwd',1)]]}-> in ptake 2 (ppar [a,b]) == r--> let {p = pbind [(K_dur,0.2),(K_midinote,pseq [62,65,69,72] inf)]->     ;q = pbind [(K_dur,0.4),(K_midinote,pseq [50,45] inf)]->     ;r = pbind [(K_dur,0.6),(K_midinote,pseq [76,79,81] inf)]}-> in audition (ppar [p,q,r])--Multiple nested `ppar` patterns.--> let {a u = pbind [(K_dur,0.2),(K_param "pan",0.5),(K_midinote,pseq u 1)]->     ;b l = pbind [(K_dur,0.4),(K_param "pan",-0.5),(K_midinote,pseq l 1)]->     ;f u l = ppar [a u,b l]->     ;h = pbind [(K_dur,prand 'α' [0.2,0.4,0.6] inf)->                ,(K_midinote,prand 'β' [72,74,76,77,79,81] inf)->                ,(K_db,-26)->                ,(K_legato,1.1)]->     ;m = pseq [pbind [(K_dur,3.2),(K_freq,return nan)]->               ,prand 'γ' [f [60,64,67,64] [48,43]->                          ,f [62,65,69,65] [50,45]->                          ,f [64,67,71,67] [52,47]] 12] inf}-> in audition (ppar [h,m])---}-ppar :: [P Event] -> P Event-ppar l = ptpar (zip (repeat 0) l)---- | Pstretch.  SC3 pattern to do time stretching.  It is equal to--- 'pmul' at 'K_stretch'.------ > let {d = pseq [pshuf 'α' [-7,-3,0,2,4,7] 2--- >               ,pseq [0,1,2,3,4,5,6,7] 1] 1--- >     ;p = pbind [(K_dur,0.15),(K_degree,d)]}--- > in audition (pseq [p,pstretch 0.5 p,pstretch 2 p] inf)-pstretch :: P Field -> P Event -> P Event-pstretch p = pmul (K_stretch,p)--{-| Ptpar.  Merge a set of 'Event' patterns each with indicated--- start 'Time'.--`ptpar` is a variant of `ppar` which allows non-equal start times.--> let {f d p n = pbind [(K_dur,d),(K_param "pan",p),(K_midinote,n)]->     ;a = f 0.2 (-1) (pseries 60 1 15)->     ;b = f 0.15 0 (pseries 58 2 15)->     ;c = f 0.1 1 (pseries 46 3 15)}-> in audition (ptpar [(0,a),(1,b),(2,c)])--> let {d = pseq [pgeom 0.05 1.1 24,pgeom 0.5 0.909 24] 2->     ;f n a p = pbind [(K_dur,d)->                      ,(K_db,a)->                      ,(K_param "pan",p)->                      ,(K_midinote,pseq [n,n-4] inf)]}-> in audition (ptpar [(0,f 53 (-20) (-0.9))->                    ,(2,f 60 (-23) (-0.3))->                    ,(4,f 67 (-26) 0.3)->                    ,(6,f 74 (-29) 0.9)])---}-ptpar :: [(Time,P Event)] -> P Event-ptpar l =-    case l of-      [] -> mempty-      [(_,p)] -> p-      (pt,p):(qt,q):r -> ptpar ((min pt qt,ptmerge (pt,p) (qt,q)) : r)---- * Instrument Event Patterns---- | Pattern from 'Instr'.  An 'Instr' is either a 'Synthdef' or a--- /name/.  In the 'Synthdef' case the instrument is asynchronously--- sent to the server before processing the event, which has timing--- implications.  The pattern constructed here uses the 'Synthdef' for--- the first element, and the subsequently the /name/.------ > audition (pbind [(K_instr,pinstr' defaultInstr)--- >                 ,(K_degree,toP [0,2,4,7])--- >                 ,(K_dur,0.25)])-pinstr' :: Instr -> P Field-pinstr' i = toP (map F_Instr (i_repeat i))--{-| 'Instr' pattern from instrument /name/.  See also `psynth` (where-the /sine/ instrument below is defined).--> let {si = return (F_Instr (Instr_Ref "sine" True))->     ;di = return (F_Instr (Instr_Ref "default" True))->     ;i = pseq [si,si,di] inf->     ;p = pbind [(K_instr,i),(K_degree,pseq [0,2,4,7] inf),(K_dur,0.25)]}-> in audition p---}-pinstr :: String -> P Field-pinstr s = pinstr' (Instr_Ref s True)--{-| `Synthdef`s can be used directly as an instrument using `psynth`.-The default synthdef is at 'Data.Default.def'.--> let sineSynth =->   let {f = control KR "freq" 440->       ;g = control KR "gate" 1->       ;a = control KR "amp" 0.1->       ;d = envASR 0.01 1 1 (EnvNum (-4))->       ;e = envGen KR g a 0 1 RemoveSynth d->       ;o = out 0 (sinOsc AR f 0 * e)}->   in synthdef "sine" o--> audition (pbind [(K_instr,psynth sineSynth)->                 ,(K_degree,toP [0,2,4,7])->                 ,(K_dur,0.25)])---}-psynth :: Synthdef -> P Field-psynth s = pinstr' (Instr_Def s True)---- * MCE Patterns---- | Two-channel MCE for /field/ patterns.------ > pmce2 (toP [1,2]) (toP [3,4]) == toP [f_array [1,3],f_array [2,4]]------ > let p = pmce2 (pseq [1,2] inf) (pseq [3,4] inf)--- > in ptake 2 p == toP [f_array [1,3],f_array [2,4]]-pmce2 :: P Field -> P Field -> P Field-pmce2 p = pzipWith (\m n -> F_Vector [m,n]) p---- | Three-channel MCE for /field/ patterns.-pmce3 :: P Field -> P Field -> P Field -> P Field-pmce3 p q = pzipWith3 (\m n o -> F_Vector [m,n,o]) p q--{-|--Remove one layer of MCE expansion at an /event/ pattern.  The-pattern will be expanded only to the width of the initial input.-Holes are filled with rests.--> let {a = pseq [65,69,74] inf->     ;b = pseq [60,64,67,72,76] inf->     ;c = pseq [pmce3 72 76 79,pmce2 a b] 1}-> in audition (p_un_mce (pbind [(K_midinote,c)->                              ,(K_param "pan",pmce2 (-1) 1)->                              ,(K_dur,1 `pcons` prepeat 0.15)]))--`p_un_mce` translates via `ppar`.  This allows `dur` related fields to-be MCE values.  The underlying event processor also implements one-layer of MCE expansion.--> audition (p_un_mce->           (pbind [(K_dur,pmce2 0.25 0.2525)->                  ,(K_legato,pmce2 0.25 2.5)->                  ,(K_freq,pmce2 (pseq [300,400,500] inf)->                                 (pseq [302,402,502,202] inf))->                  ,(K_param "pan",pmce2 (-0.5) 0.5)]))---}-p_un_mce :: P Event -> P Event-p_un_mce p =-    let l' = P.transpose_fw_def' e_rest (map e_un_mce' (unP p))-    in toP (e_par (zip (repeat 0) l'))---- * Non-SC3 Event Patterns---- | Edit 'a' at 'Key' in each element of an 'Event' pattern.-pedit :: Key -> (Field -> Field) -> P Event -> P Event-pedit k f = fmap (e_edit' k f)---- | Pattern of start times of events at event pattern.------ > p_time (pbind [(K_dur,toP [1,2,3,2,1])]) == toP [0,1,3,6,8,9]--- > p_time (pbind [(K_dur,pseries 0.5 0.5 5)]) == toP [0,0.5,1.5,3,5,7.5]-p_time :: P Event -> P Time-p_time =  pscanl (+) 0 . fmap (fwd . e_dur Nothing)---- | Pattern to extract 'a's at 'Key' from an 'Event'--- pattern.------ > pkey_m K_freq (pbind [(K_freq,return 440)]) == toP [Just 440]-pkey_m :: Key -> P Event -> P (Maybe Field)-pkey_m k = fmap (e_get k)--{-| Variant of 'ptmerge' with zero start times.--`pmerge` merges two event streams, adding /fwd'/ entries as required.--> let {p = pbind [(K_dur,0.2),(K_midinote,pseq [62,65,69,72] inf)]->     ;q = pbind [(K_dur,0.4),(K_midinote,pseq [50,45] inf)]}-> in audition (pmerge p q)---}-pmerge :: P Event -> P Event -> P Event-pmerge p q = ptmerge (0,p) (0,q)---- | Variant that does not insert key.-pmul' :: P_Bind -> P Event -> P Event-pmul' (k,p) = pzipWith (\i j -> e_edit' k (* i) j) p---- | Merge two 'Event' patterns with indicated start 'Time's.-ptmerge :: (Time,P Event) -> (Time,P Event) -> P Event-ptmerge (pt,p) (qt,q) =-    toP (e_merge (pt,F.toList p) (qt,F.toList q))---- | Left-biased union of event patterns.-punion :: P Event -> P Event -> P Event-punion = pzipWith (<>)---- | 'punion' of 'pbind' of 'return', ie. @p_with (K_Instr,psynth s)@.-p_with :: P_Bind -> P Event -> P Event-p_with = punion . pbind . return---- * Aliases---- | Type specialised 'mappend', sequences two patterns,--- ie. 'Data.List.++'.------ > 1 <> mempty <> 2 == toP [1,2]------ > let {p = prand 'α' [0,1] 3--- >     ;q = prand 'β' [5,7] 3}--- > in audition (pbind [(K_degree,pappend p q),(K_dur,0.15)])-pappend :: P a -> P a -> P a-pappend = mappend---- | Type specialised 'mconcat' (or equivalently 'msum' or--- 'Data.List.concat').------ > mconcat [pseq [1,2] 1,pseq [3,4] 2] == toP [1,2,3,4,3,4]--- > msum [pseq [1,2] 1,pseq [3,4] 2] == toP [1,2,3,4,3,4]-pconcat :: [P a] -> P a-pconcat = mconcat---- | Type specialised `mempty`, ie. 'Data.List.[]'.-pempty :: P a-pempty = mempty---- | Type specialised 'F.foldr'.------ > > (Pser([1,2,3],5) + Pseq([0,10],3)).asStream.all == [1,12,3,11,2]------ > let p = pser [1,2,3] 5 + pseq [0,10] 3--- > in F.foldr (:) [] p == [1,12,3,11,2]------ Indefinte patterns may be folded.------ > take 3 (F.foldr (:) [] (prepeat 1)) == [1,1,1]------ The `Foldable` module includes functions for 'F.product', 'F.sum',--- 'F.any', 'F.elem' etc.------ > F.product (toP [1,3,5]) == 15--- > floor (F.sum (ptake 100 (pwhite 'α' 0.25 0.75 inf))) == 51--- > F.any even (toP [1,3,5]) == False--- > F.elem 5 (toP [1,3,5]) == True-pfoldr :: (a -> b -> b) -> b -> P a -> b-pfoldr = F.foldr---- | Type specialised 'join'.------ > join (replicate 2 [1,2]) == [1,2,1,2]--- > join (preplicate 2 (toP [1,2])) == toP [1,2,1,2]-pjoin :: P (P a) -> P a-pjoin = join---- | 'join' that pushes an outer 'undecided' inward.------ > join (undecided (undecided 1)) == undecided 1--- > join (undecided (return 1)) == return 1--- > pjoin_repeat (undecided (return 1)) == pure 1 == _|_-pjoin_repeat :: P (P a) -> P a-pjoin_repeat p =-    case p of-      P (Left (P (Right l))) -> toP (cycle l)-      _ -> join p---- | Type specialised 'fmap', ie. 'Data.List.map'.-pmap :: (a -> b) -> P a -> P b-pmap = fmap---- | Type specialised '>>='.------ > (return 1 >>= return . id) == [1]--- > (undecided 1 >>= undecided . id) == undecided 1------ > (pseq [1,2] 1 >>= \x ->--- >   pseq [3,4,5] 1 >>= \y ->--- >    return (x,y)) == toP [(1,3),(1,4),(1,5),(2,3),(2,4),(2,5)]-pmbind :: P a -> (a -> P b) -> P b-pmbind = (>>=)---- | Type specialised 'pure'.-ppure :: a -> P a-ppure = pure---- | Type specialised 'return'.-preturn :: a -> P a-preturn = return---- | Type specialised 'T.traverse'.------ > let {f i e = (i + e,e * 2)--- >     ;(r,p) = T.mapAccumL f 0 (toP [1,3,5])}--- > in (r,p) == (9,toP [2,6,10])-ptraverse :: Applicative f => (a -> f b) -> P a -> f (P b)-ptraverse = T.traverse---- * NRT--{-| Transform an /event/ pattern into a /non-real time/ SC3 score.--> let n = pNRT (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)->                     ,(K_dur,pseq [0.1,0.2] 3)])-> audition n-> mapM_ (putStrLn . bundlePP) (nrt_bundles n)--Infinite 'NRT' scores are productive for 'audition'ing.--> let n' = pNRT (pbind [(K_dur,0.25),(K_freq,pseq [300,600,900] inf)])-> audition n'-> mapM_ (putStrLn . bundlePP) (take 9 (nrt_bundles n'))---}-pNRT :: P Event -> NRT-pNRT = e_nrt . Event_Seq . unP---- * UId variants---- | 'liftUId' of 'pbrown'.-pbrownM :: (UId m,Num n,Ord n,Random n) => n -> n -> n -> Int -> m (P n)-pbrownM = liftUId4 pbrown---- | 'liftUId' of 'pexprand'.-pexprandM :: (UId m,Random a,Floating a) => a -> a -> Int -> m (P a)-pexprandM = liftUId3 pexprand---- | 'liftUId' of 'prand'.-prandM :: UId m => [P a] -> Int -> m (P a)-prandM = liftUId2 prand---- | 'liftUId' of 'pshuf'.-pshufM :: UId m => [a] -> Int -> m (P a)-pshufM = liftUId2 pshuf---- | 'liftUId' of 'pwhite'.-pwhiteM :: (UId m,Random n) => n -> n -> Int -> m (P n)-pwhiteM = liftUId3 pwhite---- | 'liftUId' of 'pwhitei'.-pwhiteiM :: (UId m,RealFracE n,Random n) => n -> n -> Int -> m (P n)-pwhiteiM = liftUId3 pwhitei---- | 'liftUId' of 'pwrand'.-pwrandM :: UId m => [P a] -> [Double] -> Int -> m (P a)-pwrandM = liftUId3 pwrand---- | 'liftUId' of 'pxrand'.-pxrandM :: UId m => [P a] -> Int -> m (P a)-pxrandM = liftUId2 pxrand
Sound/SC3/Lang/Pattern/List.hs view
@@ -2,15 +2,13 @@ module Sound.SC3.Lang.Pattern.List where  import qualified Data.Map as M {- containers -}-import Data.Maybe {- base -}-import Data.Monoid {- base -} import Data.List {- base -} import qualified Sound.SC3 as S {- hsc3 -} import System.Random {- random -}  import qualified Sound.SC3.Lang.Collection as C-import qualified Sound.SC3.Lang.Math as M-import qualified Sound.SC3.Lang.Random.Gen as R+import Sound.SC3.Lang.Core+import qualified Sound.SC3.Lang.Pattern.Stream as I  -- * Data.Bool variants @@ -47,112 +45,6 @@ fwrap :: (Functor f,Ord a,Num a) => f a -> a -> a -> f a fwrap xs l r = fmap (S.genericWrap l r) xs --- * Data.List variants---- | Inverse of 'Data.List.:'.------ > map uncons [[],1:[]] == [(Nothing,[]),(Just 1,[])]-uncons :: [a] -> (Maybe a,[a])-uncons l =-    case l of-      [] -> (Nothing,[])-      x:l' -> (Just x,l')---- | 'Maybe' variant of '!!'.------ > map (lindex "str") [2,3] == [Just 'r',Nothing]-lindex :: [a] -> Int -> Maybe a-lindex l n =-    if n < 0-    then Nothing-    else case (l,n) of-           ([],_) -> Nothing-           (x:_,0) -> Just x-           (_:l',_) -> lindex l' (n - 1)---- | List section with /wrapped/ indices.------ > segment [0..4] 5 (3,5) == [3,4,0]-segment :: [a] -> Int -> (Int,Int) -> [a]-segment a k (l,r) =-    let i = map (S.genericWrap 0 (k - 1)) [l .. r]-    in map (a !!) i---- | If /n/ is 'maxBound' this is 'id', else it is 'take'.-take_inf :: Int -> [a] -> [a]-take_inf n = if n == maxBound then id else take n---- | Variant of 'transpose' for /fixed width/ interior lists.  Holes--- are represented by 'Nothing'.------ > transpose_fw undefined [] == []------ > transpose [[1,3],[2,4]] == [[1,2],[3,4]]--- > transpose_fw 2 [[1,3],[2,4]] == [[Just 1,Just 2],[Just 3,Just 4]]------ > transpose [[1,5],[2],[3,7]] == [[1,2,3],[5,7]]------ > transpose_fw 2 [[1,4],[2],[3,6]] == [[Just 1,Just 2,Just 3]--- >                                     ,[Just 4,Nothing,Just 6]]------ This function is more productive than 'transpose' for the case of--- an infinite list of finite lists.------ > map head (transpose_fw 4 (repeat [1..4])) == map Just [1,2,3,4]--- > map head (transpose (repeat [1..4])) == _|_-transpose_fw :: Int -> [[a]] -> [[Maybe a]]-transpose_fw w l =-    if null l-    then []-    else let f n = map (`lindex` n) l-         in map f [0 .. w - 1]---- | Variant of 'transpose_fw' with default value for holes.-transpose_fw_def :: a -> Int -> [[a]] -> [[a]]-transpose_fw_def def w l =-    let f n = map (fromMaybe def . (`lindex` n)) l-    in map f [0 .. w - 1]---- | Variant of 'transpose_fw_def' deriving /width/ from first element.-transpose_fw_def' :: a -> [[a]] -> [[a]]-transpose_fw_def' def l =-    case l of-      [] -> []-      h:_ -> transpose_fw_def def (length h) l---- | A 'transpose' variant, halting when first hole appears.------ > trs [[1,2,3],[4,5,6],[7,8]] == [[1,4,7],[2,5,8]]-transpose_st :: [[a]] -> [[a]]-transpose_st l =-    let (h,l') = unzip (map uncons l)-    in case all_just h of-         Just h' -> h' : transpose_st l'-         Nothing -> []---- * Data.Maybe variants---- | Variant of 'catMaybes' that returns 'Nothing' unless /all/--- elements are 'Just'.------ > map all_just [[Nothing,Just 1],[Just 0,Just 1]] == [Nothing,Just [0,1]]-all_just :: [Maybe a] -> Maybe [a]-all_just =-    let rec r l =-            case l of-              [] -> Just (reverse r)-              Nothing:_ -> Nothing-              Just e:l' -> rec (e:r) l'-    in rec []---- * Data.Monoid variants---- | 'mconcat' of 'repeat', for lists this is 'cycle'.------ > [1,2,3,1,2] `isPrefixOf` take 5 (mcycle [1,2,3])-mcycle :: Monoid a => a -> a-mcycle = mconcat . repeat- -- * Non-SC3 Patterns  -- | Count the number of `False` values following each `True` value.@@ -209,15 +101,6 @@ interleave :: [[a]] -> [a] interleave = concat . transpose --- | Remove successive duplicates.------ > rsd (stutter (repeat 2) [1,2,3]) == [1,2,3]--- > rsd [1,2,3,1,2,3] == [1,2,3,1,2,3]-rsd :: (Eq a) => [a] -> [a]-rsd =-    let f (p,_) i = (Just i,if Just i == p then Nothing else Just i)-    in mapMaybe snd . scanl f (Nothing,Nothing)- -- | Pattern where the 'tr' pattern determines the rate at which -- values are read from the `x` pattern.  For each sucessive true -- value at 'tr' the output is a (`Just` e) of each succesive element at@@ -237,7 +120,7 @@ -- -- > [4,4,1,8,5] `isPrefixOf` brown 'α' 0 9 15 brown :: (Enum e,Random n,Num n,Ord n) => e -> n -> n -> n -> [n]-brown e l r s = brown' e (repeat l) (repeat r) (repeat s)+brown e l r s = I.brown e (repeat l) (repeat r) (repeat s)  -- | PdurStutter.  SC3 pattern to partition a value into /n/ equal -- subdivisions.  Subdivides each duration by each stutter and yields@@ -248,19 +131,19 @@ -- >     ;d = [0.5,1,2,0.25,0.25]} -- > in durStutter s d == [0.5,1.0,2.0,0.25,0.25] durStutter :: Fractional a => [Int] -> [a] -> [a]-durStutter p =+durStutter =     let f s d = case s of                 0 -> []                 1 -> [d]                 _ -> replicate s (d / fromIntegral s)-    in concat . zipWith f p+    in concat .: zipWith f  -- | Pexprand.  SC3 pattern of random values that follow a exponential -- distribution. -- -- > exprand 'α' 0.0001 1 10 exprand :: (Enum e,Random a,Floating a) => e -> a -> a -> Int -> [a]-exprand e l r n = fmap (M.exprange l r) (white e 0 1 n)+exprand e l r n = take_inf n (I.exprand e l r)  -- | Pfuncn.  Variant of the SC3 pattern that evaluates a closure at -- each step that has a 'StdGen' form.@@ -286,10 +169,7 @@ -- -- > rand' 'α' [1..9] 9 == [3,9,2,9,4,7,4,3,8] rand' :: Enum e => e -> [a] -> Int -> [a]-rand' e a n =-    let k = length a - 1-        i = white e 0 k n-    in map (a !!) i+rand' e a n = take_inf n (I.rand e a)  -- | Pseq.  'concat' of 'replicate' of 'concat'. --@@ -302,20 +182,14 @@ -- > slide [1,2,3,4] 4 3 1 0 True == [1,2,3,2,3,4,3,4,1,4,1,2] -- > slide [1,2,3,4,5] 3 3 (-1) 0 True == [1,2,3,5,1,2,4,5,1] slide :: [a] -> Int -> Int -> Int -> Int -> Bool -> [a]-slide a n j s i wr =-    let k = length a-        l = enumFromThen i (i + s)-        r = map (+ (j - 1)) l-    in if wr-       then concat (take n (map (segment a k) (zip l r)))-       else error "slide: non-wrap variant not implemented"+slide a n j s i wr = concat (take n (I.slide a j s i wr))  -- | Pstutter.  Repeat each element of a pattern /n/ times. -- -- > stutter [1,2,3] [4,5,6] == [4,5,5,6,6,6] -- > stutter (repeat 2) [4,5,6] == [4,4,5,5,6,6] stutter :: [Int] -> [a] -> [a]-stutter ns = concat . zipWith replicate ns+stutter = concat .: zipWith replicate  -- | Pswitch.  SC3 pattern to select elements from a list of patterns -- by a pattern of indices.@@ -356,18 +230,18 @@ -- > white 'α' 1 9 5  == [3,9,2,9,4] -- > let p = white 'α' 0.0 1.0 3 in zipWith (-) p p == [0,0,0] white :: (Random n,Enum e) => e -> n -> n -> Int -> [n]-white e l r n = take_inf n (randomRs (l,r) (mkStdGen (fromEnum e)))+white e l r n = take_inf n (I.white e l r)  -- | Pwrand.  SC3 pattern to embed values randomly chosen from a list. -- Returns one item from the list at random for each repeat, the -- probability for each item is determined by a list of weights which--- should sum to 1.0.+-- should sum to 1.0 and must be equal in length to the selection list. -- -- > let w = C.normalizeSum [1,3,5] -- > in wrand 'ζ' [[1],[2],[3,4]] w 6 == [3,4,2,2,3,4,1,3,4] wrand :: (Enum e,Fractional n,Ord n,Random n) =>          e -> [[a]] -> [n] -> Int -> [a]-wrand e a w n = concat (take_inf n (wrand' e a w))+wrand e a w n = concat (take_inf n (I.wrand_generic e a w))  -- | Pxrand.  SC3 pattern that is like 'rand' but filters successive -- duplicates.@@ -378,26 +252,6 @@  -- * SC3 Variant Patterns --- | Underlying 'brown''.-brown_ :: (RandomGen g,Random n,Num n,Ord n) => (n,n,n) -> (n,g) -> (n,g)-brown_ (l,r,s) (n,g) =-    let (i,g') = randomR (-s,s) g-    in (S.foldToRange l r (n + i),g')---- | Brown noise with list inputs.------ > let l = brown' 'α' (repeat 1) (repeat 700) (cycle [1,20])--- > in [415,419,420,428] `isPrefixOf` l-brown' :: (Enum e,Random n,Num n,Ord n) => e -> [n] -> [n] -> [n] -> [n]-brown' e l_ r_ s_ =-    let i = (randomR (head l_,head r_) (mkStdGen (fromEnum e)))-        rec (n,g) z =-            case z of-              [] -> []-              (l,r,s):z' -> let (n',g') = brown_ (l,r,s) (n,g)-                            in n' : rec (n',g') z'-    in rec i (zip3 l_ r_ s_)- -- | Underlying 'if_demand'. if_rec :: ([Bool],[a],[a]) -> Maybe (a,([Bool],[a],[a])) if_rec i =@@ -428,13 +282,13 @@ rorate_n' p i = [i * p,i * (1 - p)]  rorate_n :: Num a => [a] -> [a] -> [a]-rorate_n p = concat . zipWith rorate_n' p+rorate_n = concat .: zipWith rorate_n'  rorate_l' :: Num a => [a] -> a -> [a] rorate_l' p i = map (* i) p  rorate_l :: Num a => [[a]] -> [a] -> [a]-rorate_l p = concat . zipWith rorate_l' p+rorate_l = concat .: zipWith rorate_l'  -- | 'white' with pattern inputs. --@@ -456,19 +310,8 @@ -- -- > whitei 'α' 1 9 5 == [5,1,7,7,8] whitei :: (Random n,S.RealFracE n,Enum e) => e -> n -> n -> Int -> [n]-whitei e l r = fmap S.floorE . white e l r---- | Underlying 'wrand'.-wrand' :: (Enum e,Fractional n,Ord n,Random n) => e -> [[a]] -> [n] -> [[a]]-wrand' e a w =-    let f g = let (r,g') = R.wchoose a w g-              in r : f g'-    in f (mkStdGen (fromEnum e))+whitei = fmap S.floorE .::: white  -- | Underlying 'xrand'. xrand' :: Enum e => e -> [[a]] -> [a]-xrand' e a =-    let k = length a - 1-        f j g = let (i,g') = randomR (0,k) g-                in if i == j then f j g' else (a !! i) ++ f i g'-    in f (-1) (mkStdGen (fromEnum e))+xrand' e = concat . I.xrand e
+ Sound/SC3/Lang/Pattern/P.hs view
@@ -0,0 +1,7 @@+-- | Composite of Pattern.P modules.+-- See <http://rd.slavepianos.org/?t=hsc3-texts> for tutorial.+module Sound.SC3.Lang.Pattern.P (module P) where++import Sound.SC3.Lang.Pattern.P.Core as P+import Sound.SC3.Lang.Pattern.P.Base as P+import Sound.SC3.Lang.Pattern.P.SC3 as P
+ Sound/SC3/Lang/Pattern/P/Base.hs view
@@ -0,0 +1,333 @@+-- | Pattern functions.+--+-- Haskell: `pappend`, `pconcat`, `pcons`, `pcycle`,+-- `pempty`,`pfilter`, `pjoin`, `prepeat`, `preplicate`, `pscanl`,+-- `psplitPlaces`, `ptail`, `ptake`, `pzip`, `pzipWith`.+--+-- Non SC3: `pbool`, `pcountpost`, `pcountpre`,`phold`, `pinterleave`,+-- `prsd`, `ptrigger`.+module Sound.SC3.Lang.Pattern.P.Base where++import Control.Applicative {- base -}+import Control.Monad {- base -}+import qualified Data.Foldable as F {- base -}+import qualified Data.List as L {- base -}+import qualified Data.List.Split as S {- split -}+import Data.Monoid {- base -}+import qualified Data.Traversable as T {- base -}++import Sound.SC3.Lang.Pattern.P.Core++import Sound.SC3.Lang.Core+import qualified Sound.SC3.Lang.Pattern.List as P+import qualified Sound.SC3.Lang.Pattern.Stream as I++-- * Math++-- | Type specialised 'maxBound', a pseudo-/infinite/ value for use at+-- pattern repeat counts.+--+-- > inf == maxBound+inf :: Int+inf = maxBound++{-| Constant /NaN/ (not a number) value.++> isNaN nan == True++A frequency value of NaN indicates a rest. This constant value can be+used as a rest indicator at a frequency model input (not at a @rest@+key).++> audition (pbind [(K_dur,pseq [0.1,0.7] inf)+>                 ,(K_legato,0.2)+>                 ,(K_degree,pseq [0,2,return nan] inf)])++-}+nan :: Floating a => a+nan = sqrt (-1)++-- * Data.List Patterns++-- | Pattern variant of 'Data.List.:'.+--+-- > pcons 'α' (pn (return 'β') 2) == toP "αββ"+pcons :: a -> P a -> P a+pcons = mappend . return++-- | Pattern variant of 'Data.List.null'.+--+-- > pnull mempty == True+-- > pnull (undecided 'a') == False+-- > pnull (pure 'a') == False+-- > pnull (return 'a') == False+pnull :: P a -> Bool+pnull = null . unP++-- | Alias for 'pure', pattern variant of 'Data.List.repeat'.+--+-- > ptake 5 (prepeat 3) == toP [3,3,3,3,3]+-- > ptake 5 (pure 3) == toP [3,3,3,3,3]+-- > take 5 (pure 3) == [3]+prepeat :: a -> P a+prepeat = pure++-- | Pattern variant of 'splitAt'.+psplitAt :: Int -> P a -> (P a,P a)+psplitAt n p =+    let (i,j) = splitAt n (unP p)+    in (toP i,toP j)++-- * Data.List.Split++-- | Pattern variant of 'Data.List.Split.splitPlaces'.+--+-- > psplitPlaces' (toP [1,2,3]) (pseries 1 1 6) == toP [[1],[2,3],[4,5,6]]+-- > psplitPlaces' (toP [1,2,3]) (toP ['a'..]) == toP ["a","bc","def"]+psplitPlaces' :: P Int -> P a -> P [a]+psplitPlaces' = liftP2 S.splitPlaces++-- | 'fmap' 'toP' of 'psplitPlaces''.+--+-- > psplitPlaces (toP [1,2,3]) (toP ['a'..]) == toP (map toP ["a","bc","def"])+psplitPlaces :: P Int -> P a -> P (P a)+psplitPlaces = fmap toP .: psplitPlaces'++-- | Pattern variant of 'take_inf', see also 'pfinval'.+--+-- > ptake 5 (pseq [1,2,3] 2) == toP [1,2,3,1,2]+-- > ptake 5 (toP [1,2,3]) == toP [1,2,3]+-- > ptake 5 (pseq [1,2,3] inf) == toP [1,2,3,1,2]+-- > ptake 5 (pwhite 'α' 0 5 inf) == toP [5,2,1,2,0]+--+-- Note that `ptake` does not extend the input pattern, unlike `pser`.+--+-- > ptake 5 (toP [1,2,3]) == toP [1,2,3]+-- > pser [1,2,3] 5 == toP [1,2,3,1,2]+ptake :: Int -> P a -> P a+ptake n = liftP (take_inf n)++-- | Type specialised 'mcycle'.+--+-- > ptake 5 (pcycle 1) == preplicate 5 1+-- > ptake 5 (pcycle (pure 1)) == preplicate 5 1+-- > ptake 5 (pcycle (return 1)) == preplicate 5 1+pcycle :: P a -> P a+pcycle = mcycle++-- | Type specialised 'mfilter'.  Aliased to `pselect`.  See also+-- `preject`.+--+-- > mfilter even (pseq [1,2,3] 2) == toP [2,2]+-- > mfilter (< 3) (pseq [1,2,3] 2) == toP [1,2,1,2]+pfilter :: (a -> Bool) -> P a -> P a+pfilter = mfilter++-- | Pattern variant of `replicate`.+--+-- > preplicate 4 1 == toP [1,1,1,1]+--+-- Compare to `pn`:+--+-- > pn 1 4 == toP [1,1,1,1]+-- > pn (toP [1,2]) 3 == toP [1,2,1,2,1,2]+-- > preplicate 4 (toP [1,2]) :: P (P Int)+preplicate :: Int -> a -> P a+preplicate n = toP . (if n == inf then repeat else replicate n)++-- | Pattern variant of `scanl`.  `scanl` is similar to `foldl`, but+-- returns a list of successive reduced values from the left.  pscanl+-- is an accumulator, it provides a mechanism for state to be threaded+-- through a pattern. It can be used to write a function to remove+-- succesive duplicates from a pattern, to count the distance between+-- occurences of an element in a pattern and so on.+--+-- > F.foldl (\x y -> 2 * x + y) 4 (pseq [1,2,3] 1) == 43+-- > pscanl (\x y -> 2 * x + y) 4 (pseq [1,2,3] 1) == toP [4,9,20,43]+--+-- > F.foldl (flip (:)) [] (toP [1..3]) == [3,2,1]+-- > pscanl (flip (:)) [] (toP [1..3]) == toP [[],[1],[2,1],[3,2,1]]+--+-- > F.foldl (+) 0 (toP [1..5]) == 15+-- > pscanl (+) 0 (toP [1..5]) == toP [0,1,3,6,10,15]+pscanl :: (a -> b -> a) -> a -> P b -> P a+pscanl f i = liftP (L.scanl f i)++-- | 'pdrop' @1@.  Pattern variant of `Data.List.tail`.  Drops first+-- element from pattern.  Note that the haskell `tail` function is+-- partial, although `drop` is not.  `ptake` is equal to `pdrop 1`.+--+-- > tail [] == _|_+-- > drop 1 [] == []+--+-- > ptail (toP [1,2]) == toP [2]+-- > ptail mempty == mempty+ptail :: P a -> P a+ptail = liftP (drop 1)++-- | Variant of 'L.transpose'.+--+-- > L.transpose [[1,2],[3,4,5]] == [[1,3],[2,4],[5]]+-- > ptranspose [toP [1,2],toP [3,4,5]] == toP [[1,3],[2,4],[5]]+--+-- > let p = ptranspose [pseq [1,2] inf,pseq [4,5] inf]+-- > in ptake 2 (pdrop (2^16) p) == toP [[1,4],[2,5]]+ptranspose :: [P a] -> P [a]+ptranspose l = toP (L.transpose (map unP l))++-- | An /implicitly repeating/ pattern variant of 'transpose_st'.+ptranspose_st_repeat :: [P a] -> P [a]+ptranspose_st_repeat l = toP (transpose_st (map unP_repeat l))++-- * Non-SC3 Patterns++-- | Type specialised 'P.fbool'.+pbool :: (Ord a,Num a) => P a -> P Bool+pbool = P.fbool++-- | 'mconcat' of 'replicate'.+pconcatReplicate :: Int -> P a -> P a+pconcatReplicate = mconcat .: replicate++-- | Lifted 'P.countpost'.+pcountpost :: P Bool -> P Int+pcountpost = liftP P.countpost++-- | Lifted 'P.countpre'.+pcountpre :: P Bool -> P Int+pcountpre = liftP P.countpre++-- | Lifted 'P.hold'.+phold :: P a -> P a+phold = liftP P.hold++-- | Lifted 'P.interleave2'.+--+-- > let p = pinterleave2 (pwhite 'α' 1 9 inf) (pseries 10 1 5)+-- > in [3,10,9,11,2,12,9,13,4,14] `L.isPrefixOf` unP p+pinterleave2 :: P a -> P a -> P a+pinterleave2 = liftP2 P.interleave2++-- | Lifted 'P.interleave'.+--+-- > pinterleave [pwhitei 'α' 0 4 3,pwhitei 'β' 5 9 3] == toP [2,7,0,5,3,6]+pinterleave :: [P a] -> P a+pinterleave = toP . P.interleave . map unP++-- | Lifted 'L.isPrefixOf'.+pisPrefixOf :: Eq a => P a -> P a -> Bool+pisPrefixOf p q = L.isPrefixOf (unP p) (unP q)++-- | Lifted 'I.rsd'.+--+-- > prsd (pstutter 2 (toP [1,2,3])) == toP [1,2,3]+-- > prsd (pseq [1,2,3] 2) == toP [1,2,3,1,2,3]+prsd :: (Eq a) => P a -> P a+prsd = liftP I.rsd++-- | Lifted 'P.trigger'.+--+-- > let {tr = pbool (toP [0,1,0,0,1,1])+-- >     ;p = ptrigger tr (toP [1,2,3])+-- >     ;r = [Nothing,Just 1,Nothing,Nothing,Just 2,Just 3]}+-- > in p == toP r+ptrigger :: P Bool -> P a -> P (Maybe a)+ptrigger p q =+    let r = pcountpre p+        f i x = preplicate i Nothing <> return (Just x)+    in join (pzipWith f r q)++-- * Aliases++-- | Type specialised 'mappend', sequences two patterns,+-- ie. 'Data.List.++'.+--+-- > 1 <> mempty <> 2 == toP [1,2]+--+-- > let {p = prand 'α' [0,1] 3+-- >     ;q = prand 'β' [5,7] 3}+-- > in audition (pbind [(K_degree,pappend p q),(K_dur,0.15)])+pappend :: P a -> P a -> P a+pappend = mappend++-- | Type specialised 'mconcat' (or equivalently 'msum' or+-- 'Data.List.concat').+--+-- > mconcat [pseq [1,2] 1,pseq [3,4] 2] == toP [1,2,3,4,3,4]+-- > msum [pseq [1,2] 1,pseq [3,4] 2] == toP [1,2,3,4,3,4]+pconcat :: [P a] -> P a+pconcat = mconcat++-- | Type specialised `mempty`, ie. 'Data.List.[]'.+pempty :: P a+pempty = mempty++-- | Type specialised 'F.foldr'.+--+-- > > (Pser([1,2,3],5) + Pseq([0,10],3)).asStream.all == [1,12,3,11,2]+--+-- > let p = pser [1,2,3] 5 + pseq [0,10] 3+-- > in F.foldr (:) [] p == [1,12,3,11,2]+--+-- Indefinte patterns may be folded.+--+-- > take 3 (F.foldr (:) [] (prepeat 1)) == [1,1,1]+--+-- The `Foldable` module includes functions for 'F.product', 'F.sum',+-- 'F.any', 'F.elem' etc.+--+-- > F.product (toP [1,3,5]) == 15+-- > floor (F.sum (ptake 100 (pwhite 'α' 0.25 0.75 inf))) == 51+-- > F.any even (toP [1,3,5]) == False+-- > F.elem 5 (toP [1,3,5]) == True+pfoldr :: (a -> b -> b) -> b -> P a -> b+pfoldr = F.foldr++-- | Type specialised 'join'.+--+-- > join (replicate 2 [1,2]) == [1,2,1,2]+-- > join (preplicate 2 (toP [1,2])) == toP [1,2,1,2]+pjoin :: P (P a) -> P a+pjoin = join++-- | 'join' that pushes an outer 'undecided' inward.+--+-- > join (undecided (undecided 1)) == undecided 1+-- > join (undecided (return 1)) == return 1+-- > pjoin_repeat (undecided (return 1)) == pure 1 == _|_+pjoin_repeat :: P (P a) -> P a+pjoin_repeat p =+    case p of+      P (Left (P (Right l))) -> toP (cycle l)+      _ -> join p++-- | Type specialised 'fmap', ie. 'Data.List.map'.+pmap :: (a -> b) -> P a -> P b+pmap = fmap++-- | Type specialised '>>='.+--+-- > (return 1 >>= return . id) == [1]+-- > (undecided 1 >>= undecided . id) == undecided 1+--+-- > (pseq [1,2] 1 >>= \x ->+-- >   pseq [3,4,5] 1 >>= \y ->+-- >    return (x,y)) == toP [(1,3),(1,4),(1,5),(2,3),(2,4),(2,5)]+pmbind :: P a -> (a -> P b) -> P b+pmbind = (>>=)++-- | Type specialised 'pure'.+ppure :: a -> P a+ppure = pure++-- | Type specialised 'return'.+preturn :: a -> P a+preturn = return++-- | Type specialised 'T.traverse'.+--+-- > let {f i e = (i + e,e * 2)+-- >     ;(r,p) = T.mapAccumL f 0 (toP [1,3,5])}+-- > in (r,p) == (9,toP [2,6,10])+ptraverse :: Applicative f => (a -> f b) -> P a -> f (P b)+ptraverse = T.traverse
+ Sound/SC3/Lang/Pattern/P/Core.hs view
@@ -0,0 +1,261 @@+-- | 'P' type, instance and core functions.+module Sound.SC3.Lang.Pattern.P.Core where++import Control.Applicative hiding ((<*)) {- base -}+import Control.Monad {- base -}+import Data.Bifunctor {- bifunctors -}+import qualified Data.Foldable as F {- base -}+import qualified Data.List as L {- base -}+import Data.Monoid {- base -}+import qualified Data.Traversable as T {- base -}++import Sound.SC3 (OrdE(..)) {- hsc3 -}++-- * P++-- | Patterns are opaque.  @P a@ is a pattern with elements of type+-- @a@.  Patterns are constructed, manipulated and destructured using+-- the functions provided, ie. the pattern instances for 'return',+-- 'pure' and 'F.toList', and the pattern specific functions+-- 'undecided' and 'toP'.+--+-- > F.toList (toP [1,2,3] * 2) == [2,4,6]+--+-- Patterns are 'Functor's.  'fmap' applies a function to each element+-- of a pattern.+--+-- > fmap (* 2) (toP [1,2,3,4,5]) == toP [2,4,6,8,10]+--+-- Patterns are 'Monoid's.  'mempty' is the empty pattern, and+-- 'mappend' ('<>') makes a sequence of two patterns.+--+-- > 1 <> mempty <> 2 == toP [1,2]+--+-- Patterns are 'Applicative'.  The pattern instance is pointwise &+-- truncating, as for 'ZipList'.  'pure' lifts a value into an+-- infinite pattern of itself, '<*>' applies a pattern of functions to+-- a pattern of values.  This is distinct from the combinatorial+-- instance for ordinary lists, ie. where 'pure' is 'return' and '<*>'+-- is 'ap'.+--+-- > liftA2 (+) (toP [1,2]) (toP [3,4,5]) == toP [4,6]+-- > liftA2 (+) [1,2] [3,4,5] == [4,5,6,5,6,7]+--+-- Patterns are 'Monad's, and therefore allow /do/ notation.+--+-- > let p = do {x <- toP [1,2]; y <- toP [3,4,5]; return (x,y)}+-- > in p == toP [(1,3),(1,4),(1,5),(2,3),(2,4),(2,5)]+--+-- Patterns are 'Num'erical.  The instances can be derived from the+-- 'Applicative' instance.+--+-- > 1 + toP [2,3,4] == liftA2 (+) 1 (toP [2,3,4])+data P a = P {unP_either :: Either a [a]}+           deriving (Eq,Show)++-- | Lift a value to a pattern deferring deciding if the constructor+-- ought to be 'pure' or 'return' to the consuming function.  The+-- pattern instances for 'fromInteger' and 'fromRational' make+-- 'undecided' patterns.  In general /horizontal/ functions (ie. '<>')+-- resolve using 'return' and /vertical/ functions (ie. 'zip') resolve+-- using 'pure'.  In the documentation functions that resolve using+-- 'pure' are annotated as /implicitly repeating/.+--+-- > 1 <> toP [2,3] == return 1 <> toP [2,3]+-- > toP [1,2] * 3  == toP [1,2] * pure 3+undecided :: a -> P a+undecided a = P (Left a)++{- | The basic list to pattern function, inverse is 'unP'.++> unP (toP "str") == "str"++There is a @default@ sound, given by 'defaultSynthdef' from "Sound.SC3".++> audition defaultSynthdef++If no instrument is specified we hear the default.++> audition (pbind [(K_degree,pxrand 'α' [0,1,5,7] inf)+>                 ,(K_dur,toP [0.1,0.2,0.1])])++> > Pbind(\degree,(Pxrand([0,1,5,7],inf))+> >      ,\dur,Pseq([0.1,0.2,0.1],1)).play++The pattern above is finite, `toP` can sometimes be replaced with+`pseq`.++> audition (pbind [(K_degree,pxrand 'α' [0,1,5,7] inf)+>                 ,(K_dur,pseq [0.1,0.2,0.1] inf)])++-}+toP :: [a] -> P a+toP = P . Right++-- | Type specialised 'F.toList'.  'undecided' values are singular.+--+-- > F.toList (undecided 'a') == ['a']+-- > unP (return 'a') == ['a']+-- > "aaa" `L.isPrefixOf` unP (pure 'a')+unP :: P a -> [a]+unP = either return id . unP_either++-- | Variant of 'unP' where 'undecided' values are 'repeat'ed.+--+-- > unP_repeat (return 'a') == ['a']+-- > take 2 (unP_repeat (undecided 'a')) == ['a','a']+-- > take 2 (unP_repeat (pure 'a')) == ['a','a']+unP_repeat :: P a -> [a]+unP_repeat = either repeat id . unP_either++instance Functor P where+    fmap f (P p) = P (bimap f (map f) p)++instance Monoid (P a) where+    mappend p q = toP (unP p ++ unP q)+    mempty = toP []++instance Applicative P where+    pure = toP . repeat+    f <*> e = pzipWith ($) f e++instance Alternative P where+    empty = mempty+    (<|>) = mappend++instance F.Foldable P where+    foldr f i p = L.foldr f i (unP p)++instance T.Traversable P where+    traverse f p = pure toP <*> T.traverse f (unP p)++instance Monad P where+    m >>= k =+        case m of+          P (Left e) -> k e+          P (Right l) -> L.foldr (mappend . k) mempty l+    return x = toP [x]++instance MonadPlus P where+    mzero = mempty+    mplus = mappend++instance (Num a) => Num (P a) where+    (+) = pzipWith (+)+    (-) = pzipWith (-)+    (*) = pzipWith (*)+    abs = fmap abs+    signum = fmap signum+    negate = fmap negate+    fromInteger = undecided . fromInteger++instance (Fractional a) => Fractional (P a) where+    (/) = pzipWith (/)+    recip = fmap recip+    fromRational = undecided . fromRational++instance (Ord a) => Ord (P a) where+    (>) = error ("~> Ord>*")+    (>=) = error ("~> Ord>=*")+    (<) = error ("~> Ord<*")+    (<=) = error ("~> Ord<=*")++instance (OrdE a) => OrdE (P a) where+    (>*) = pzipWith (>*)+    (>=*) = pzipWith (>=*)+    (<*) = pzipWith (<*)+    (<=*) = pzipWith (<=*)++-- * Lift P++-- | Lift unary list function to pattern function.+liftP :: ([a] -> [b]) -> P a -> P b+liftP f = toP . f . unP++-- | Lift binary list function to pattern function.+--+-- > liftP2 (zipWith (+)) (toP [1,2]) (toP [3,4,5]) == toP [4,6]+-- > liftA2 (+) (toP [1,2]) (toP [3,4,5]) == toP [4,6]+liftP2 :: ([a] -> [b] -> [c]) -> P a -> P b -> P c+liftP2 f p q =+    let p' = unP p+        q' = unP q+    in toP (f p' q')++-- | Lift binary list function to /implicitly repeating/ pattern function.+liftP2_repeat :: ([a] -> [b] -> [c]) -> P a -> P b -> P c+liftP2_repeat f p q =+    let p' = unP_repeat p+        q' = unP_repeat q+    in toP (f p' q')++-- | Lift ternary list function to pattern function.+liftP3 :: ([a] -> [b] -> [c] -> [d]) -> P a -> P b -> P c -> P d+liftP3 f p q r =+    let p' = unP p+        q' = unP q+        r' = unP r+    in toP (f p' q' r')++-- | Lift ternary list function to /implicitly repeating/ pattern function.+liftP3_repeat :: ([a] -> [b] -> [c] -> [d]) -> P a -> P b -> P c -> P d+liftP3_repeat f p q r =+    let p' = unP_repeat p+        q' = unP_repeat q+        r' = unP_repeat r+    in toP (f p' q' r')++-- * Zip P++-- | An /implicitly repeating/ pattern variant of 'zipWith'.+--+-- > zipWith (*) [1,2,3] [5,6] == [5,12]+-- > pzipWith (*) (toP [1,2,3]) (toP [5,6]) == toP [5,12]+--+-- It is the basis for lifting binary operators to patterns.+--+-- > toP [1,2,3] * toP [5,6] == toP [5,12]+--+-- > let p = pzipWith (,) (pseq [1,2] 2) (pseq [3,4] inf)+-- > in p == toP [(1,3),(2,4),(1,3),(2,4)]+--+-- > zipWith (,) (return 0) (return 1) == return (0,1)+-- > pzipWith (,) 0 1 == undecided (0,1)+pzipWith :: (a -> b -> c) -> P a -> P b -> P c+pzipWith f p q =+    case (p,q) of+      (P (Left m),P (Left n)) -> undecided (f m n)+      _ -> toP (zipWith f (unP_repeat p) (unP_repeat q))++-- | An /implicitly repeating/ pattern variant of 'zipWith3'.+pzipWith3 :: (a -> b -> c -> d) -> P a -> P b -> P c -> P d+pzipWith3 f p q r =+    case (p,q,r) of+      (P (Left m),P (Left n),P (Left o)) -> undecided (f m n o)+      _ -> toP (zipWith3 f (unP_repeat p) (unP_repeat q) (unP_repeat r))++-- | An /implicitly repeating/ pattern variant of 'zip'.+--+-- > zip (return 0) (return 1) == return (0,1)+-- > pzip (undecided 3) (undecided 4) == undecided (3,4)+-- > pzip 0 1 == undecided (0,1)+--+-- Note that 'pzip' is otherwise like haskell 'zip', ie. truncating.+--+-- > zip [1,2] [0] == [(1,0)]+-- > pzip (toP [1,2]) (return 0) == toP [(1,0)]+-- > pzip (toP [1,2]) (pure 0) == toP [(1,0),(2,0)]+-- > pzip (toP [1,2]) 0 == toP [(1,0),(2,0)]+pzip :: P a -> P b -> P (a,b)+pzip = pzipWith (,)++-- | Pattern variant of 'zip3'.+pzip3 :: P a -> P b -> P c -> P (a,b,c)+pzip3 = pzipWith3 (,,)++-- | Pattern variant on 'unzip'.+--+-- > let p = punzip (pzip (toP [1,2,3]) (toP [4,5]))+-- > in p == (toP [1,2],toP [4,5])+punzip :: P (a,b) -> (P a,P b)+punzip p = let (i,j) = unzip (unP p) in (toP i,toP j)
+ Sound/SC3/Lang/Pattern/P/Event.hs view
@@ -0,0 +1,574 @@+-- | @sclang@ event pattern functions.+--+-- SC3 /event/ patterns: `padd` (Padd), `pbind` (Pbind), `pkey`+-- (Pkey), `pmono` (Pmono), `pmul` (Pmul), `ppar` (Ppar), `pstretch`+-- (Pstretch), `ptpar` (Ptpar).  `pedit`, `pinstr`, `pmce2`, `psynth`,+-- `punion`.+module Sound.SC3.Lang.Pattern.P.Event where++import qualified Data.Foldable as F {- base -}+import Data.Maybe {- base -}+import Data.Monoid {- base -}++import Sound.OSC {- hsc3 -}+import Sound.SC3 {- hsc3 -}++import Sound.SC3.Lang.Control.Duration+import Sound.SC3.Lang.Control.Event+import Sound.SC3.Lang.Control.Instrument+import Sound.SC3.Lang.Core+import Sound.SC3.Lang.Pattern.P++-- * SC3 Event Patterns++-- | NewType for event patterns.+newtype P_Event = P_Event {p_Event :: P Event}++-- | 'P_Event' is audible, 'P' 'Event' could be as well but it'd be an orphan instance.+instance Audible P_Event where+    play_at _ = e_play . Event_Seq . unP . p_Event++pplay :: Transport m => P Event -> m ()+pplay = play . P_Event++-- | 'audition' of 'P_Event'.+paudition :: P Event -> IO ()+paudition = audition . P_Event++-- | Synonym for ('Key','P Field').+type P_Bind = (Key,P Field)++{-|+Padd.  Add a value to an existing key, or set the key if it doesn't exist.++> > p = Padd(\freq,801,Pbind(\freq,Pseq([100],1)));+> > p.asStream.all(()) == [('freq':901)]++> let p = padd (K_freq,801) (pbind [(K_freq,return 100)])+> in p == pbind [(K_freq,return 901)]++> > Padd(\freq,Pseq([401,801],2),Pbind(\freq,100)).play++> paudition (padd (K_freq,pseq [401,801] 2) (pbind [(K_freq,100)]))++> let {d = pseq [pshuf 'α' [-7,-3,0,2,4,7] 2+>               ,pseq [0,1,2,3,4,5,6,7] 1] 1+>     ;p = pbind [(K_dur,0.15),(K_degree,d)]+>     ;t n = padd (K_mtranspose,n) p}+> in paudition (pseq [p,t 1,t 2] inf)++-}+padd :: P_Bind -> P Event -> P Event+padd (k,p) = pzipWith (\i j -> e_edit k 0 (+ i) j) p++{-| Pbind.  SC3 pattern to assign keys to a set of 'Field' patterns+making an 'Event' pattern.++Each input pattern is assigned to key in the resulting event pattern.++There are a set of reserved keys that have particular roles in the+pattern library.++> > p = Pbind(\x,Pseq([1,2,3],1),\y,Pseed(Pn(100,1),Prand([4,5,6],inf)));+> > p.asStream.all(()) == [('y':4,'x':1),('y':6,'x':2),('y':4,'x':3)]++> let p = pbind [(K_param "x",prand 'α' [100,300,200] inf)+>               ,(K_param "y",pseq [1,2,3] 1)]+> in pkey (K_param "x") p == toP [200,200,300]++'K_param' can be elided if /OverloadedStrings/ are in place.++> :set -XOverloadedStrings++> ptake 2 (pbind [("x",pwhitei 'α' 0 9 inf)+>                ,("y",pseq [1,2,3] inf)])++'Event's implement variations on the @SC3@ 'Dur' and+'Sound.SC3.Lang.Control.Pitch.Pitch' models.++> > Pbind(\freq,Prand([300,500,231.2,399.2],inf),+> >       \dur,0.1).play;++> paudition (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)+>                  ,(K_dur,0.1)])++> > Pbind(\freq, Prand([300,500,231.2,399.2],inf),+> >       \dur,Prand([0.1,0.3],inf)).play;++> paudition (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)+>                  ,(K_dur,prand 'β' [0.1,0.3] inf)])++> > Pbind(\freq,Prand([1,1.2,2,2.5,3,4],inf) * 200,+> >       \dur,0.1).play;++> paudition (pbind [(K_freq,prand 'α' [1,1.2,2,2.5,3,4] inf * 200)+>                  ,(K_dur,0.1)])++> paudition (pbind [(K_freq,pseq [440,550,660,770] 2)+>                  ,(K_dur,pseq [0.1,0.15,0.1] inf)+>                  ,(K_amp,pseq [0.1,0.05] inf)+>                  ,(K_param "pan",pseq [-1,0,1] inf)])++A finite binding stops the `Event` pattern.++> > Pbind(\freq,Prand([300,500,231.2,399.2],inf),+> >       \dur,Pseq([0.1,0.2],3)).play;++> paudition (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)+>                  ,(K_dur,pseq [0.1,0.2] 3)])++> > Pbind(\freq,Prand([300,500,231.2,399.2],inf),+> >       \dur,Prand([0.1,0.3],inf)).play++All infinite inputs:++> paudition (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)+>                  ,(K_dur,prand 'β' [0.1,0.3] inf)])++Implicit /field/ patterns is this context are infinite.++> paudition (pbind [(K_freq,prand 'α' [1,1.2,2,2.5,3,4] inf * 200)+>                  ,(K_dur,0.1)])++> let test = let {freq = control KR "freq" 440+>                ;amp = control KR "amp" 0.1+>                ;nharms = control KR "nharms" 10+>                ;pan = control KR "pan" 0+>                ;gate = control KR "gate" 1+>                ;s = blip AR freq nharms * amp+>                ;e = linen gate 0.01 0.6 0.4 RemoveSynth+>                ;o = offsetOut 0 (pan2 s pan e)}+>            in synthdef "test" o++> paudition (pbind [(K_instr,psynth test)+>                  ,(K_freq,prand 'α' [1,1.2,2,2.5,3,4] inf * 200)+>                  ,(K_dur,0.1)])++> paudition (pbind [(K_instr,psynth test)+>                  ,(K_param "nharms",pseq [4,10,40] inf)+>                  ,(K_dur,pseq [1,1,2,1] inf / 10)+>                  ,(K_freq,pn (pseries 1 1 16 * 50) 4)+>                  ,(K_sustain,pseq [1/10,0.5,1,2] inf)])++> let acid = let {freq = control KR "freq" 1000+>                ;gate = control KR "gate" 1+>                ;pan = control KR "pan" 0+>                ;cut = control KR "cut" 4000+>                ;res = control KR "res" 0.8+>                ;amp = control KR "amp" 1+>                ;s = rlpf (pulse AR freq 0.05) cut res+>                ;d = envLinen 0.01 1 0.3 1+>                ;e = envGen KR gate amp 0 1 RemoveSynth d+>                ;o = out 0 (pan2 s pan e)}+>            in synthdef "acid" o++> > Pbind(\instrument,\acid,+> >       \dur,Pseq([0.25,0.5,0.25],4),+> >       \root,-24,+> >       \degree,Pseq([0,3,5,7,9,11,5,1],inf),+> >       \pan,Pfunc({1.0.rand2}),+> >       \cut,Pxrand([1000,500,2000,300],inf),+> >       \rez,Pfunc({0.7.rand +0.3}),+> >       \amp,0.2).play++> paudition (pbind [(K_instr,psynth acid)+>                  ,(K_dur,pseq [0.25,0.5,0.25] 4)+>                  ,(K_root,-24)+>                  ,(K_degree,pseq [0,3,5,7,9,11,5,1] inf)+>                  ,(K_param "pan",pwhite 'α' (-1.0) 1.0 inf)+>                  ,(K_param "cut",pxrand 'β' [1000,500,2000,300] inf)+>                  ,(K_param "res",pwhite 'γ' 0.3 1.0 inf)+>                  ,(K_amp,0.2)])++> > Pseq([Pbind(\instrument,\acid,+> >             \dur,Pseq([0.25,0.5,0.25],4),+> >             \root,-24,+> >             \degree,Pseq([0,3,5,7,9,11,5,1],inf),+> >             \pan,Pfunc({1.0.rand2}),+> >             \cut,Pxrand([1000,500,2000,300],inf),+> >             \rez,Pfunc({0.7.rand + 0.3}),+> >             \amp,0.2),+> >       Pbind(\instrument,\acid,+> >             \dur,Pseq([0.25],6),+> >             \root,-24,+> >             \degree,Pseq([18,17,11,9],inf),+> >             \pan,Pfunc({1.0.rand2}),+> >             \cut,1500,+> >             \rez,Pfunc({0.7.rand + 0.3}),+> >             \amp,0.16)],inf).play++> paudition (pseq [pbind [(K_instr,psynth acid)+>                        ,(K_dur,pseq [0.25,0.5,0.25] 4)+>                        ,(K_root,-24)+>                        ,(K_degree,pseq [0,3,5,7,9,11,5,1] inf)+>                        ,(K_param "pan",pwhite 'α' (-1.0) 1.0 inf)+>                        ,(K_param "cut",pxrand 'β' [1000,500,2000,300] inf)+>                        ,(K_param "res",pwhite 'γ' 0.3 1.0 inf)+>                        ,(K_amp,0.2)]+>                 ,pbind [(K_instr,psynth acid)+>                        ,(K_dur,pn 0.25 6)+>                        ,(K_root,-24)+>                        ,(K_degree,pser [18,17,11,9] inf)+>                        ,(K_param "pan",pwhite 'δ' (-1.0) 1.0 inf)+>                        ,(K_param "cut",1500)+>                        ,(K_param "res",pwhite 'ε' 0.3 1.0 inf)+>                        ,(K_amp,0.16)]] inf)++> > Pbind(\instrument, \acid,+> >       \dur, Pseq([0.25,0.5,0.25], inf),+> >       \root, [-24,-17],+> >       \degree, Pseq([0,3,5,7,9,11,5,1], inf),+> >       \pan, Pfunc({1.0.rand2}),+> >       \cut, Pxrand([1000,500,2000,300], inf),+> >       \rez, Pfunc({0.7.rand +0.3}),+> >       \amp, 0.2).play;++> paudition (pbind [(K_instr,psynth acid)+>                  ,(K_dur,pseq [0.25,0.5,0.25] inf)+>                  ,(K_root,pmce2 (-24) (-17))+>                  ,(K_degree,pseq [0,3,5,7,9,11,5,1] inf)+>                  ,(K_param "pan",pwhite 'α' (-1.0) 1.0 inf)+>                  ,(K_param "cut",pxrand 'β' [1000,500,2000,300] inf)+>                  ,(K_param "res",pwhite 'γ' 0.3 1.0 inf)+>                  ,(K_amp,0.2)])++A persistent synthesis node with /freq/ and /amp/ controls.++> import Sound.SC3.ID++> let {freq = control KR "freq" 440+>     ;amp = control KR "amp" 0.6+>     ;n = pinkNoise 'α' AR * amp}+> in audition (out 0 (pan2 (moogFF n freq 2 0) 0 1))++A pattern to set /freq/ and /amp/ controls at the most recently+instantiated synthesis node.++> :set -XOverloadedStrings++> paudition (pbind [(K_type,prepeat "n_set")+>                  ,(K_id,(-1))+>                  ,(K_freq,pwhite 'α' 100 1000 inf)+>                  ,(K_dur,0.2)+>                  ,(K_amp,toP [1,0.99 .. 0.1])])++> let berlinb =+>   let {k = control KR+>       ;o = k "out" 0+>       ;f = k "freq" 80+>       ;a = k "amp" 0.01+>       ;p = k "pan" 0+>       ;g = k "gate" 1+>       ;env = decay2 g 0.05 8 * 0.0003+>       ;syn = rlpf (lfPulse AR f 0 (sinOsc KR 0.12 (mce2 0 (pi/2)) * 0.48 + 0.5))+>                   (f * (sinOsc KR 0.21 0 * 18 + 20))+>                   0.07+>       ;syn_env = syn * env+>       ;kil = detectSilence (mceChannel 0 syn_env) 0.1 0.2 RemoveSynth}+>   in mrg2 (out o (a * mix (panAz 4 syn_env (mce2 p (p + 1)) 1 2 0.5))) kil++> paudition (ppar [pbind [(K_degree,pseq [0,1,2,4,6,3,4,8] inf)+>                        ,(K_dur,0.5)+>                        ,(K_octave,3)+>                        ,(K_instr,psynth (synthdef "berlinb" berlinb))]+>                 ,pbind [(K_degree,pseq [0,1,2,4,6,3,4,8] inf)+>                        ,(K_dur,0.5)+>                        ,(K_octave,pmce2 2 1)+>                        ,(K_param "pan",pwhite 'a' (-1) 1 inf)+>                        ,(K_instr,psynth (synthdef "berlinb" berlinb))]])++-}+pbind :: [P_Bind] -> P Event+pbind xs =+    let xs' = fmap (\(k,v) -> pzip (undecided k) v) xs+        xs'' = ptranspose_st_repeat xs'+    in fmap e_from_list xs''++-- | Operator to lift 'F_Value' pattern to 'P_Bind' tuple.+--+-- > let {r = True `pcons` preplicate 3 False :: P Bool}+-- > in pbind [K_rest <| r] == pbind [(K_rest,pseq [1,0,0,0] 1)]+(<|) :: F_Value v => Key -> P v -> P_Bind+(<|) k p = (k,fmap toF p)+infixl 3 <|++{- | Pkey.  SC3 pattern to read 'Key' at 'Event' pattern.  Note+-- however that in haskell is usually more appropriate to name the+-- pattern using /let/.++> pkey K_freq (pbind [(K_freq,return 440)]) == toP [440]+> pkey K_amp (pbind [(K_amp,toP [0,1])]) == toP [0,1]++> > Pbind(\degree,Pseq([Pseries(-7,1,14),Pseries(7,-1,14)],inf),+> >       \dur,0.25,+> >       \legato,Pkey(\degree).linexp(-7,7,2.0,0.05)).play++> let {d = pseq [pseries (-7) 1 14,pseries 7 (-1) 14] inf+>     ;l = fmap (Sound.SC3.Lang.Math.linexp (-7) 7 2 0.05) d}+> in paudition (pbind [(K_degree,d)+>                     ,(K_dur,0.25)+>                     ,(K_legato,l)])++-}+pkey :: Key -> P Event -> P Field+pkey k = fmap (fromJust . e_get k)++{- | Pmono.  SC3 pattern that is a variant of 'pbind' for controlling+-- monophonic (persistent) synthesiser nodes.++> let p = [(K_instr,pinstr' (Instr_Ref "default" False))+>         ,(K_id,100)+>         ,(K_degree,pxrand 'α' [0,2,4,5,7,9,11] inf)+>         ,(K_amp,pwrand 'β' [0.05,0.2] [0.7,0.3] inf)+>         ,(K_dur,0.25)]+> in paudition (pmono p)++-}+pmono :: [P_Bind] -> P Event+pmono b =+    let ty = fmap F_String ("s_new" `pcons` prepeat "n_set")+    in pbind ((K_type,ty) : b)++-- | Pmul.  SC3 pattern to multiply an existing key by a value, or set+-- the key if it doesn't exist.+--+-- > let p = pbind [(K_dur,0.15),(K_freq,prand 'α' [440,550,660] 6)]+-- > in paudition (pseq [p,pmul (K_freq,2) p,pmul (K_freq,0.5) p] 2)+pmul :: P_Bind -> P Event -> P Event+pmul (k,p) = pzipWith (\i j -> e_edit k 1 (* i) j) p++{-| Ppar.  Variant of 'ptpar' with zero start times.++The result of `pmerge` can be merged again, `ppar` merges a list of+patterns.++> let {a = pbind [(K_param "a",pseq [1,2,3] inf)]+>     ;b = pbind [(K_param "b",pseq [4,5,6] inf)]+>     ;r = toP [e_from_list [(K_param "a",1),(K_fwd',0)]+>              ,e_from_list [(K_param "b",4),(K_fwd',1)]]}+> in ptake 2 (ppar [a,b]) == r++> let {p = pbind [(K_dur,0.2),(K_midinote,pseq [62,65,69,72] inf)]+>     ;q = pbind [(K_dur,0.4),(K_midinote,pseq [50,45] inf)]+>     ;r = pbind [(K_dur,0.6),(K_midinote,pseq [76,79,81] inf)]}+> in paudition (ppar [p,q,r])++Multiple nested `ppar` patterns.++> let {a u = pbind [(K_dur,0.2),(K_param "pan",0.5),(K_midinote,pseq u 1)]+>     ;b l = pbind [(K_dur,0.4),(K_param "pan",-0.5),(K_midinote,pseq l 1)]+>     ;f u l = ppar [a u,b l]+>     ;h = pbind [(K_dur,prand 'α' [0.2,0.4,0.6] inf)+>                ,(K_midinote,prand 'β' [72,74,76,77,79,81] inf)+>                ,(K_db,-26)+>                ,(K_legato,1.1)]+>     ;m = pseq [pbind [(K_dur,3.2),(K_freq,return nan)]+>               ,prand 'γ' [f [60,64,67,64] [48,43]+>                          ,f [62,65,69,65] [50,45]+>                          ,f [64,67,71,67] [52,47]] 12] inf}+> in paudition (ppar [h,m])++-}+ppar :: [P Event] -> P Event+ppar l = ptpar (zip (repeat 0) l)++-- | Pstretch.  SC3 pattern to do time stretching.  It is equal to+-- 'pmul' at 'K_stretch'.+--+-- > let {d = pseq [pshuf 'α' [-7,-3,0,2,4,7] 2+-- >               ,pseq [0,1,2,3,4,5,6,7] 1] 1+-- >     ;p = pbind [(K_dur,0.15),(K_degree,d)]}+-- > in paudition (pseq [p,pstretch 0.5 p,pstretch 2 p] inf)+pstretch :: P Field -> P Event -> P Event+pstretch p = pmul (K_stretch,p)++{-| Ptpar.  Merge a set of 'Event' patterns each with indicated+-- start 'Time'.++`ptpar` is a variant of `ppar` which allows non-equal start times.++> let {f d p n = pbind [(K_dur,d),(K_param "pan",p),(K_midinote,n)]+>     ;a = f 0.2 (-1) (pseries 60 1 15)+>     ;b = f 0.15 0 (pseries 58 2 15)+>     ;c = f 0.1 1 (pseries 46 3 15)}+> in paudition (ptpar [(0,a),(1,b),(2,c)])++> let {d = pseq [pgeom 0.05 1.1 24,pgeom 0.5 0.909 24] 2+>     ;f n a p = pbind [(K_dur,d)+>                      ,(K_db,a)+>                      ,(K_param "pan",p)+>                      ,(K_midinote,pseq [n,n-4] inf)]}+> in audition (ptpar [(0,f 53 (-20) (-0.9))+>                    ,(2,f 60 (-23) (-0.3))+>                    ,(4,f 67 (-26) 0.3)+>                    ,(6,f 74 (-29) 0.9)])++-}+ptpar :: [(Time,P Event)] -> P Event+ptpar l =+    case l of+      [] -> mempty+      [(_,p)] -> p+      (pt,p):(qt,q):r -> ptpar ((min pt qt,ptmerge (pt,p) (qt,q)) : r)++-- * Instrument Event Patterns++-- | Pattern from 'Instr'.  An 'Instr' is either a 'Synthdef' or a+-- /name/.  In the 'Synthdef' case the instrument is asynchronously+-- sent to the server before processing the event, which has timing+-- implications.  The pattern constructed here uses the 'Synthdef' for+-- the first element, and the subsequently the /name/.+--+-- > paudition (pbind [(K_instr,pinstr' defaultInstr)+-- >                  ,(K_degree,toP [0,2,4,7])+-- >                  ,(K_dur,0.25)])+pinstr' :: Instr -> P Field+pinstr' i = toP (map F_Instr (i_repeat i))++{-| 'Instr' pattern from instrument /name/.  See also `psynth` (where+the /sine/ instrument below is defined).++> let {si = return (F_Instr (Instr_Ref "sine" True))+>     ;di = return (F_Instr (Instr_Ref "default" True))+>     ;i = pseq [si,si,di] inf+>     ;p = pbind [(K_instr,i),(K_degree,pseq [0,2,4,7] inf),(K_dur,0.25)]}+> in paudition p++-}+pinstr :: String -> P Field+pinstr s = pinstr' (Instr_Ref s True)++{-| `Synthdef`s can be used directly as an instrument using `psynth`.+The default synthdef is at 'Data.Default.def'.++> let sineSynth =+>   let {f = control KR "freq" 440+>       ;g = control KR "gate" 1+>       ;a = control KR "amp" 0.1+>       ;d = envASR 0.01 1 1 (EnvNum (-4))+>       ;e = envGen KR g a 0 1 RemoveSynth d+>       ;o = out 0 (sinOsc AR f 0 * e)}+>   in synthdef "sine" o++> paudition (pbind [(K_instr,psynth sineSynth)+>                  ,(K_degree,toP [0,2,4,7])+>                  ,(K_dur,0.25)])++-}+psynth :: Synthdef -> P Field+psynth s = pinstr' (Instr_Def s True)++-- * MCE Patterns++-- | Two-channel MCE for /field/ patterns.+--+-- > pmce2 (toP [1,2]) (toP [3,4]) == toP [f_array [1,3],f_array [2,4]]+--+-- > let p = pmce2 (pseq [1,2] inf) (pseq [3,4] inf)+-- > in ptake 2 p == toP [f_array [1,3],f_array [2,4]]+pmce2 :: P Field -> P Field -> P Field+pmce2 p = pzipWith (\m n -> F_Vector [m,n]) p++-- | Three-channel MCE for /field/ patterns.+pmce3 :: P Field -> P Field -> P Field -> P Field+pmce3 p q = pzipWith3 (\m n o -> F_Vector [m,n,o]) p q++{-|++Remove one layer of MCE expansion at an /event/ pattern.  The+pattern will be expanded only to the width of the initial input.+Holes are filled with rests.++> let {a = pseq [65,69,74] inf+>     ;b = pseq [60,64,67,72,76] inf+>     ;c = pseq [pmce3 72 76 79,pmce2 a b] 1}+> in paudition (p_un_mce (pbind [(K_midinote,c)+>                               ,(K_param "pan",pmce2 (-1) 1)+>                               ,(K_dur,1 `pcons` prepeat 0.15)]))++`p_un_mce` translates via `ppar`.  This allows `dur` related fields to+be MCE values.  The underlying event processor also implements one+layer of MCE expansion.++> paudition (p_un_mce+>            (pbind [(K_dur,pmce2 0.25 0.2525)+>                   ,(K_legato,pmce2 0.25 2.5)+>                   ,(K_freq,pmce2 (pseq [300,400,500] inf)+>                                  (pseq [302,402,502,202] inf))+>                   ,(K_param "pan",pmce2 (-0.5) 0.5)]))++-}+p_un_mce :: P Event -> P Event+p_un_mce p =+    let l' = transpose_fw_def' e_rest (map e_un_mce' (unP p))+    in toP (e_par (zip (repeat 0) l'))++-- * Non-SC3 Event Patterns++-- | Edit 'a' at 'Key' in each element of an 'Event' pattern.+pedit :: Key -> (Field -> Field) -> P Event -> P Event+pedit k f = fmap (e_edit' k f)++-- | Pattern of start times of events at event pattern.+--+-- > p_time (pbind [(K_dur,toP [1,2,3,2,1])]) == toP [0,1,3,6,8,9]+-- > p_time (pbind [(K_dur,pseries 0.5 0.5 5)]) == toP [0,0.5,1.5,3,5,7.5]+p_time :: P Event -> P Time+p_time =  pscanl (+) 0 . fmap (fwd . e_dur Nothing)++-- | Pattern to extract 'a's at 'Key' from an 'Event'+-- pattern.+--+-- > pkey_m K_freq (pbind [(K_freq,return 440)]) == toP [Just 440]+pkey_m :: Key -> P Event -> P (Maybe Field)+pkey_m k = fmap (e_get k)++{-| Variant of 'ptmerge' with zero start times.++`pmerge` merges two event streams, adding /fwd'/ entries as required.++> let {p = pbind [(K_dur,0.2),(K_midinote,pseq [62,65,69,72] inf)]+>     ;q = pbind [(K_dur,0.4),(K_midinote,pseq [50,45] inf)]}+> in paudition (pmerge p q)++-}+pmerge :: P Event -> P Event -> P Event+pmerge p q = ptmerge (0,p) (0,q)++-- | Variant that does not insert key.+pmul' :: P_Bind -> P Event -> P Event+pmul' (k,p) = pzipWith (\i j -> e_edit' k (* i) j) p++-- | Merge two 'Event' patterns with indicated start 'Time's.+ptmerge :: (Time,P Event) -> (Time,P Event) -> P Event+ptmerge (pt,p) (qt,q) =+    toP (e_merge (pt,F.toList p) (qt,F.toList q))++-- | Left-biased union of event patterns.+punion :: P Event -> P Event -> P Event+punion = pzipWith (<>)++-- | 'punion' of 'pbind' of 'return', ie. @p_with (K_Instr,psynth s)@.+p_with :: P_Bind -> P Event -> P Event+p_with = punion . pbind . return++-- * NRT++{-| Transform an /event/ pattern into a /non-real time/ SC3 score.++> let n = pNRT (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)+>                     ,(K_dur,pseq [0.1,0.2] 3)])++> audition n++> mapM_ (putStrLn . bundlePP) (nrt_bundles n)++Infinite 'NRT' scores are productive for 'audition'ing.++> let n' = pNRT (pbind [(K_dur,0.25),(K_freq,pseq [300,600,900] inf)])+> audition n'+> mapM_ (putStrLn . bundlePP) (take 9 (nrt_bundles n'))++-}+pNRT :: P Event -> NRT+pNRT = e_nrt . Event_Seq . unP
+ Sound/SC3/Lang/Pattern/P/SC3.hs view
@@ -0,0 +1,883 @@+-- | @sclang@ value pattern functions.+--+-- SC3 /value/ patterns: `pbrown` (Pbrown), `pclutch` (Pclutch),+-- `pcollect` (Pcollect), `pconst` (Pconst), `pdegreeToKey`+-- (PdegreeToKey), `pdiff` (Pdiff), `pdrop` (Pdrop), `pdurStutter`+-- (PdurStutter), `pexprand` (Pexprand), `pfinval` (Pfinval), `pfuncn`+-- (Pfuncn), `pgeom` (Pgeom), `pif` (Pif), `place` (Place), `pn` (Pn),+-- `ppatlace` (Ppatlace), `prand` (Prand), `preject` (Preject),+-- `prorate` (Prorate), `pselect` (Pselect), `pseq` (Pseq), `pser`+-- (Pser), `pseries` (Pseries), `pshuf` (Pshuf), `pslide` (Pslide),+-- `pstutter` (Pstutter), `pswitch1` (Pswitch1), `pswitch` (Pswitch),+-- `ptuple` (Ptuple), `pwhite` (Pwhite), `pwrand` (Pwrand), `pwrap`+-- (Pwrap), `pxrand` (Pxrand).+--+-- SC3 variant patterns: `pbrown`', `prand'`, `prorate'`, `pseq1`,+-- `pseqn`, `pser1`, `pseqr`, `pwhite'`, `pwhitei`.+--+-- SC3 collection patterns: `pfold`+module Sound.SC3.Lang.Pattern.P.SC3 where++import Control.Monad {- base -}+import qualified Data.List as L {- base -}+import Data.Monoid {- base -}+import System.Random {- random -}++import Sound.SC3 {- hsc3 -}++import Sound.SC3.Lang.Core+import Sound.SC3.Lang.Pattern.P.Core+import Sound.SC3.Lang.Pattern.P.Base++import qualified Sound.SC3.Lang.Collection as C+import qualified Sound.SC3.Lang.Math as M+import qualified Sound.SC3.Lang.Pattern.List as P+import qualified Sound.SC3.Lang.Pattern.Stream as I+import qualified Sound.SC3.Lang.Random.Gen as R++-- * SC3 Collection Patterns++-- | Variant of 'C.flop'.+--+-- > pflop' [toP [1,2],toP [3,4,5]] == toP [[1,3],[2,4],[1,5]]+-- > pflop' [toP [1,2],3] == toP [[1,3],[2,3]]+-- > pflop' [pseq [1,2] 1,pseq [3,4] inf]+pflop' :: [P a] -> P [a]+pflop' l = toP (C.flop (map unP l))++-- | 'fmap' 'toP' of 'pflop''.+--+-- > C.flop [[1,2],[3,4,5]] == [[1,3],[2,4],[1,5]]+-- > pflop [toP [1,2],toP [3,4,5]] == toP (map toP [[1,3],[2,4],[1,5]])+pflop :: [P a] -> P (P a)+pflop = fmap toP . pflop'++{- | Type specialised 'P.ffold'.++> pfold (toP [10,11,12,-6,-7,-8]) (-7) 11 == toP [10,11,10,-6,-7,-6]++> audition (pbind [(K_degree,pfold (pseries 4 1 inf) (-7) 11)+>                 ,(K_dur,0.0625)])++The underlying primitive is then `fold_` function.++> let f = fmap (\n -> fold_ n (-7) 11)+> in audition (pbind [(K_degree,f (pseries 4 1 inf))+>                    ,(K_dur,0.0625)])++-}+pfold :: (RealFrac n) => P n -> n -> n -> P n+pfold = P.ffold++-- | Pattern variant of 'C.normalizeSum'.+pnormalizeSum :: Fractional n => P n -> P n+pnormalizeSum = liftP C.normalizeSum++-- * SC3 Patterns++{-| Pbrown.  Lifted 'P.brown'.  SC3 pattern to generate+psuedo-brownian motion.++> pbrown 'α' 0 9 1 5 == toP [4,4,5,4,3]++> audition (pbind [(K_dur,0.065)+>                 ,(K_freq,pbrown 'α' 440 880 20 inf)])++-}+pbrown :: (Enum e,Random n,Num n,Ord n) => e -> n -> n -> n -> Int -> P n+pbrown e l r s n = ptake n (toP (P.brown e l r s))++{-| Pclutch.  SC3 sample and hold pattern.  For true values in the+control pattern, step the value pattern, else hold the previous value.++> > c = Pseq([1,0,1,0,0,1,1],inf);+> > p = Pclutch(Pser([1,2,3,4,5],8),c);+> > r = [1,1,2,2,2,3,4,5,5,1,1,1,2,3];+> > p.asStream.all == r++> let {c = pbool (pseq [1,0,1,0,0,1,1] inf)+>     ;p = pclutch (pser [1,2,3,4,5] 8) c+>     ;r = toP [1,1,2,2,2,3,4,5,5,1,1,1,2,3]}+> in p == toP [1,1,2,2,2,3,4,5,5,1,1,1,2,3]++Note the initialization behavior, nothing is generated until the+first true value.++> let {p = pseq [1,2,3,4,5] 1+>     ;q = pbool (pseq [0,0,0,0,0,0,1,0,0,1,0,1] 1)}+> in pclutch p q == toP [1,1,1,2,2,3]++> > Pbind(\degree,Pstutter(Pwhite(3,10,inf),Pwhite(-4,11,inf)),+> >       \dur,Pclutch(Pwhite(0.1,0.4,inf),+> >                    Pdiff(Pkey(\degree)).abs > 0),+> >       \legato,0.3).play;++> let {d = pstutter (pwhite 'α' 3 10 inf) (pwhitei 'β' (-4) 11 inf)+>     ;p = [(K_degree,d)+>          ,(K_dur,pclutch (pwhite 'γ' 0.1 0.4 inf)+>                          (pbool (abs (pdiff d) >* 0)))+>          ,(K_legato,0.3)]}+> in audition (pbind p)++-}+pclutch :: P a -> P Bool -> P a+pclutch p q =+    let r = fmap (+ 1) (pcountpost q)+    in pstutter r p++-- | Pcollect.  SC3 name for 'fmap', ie. patterns are functors.+--+-- > > Pcollect({|i| i * 3},Pseq(#[1,2,3],1)).asStream.all == [3,6,9]+-- > pcollect (* 3) (toP [1,2,3]) == toP [3,6,9]+--+-- > > Pseq(#[1,2,3],1).collect({|i| i * 3}).asStream.all == [3,6,9]+-- > fmap (* 3) (toP [1,2,3]) == toP [3,6,9]+pcollect :: (a -> b) -> P a -> P b+pcollect = fmap++{- | Pconst.  SC3 pattern to constrain the sum of a numerical pattern.+Is equal to /p/ until the accumulated sum is within /t/ of /n/.  At+that point, the difference between the specified sum and the+accumulated sum concludes the pattern.++> > p = Pconst(10,Pseed(Pn(1000,1),Prand([1,2,0.5,0.1],inf),0.001));+> > p.asStream.all == [0.5,0.1,0.5,1,2,2,0.5,1,0.5,1,0.9]++> let p = pconst 10 (prand 'α' [1,2,0.5,0.1] inf) 0.001+> in (p,Data.Foldable.sum p)++> > Pbind(\degree,Pseq([-7,Pwhite(0,11,inf)],1),+> >       \dur,Pconst(4,Pwhite(1,4,inf) * 0.25)).play++> let p = [(K_degree,pcons (-7) (pwhitei 'α' 0 11 inf))+>         ,(K_dur,pconst 4 (pwhite 'β' 1 4 inf * 0.25) 0.001)]+> in audition (pbind p)++-}+pconst :: (Ord a,Num a) => a -> P a -> a -> P a+pconst n p t =+    let f _ [] = []+        f j (i:is) = if i + j < n - t+                     then i : f (j + i) is+                     else [n - j]+    in toP (f 0 (unP p))++{-| PdegreeToKey.  SC3 pattern to derive notes from an index into a+scale.++> let {p = pseq [0,1,2,3,4,3,2,1,0,2,4,7,4,2] 2+>     ;q = pure [0,2,4,5,7,9,11]+>     ;r = [0,2,4,5,7,5,4,2,0,4,7,12,7,4,0,2,4,5,7,5,4,2,0,4,7,12,7,4]}+> in pdegreeToKey p q (pure 12) == toP r++> let {p = pseq [0,1,2,3,4,3,2,1,0,2,4,7,4,2] 2+>     ;q = pseq (map return [[0,2,4,5,7,9,11],[0,2,3,5,7,8,11]]) 1+>     ;r = [0,2,4,5,7,5,4,2,0,4,7,12,7,4,0,2,3,5,7,5,3,2,0,3,7,12,7,3]}+> in pdegreeToKey p (pstutter 14 q) (pure 12) == toP r++This is the pattern variant of 'M.degreeToKey'.++> let s = [0,2,4,5,7,9,11]+> in map (M.degreeToKey s 12) [0,2,4,7,4,2,0] == [0,4,7,12,7,4,0]++> > Pbind(\note,PdegreeToKey(Pseq([1,2,3,2,5,4,3,4,2,1],2),+> >                          #[0,2,3,6,7,9],+> >                          12),\dur,0.25).play++> let {n = pdegreeToKey (pseq [1,2,3,2,5,4,3,4,2,1] 2)+>                       (pure [0,2,3,6,7,9])+>                       12}+> in audition (pbind [(K_note,n),(K_dur,0.25)])++> > s = #[[0,2,3,6,7,9],[0,1,5,6,7,9,11],[0,2,3]];+> > d = [1,2,3,2,5,4,3,4,2,1];+> > Pbind(\note,PdegreeToKey(Pseq(d,4),+> >                          Pstutter(3,Prand(s,inf)),+> >                          12),\dur,0.25).play;++> let {s = map return [[0,2,3,6,7,9],[0,1,5,6,7,9,11],[0,2,3]]+>     ;d = [1,2,3,2,5,4,3,4,2,1]+>     ;k = pdegreeToKey (pseq d 4)+>                       (pstutter 3 (prand 'α' s 14))+>                       (pn 12 40)}+> in audition (pbind [(K_note,k),(K_dur,0.25)])++-}+pdegreeToKey :: (RealFrac a) => P a -> P [a] -> P a -> P a+pdegreeToKey = pzipWith3 (\i j k -> M.degreeToKey j k i)++-- | Pdiff.  SC3 pattern to calculate adjacent element difference.+--+-- > > Pdiff(Pseq([0,2,3,5,6,8,9],1)).asStream.all == [2,1,2,1,2,1]+-- > pdiff (pseq [0,2,3,5,6,8,9] 1) == toP [2,1,2,1,2,1]+pdiff :: Num n => P n -> P n+pdiff p = ptail p - p++-- | Pdrop.  Lifted 'L.drop'.+--+-- > > p = Pseries(1,1,20).drop(5);+-- > > p.asStream.all == [6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]+--+-- > pdrop 5 (pseries 1 1 10) == toP [6,7,8,9,10]+-- > pdrop 1 mempty == mempty+pdrop :: Int -> P a -> P a+pdrop n = liftP (drop n)++{- | PdurStutter.  Lifted 'P.durStutter'.++> > s = Pseq(#[1,1,1,1,1,2,2,2,2,2,0,1,3,4,0],inf);+> > d = Pseq(#[0.5,1,2,0.25,0.25],1);+> > PdurStutter(s,d).asStream.all == [0.5,1,2,0.25,0.25]++> let {s = pseq [1,1,1,1,1,2,2,2,2,2,0,1,3,4,0] inf+>     ;d = pseq [0.5,1,2,0.25,0.25] 1}+> in pdurStutter s d == toP [0.5,1.0,2.0,0.25,0.25]++Applied to duration.++> > d = PdurStutter(Pseq(#[1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4],inf),+> >                 Pseq(#[0.5,1,2,0.25,0.25],inf));+> > Pbind(\freq,440,\dur,d).play++> let {s = pseq [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4] inf+>     ;d = pseq [0.5,1,2,0.25,0.25] inf}+> in audition (pbind [(K_freq,440),(K_dur,pdurStutter s d)])++Applied to frequency.++> let {s = pseq [1,1,1,1,1,2,2,2,2,2,3,3,3,3,4,4,0,4,4] inf+>     ;d = pseq [0,2,3,5,7,9,10] inf + 80}+> in audition (pbind [(K_midinote,pdurStutter s d),(K_dur,0.15)])++-}+pdurStutter :: Fractional a => P Int -> P a -> P a+pdurStutter = liftP2 P.durStutter++-- | Pexprand.  Lifted 'P.exprand'.+--+-- > > Pexprand(0.0001,1,10).asStream.all+-- > pexprand 'α' 0.0001 1 10+--+-- > > Pbind(\freq,Pexprand(0.0001,1,inf) * 600 + 300,\dur,0.02).play+--+-- > audition (pbind [(K_freq,pexprand 'α' 0.0001 1 inf * 600 + 300)+-- >                 ,(K_dur,0.02)])+pexprand :: (Enum e,Random a,Floating a) => e -> a -> a -> Int -> P a+pexprand e l r = toP . P.exprand e l r++-- | Pfinval.  Alias for 'ptake'+--+-- > > Pfinval(5,Pseq(#[1,2,3],inf)).asStream.all == [1,2,3,1,2]+-- > pfinval 5 (pseq [1,2,3] inf) == toP [1,2,3,1,2]+pfinval :: Int -> P a -> P a+pfinval = ptake++{-|+A variant of the SC3 pattern that evaluates a closure at each+step.  The haskell variant function has a 'StdGen' form.++> > p = Pfuncn({exprand(0.1,0.3) + #[1,2,3,6,7].choose},inf);+> > Pbind(\freq,p * 100 + 300,\dur,0.02).play++> let {exprand = Sound.SC3.Lang.Random.Gen.exprand+>     ;choose = Sound.SC3.Lang.Random.Gen.choose+>     ;p = pfuncn 'α' (exprand 0.1 0.3) inf+>     ;q = pfuncn 'β' (choose [1,2,3,6,7]) inf}+> in audition (pbind [(K_freq,(p + q) * 100 + 300),(K_dur,0.02)])++Of course in this case there is a pattern equivalent.++> let {p = pexprand 'α' 0.1 0.3 inf + prand 'β' [1,2,3,6,7] inf}+> in audition (pbind [(K_freq,p * 100 + 300),(K_dur,0.02)])++-}+pfuncn :: Enum e => e -> (StdGen -> (n,StdGen)) -> Int -> P n+pfuncn e f n = toP (P.funcn e f n)++{- | Pgeom.  SC3 geometric series pattern.++> > Pgeom(3,6,5).asStream.all == [3,18,108,648,3888]+> pgeom 3 6 5 == toP [3,18,108,648,3888]++> > Pgeom(1,2,10).asStream.all == [1,2,4,8,16,32,64,128,256,512]+> pgeom 1 2 10 == toP [1,2,4,8,16,32,64,128,256,512]++Real numbers work as well.++> > p = Pgeom(1.0,1.1,6).collect({|i| (i * 100).floor});+> > p.asStream.all == [100,110,121,133,146,161];++> let p = fmap (floor . (* 100)) (pgeom 1.0 1.1 6)+> in p == toP [100,110,121,133,146,161]++> > Pbind(\degree,Pseries(-7,1,15),+> >       \dur,Pgeom(0.5,0.89140193218427,15)).play;++> audition (pbind [(K_degree,pseries (-7) 1 15)+>                 ,(K_dur,pgeom 0.5 0.89140193218427 15)])++There is a list variant.++> > 5.geom(3,6)+> C.geom 5 3 6 == [3,18,108,648,3888]++-}+pgeom :: (Num a) => a -> a -> Int -> P a+pgeom i s n = toP (C.geom n i s)++-- | Pif.  SC3 /implicitly repeating/ pattern-based conditional expression.+--+-- > > a = Pfunc({0.3.coin});+-- > > b = Pwhite(0,9,3);+-- > > c = Pwhite(10,19,3);+-- > > Pfin(9,Pif(a,b,c)).asStream.all+--+-- > let {a = fmap (< 0.75) (pwhite 'α' 0.0 1.0 inf)+-- >     ;b = pwhite 'β' 0 9 6+-- >     ;c = pwhite 'γ' 10 19 6}+-- > in pif a b c * (-1) == toP [-7,-3,-11,-17,-18,-6,-3,-4,-5]+pif :: P Bool -> P a -> P a -> P a+pif = liftP3_repeat P.if_demand++-- | Place.  SC3 interlaced embedding of subarrays.+--+-- > > Place([0,[1,2],[3,4,5]],3).asStream.all == [0,1,3,0,2,4,0,1,5]+-- > C.lace 9 [[0],[1,2],[3,4,5]] == [0,1,3,0,2,4,0,1,5]+-- > place [[0],[1,2],[3,4,5]] 3 == toP [0,1,3,0,2,4,0,1,5]+--+-- > > Place(#[1,[2,5],[3,6]],2).asStream.all == [1,2,3,1,5,6]+-- > C.lace 6 [[1],[2,5],[3,6]] == [1,2,3,1,5,6]+-- > place [[1],[2,5],[3,6]] 2 == toP [1,2,3,1,5,6]+--+-- > C.lace 12 [[1],[2,5],[3,6..]] == [1,2,3,1,5,6,1,2,9,1,5,12]+-- > place [[1],[2,5],[3,6..]] 4 == toP [1,2,3,1,5,6,1,2,9,1,5,12]+place :: [[a]] -> Int -> P a+place a n =+    let f = toP . concat . take_inf n . L.transpose . map cycle+    in f a++-- | Pn.  SC3 pattern to repeat the enclosed pattern a number of+-- times.+--+-- > pn 1 4 == toP [1,1,1,1]+-- > pn (toP [1,2,3]) 3 == toP [1,2,3,1,2,3,1,2,3]+--+-- This is related to `concat`.`replicate` in standard list processing.+--+-- > concat (replicate 4 [1]) == [1,1,1,1]+-- > concat (replicate 3 [1,2,3]) == [1,2,3,1,2,3,1,2,3]+--+-- There is a `pconcatReplicate` near-alias (reversed argument order).+--+-- > pconcatReplicate 4 1 == toP [1,1,1,1]+-- > pconcatReplicate 3 (toP [1,2]) == toP [1,2,1,2,1,2]+--+-- This is productive over infinite lists.+--+-- > concat (replicate inf [1])+-- > pconcat (replicate inf 1)+-- > pconcatReplicate inf 1+pn :: P a -> Int -> P a+pn p n = mconcat (replicate n p)++{- | Ppatlace.  SC3 /implicitly repeating/ pattern to lace input patterns.++> > p = Ppatlace([1,Pseq([2,3],2),4],5);+> > p.asStream.all == [1,2,4,1,3,4,1,2,4,1,3,4,1,4]++> ppatlace [1,pseq [2,3] 2,4] 5 == toP [1,2,4,1,3,4,1,2,4,1,3,4,1,4]++> > p = Ppatlace([1,Pseed(Pn(1000,1),Prand([2,3],inf))],5);+> > p.asStream.all == [1,3,1,3,1,3,1,2,1,2]++> ppatlace [1,prand 'α' [2,3] inf] 5 == toP [1,3,1,2,1,3,1,2,1,2]++> > Pbind(\degree,Ppatlace([Pseries(0,1,8),Pseries(2,1,7)],inf),+> >       \dur,0.25).play;++> let p = [(K_degree,ppatlace [pseries 0 1 8,pseries 2 1 7] inf)+>         ,(K_dur,0.125)]+> in audition (pbind p)++-}+ppatlace :: [P a] -> Int -> P a+ppatlace a n =+    let a' = L.transpose (map unP_repeat a)+    in toP (L.concat (take_inf n a'))++{-| Prand.  SC3 pattern to make n random selections from a list of+patterns, the resulting pattern is flattened (joined).++> > p = Pseed(Pn(1000,1),Prand([1,Pseq([10,20,30]),2,3,4,5],6));+> > p.asStream.all == [3,5,3,10,20,30,2,2]++> prand 'α' [1,toP [10,20],2,3,4,5] 5 == toP [5,2,10,20,2,1]++> > Pbind(\note,Prand([0,1,5,7],inf),\dur,0.25).play++> audition (pbind [(K_note,prand 'α' [0,1,5,7] inf),(K_dur,0.25)])++Nested sequences of pitches:++> > Pbind(\midinote,Prand([Pseq(#[60,61,63,65,67,63]),+> >                        Prand(#[72,73,75,77,79],6),+> >                        Pshuf(#[48,53,55,58],2)],inf),+> >       \dur,0.25).play++> let {n = prand 'α' [pseq [60,61,63,65,67,63] 1+>                    ,prand 'β' [72,73,75,77,79] 6+>                    ,pshuf 'γ' [48,53,55,58] 2] inf}+> in audition (pbind [(K_midinote,n),(K_dur,0.075)])++The below cannot be written as intended with the list+based pattern library.  This is precisely because the+noise patterns are values, not processes with a state+threaded non-locally.++> do {n0 <- Sound.SC3.Lang.Random.IO.rrand 2 5+>    ;n1 <- Sound.SC3.Lang.Random.IO.rrand 3 9+>    ;let p = pseq [prand 'α' [pempty,pseq [24,31,36,43,48,55] 1] 1+>                  ,pseq [60,prand 'β' [63,65] 1+>                        ,67,prand 'γ' [70,72,74] 1] n0+>                  ,prand 'δ' [74,75,77,79,81] n1] inf+>     in return (ptake 24 p)}++-}+prand :: Enum e => e -> [P a] -> Int -> P a+prand = join .:: prand'++-- | Preject.  SC3 pattern to rejects values for which the predicate+-- is true.  reject f is equal to filter (not . f).+--+-- > preject (== 1) (pseq [1,2,3] 2) == toP [2,3,2,3]+-- > pfilter (not . (== 1)) (pseq [1,2,3] 2) == toP [2,3,2,3]+--+-- > > p = Pseed(Pn(1000,1),Pwhite(0,255,20).reject({|x| x.odd}));+-- > > p.asStream.all == [224,60,88,94,42,32,110,24,122,172]+--+-- > preject odd (pwhite 'α' 0 255 10) == toP [32,158,62,216,240,20]+--+-- > > p = Pseed(Pn(1000,1),Pwhite(0,255,20).select({|x| x.odd}));+-- > > p.asStream.all == [151,157,187,129,45,245,101,79,77,243]+--+-- > pselect odd (pwhite 'α' 0 255 10) == toP [241,187,119,127]+preject :: (a -> Bool) -> P a -> P a+preject f = liftP (filter (not . f))++{- | Prorate.  SC3 /implicitly repeating/ sub-dividing pattern.++> > p = Prorate(Pseq([0.35,0.5,0.8]),1);+> > p.asStream.all == [0.35,0.65,0.5,0.5,0.8,0.2];++> let p = prorate (fmap Left (pseq [0.35,0.5,0.8] 1)) 1+> in fmap roundE (p * 100) == toP [35,65,50,50,80,20]++> > p = Prorate(Pseq([0.35,0.5,0.8]),Pseed(Pn(100,1),Prand([20,1],inf)));+> > p.asStream.all == [7,13,0.5,0.5,16,4]++> let p = prorate (fmap Left (pseq [0.35,0.5,0.8] 1))+>                 (prand 'α' [20,1] 3)+> in fmap roundE (p * 100) == toP [35,65,1000,1000,80,20]++> > l = [[1,2],[5,7],[4,8,9]].collect(_.normalizeSum);+> > Prorate(Pseq(l,1)).asStream.all++> let l = map (Right . C.normalizeSum) [[1,2],[5,7],[4,8,9]]+> in prorate (toP l) 1++> > Pfinval(5,Prorate(0.6,0.5)).asStream.all == [0.3,0.2,0.3,0.2,0.3]++> pfinval 5 (prorate (fmap Left 0.6) 0.5) == toP [0.3,0.2,0.3,0.2,0.3]++> > Pbind(\degree,Pseries(4,1,inf).fold(-7,11),+> >       \dur,Prorate(0.6,0.5)).play++> audition (pbind [(K_degree,pfold (pseries 4 1 inf) (-7) 11)+>                 ,(K_dur,prorate (fmap Left 0.6) 0.25)])++-}+prorate :: Num a => P (Either a [a]) -> P a -> P a+prorate = pjoin_repeat .: pzipWith prorate'++-- | Pselect.  See 'pfilter'.+--+-- > pselect (< 3) (pseq [1,2,3] 2) == toP [1,2,1,2]+pselect :: (a -> Bool) -> P a -> P a+pselect f = liftP (filter f)++{-| Pseq.  SC3 pattern to cycle over a list of patterns. The repeats+pattern gives the number of times to repeat the entire list.++> pseq [return 1,return 2,return 3] 2 == toP [1,2,3,1,2,3]+> pseq [1,2,3] 2 == toP [1,2,3,1,2,3]+> pseq [1,pn 2 2,3] 2 == toP [1,2,2,3,1,2,2,3]++There is an 'inf' value for the repeats variable.++> ptake 3 (pdrop (10^5) (pseq [1,2,3] inf)) == toP [2,3,1]++Unlike the SC3 Pseq, `pseq` does not have an offset argument to give a+starting offset into the list.++> pseq (C.rotate 3 [1,2,3,4]) 3 == toP [2,3,4,1,2,3,4,1,2,3,4,1]++As scale degrees.++> > Pbind(\degree,Pseq(#[0,0,4,4,5,5,4],1),+> >       \dur,Pseq(#[0.5,0.5,0.5,0.5,0.5,0.5,1],1)).play++> audition (pbind [(K_degree,pseq [0,0,4,4,5,5,4] 1)+>                 ,(K_dur,pseq [0.5,0.5,0.5,0.5,0.5,0.5,1] 1)])++> > Pseq(#[60,62,63,65,67,63],inf) + Pseq(#[0,0,0,0,-12],inf)++> let n = pseq [60,62,63,65,67,63] inf + pser [0,0,0,0,-12] 25+> in audition (pbind [(K_midinote,n),(K_dur,0.2)])++Pattern `b` pattern sequences `a` once normally, once transposed up a+fifth and once transposed up a fourth.++> > a = Pseq(#[60,62,63,65,67,63]);+> > b = Pseq([a,a + 7,a + 5],inf);+> > Pbind(\midinote,b,\dur,0.3).play++> let {a = pseq [60,62,63,65,67,63] 1+>     ;b = pseq [a,a + 7,a + 5] inf}+> in audition (pbind [(K_midinote,b),(K_dur,0.13)])++-}+pseq :: [P a] -> Int -> P a+pseq a i =+    let a' = mconcat a+    in if i == inf then pcycle a' else pn a' i++-- | Pser.  SC3 pattern that is like 'pseq', however the repeats+-- variable gives the number of elements in the sequence, not the+-- number of cycles of the pattern.+--+-- > pser [1,2,3] 5 == toP [1,2,3,1,2]+-- > pser [1,pser [10,20] 3,3] 9 == toP [1,10,20,10,3,1,10,20,10]+-- > pser [1,2,3] 5 * 3 == toP [3,6,9,3,6]+pser :: [P a] -> Int -> P a+pser a i = ptake i (pcycle (mconcat a))++-- | Pseries.  SC3 arithmetric series pattern, see also 'pgeom'.+--+-- > pseries 0 2 10 == toP [0,2,4,6,8,10,12,14,16,18]+-- > pseries 9 (-1) 10 == toP [9,8 .. 0]+-- > pseries 1.0 0.2 3 == toP [1.0::Double,1.2,1.4]+pseries :: (Num a) => a -> a -> Int -> P a+pseries i s n = toP (C.series n i s)++{- | Pshuf.  SC3 pattern to return @n@ repetitions of a shuffled+-- sequence.++> > Pshuf([1,2,3,4],2).asStream.all+> pshuf 'α' [1,2,3,4] 2 == toP [2,4,3,1,2,4,3,1]++> > Pbind(\degree,Pshuf([0,1,2,4,5],inf),\dur,0.25).play++> audition (pbind [(K_degree,pshuf 'α' [0,1,2,4,5] inf)+>                 ,(K_dur,0.25)])++-}+pshuf :: Enum e => e -> [a] -> Int -> P a+pshuf e a =+    let (a',_) = R.scramble a (mkStdGen (fromEnum e))+    in pn (toP a')++{- | Pslide.  Lifted 'P.slide'.++> > Pslide([1,2,3,4],inf,3,1,0).asStream.all+> pslide [1,2,3,4] 4 3 1 0 True == toP [1,2,3,2,3,4,3,4,1,4,1,2]+> pslide [1,2,3,4,5] 3 3 (-1) 0 True == toP [1,2,3,5,1,2,4,5,1]++> > Pbind(\degree,Pslide((-6,-4 .. 12),8,3,1,0),+> >       \dur,Pseq(#[0.1,0.1,0.2],inf),+> >       \sustain,0.15).play++> audition (pbind [(K_degree,pslide [-6,-4 .. 12] 8 3 1 0 True)+>                 ,(K_dur,pseq [0.05,0.05,0.1] inf)+>                 ,(K_sustain,0.15)])++-}+pslide :: [a] -> Int -> Int -> Int -> Int -> Bool -> P a+pslide = toP .::::: P.slide++{- | Pstutter.  SC3 /implicitly repeating/ pattern to repeat each+-- element of a pattern /n/ times.++> > Pstutter(2,Pseq([1,2,3],1)).asStream.all == [1,1,2,2,3,3]+> pstutter 2 (pseq [1,2,3] 1) == toP [1,1,2,2,3,3]++The count input may be a pattern.++> let {p = pseq [1,2] inf+>     ;q = pseq [1,2,3] 2}+> in pstutter p q == toP [1,2,2,3,1,1,2,3,3]++> pstutter (toP [1,2,3]) (toP [4,5,6]) == toP [4,5,5,6,6,6]+> pstutter 2 (toP [4,5,6]) == toP [4,4,5,5,6,6]++Stutter scale degree and duration with the same random sequence.++> > Pbind(\n,Pwhite(3,10,inf),+> >       \degree,Pstutter(Pkey(\n),Pwhite(-4,11,inf)),+> >       \dur,Pstutter(Pkey(\n),Pwhite(0.05,0.4,inf)),+> >       \legato,0.3).play++> let {n = pwhite 'α' 3 10 inf+>     ;p = [(K_degree,pstutter n (pwhitei 'β' (-4) 11 inf))+>          ,(K_dur,pstutter n (pwhite 'γ' 0.05 0.4 inf))+>          ,(K_legato,0.3)]}+> in audition (pbind p)++-}+pstutter :: P Int -> P a -> P a+pstutter = liftP2_repeat P.stutter++-- | Pswitch.  Lifted 'P.switch'.+--+-- > let p = pswitch [pseq [1,2,3] 2,pseq [65,76] 1,800] (toP [2,2,0,1])+-- > in p == toP [800,800,1,2,3,1,2,3,65,76]+pswitch :: [P a] -> P Int -> P a+pswitch l = liftP (P.switch (map unP l))++-- | Pswitch1.  Lifted /implicitly repeating/ 'P.switch1'.+--+-- > > l = [Pseq([1,2,3],inf),Pseq([65,76],inf),8];+-- > > p = Pswitch1(l,Pseq([2,2,0,1],3));+-- > > p.asStream.all == [8,8,1,65,8,8,2,76,8,8,3,65];+--+-- > let p = pswitch1 [pseq [1,2,3] inf+-- >                  ,pseq [65,76] inf+-- >                  ,8] (pseq [2,2,0,1] 6)+-- > in p == toP [8,8,1,65,8,8,2,76,8,8,3,65,8,8,1,76,8,8,2,65,8,8,3,76]+pswitch1 :: [P a] -> P Int -> P a+pswitch1 l = liftP (P.switch1 (map unP_repeat l))++-- | Ptuple.  'pseq' of 'ptranspose_st_repeat'.+--+-- > > l = [Pseries(7,-1,8),3,Pseq([9,7,4,2],1),Pseq([4,2,0,0,-3],1)];+-- > > p = Ptuple(l,1);+-- > > p.asStream.all == [[7,3,9,4],[6,3,7,2],[5,3,4,0],[4,3,2,0]]+--+-- > let p = ptuple [pseries 7 (-1) 8+-- >                ,3+-- >                ,pseq [9,7,4,2] 1+-- >                ,pseq [4,2,0,0,-3] 1] 1+-- > in p == toP [[7,3,9,4],[6,3,7,2],[5,3,4,0],[4,3,2,0]]+ptuple :: [P a] -> Int -> P [a]+ptuple p = pseq [ptranspose_st_repeat p]++{- | Pwhite.  Lifted 'P.white'.++> pwhite 'α' 0 9 5 == toP [3,0,1,6,6]+> pwhite 'α' 0 9 5 - pwhite 'α' 0 9 5 == toP [0,0,0,0,0]++The pattern below is alternately lower and higher noise.++> let {l = pseq [0.0,9.0] inf+>     ;h = pseq [1.0,12.0] inf}+> in audition (pbind [(K_freq,pwhite' 'α' l h * 20 + 800)+>                    ,(K_dur,0.25)])++-}+pwhite :: (Random n,Enum e) => e -> n -> n -> Int -> P n+pwhite = toP .::: P.white++{- | Pwrand.  Lifted 'P.wrand'.++> let w = C.normalizeSum [12,6,3]+> in pwrand 'α' [1,2,3] w 6 == toP [2,1,2,3,3,2]++> > r = Pwrand.new([1,2,Pseq([3,4],1)],[1,3,5].normalizeSum,6);+> > p = Pseed(Pn(100,1),r);+> > p.asStream.all == [2,3,4,1,3,4,3,4,2]++> let w = C.normalizeSum [1,3,5]+> in pwrand 'ζ' [1,2,pseq [3,4] 1] w 6 == toP [3,4,2,2,3,4,1,3,4]++> > Pbind(\degree,Pwrand((0..7),[4,1,3,1,3,2,1].normalizeSum,inf),+> >       \dur,0.25).play;++> let {w = C.normalizeSum [4,1,3,1,3,2,1]+>     ;d = pwrand 'α' (C.series 7 0 1) w inf}+> in audition (pbind [(K_degree,d),(K_dur,0.25)])++-}+pwrand :: (Enum e) => e -> [P a] -> [Double] -> Int -> P a+pwrand e a w = toP . P.wrand e (map unP a) w++-- | Pwrap.  Type specialised 'P.fwrap', see also 'pfold'.+--+-- > > p = Pwrap(Pgeom(200,1.25,9),200,1000.0);+-- > > r = p.asStream.all.collect({|n| n.round});+-- > > r == [200,250,313,391,488,610,763,954,392];+--+-- > let p = fmap roundE (pwrap (pgeom 200 1.25 9) 200 1000)+-- > in p == toP [200,250,312,391,488,610,763,954,391]+pwrap :: (Ord a,Num a) => P a -> a -> a -> P a+pwrap = P.fwrap++-- | Pxrand.  Lifted 'P.xrand'.+--+-- > let p = pxrand 'α' [1,toP [2,3],toP [4,5,6]] 9+-- > in p == toP [4,5,6,2,3,4,5,6,1]+--+-- > > Pbind(\note,Pxrand([0,1,5,7],inf),\dur,0.25).play+--+-- > audition (pbind [(K_note,pxrand 'α' [0,1,5,7] inf),(K_dur,0.25)])+pxrand :: Enum e => e -> [P a] -> Int -> P a+pxrand e a n = toP (P.xrand e (map unP a) n)++-- * Variant SC3 Patterns++-- | Lifted /implicitly repeating/ 'P.pbrown''.+--+-- > pbrown' 'α' 1 700 (pseq [1,20] inf) 4 == toP [415,419,420,428]+pbrown' :: (Enum e,Random n,Num n,Ord n) =>+           e -> P n -> P n -> P n -> Int -> P n+pbrown' e l r s n =+    let f = liftP3_repeat (I.brown e)+    in ptake n (f l r s)++-- | Un-joined variant of 'prand'.+--+-- > let p = prand' 'α' [1,toP [2,3],toP [4,5,6]] 5+-- > in p == toP [toP [4,5,6],toP [4,5,6],toP [2,3],toP [4,5,6],1]+prand' :: Enum e => e -> [P a] -> Int -> P (P a)+prand' e a n = toP (P.rand' e a n)++-- | Underlying pattern for 'prorate'.+--+-- > prorate' (Left 0.6) 0.5+prorate' :: Num a => Either a [a] -> a -> P a+prorate' p =+    case p of+      Left p' -> toP . P.rorate_n' p'+      Right p' -> toP . P.rorate_l' p'++{-|+Variant of `pseq` that retrieves only one value from each pattern+on each list traversal.  Compare to `pswitch1`.++> pseq [pseq [1,2] 1,pseq [3,4] 1] 2 == toP [1,2,3,4,1,2,3,4]+> pseq1 [pseq [1,2] 1,pseq [3,4] 1] 2 == toP [1,3,2,4]+> pseq1 [pseq [1,2] inf,pseq [3,4] inf] 3 == toP [1,3,2,4,1,3]++> let {p = prand' 'α' [pempty,toP [24,31,36,43,48,55]] inf+>     ;q = pflop [60,prand 'β' [63,65] inf+>                ,67,prand 'γ' [70,72,74] inf]+>     ;r = psplitPlaces (pwhite 'δ' 3 9 inf)+>                       (toP [74,75,77,79,81])+>     ;n = pjoin (pseq1 [p,q,r] inf)}+> in audition (pbind [(K_midinote,n),(K_dur,0.13)])++-}+pseq1 :: [P a] -> Int -> P a+pseq1 a i = join (ptake i (pflop a))++-- | A variant of 'pseq' to aid translating a common SC3 idiom where a+-- finite random pattern is included in a @Pseq@ list.  In the SC3+-- case, at each iteration a new computation is run.  This idiom does+-- not directly translate to the declarative haskell pattern library.+--+-- > > Pseq([1,Prand([2,3],1)],5).asStream.all+-- > pseq [1,prand 'α' [2,3] 1] 5 == toP [1,3,1,3,1,3,1,3,1,3]+--+-- Although the intended pattern can usually be expressed using an+-- alternate construction:+--+-- > > Pseq([1,Prand([2,3],1)],5).asStream.all+-- > ppatlace [1,prand 'α' [2,3] inf] 5 == toP [1,3,1,2,1,3,1,2,1,2]+--+-- the 'pseqn' variant handles many common cases.+--+-- > > Pseq([Pn(8,2),Pwhite(9,16,1)],5).asStream.all+--+-- > let p = pseqn [2,1] [8,pwhite 'α' 9 16 inf] 5+-- > in p == toP [8,8,10,8,8,9,8,8,12,8,8,15,8,8,15]+pseqn :: [Int] -> [P a] -> Int -> P a+pseqn n q =+    let rec p c = if c == 0+                  then mempty+                  else let (i,j) = unzip (zipWith psplitAt n p)+                       in mconcat i <> rec j (c - 1)+    in rec (map pcycle q)++{-|++A variant of 'pseq' that passes a new seed at each invocation,+see also 'pfuncn'.++> > pseqr (\e -> [pshuf e [1,2,3,4] 1]) 2 == toP [2,3,4,1,4,1,2,3]++> let {d = pseqr (\e -> [pshuf e [-7,-3,0,2,4,7] 4+>                       ,pseq [0,1,2,3,4,5,6,7] 1]) inf}+> in audition (pbind [(K_degree,d),(K_dur,0.15)])++> > Pbind(\dur,0.2,+> >       \midinote,Pseq([Pshuf(#[60,61,62,63,64,65,66,67],3)],inf)).play++> let {m = pseqr (\e -> [pshuf e [60,61,62,63,64,65,66,67] 3]) inf}+> in audition (pbind [(K_dur,0.2),(K_midinote,m)])++-}+pseqr :: (Int -> [P a]) -> Int -> P a+pseqr f n = mconcat (L.concatMap f [1 .. n])++-- | Variant of 'pser' that consumes sub-patterns one element per+-- iteration.+--+-- > pser1 [1,pser [10,20] 3,3] 9 == toP [1,10,3,1,20,3,1,10,3]+pser1 :: [P a] -> Int -> P a+pser1 a i = ptake i (join (pflop a))++-- | Lifted /implicitly repeating/ 'P.pwhite'.+--+-- > pwhite' 'α' 0 (pseq [9,19] 3) == toP [3,0,1,6,6,15]+pwhite' :: (Enum e,Random n) => e -> P n -> P n -> P n+pwhite' e = liftP2_repeat (P.white' e)++-- | Lifted 'P.whitei'.+--+-- > pwhitei 'α' 1 9 5 == toP [5,1,7,7,8]+--+-- > audition (pbind [(K_degree,pwhitei 'α' 0 8 inf),(K_dur,0.15)])+pwhitei :: (RealFracE n,Random n,Enum e) => e -> n -> n -> Int -> P n+pwhitei =  toP .::: P.whitei++-- * UId variants++-- | 'liftUId' of 'pbrown'.+pbrownM :: (UId m,Num n,Ord n,Random n) => n -> n -> n -> Int -> m (P n)+pbrownM = liftUId4 pbrown++-- | 'liftUId' of 'pexprand'.+pexprandM :: (UId m,Random a,Floating a) => a -> a -> Int -> m (P a)+pexprandM = liftUId3 pexprand++-- | 'liftUId' of 'prand'.+prandM :: UId m => [P a] -> Int -> m (P a)+prandM = liftUId2 prand++-- | 'liftUId' of 'pshuf'.+pshufM :: UId m => [a] -> Int -> m (P a)+pshufM = liftUId2 pshuf++-- | 'liftUId' of 'pwhite'.+pwhiteM :: (UId m,Random n) => n -> n -> Int -> m (P n)+pwhiteM = liftUId3 pwhite++-- | 'liftUId' of 'pwhitei'.+pwhiteiM :: (UId m,RealFracE n,Random n) => n -> n -> Int -> m (P n)+pwhiteiM = liftUId3 pwhitei++-- | 'liftUId' of 'pwrand'.+pwrandM :: UId m => [P a] -> [Double] -> Int -> m (P a)+pwrandM = liftUId3 pwrand++-- | 'liftUId' of 'pxrand'.+pxrandM :: UId m => [P a] -> Int -> m (P a)+pxrandM = liftUId2 pxrand
+ Sound/SC3/Lang/Pattern/Plain.hs view
@@ -0,0 +1,5 @@+module Sound.SC3.Lang.Pattern.Plain (module P) where++import Sound.SC3.Lang.Math as P+import Sound.SC3.Lang.Pattern.Bind as P+import Sound.SC3.Lang.Pattern.Stream as P
+ Sound/SC3/Lang/Pattern/Stream.hs view
@@ -0,0 +1,139 @@+-- | Infinte list @SC3@ pattern functions.+module Sound.SC3.Lang.Pattern.Stream where++import Data.List {- base -}+import Data.Maybe {- base -}+import System.Random {- random -}++import qualified Sound.SC3 as S {- hsc3 -}++import Sound.SC3.Lang.Core {- hsc3-lang -}+import qualified Sound.SC3.Lang.Math as M {- hsc3-lang -}+import qualified Sound.SC3.Lang.Random.Gen as R++-- | Remove successive duplicates.+--+-- > rsd [1,2,3,1,2,3] == [1,2,3,1,2,3]+rsd :: (Eq a) => [a] -> [a]+rsd =+    let f (p,_) i = (Just i,if Just i == p then Nothing else Just i)+    in mapMaybe snd . scanl f (Nothing,Nothing)++-- | True if /a/ is initially equal to /b/.+iEq :: Eq a => [a] -> [a] -> Bool+iEq = flip isPrefixOf++-- | Take elements from /l/ until all elements in /s/ have been seen.+-- If /s/ contains duplicate elements these must be seen multiple+-- times.+--+-- > take_until_forms_set "abc" "a random sentence beginning" == "a random sentence b"+take_until_forms_set :: Eq a => [a] -> [a] -> [a]+take_until_forms_set s l =+    if null s+    then []+    else case l of+           [] -> []+           e:l' -> e : take_until_forms_set (delete e s) l'++-- | Underlying 'brown'.+brown_ :: (RandomGen g,Random n,Num n,Ord n) => (n,n,n) -> (n,g) -> (n,g)+brown_ (l,r,s) (n,g) =+    let (i,g') = randomR (-s,s) g+    in (S.foldToRange l r (n + i),g')++-- | Brown noise with list inputs.+--+-- > let l = brown 'α' (repeat 1) (repeat 700) (cycle [1,20])+-- > in l `iEq` [415,419,420,428]+brown :: (Enum e,Random n,Num n,Ord n) => e -> [n] -> [n] -> [n] -> [n]+brown e l_ r_ s_ =+    let i = (randomR (head l_,head r_) (mkStdGen (fromEnum e)))+        rec (n,g) z =+            case z of+              [] -> []+              (l,r,s):z' -> let (n',g') = brown_ (l,r,s) (n,g)+                            in n' : rec (n',g') z'+    in rec i (zip3 l_ r_ s_)++-- | 'M.exprange' of 'white'+exprand :: (Enum e,Random a,Floating a) => e -> a -> a -> [a]+exprand e l r = fmap (M.exprange l r) (white e 0 1)++-- | Geometric series.+--+-- > geom 3 6 `iEq` [3,18,108,648,3888,23328,139968]+geom :: Num a => a -> a -> [a]+geom i s = iterate (* s) i++-- > lace [[0],[1,2],[3,4,5]] `iEq` [0,1,3,0,2,4,0,1,5]+-- > lace [[1],[2,5],[3,6]] `iEq` [1,2,3,1,5,6]+-- > lace [[1],[2,5],[3,6..]] `iEq` [1,2,3,1,5,6,1,2,9,1,5,12]+lace :: [[a]] -> [a]+lace = concat . transpose . map cycle++-- | Random elements from list.+--+-- > take_until_forms_set "string" (rand 'α' "string") == "grtrsiirn"+rand :: Enum e => e -> [a] -> [a]+rand e a =+    let k = length a - 1+    in map (a !!) (white e 0 k)++-- | List section with /wrapped/ indices.+--+-- > segment [0..4] 5 (3,5) == [3,4,0]+segment :: [a] -> Int -> (Int,Int) -> [a]+segment a k (l,r) =+    let i = map (S.genericWrap 0 (k - 1)) [l .. r]+    in map (a !!) i++-- > slide [1,2,3,4] 4 1 0 True `iEq` [[1,2,3,4],[2,3,4,1],[3,4,1,2],[4,1,2,3]]+-- > slide [1,2,3,4,5] 3 (-1) 0 True `iEq` [[1,2,3],[5,1,2],[4,5,1],[3,4,5],[2,3,4]]+slide :: [a] -> Int -> Int -> Int -> Bool -> [[a]]+slide a j s i wr =+    let k = length a+        l = enumFromThen i (i + s)+        r = map (+ (j - 1)) l+    in if wr+       then map (segment a k) (zip l r)+       else error "slide: non-wrap variant not implemented"++-- | 'concat' of 'slide'.+slidec :: [a] -> Int -> Int -> Int -> Bool -> [a]+slidec = concat .:::: slide++-- | White noise.+--+-- > take_until_forms_set [1..5] (white 'α' 1 5) == [4,1,2,2,2,1,2,1,2,5,1,4,3]+white :: (Random n,Enum e) => e -> n -> n -> [n]+white e l r = randomRs (l,r) (mkStdGen (fromEnum e))++-- | Weighted selection of elements from a list.+wrand_generic :: (Enum e,Fractional n,Ord n,Random n) => e -> [a] -> [n] -> [a]+wrand_generic e a w =+    let f g = let (r,g') = R.wchoose a w g+              in r : f g'+    in if length a /= length w+       then error "wrand_generic: a/w must be of equal length"+       else f (mkStdGen (fromEnum e))++-- | Type restricted variant.+--+-- > import qualified Sound.SC3.Lang.Collection as C+--+-- > let {w = C.normalizeSum [1..5]+-- >     ;r = wrand 'ζ' "wrand" w}+-- > in take_until_forms_set "wrand" r == "dnanrdnaddrnrrndrrdw"+wrand :: Enum e => e -> [a] -> [Double] -> [a]+wrand = wrand_generic++-- | Select elements from /l/ in random sequence, but do not immediately repeat an element.+--+-- > take_until_forms_set "string" (xrand 'α' "string") == "grtrsirn"+xrand :: Enum e => e -> [a] -> [a]+xrand e a =+    let g = mkStdGen (fromEnum e)+        k = length a - 1+        r = rsd (randomRs (0,k) g)+    in map (a !!) r
Sound/SC3/Lang/Random/Gen.hs view
@@ -1,36 +1,71 @@ -- | 'RandomGen' based @sclang@ random number functions. module Sound.SC3.Lang.Random.Gen where +import qualified Data.DList as DL {- dlist -} import Data.Maybe {- base  -} import System.Random {- random -} import System.Random.Shuffle {- random-shuffle -}  import qualified Sound.SC3.Lang.Collection as C+import Sound.SC3.Lang.Core import qualified Sound.SC3.Lang.Math as M  -- | @SimpleNumber.rand@ is 'randomR' in (0,/n/). rand :: (RandomGen g,Random n,Num n) => n -> g -> (n,g) rand n = randomR (0,n) --- | Construct variant of /f/ generating /k/ values.-kvariant :: Int -> (g->(a,g)) -> g->([a],g)-kvariant k f =+-- | State modifying variant of 'iterate'.  Lifts random generator+-- functions to infinte lists.+--+-- > let r = [3,1,7,0,12,1,6,4,12,11,7,4]+-- > in take 12 (r_iterate (rand 12) (mkStdGen 0)) == r+r_iterate :: (t -> (a, t)) -> t -> [a]+r_iterate f g = let (r,g') = f g in r : r_iterate f g'++-- | Function underlying both 'kvariant' and 'kvariant''.+mk_kvariant :: r -> (t -> r -> r) -> (r -> r') -> Int -> (g -> (t,g)) -> g -> (r',g)+mk_kvariant k_nil k_join un_k k f =     let go x i g = case i of-                     0 -> (x,g)+                     0 -> (un_k x,g)                      _ -> let (y,g') = f g-                          in go (y:x) (i - 1) g'-    in go [] k+                          in go (k_join y x) (i - 1) g'+    in go k_nil k +-- | Construct variant of /f/ generating /k/ values.  Note that the+-- result is the reverse of the initial sequence given by 'r_iterate'.+--+-- > let r = [3,1,7,0,12,1,6,4,12,11,7,4]+-- > in fst (kvariant 12 (rand 12) (mkStdGen 0)) == reverse r+kvariant :: Int -> (g->(a,g)) -> g->([a],g)+kvariant = mk_kvariant [] (:) id++-- | Variant of 'kvariant' that generates sequence in the same order+-- as 'r_iterate'.  There is perhaps a slight overhead from using a+-- difference list.+--+-- > let r = [3,1,7,0,12,1,6,4,12,11,7,4]+-- > in fst (kvariant' 12 (rand 12) (mkStdGen 0)) == r+kvariant' :: Int -> (g->(a,g)) -> g->([a],g)+kvariant' = mk_kvariant DL.empty (flip DL.snoc) DL.toList+ -- | Variant of 'rand' generating /k/ values. -- -- > fst (nrand 10 (5::Int) (mkStdGen 246873)) == [0,5,4,0,4,5,3,2,3,1] nrand :: (RandomGen g,Random n,Num n) => Int -> n -> g -> ([n],g) nrand k = kvariant k . rand +-- | Stream variant of 'rand'.+s_rand :: (RandomGen g,Random n,Num n) => n -> g -> [n]+s_rand = r_iterate . rand+ -- | @SimpleNumber.rand2@ is 'randomR' in (-/n/,/n/). rand2 :: (RandomGen g,Random n,Num n) => n -> g -> (n,g) rand2 n = randomR (-n,n) +-- | Stream variant of 'rand2'.+s_rand2 :: (RandomGen g,Random n,Num n) => n -> g -> [n]+s_rand2 = r_iterate . rand2+ -- | Variant of 'rand2' generating /k/ values. nrand2 :: (RandomGen g,Random a,Num a) => Int -> a -> g -> ([a],g) nrand2 k = kvariant k . rand2@@ -41,7 +76,7 @@  -- | Variant of 'rrand' generating /k/ values. nrrand :: (RandomGen g,Random a,Num a) => Int -> a -> a -> g -> ([a],g)-nrrand k l = kvariant k . rrand l+nrrand k = kvariant k .: rrand  -- | @SequenceableCollection.choose@ selects an element at random. choose :: RandomGen g => [a] -> g -> (a,g)@@ -63,7 +98,7 @@ -- | Variant of 'exprand' generating /k/ values. nexprand :: (Floating n,Random n,RandomGen g) =>             Int -> n -> n -> g -> ([n],g)-nexprand k l = kvariant k . exprand l+nexprand k = kvariant k .: exprand  -- | @SimpleNumber.coin@ is 'True' at given probability, which is in -- range (0,1).@@ -88,8 +123,21 @@  -- | @SequenceableCollection.wchoose@ selects an element from a list -- given a list of weights which sum to @1@.+--+-- > kvariant 10 (wchoose "abcd" (C.normalizeSum [8,4,2,1])) (mkStdGen 0) wchoose :: (RandomGen g,Random a,Ord a,Fractional a) => [b] -> [a] -> g -> (b,g) wchoose l w g =   let (i,g') = randomR (0.0,1.0) g       n = fromMaybe (error "wchoose: windex") (C.windex w i)   in (l !! n,g')++-- | Variant that applies 'C.normalizeSum' to weights.+--+-- > let r = "dcbbacaadd"+-- > in r == fst (kvariant 10 (wchoose_N "abcd" [8,4,2,1]) (mkStdGen 0))+wchoose_N :: (Fractional a,Ord a,RandomGen g,Random a) => [b] -> [a] -> g -> (b, g)+wchoose_N l w = wchoose l (C.normalizeSum w)++-- | 'kvariant' of 'wchoose_N'.+nwchoose_N :: (Fractional a,Ord a,RandomGen g,Random a) => Int -> [b] -> [a] -> g -> ([b], g)+nwchoose_N n = kvariant n .: wchoose_N
+ Sound/SC3/Lang/Random/ID.hs view
@@ -0,0 +1,18 @@+-- | 'ID' variants of "Sound.SC3.Lang.Random.Gen".+module Sound.SC3.Lang.Random.ID where++import System.Random {- random -}++import qualified Sound.SC3.Lang.Random.Gen as G++id_rand :: Enum e => e -> (StdGen -> (a,StdGen)) -> a+id_rand e f = fst (f (mkStdGen (fromEnum e)))++nchoose :: Enum e => e -> Int -> [a] -> [a]+nchoose e n l = id_rand e (G.nchoose n l)++rand :: (Random a, Num a, Enum e) => e -> a -> a+rand e n = id_rand e (G.rand n)++rrand :: (Random a, Num a, Enum e) => e -> a -> a -> a+rrand e l r = id_rand e (G.rrand l r)
Sound/SC3/Lang/Random/IO.hs view
@@ -4,6 +4,7 @@ import Control.Monad.IO.Class {- transformers -} import System.Random {- random -} +import Sound.SC3.Lang.Core import Sound.SC3.Lang.Random.Gen as R  -- | 'liftIO' of 'randomRIO'.@@ -24,7 +25,7 @@  -- | Variant of 'rand2' generating /k/ values. nrand2 :: (Random a, Num a) => Int -> a -> IO [a]-nrand2 k = randomG . R.nrand2 k+nrand2 = randomG .: R.nrand2  -- | @SimpleNumber.rrand@ is 'curry' 'randomRIO'. rrand :: (MonadIO m,Random n) => n -> n -> m n@@ -32,7 +33,7 @@  -- | Variant of 'rrand' generating /k/ values. nrrand :: (MonadIO m,Random a, Num a) => Int -> a -> a -> m [a]-nrrand k l = randomG . R.nrrand k l+nrrand = randomG .:: R.nrrand  -- | @SequenceableCollection.choose@ selects an element at random. choose :: MonadIO m => [a] -> m a@@ -41,7 +42,7 @@ -- | @SimpleNumber.exprand@ generates exponentially distributed random -- number in the given interval. exprand :: (MonadIO m,Floating n,Random n) => n -> n -> m n-exprand l = randomG . R.exprand l+exprand = randomG .: R.exprand  -- | @SimpleNumber.coin@ is 'True' at given probability, which is in -- range (0,1).@@ -55,5 +56,5 @@ -- | @SequenceableCollection.wchoose@ selects an element from a list -- given a list of weights which sum to @1@. wchoose :: (MonadIO m,Random a,Ord a,Fractional a) => [b] -> [a] -> m b-wchoose l = randomG . R.wchoose l+wchoose = randomG .: R.wchoose 
Sound/SC3/Lang/Random/Lorrain_1980.hs view
@@ -24,6 +24,8 @@  -- | §4.3.5 (τ=1) --+-- > h [map (cauchy 1.0) r]+-- -- > import Data.Maybe -- > let narrow z n = if n < -z || n > z then Nothing else Just n -- > h [mapMaybe (narrow 10 . cauchy 1.0) r]@@ -63,10 +65,13 @@ -- | §4.4.2 (Algorithm 15) -- -- > let adj l = case l of {[] -> []; p:q:l' -> (p,q) : adj l'}--- > h [mapMaybe (beta 0.5 0.5) (adj r)]--- > h [mapMaybe (beta 0.25 0.25) (adj r)]--- > h [mapMaybe (beta 0.75 0.5) (adj r)]--- > h [mapMaybe (beta 0.5 0.75) (adj r)]+-- > let r' = adj r+-- > h [mapMaybe (beta 0.45 0.45) r'+-- >   ,mapMaybe (beta 0.65 0.45) r'+-- >   ,mapMaybe (beta 0.45 0.65) r']+--+-- > h [mapMaybe (beta 0.35 0.5) r'+-- >   ,mapMaybe (beta 0.5 0.65) r'] beta :: (Floating a,Ord a) => a -> a -> (a,a) -> Maybe a beta a b (u1,u2) =     let ea = 1.0 / a
Sound/SC3/Lang/Random/Monad.hs view
@@ -3,7 +3,10 @@  import Control.Monad {- base -} import Control.Monad.Random {- MonadRandom -}+import Data.Maybe {- base  -} +import qualified Sound.SC3.Lang.Collection as C+import Sound.SC3.Lang.Core import qualified Sound.SC3.Lang.Math as M  -- | @SimpleNumber.rand@ is 'getRandomR' in (0,/n/).@@ -41,7 +44,7 @@ -- -- > evalRand (nrrand 4 3 9) (mkStdGen 1) == [5,8,9,6] nrrand :: (RandomGen g,Random n,Num n) => Int -> n -> n -> Rand g [n]-nrrand k l = replicateM k . rrand l+nrrand k = replicateM k .: rrand  -- | @SequenceableCollection.choose@ selects an element at random. --@@ -51,6 +54,15 @@   i <- rand (length l - 1)   return (l !! i) +wchoose :: (RandomGen g,Fractional t,Ord t,Random t) => [a] -> [t] -> Rand g a+wchoose l w = do+  i <- rrand 0.0 1.0+  let n = fromMaybe (error "wchoose: windex") (C.windex w i)+  return (l !! n)++wchoose_N :: (RandomGen g,Fractional t,Ord t,Random t) => [a] -> [t] -> Rand g a+wchoose_N l w = wchoose l (C.normalizeSum w)+ -- | Variant of 'choose' generating /k/ values. -- -- > evalRand (nchoose 4 [3..9]) (mkStdGen 1) == [5,8,9,6]@@ -72,4 +84,5 @@ -- > let r = nexprand 3 10 100 >>= return . map floor -- > in evalRand r (mkStdGen 1) == [22,21,13] nexprand :: (Floating n,Random n,RandomGen g) => Int -> n -> n -> Rand g [n]-nexprand k l = replicateM k . exprand l+nexprand k = replicateM k .: exprand+
hsc3-lang.cabal view
@@ -1,16 +1,16 @@ Name:              hsc3-lang-Version:           0.14+Version:           0.15 Synopsis:          Haskell SuperCollider Language Description:       Haskell library defining operations from the                    SuperCollider language class library License:           GPL Category:          Sound-Copyright:         (c) Rohan Drape, 2007-2013+Copyright:         (c) Rohan Drape, 2007-2014 Author:            Rohan Drape Maintainer:        rd@slavepianos.org Stability:         Experimental-Homepage:          http://rd.slavepianos.org/?t=hsc3-lang-Tested-With:       GHC == 7.6.1+Homepage:          http://rd.slavepianos.org/t/hsc3-lang+Tested-With:       GHC == 7.8.2 Build-Type:        Simple Cabal-Version:     >= 1.8 @@ -23,37 +23,54 @@                    bytestring,                    containers,                    data-default,+                   data-ordlist,+                   dlist,+                   hashable,                    hmatrix-special,-                   hosc == 0.14.*,-                   hsc3 == 0.14.*,+                   hosc == 0.15.*,+                   hsc3 == 0.15.*,                    MonadRandom,                    transformers,                    split,                    random,                    random-shuffle,-                   transformers+                   transformers,+                   vector   GHC-Options:     -Wall -fwarn-tabs   Exposed-modules: Sound.SC3.Lang.Collection+                   Sound.SC3.Lang.Collection.Array                    Sound.SC3.Lang.Collection.Extension                    Sound.SC3.Lang.Collection.Numerical.Extending                    Sound.SC3.Lang.Collection.Numerical.Truncating                    Sound.SC3.Lang.Collection.Universal.Datum+                   Sound.SC3.Lang.Collection.Vector                    Sound.SC3.Lang.Control.Duration                    Sound.SC3.Lang.Control.Event                    Sound.SC3.Lang.Control.Instrument                    Sound.SC3.Lang.Control.Midi+                   Sound.SC3.Lang.Control.Midi.ST                    Sound.SC3.Lang.Control.Pitch                    Sound.SC3.Lang.Control.OverlapTexture+                   Sound.SC3.Lang.Core+                   Sound.SC3.Lang.Data.CMUdict                    Sound.SC3.Lang.Data.Modal                    Sound.SC3.Lang.Data.Vowel                    Sound.SC3.Lang.Math                    Sound.SC3.Lang.Math.Warp                    Sound.SC3.Lang.Math.Window                    Sound.SC3.Lang.Pattern-                   Sound.SC3.Lang.Pattern.ID+                   Sound.SC3.Lang.Pattern.Bind                    Sound.SC3.Lang.Pattern.List+                   Sound.SC3.Lang.Pattern.P+                   Sound.SC3.Lang.Pattern.P.Base+                   Sound.SC3.Lang.Pattern.P.Core+                   Sound.SC3.Lang.Pattern.P.Event+                   Sound.SC3.Lang.Pattern.P.SC3+                   Sound.SC3.Lang.Pattern.Plain+                   Sound.SC3.Lang.Pattern.Stream                    Sound.SC3.Lang.Random.Lorrain_1980                    Sound.SC3.Lang.Random.Gen+                   Sound.SC3.Lang.Random.ID                    Sound.SC3.Lang.Random.IO                    Sound.SC3.Lang.Random.Monad