packages feed

csound-expression 4.7.1 → 4.8

raw patch · 12 files changed

+1059/−62 lines, 12 filesdep ~csound-expression-typeddep ~temporal-mediaPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: csound-expression-typed, temporal-media

API changes (from Hackage documentation)

- Csound.Air.Wave: on :: SigSpace a => Sig -> Sig -> a -> a
- Csound.Air.Wave: uon :: SigSpace a => Sig -> Sig -> a -> a
- Csound.SigSpace: instance At Sig (SE Sig) a => At Sig (SE Sig) (Source a)
- Csound.SigSpace: instance At Sig2 (SE Sig2) a => At Sig2 (SE Sig2) (Source a)
- Csound.SigSpace: instance At Sig2 Sig2 a => At Sig2 Sig2 (Source a)
- Csound.SigSpace: instance SigSpace a => SigSpace (Source a)
+ Csound.Air.Envelope: class HumanizeTime a where type family HumanizeTimeOut a :: *
+ Csound.Air.Envelope: class HumanizeValue a where type family HumanizeValueOut a :: *
+ Csound.Air.Envelope: class HumanizeValueTime a where type family HumanizeValueTimeOut a :: *
+ Csound.Air.Envelope: data Seq
+ Csound.Air.Envelope: htime :: HumanizeTime a => Sig -> a -> HumanizeTimeOut a
+ Csound.Air.Envelope: humanTime :: HumanizeTime a => Sig -> a -> HumanizeTimeOut a
+ Csound.Air.Envelope: humanVal :: HumanizeValue a => Sig -> a -> HumanizeValueOut a
+ Csound.Air.Envelope: humanValTime :: HumanizeValueTime a => Sig -> Sig -> a -> HumanizeValueTimeOut a
+ Csound.Air.Envelope: hval :: HumanizeValue a => Sig -> a -> HumanizeValueOut a
+ Csound.Air.Envelope: hvalTime :: HumanizeValueTime a => Sig -> Sig -> a -> HumanizeValueTimeOut a
+ Csound.Air.Envelope: instance Delay Seq
+ Csound.Air.Envelope: instance Duration Seq
+ Csound.Air.Envelope: instance Fractional Seq
+ Csound.Air.Envelope: instance HumanizeTime ([D] -> D -> Sig)
+ Csound.Air.Envelope: instance HumanizeTime ([D] -> Sig)
+ Csound.Air.Envelope: instance HumanizeTime ([Seq] -> Sig -> Sig)
+ Csound.Air.Envelope: instance HumanizeValue ([D] -> D -> Sig)
+ Csound.Air.Envelope: instance HumanizeValue ([D] -> Sig)
+ Csound.Air.Envelope: instance HumanizeValue ([Seq] -> Sig -> Sig)
+ Csound.Air.Envelope: instance HumanizeValue ([Sig] -> Sig -> Sig)
+ Csound.Air.Envelope: instance HumanizeValueTime ([D] -> D -> Sig)
+ Csound.Air.Envelope: instance HumanizeValueTime ([D] -> Sig)
+ Csound.Air.Envelope: instance HumanizeValueTime ([Seq] -> Sig -> Sig)
+ Csound.Air.Envelope: instance Melody Seq
+ Csound.Air.Envelope: instance Num Seq
+ Csound.Air.Envelope: instance Rest Seq
+ Csound.Air.Envelope: instance Stretch Seq
+ Csound.Air.Envelope: iseqPw :: Sig -> [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: iseqRamp :: Sig -> [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: iseqSaw :: [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: iseqSqr :: [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: ixseqSaw :: [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: onBeat :: Seq -> Seq
+ Csound.Air.Envelope: onBeats :: Sig -> Seq -> Seq
+ Csound.Air.Envelope: seqAdsr :: Sig -> Sig -> Sig -> Sig -> [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: seqAdsr_ :: Sig -> Sig -> Sig -> Sig -> Sig -> [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: seqAsc :: [Int] -> Seq
+ Csound.Air.Envelope: seqConst :: [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: seqDesc :: [Int] -> Seq
+ Csound.Air.Envelope: seqExp :: [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: seqHalf :: [Int] -> Seq
+ Csound.Air.Envelope: seqLin :: [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: seqPat :: [Int] -> Seq
+ Csound.Air.Envelope: seqPw :: Sig -> [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: seqRamp :: Sig -> [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: seqSaw :: [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: seqSqr :: [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: seqTri :: [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: seqTriRamp :: Sig -> [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: toSeq :: Sig -> Seq
+ Csound.Air.Envelope: xseqAdsr :: Sig -> Sig -> Sig -> Sig -> [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: xseqAdsr_ :: Sig -> Sig -> Sig -> Sig -> Sig -> [Seq] -> Sig -> Sig
+ Csound.Air.Envelope: xseqSaw :: [Seq] -> Sig -> Sig
+ Csound.Air.Live: hinstrChooser :: Sigs b => [(String, a -> SE b)] -> Int -> Source (a -> SE b)
+ Csound.Air.Live: hmidiChooser :: Sigs a => [(String, Msg -> SE a)] -> Int -> Source a
+ Csound.Air.Live: uiBox :: String -> Source FxFun -> Bool -> Source FxFun
+ Csound.Air.Live: uiMidi :: [(String, Msg -> SE Sig2)] -> Int -> Source FxFun
+ Csound.Air.Live: vinstrChooser :: Sigs b => [(String, a -> SE b)] -> Int -> Source (a -> SE b)
+ Csound.Air.Live: vmidiChooser :: Sigs a => [(String, Msg -> SE a)] -> Int -> Source a
+ Csound.Air.Looper: LoopControl :: Maybe (Evt D) -> Maybe ([Evt D]) -> Maybe Tick -> Maybe (Evt D) -> LoopControl
+ Csound.Air.Looper: LoopSpec :: [Sig] -> [FxFun] -> [FxFun] -> [Sig] -> [Sig] -> Int -> [[Int]] -> [Sig] -> LoopControl -> LoopSpec
+ Csound.Air.Looper: data LoopControl
+ Csound.Air.Looper: data LoopSpec
+ Csound.Air.Looper: instance Default LoopControl
+ Csound.Air.Looper: instance Default LoopSpec
+ Csound.Air.Looper: loopControl :: LoopSpec -> LoopControl
+ Csound.Air.Looper: loopDel :: LoopControl -> Maybe Tick
+ Csound.Air.Looper: loopFade :: LoopControl -> Maybe ([Evt D])
+ Csound.Air.Looper: loopFades :: LoopSpec -> [[Int]]
+ Csound.Air.Looper: loopInitInstr :: LoopSpec -> Int
+ Csound.Air.Looper: loopMixVal :: LoopSpec -> [Sig]
+ Csound.Air.Looper: loopPostfx :: LoopSpec -> [FxFun]
+ Csound.Air.Looper: loopPostfxVal :: LoopSpec -> [Sig]
+ Csound.Air.Looper: loopPrefx :: LoopSpec -> [FxFun]
+ Csound.Air.Looper: loopPrefxVal :: LoopSpec -> [Sig]
+ Csound.Air.Looper: loopRepeatFades :: LoopSpec -> [Sig]
+ Csound.Air.Looper: loopTap :: LoopControl -> Maybe (Evt D)
+ Csound.Air.Looper: loopThrough :: LoopControl -> Maybe (Evt D)
+ Csound.Air.Looper: midiLoop :: LoopSpec -> D -> [D] -> [Msg -> SE Sig2] -> Source Sig2
+ Csound.Air.Looper: sfLoop :: LoopSpec -> D -> [D] -> [(Sf, D)] -> Source Sig2
+ Csound.Air.Looper: sigLoop :: LoopSpec -> D -> [D] -> [Sig2] -> Source Sig2
+ Csound.Air.Seg: instance Sigs a => Harmony (Seg a)
+ Csound.Air.Seg: instance Sigs a => Melody (Seg a)
+ Csound.Control.Evt: snaps2 :: Sig2 -> Evt (D, D)
+ Csound.Control.Gui: hlifts :: ([a] -> b) -> [Source a] -> Source b
+ Csound.Control.Gui: hlifts' :: [Double] -> ([a] -> b) -> [Source a] -> Source b
+ Csound.Control.Gui: instance At Sig (SE Sig) a => At Sig (SE Sig) (Source a)
+ Csound.Control.Gui: instance At Sig2 (SE Sig2) a => At Sig2 (SE Sig2) (Source a)
+ Csound.Control.Gui: instance At Sig2 Sig2 a => At Sig2 Sig2 (Source a)
+ Csound.Control.Gui: instance SigSpace a => SigSpace (Source a)
+ Csound.Control.Gui: joinSource :: Source (SE a) -> Source a
+ Csound.Control.Gui: sinkSlice :: SinkSource a -> Sink a
+ Csound.Control.Gui: sourceSlice :: SinkSource a -> Source a
+ Csound.Control.Gui: vlifts :: ([a] -> b) -> [Source a] -> Source b
+ Csound.Control.Gui: vlifts' :: [Double] -> ([a] -> b) -> [Source a] -> Source b
+ Csound.Control.Gui.Widget: button' :: Tick -> String -> Source Tick
+ Csound.Control.Gui.Widget: hradio' :: Evt D -> [String] -> Int -> Source (Evt D)
+ Csound.Control.Gui.Widget: hradioSig' :: Sig -> [String] -> Int -> Source Sig
+ Csound.Control.Gui.Widget: knob' :: Sig -> String -> ValSpan -> Double -> Source Sig
+ Csound.Control.Gui.Widget: rangeJoy :: Bool -> Range Int -> Range Int -> (Int, Int) -> Source (Evt D, Evt D)
+ Csound.Control.Gui.Widget: rangeJoy2 :: Bool -> Range Int -> Range Int -> (Int, Int) -> Source (Evt (D, D))
+ Csound.Control.Gui.Widget: rangeJoySig :: Range Int -> Range Int -> (Int, Int) -> Source (Sig, Sig)
+ Csound.Control.Gui.Widget: rangeKnob :: Bool -> Range Int -> Int -> Source (Evt D)
+ Csound.Control.Gui.Widget: rangeKnobSig :: Range Int -> Int -> Source Sig
+ Csound.Control.Gui.Widget: rangeSlider :: Bool -> Range Int -> Int -> Source (Evt D)
+ Csound.Control.Gui.Widget: rangeSliderSig :: Range Int -> Int -> Source Sig
+ Csound.Control.Gui.Widget: setKnob :: String -> ValSpan -> Double -> SinkSource Sig
+ Csound.Control.Gui.Widget: setSlider :: String -> ValSpan -> Double -> SinkSource Sig
+ Csound.Control.Gui.Widget: slider' :: Sig -> String -> ValSpan -> Double -> Source Sig
+ Csound.Control.Gui.Widget: toggle' :: Evt D -> String -> Bool -> Source (Evt D)
+ Csound.Control.Gui.Widget: toggleSig' :: Sig -> String -> Bool -> Source Sig
+ Csound.Control.Gui.Widget: type Range a = (a, a)
+ Csound.Control.Gui.Widget: uknob' :: Sig -> Double -> Source Sig
+ Csound.Control.Gui.Widget: uslider' :: Sig -> Double -> Source Sig
+ Csound.Control.Gui.Widget: vradio' :: Evt D -> [String] -> Int -> Source (Evt D)
+ Csound.Control.Gui.Widget: vradioSig' :: Sig -> [String] -> Int -> Source Sig
+ Csound.Control.Instr: playWhen :: Sigs a => BoolSig -> (b -> SE a) -> (b -> SE a)
+ Csound.SigSpace: mixAt :: (At a b c, c ~ AtOut a b c, SigSpace c, Num c) => Sig -> (a -> b) -> c -> c
+ Csound.SigSpace: on :: SigSpace a => Sig -> Sig -> a -> a
+ Csound.SigSpace: uon :: SigSpace a => Sig -> Sig -> a -> a
- Csound.Control.Gui.Widget: xknob :: Double -> Double -> Double -> Source Sig
+ Csound.Control.Gui.Widget: xknob :: Range Double -> Double -> Source Sig
- Csound.Control.Gui.Widget: xslider :: Double -> Double -> Double -> Source Sig
+ Csound.Control.Gui.Widget: xslider :: Range Double -> Double -> Source Sig

Files

csound-expression.cabal view
@@ -1,5 +1,5 @@ Name:          csound-expression-Version:       4.7.1+Version:       4.8 Cabal-Version: >= 1.6 License:       BSD3 License-file:  LICENSE@@ -68,7 +68,7 @@   Ghc-Options:    -Wall   Build-Depends:         base >= 4, base < 5, process, data-default, Boolean >= 0.1.0, colour >= 2.0, transformers >= 0.3,-        csound-expression-typed >= 0.0.7.5, csound-expression-dynamic >= 0.1.4.3, temporal-media >= 0.5.0,+        csound-expression-typed >= 0.0.7.6, csound-expression-dynamic >= 0.1.4.3, temporal-media >= 0.6.0,         csound-expression-opcodes >= 0.0.2   Hs-Source-Dirs:      src/   Exposed-Modules:@@ -85,6 +85,7 @@         Csound.Air.Live         Csound.Air.Seg         Csound.Air.Sampler+        Csound.Air.Looper         Csound.Air.Misc         Csound.Air.Hvs         
src/Csound/Air.hs view
@@ -22,8 +22,11 @@     module Csound.Air.Fx,        -- | Widgets to make live performances.-    module Csound.Air.Live,  +    module Csound.Air.Live,  +    -- | A multitap looper.+    module Csound.Air.Looper,   +     -- | Scheduling signals with event streams     module Csound.Air.Seg, @@ -42,6 +45,7 @@ import Csound.Air.Spec import Csound.Air.Fx import Csound.Air.Live+import Csound.Air.Looper import Csound.Air.Seg import Csound.Air.Sampler import Csound.Air.Misc
src/Csound/Air/Envelope.hs view
@@ -1,10 +1,21 @@+{-#  Language TypeFamilies, FlexibleInstances #-} -- | Envelopes module Csound.Air.Envelope (     leg, xeg,     -- * Relative duration     onIdur, lindur, expdur, linendur,-    onDur, lindurBy, expdurBy, linendurBy,    +    onDur, lindurBy, expdurBy, linendurBy,  ++    -- * Faders+    fadeIn, fadeOut, fades, expFadeIn, expFadeOut, expFades,++    -- * Humanize    +    HumanizeValue(..), HumanizeTime(..), HumanizeValueTime(..),+    hval, htime, hvalTime,+     -- * Looping envelopes   ++    -- ** Simple     lpshold, loopseg, loopxseg, lpsholdBy, loopsegBy, loopxsegBy,     holdSeq, linSeq, expSeq,     linloop, exploop, sah, stepSeq, @@ -12,13 +23,25 @@     pwSeq, ipwSeq, rampSeq, irampSeq, xrampSeq, ixrampSeq,     adsrSeq, xadsrSeq, adsrSeq_, xadsrSeq_,   -    -- * Faders-    fadeIn, fadeOut, fades, expFadeIn, expFadeOut, expFades+    -- ** Complex+    Seq, toSeq, onBeat, onBeats, +    seqConst, seqLin, seqExp,++    seqPw, iseqPw, seqSqr, iseqSqr,+    seqSaw, iseqSaw, xseqSaw, ixseqSaw, seqRamp, iseqRamp, seqTri, seqTriRamp,+    seqAdsr, xseqAdsr, seqAdsr_, xseqAdsr_,++    seqPat, seqAsc, seqDesc, seqHalf+ ) where +import Control.Monad+import Control.Applicative import Data.List(intersperse) +import Temporal.Media+ import Csound.Typed import Csound.Typed.Opcode hiding (lpshold, loopseg, loopxseg) import qualified Csound.Typed.Opcode as C(lpshold, loopseg, loopxseg)@@ -448,3 +471,409 @@          groupSegs :: [[Sig]] -> [Sig]         groupSegs as = concat $ intersperse [0] as+++-- | The seq is a type for step sequencers. +-- The step sequencer is a monophonic control signal.+-- Most often step sequencer is a looping segment of+-- some values. It's used to create bas lines or conrtrol the frequency of+-- the filter in dub or trance music. There are simple functions+-- for creation of step sequencers defined in the module "Csound.Air.Envelope".+--+-- Basically the step sequence is a list of pairs:+--+-- >  [(valA, durA), (valB, durB), (valC, durC)]+--+-- each pair defines a segment of height valN that lasts for durN.+-- The sequence is repeated with the given frequency. Each segment+-- has certain shape. It can be a constant or line segment or +-- fragment of square wave or fragment of an adsr envelope. +-- There are many predefined functions.+--+-- With Seq we can construct control signals in very flexible way.+-- We can use the score composition functions for creation of sequences.+-- We can use @mel@ for sequencing of individual steps, we can use @str@+-- for stretching the sequence in time domain, we can delay with @del@.+--+-- Here is an example:+--+-- > dac $ tri $ seqConst [str 0.25 $ mel [440, 220, 330, 220], 110] 1+--+-- We can see how the function @str@ was used to make a certain segment faster.+-- There are numerical instaces for Seq. Bt it defines only functions @fronInteger@ and+-- @fromRational@.+newtype Seq = Seq { unSeq :: [Seq1] }++data Seq1 = Rest {+        seq1Dur :: Sig } +    | Seq1 {+          seq1Dur :: Sig+        , seq1Val :: Sig+    }++type instance DurOf Seq = Sig++instance Duration Seq where+    dur (Seq as) = sum $ fmap seq1Dur as++instance Rest Seq where+    rest t = Seq [Rest t]++instance Delay Seq where+    del t a = mel [rest t, a]++instance Melody Seq where+    mel as = Seq $ as >>= unSeq    ++instance Stretch Seq where+    str t (Seq as) = Seq $ fmap (updateDur t) as+        where updateDur k a = a { seq1Dur = k * seq1Dur a }++-- | Creates a +toSeq :: Sig -> Seq+toSeq a = Seq [Seq1 1 a]++-- | Squashes a sequence to a single beat.+onBeat :: Seq -> Seq+onBeat a = str (1 / dur a) a++-- | Squashes a sequence to a single beat and then stretches to the given value.+onBeats :: Sig -> Seq -> Seq+onBeats k = str k . onBeat++instance Num Seq where+    fromInteger n = toSeq $ fromInteger n+    (+) = undefined+    (*) = undefined+    negate = undefined+    abs = undefined+    signum = undefined++instance Fractional Seq where+    fromRational = toSeq . fromRational+    (/) = undefined++-------------------------------------------------++seqGen0 :: ([Sig] -> Sig -> Sig) -> (Sig -> Sig -> [Sig]) -> [Seq] -> Sig -> Sig+seqGen0 loopFun segFun as = loopFun (renderSeq0 segFun $ mel as)++seqGen1 :: ([Sig] -> Sig -> Sig) -> (Sig -> Sig -> [Sig]) -> [Seq] -> Sig -> Sig+seqGen1 loopFun segFun as = loopFun (renderSeq1 segFun $ mel as)++simpleSeq0 loopFun = seqGen0 loopFun $ \dt val -> [val, dt]+simpleSeq1 loopFun = seqGen0 loopFun $ \dt val -> [val, dt]++seq0 = seqGen0 lpshold+seq1 = seqGen1 loopseg+seqx = seqGen1 loopxseg++-- | A sequence of constant segments.+seqConst :: [Seq] -> Sig -> Sig+seqConst = simpleSeq0 lpshold++-- | A linear sequence.+seqLin :: [Seq] -> Sig -> Sig+seqLin = simpleSeq1 loopseg++-- | An exponential sequence.+seqExp :: [Seq] -> Sig -> Sig+seqExp = simpleSeq1 loopxseg++-------------------------------------------------+-- square++-- | The sequence of pulse width waves.+-- The first argument is a duty cycle (ranges from 0 to 1).+seqPw :: Sig -> [Seq] -> Sig -> Sig+seqPw k = seq0 $ \dt val -> [val, dt * k, 0, dt * (1 - k)]++-- | The sequence of inversed pulse width waves.+iseqPw :: Sig -> [Seq] -> Sig -> Sig+iseqPw k = seq0 $ \dt val -> [0, dt * k, val, dt * (1 - k)]++-- | The sequence of square waves.+seqSqr :: [Seq] -> Sig -> Sig+seqSqr = seqPw 0.5++-- | The sequence of inversed square waves.+iseqSqr :: [Seq] -> Sig -> Sig+iseqSqr = iseqPw 0.5++-- saw++saw1  dt val = [val, dt, 0, 0]+isaw1 dt val = [0, dt, val, 0]++-- | The sequence of sawtooth waves.+seqSaw :: [Seq] -> Sig -> Sig+seqSaw = seq1 saw1++-- | The sequence of inversed sawtooth waves.+iseqSaw :: [Seq] -> Sig -> Sig+iseqSaw = seq1 isaw1++-- | The sequence of exponential sawtooth waves.+xseqSaw :: [Seq] -> Sig -> Sig+xseqSaw = seqx saw1++-- | The sequence of inversed exponential sawtooth waves.+ixseqSaw :: [Seq] -> Sig -> Sig+ixseqSaw = seqx isaw1++-- | The sequence of ramp  functions. The first argument is a duty cycle.+seqRamp :: Sig -> [Seq] -> Sig -> Sig+seqRamp k = seq1 $ \dt val -> [val, k * dt, 0, (1 - k) * dt, 0, 0]++-- | The sequence of inversed ramp  functions. The first argument is a duty cycle.+iseqRamp :: Sig -> [Seq] -> Sig -> Sig+iseqRamp k = seq1 $ \dt val -> [0, k * dt, val, (1 - k) * dt, 0, 0]++-- tri++-- | The sequence of triangular waves.+seqTri :: [Seq] -> Sig -> Sig+seqTri = seqTriRamp 0.5++-- | The sequence of ramped triangular waves.+seqTriRamp :: Sig -> [Seq] -> Sig -> Sig+seqTriRamp k = seq1 $ \dt val -> [0, dt * k, val, dt * (1 - k)]++-- adsr++adsr1 a d s r dt val = [0, a * dt, val, d * dt, s * val, (1 - a - r), s * val, r * dt ]+adsr1_ a d s r rest dt val = [0, a * dt, val, d * dt, s * val, (1 - a - r - rest), s * val, r * dt, 0, rest ]++-- | The sequence of ADSR-envelopes.+--+-- > seqAdsr att dec sus rel+--+-- It has to be:+--+-- > att + dec + sus_time + rel == 1+seqAdsr :: Sig -> Sig -> Sig -> Sig -> [Seq] -> Sig -> Sig+seqAdsr a d s r = seq1 (adsr1 a d s r)++-- | The sequence of exponential ADSR-envelopes.+xseqAdsr :: Sig -> Sig -> Sig -> Sig -> [Seq] -> Sig -> Sig+xseqAdsr a d s r = seqx (adsr1 a d s r)++-- | The sequence of ADSR-envelopes with rest at the end.+--+-- > seqAdsr att dec sus rel rest+--+-- It has to be:+--+-- > att + dec + sus_time + rel + rest == 1++seqAdsr_ :: Sig -> Sig -> Sig -> Sig -> Sig -> [Seq] -> Sig -> Sig+seqAdsr_ a d s r rest = seq1 (adsr1_ a d s r rest)++-- | The sequence of exponential ADSR-envelopes with rest at the end.+xseqAdsr_ :: Sig -> Sig -> Sig -> Sig -> Sig -> [Seq] -> Sig -> Sig+xseqAdsr_ a d s r rest = seqx (adsr1_ a d s r rest)++-------------------------------------------------++renderSeq0 :: (Sig -> Sig -> [Sig]) -> Seq -> [Sig]+renderSeq0 f (Seq as) = as >>= phi+    where +        phi x = case x of+            Seq1 dt val -> f dt val+            Rest dt     -> [0, dt]++renderSeq1 :: (Sig -> Sig -> [Sig]) -> Seq -> [Sig]+renderSeq1 f (Seq as) = as >>= phi+    where +        phi x = case x of+            Seq1 dt val -> f dt val+            Rest dt     -> [0, dt, 0, 0]++-------------------------------------------------++genSeqPat :: (Int -> [Double]) -> [Int] -> Seq+genSeqPat g ns = mel (ns >>= f)+    where f n +            | n <= 0 = []+            | n == 1 = [1]+            | otherwise = fmap (toSeq . sig . double) $ g n++-- | Function for creation of accented beats. +-- The steady beat pattern of accents is repeated.+-- The first argument describes the list of integers.+-- Each integer is a main beat and the length of the beat.+-- We can create a typical latino beat:+--+-- > dac $ mul (seqSaw [seqPat [3, 3, 2]] 1) white+seqPat :: [Int] -> Seq+seqPat ns = mel (ns >>= f)+    where f n +            | n <= 0 = []+            | n == 1 = [1]+            | otherwise = [1, rest $ sig $ int $ n - 1]++rowDesc n = [1, 1 - recipN .. recipN ]+    where recipN = 1/ fromIntegral n++-- | It's like @seqPat@ but inplace of rests it fills the gaps with+-- segments descending in value.+--+-- > dac $ mul (seqSaw [seqDesc [3, 3, 2]] 1) white+seqDesc :: [Int] -> Seq+seqDesc = genSeqPat rowDesc+    +-- | It's like @seqPat@ but inplace of rests it fills the gaps with+-- segments ascending in value.+--+-- > dac $ mul (seqSaw [seqAsc [3, 3, 2]] 1) white+seqAsc :: [Int] -> Seq+seqAsc = genSeqPat (\n -> let xs = rowDesc n in head xs : reverse (tail xs))++-- | It's like @seqPat@ but inplace of rests it fills the gaps with 0.5s.+--+-- > dac $ mul (seqSaw [seqHalf [3, 3, 2]] 1) white+seqHalf :: [Int] -> Seq+seqHalf = genSeqPat $ (\n -> 1 : take (n - 1) (repeat 0.5))++-------------------------------------------------+-- humanizers++-- | Alias for @humanVal@.+hval :: HumanizeValue a => Sig -> a -> HumanizeValueOut a+hval = humanVal++-- | Alias for @humanTime@.+htime :: HumanizeTime a => Sig -> a -> HumanizeTimeOut a+htime = humanTime++-- | Alias for @humanValTime@.+hvalTime :: HumanizeValueTime a => Sig -> Sig -> a -> HumanizeValueTimeOut a+hvalTime = humanValTime++-- value++-- | A function transformer (decorator). We can transform an envelope producer+-- so that all values are sumed with some random value. The amplitude of the+-- random value is given with the first argument.+--+-- It can transform linseg, expseg, sequence producers and simplified sequence producers. +--+-- An example:+--+-- > dac $ mul (humanVal 0.1 sqrSeq [1, 0.5, 0.2, 0.1] 1) $ white+--+-- As you can see it transforms the whole function. So we don't need for extra parenthesis.+class HumanizeValue a where+    type HumanizeValueOut a :: *+    humanVal :: Sig -> a -> HumanizeValueOut a++rndVal :: Sig -> Sig -> Sig -> SE Sig+rndVal cps dr val = fmap (+ val) $ randh dr cps++rndValD :: Sig -> D -> SE D+rndValD dr val = fmap (+ val) $ random (- (ir dr)) (ir dr)++instance HumanizeValue ([Seq] -> Sig -> Sig) where+    type HumanizeValueOut ([Seq] -> Sig -> Sig) = [Seq] -> Sig -> SE Sig+    humanVal dr f = \sq cps -> fmap (\x -> f x cps) (mapM (humanSeq cps) sq)+        where+            humanSeq cps (Seq as) = fmap Seq $ forM as $ \x -> case x of+                Rest _      -> return x+                Seq1 dt val -> fmap (Seq1 dt) $ rndVal cps dr val++instance HumanizeValue ([Sig] -> Sig -> Sig) where+    type HumanizeValueOut ([Sig] -> Sig -> Sig) = [Sig] -> Sig -> SE Sig+    humanVal dr f = \sq cps -> fmap (\x -> f x cps) (mapM (humanSig cps) sq)+        where humanSig cps val = rndVal cps dr val++instance HumanizeValue ([D] -> Sig) where+    type HumanizeValueOut ([D] -> Sig) = [D] -> SE Sig+    humanVal dr f = \xs -> fmap f $ mapM human1 $ zip [0 ..] xs+        where human1 (n, a)+                    | mod n 2 == 1 = rndValD dr a+                    | otherwise    = return a++instance HumanizeValue ([D] -> D -> Sig) where+    type HumanizeValueOut ([D] -> D -> Sig) = [D] -> D -> SE Sig+    humanVal dr f = \xs release -> fmap (flip f release) $ mapM human1 $ zip [0 ..] xs+        where human1 (n, a)+                    | mod n 2 == 1 = rndValD dr a+                    | otherwise    = return a++-- time++-- | A function transformer (decorator). We can transform an envelope producer+-- so that all durations are sumed with some random value. The amplitude of the+-- random value is given with the first argument.+--+-- It can transform linseg, expseg, sequence producers and simplified sequence producers. +--+-- An example:+--+-- > dac $ mul (humanTime 0.1 sqrSeq [1, 0.5, 0.2, 0.1] 1) $ white+--+-- As you can see it transforms the whole function. So we don't need for extra parenthesis.+class HumanizeTime a where+    type HumanizeTimeOut a :: *+    humanTime :: Sig -> a -> HumanizeTimeOut a++instance HumanizeTime ([Seq] -> Sig -> Sig) where+    type HumanizeTimeOut ([Seq] -> Sig -> Sig) = [Seq] -> Sig -> SE Sig+    humanTime dr f = \sq cps -> fmap (\x -> f x cps) (mapM (humanSeq cps) sq)+        where+            humanSeq cps (Seq as) = fmap Seq $ forM as $ \x -> case x of+                Rest dt     -> fmap Rest $ rndVal cps dr dt+                Seq1 dt val -> fmap (flip Seq1 val) $ rndVal cps dr dt++instance HumanizeTime ([D] -> Sig) where+    type HumanizeTimeOut ([D] -> Sig) = [D] -> SE Sig+    humanTime dr f = \xs -> fmap f $ mapM human1 $ zip [0 ..] xs+        where human1 (n, a)+                    | mod n 2 == 0 = rndValD dr a+                    | otherwise    = return a++instance HumanizeTime ([D] -> D -> Sig) where+    type HumanizeTimeOut ([D] -> D -> Sig) = [D] -> D -> SE Sig+    humanTime dr f = \xs release -> liftA2 f (mapM human1 $ zip [0 ..] xs) (rndValD dr release)+        where human1 (n, a)+                    | mod n 2 == 0 = rndValD dr a+                    | otherwise    = return a++-- value & time++-- | A function transformer (decorator). We can transform an envelope producer+-- so that all values and durations are sumed with some random value. The amplitude of the+-- random value is given with the first two arguments.+--+-- It can transform linseg, expseg, sequence producers and simplified sequence producers. +--+-- An example:+--+-- > dac $ mul (humanValTime 0.1 0.1 sqrSeq [1, 0.5, 0.2, 0.1] 1) $ white+--+-- As you can see it transforms the whole function. So we don't need for extra parenthesis.+class HumanizeValueTime a where+    type HumanizeValueTimeOut a :: *+    humanValTime :: Sig -> Sig -> a -> HumanizeValueTimeOut a++instance HumanizeValueTime ([Seq] -> Sig -> Sig) where+    type HumanizeValueTimeOut ([Seq] -> Sig -> Sig) = [Seq] -> Sig -> SE Sig+    humanValTime drVal drTime f = \sq cps -> fmap (\x -> f x cps) (mapM (humanSeq cps) sq)+        where+            humanSeq cps (Seq as) = fmap Seq $ forM as $ \x -> case x of+                Rest dt     -> fmap Rest $ rndVal cps drTime dt+                Seq1 dt val -> liftA2 Seq1 (rndVal cps drTime dt) (rndVal cps drVal val)++instance HumanizeValueTime ([D] -> Sig) where+    type HumanizeValueTimeOut ([D] -> Sig) = [D] -> SE Sig+    humanValTime drVal drTime f = \xs -> fmap f $ mapM human1 $ zip [0 ..] xs+        where human1 (n, a)+                    | mod n 2 == 1 = rndValD drVal  a+                    | otherwise    = rndValD drTime a++instance HumanizeValueTime ([D] -> D -> Sig) where+    type HumanizeValueTimeOut ([D] -> D -> Sig) = [D] -> D -> SE Sig+    humanValTime drVal drTime f = \xs release -> liftA2 f (mapM human1 $ zip [0 ..] xs) (rndValD drTime release)+        where human1 (n, a)+                    | mod n 2 == 1 = rndValD drVal  a+                    | otherwise    = rndValD drTime a
src/Csound/Air/Live.hs view
@@ -5,13 +5,17 @@     mixer, hmixer, mixMono,      -- * Effects-    FxFun, FxUI(..), fxBox,+    FxFun, FxUI(..), fxBox, uiBox,     fxColor, fxVer, fxHor, fxSca, fxApp, +    -- * Instrument choosers+    hinstrChooser, vinstrChooser,+    hmidiChooser, vmidiChooser,+     -- ** Fx units     uiDistort, uiChorus, uiFlanger, uiPhaser, uiDelay, uiEcho,     uiFilter, uiReverb, uiGain, uiWhite, uiPink, uiFx, uiRoom,-    uiHall, uiCave, uiSig, uiMix,+    uiHall, uiCave, uiSig, uiMix, uiMidi,       -- * Static widgets     AdsrBound(..), AdsrInit(..),@@ -28,7 +32,9 @@  import Csound.Typed import Csound.Typed.Gui-import Csound.Control.Gui(funnyRadio, mapSource)+import Csound.Control.Evt+import Csound.Control.Instr+import Csound.Control.Gui import Csound.Typed.Opcode hiding (space) import Csound.SigSpace import Csound.Air.Wave@@ -152,8 +158,19 @@             | otherwise = f gs             where f xs = uiGroupGui gOff (ver xs) +-- | Creates an FX-box from the given visual representation.+-- It insertes a big On/Off button atop of the GUI.+uiBox :: String -> Source FxFun -> Bool -> Source FxFun +uiBox name fx onOff = mapGuiSource (setBorder UpBoxBorder) $ vlift2' uiOnOffSize uiBoxSize go off fx+    where+        off =  mapGuiSource (setFontSize 25) $ toggleSig name onOff +        go off fx arg = mul off $ fx arg++uiOnOffSize = 1.7+uiBoxSize   = 8+ uiGroupGui :: Gui -> Gui -> Gui -uiGroupGui a b =ver [sca 1.7 a, sca 8 b]+uiGroupGui a b =ver [sca uiOnOffSize a, sca uiBoxSize b]  sourceColor2 :: Color -> Source a -> Source a sourceColor2 col a = source $ do@@ -283,9 +300,10 @@ uiCave :: Bool -> Source FxFun uiCave isOn = sourceColor2 C.darkviolet $ uiFx "Cave" magicCave2 isOn --- | The widget for selecting a midi instrument. -uiMidi :: Bool -> [(String, Msg -> SE Sig2)] -> Source FxFun-uiMidi isOn as = sourceColor2 C.forestgreen $ undefined+-- | Midi chooser implemented as FX-box.+uiMidi :: [(String, Msg -> SE Sig2)] -> Int -> Source FxFun +uiMidi xs initVal = sourceColor2 C.forestgreen $ uiBox "Midi" fx True+    where fx = lift1 (\aout arg -> return $ aout + arg) $ vmidiChooser xs initVal  -- | the widget for mixing in a signal to the signal. uiSig :: String -> Bool -> Source Sig2 -> Source FxFun@@ -353,3 +371,31 @@ masterVolumeKnob :: Source Sig masterVolumeKnob = knob "master" uspan 0.5 ++----------------------------------------------------+-- instrument choosers++genMidiChooser chooser xs initVal = joinSource $ lift1 midi $ chooser xs initVal++-- | Chooses a midi instrument among several alternatives. It uses the @hradio@ for GUI groupping.+hmidiChooser :: Sigs a => [(String, Msg -> SE a)] -> Int -> Source a+hmidiChooser = genMidiChooser hinstrChooser++-- | Chooses a midi instrument among several alternatives. It uses the @vradio@ for GUI groupping.+vmidiChooser :: Sigs a => [(String, Msg -> SE a)] -> Int -> Source a+vmidiChooser = genMidiChooser vinstrChooser++-- | Chooses an instrument among several alternatives. It uses the @hradio@ for GUI groupping.+hinstrChooser :: (Sigs b) => [(String, a -> SE b)] -> Int -> Source (a -> SE b)+hinstrChooser = genInstrChooser hradioSig++-- | Chooses an instrument among several alternatives. It uses the @vradio@ for GUI groupping.+vinstrChooser :: (Sigs b) => [(String, a -> SE b)] -> Int -> Source (a -> SE b)+vinstrChooser = genInstrChooser vradioSig++genInstrChooser :: (Sigs b) => ([String] -> Int -> Source Sig) -> [(String, a -> SE b)] -> Int -> Source (a -> SE b)+genInstrChooser widget xs initVal = lift1 go $ widget names initVal+    where +        (names, instrs) = unzip xs+        go instrId arg = fmap sum $ mapM ( $ arg) $ zipWith (\n instr -> playWhen (sig (int n) ==* instrId) instr) [0 ..] instrs+            
+ src/Csound/Air/Looper.hs view
@@ -0,0 +1,244 @@+-- | A multitap looper.+module Csound.Air.Looper (+	LoopSpec(..), LoopControl(..),+	sigLoop, midiLoop, sfLoop+) where++import Control.Monad+import Data.List++import Data.Default+import Data.Boolean+import Csound.Typed +import Csound.Typed.Gui hiding (button)+import Csound.Control.Evt+import Csound.Control.Instr+import Csound.Control.Gui +import Csound.Control.Sf++import Csound.Typed.Opcode hiding (space, button)+import Csound.SigSpace+import Csound.Air.Live	+import Csound.Air.Wave+import Csound.Air.Fx+import Csound.Air.Filter+import Csound.Air.Misc+++-- | The type for fine tuning of the looper. Let's review the values:+-- +-- * @loopMixVal@ - list of initial values for mix levels (default is 0.5 for all taps)+--+-- * @loopPrefx@ - list of pre-loop effects (the default is do-nothing effect)+--+-- * @loopPostfx@ - list of post-loop effects (the default is do-nothing effect)+--+-- * @loopPrefxVal - list of dry/wet values for pre-looop effects (the default is 0.5 for all taps)+--+-- * @loopPostfxVal - list of dry/wet values for post-looop effects (the default is 0.5 for all taps)+--+-- * @loopInitInstr@  - the initial sounding tap (sound source) (what tap we are going to record when the looper starts up).+--+-- * @loopFades@ - the list of instrument groups to fade/out. Eachl list item is a list of integers+-- where an integer points to a tap number. By default a single fader is given to each tap.+-- with lists of integers we can group the sound sources by their functions in the song.+-- We may group all harmonic instruments in a single group and all drums into another group.+--+-- * @loopReeatFades@ -- a repeat fade weight is a value that represents +--    an amount of repetition. A looping tap is implemented as a delay tap with+--   big feedback. The repeat fades equals to the feedback amount. It have to be not bigger+-- 	 than 1. If the value equals to 1 than the loop is repeated forever. If it's lower+--   than 1 the loop is gradually going to fade. +--+-- * @loopControl@ -- specifies an external controllers for the looper.+--   See the docs for the type @LoopSpec@.+data LoopSpec = LoopSpec +	{ loopMixVal  :: [Sig]+	, loopPrefx  :: [FxFun]+	, loopPostfx :: [FxFun]+	, loopPrefxVal :: [Sig]+	, loopPostfxVal :: [Sig]	+	, loopInitInstr :: Int+	, loopFades :: [[Int]]	+	, loopRepeatFades :: [Sig]+	, loopControl :: LoopControl+	}++instance Default LoopSpec where+	def = LoopSpec {+		  loopPrefx  		= []+		, loopPostfx 		= []+		, loopPrefxVal 		= []+		, loopPostfxVal 	= []+		, loopMixVal      	= []+		, loopInitInstr 	= 0+		, loopFades 		= []+		, loopRepeatFades   = []+		, loopControl       = def+		}		++-- | External controllers. We can control the looper with+-- UI-widgets but sometimes it's convenient to control the+-- loper with some external midi-device. This structure mocks+-- all controls (except knobs for effects and mix).+--+-- * @loopTap@ - selects the current tap. It's a stream of integers (from 0 to a given integer).+--+-- * @loopFade@ - can fade in or fade out a group of taps. It's a list of toggle-like event streams.+--   they produce 1s for on and 0s for off.+--+-- * @loopDel@ - is for deleting the content of a given tap. It's just a click of the button.+--   So the value should be an event stream of units (which is @Tick = Evt Unit@).+--+-- * @loopThrough@ - is an event stream of toggles.+--+-- All values are wrapped in the @Maybe@ type. If the value is @Nothing@ in the given cell+-- the looper is controled only with virtual widgets.+--+-- There is an instance of @Default@ for @LoopControl@ with all values set to @Nothing@.+-- It's useful when we want to control only  a part of parameters externally.+-- We can use the value @def@ to set the  rest parameters:+--+-- > def { loopTap = Just someEvt }+data LoopControl = LoopControl +	{ loopTap  :: Maybe (Evt D)+	, loopFade :: Maybe ([Evt D])+	, loopDel  :: Maybe Tick+	, loopThrough :: Maybe (Evt D)+	}++instance Default LoopControl where+	def = LoopControl {+		  loopTap  = Nothing+		, loopFade = Nothing+		, loopDel  = Nothing+		, loopThrough = Nothing }++type TapControl     = [String] -> Int -> Source Sig+type FadeControl    = [String -> Source (Evt D)]+type DelControl     = Source Tick+type ThroughControl = Source Sig++-- | The @midiLoop@ that is adapted for usage with soundfonts.+-- It takes in a list of pairs of sound fonts as sound sources.+-- The second value in the pair is the release time for the given sound font.+sfLoop :: LoopSpec -> D -> [D] -> [(Sf, D)] -> Source Sig2+sfLoop spec dtBpm times fonts = midiLoop spec dtBpm times $ fmap (uncurry sfMsg) fonts++-- | The @sigLoop@ that is adapted for usage with midi instruments.+-- It takes a list of midi instruments in place of signal inputs. The rest is the same+midiLoop :: LoopSpec -> D -> [D] -> [Msg -> SE Sig2] -> Source Sig2+midiLoop = genLoop $ \cond midiInstr -> midi $ playWhen cond midiInstr ++-- | Simple multitap Looper. We can create as many taps as we like+-- also we can create fade outs/ins insert effects and control mix. +--+-- > sigLoop spec bpm times imputs +--+-- Arguments:+--+-- * looper @spec@ (see the docs for the type)+--+-- * main @bpm@ rate. All taps are aligned with the main rate+--+-- * list of multipliers for each tap. Each tap is going to have a fixed+--    length that is a multiplier of the main rate. It doesn't have to be+--    an integer. So we can create weird drum patterns with odd loop durations.+--+-- * list of signal sources. By convention all sources are stereo signals.+--    We can use the function @fromMono@ to convert the mono signal to stereo.+sigLoop :: LoopSpec -> D -> [D] -> [Sig2] -> Source Sig2+sigLoop = genLoop $ \cond asig -> return $ mul (ifB cond 1 0) asig++getControls :: LoopControl -> (TapControl, FadeControl, DelControl, ThroughControl)+getControls a =	+	( maybe hradioSig (hradioSig' . evtToSig (-1)) (loopTap a)+	, fmap (\f x -> f x True) $ maybe (repeat toggle) (\xs -> fmap toggle' xs ++ repeat toggle) (loopFade a)+	, ( $ "del") $ maybe button button' (loopDel a)+	, (\f -> f "through" False) $ maybe toggleSig (toggleSig' . evtToSig (-1))  (loopThrough a)) ++genLoop :: (BoolSig -> a -> SE Sig2) -> LoopSpec -> D -> [D] -> [a] -> Source Sig2+genLoop playInstr spec dtBpm times' instrs = do+	(preFxKnobGui, preFxKnobWrite, preFxKnobRead) <- setKnob "pre" (linSpan 0 1) 0.5+	(postFxKnobGui, postFxKnobWrite, postFxKnobRead) <- setKnob "post" (linSpan 0 1) 0.5+	(mixKnobGui, mixKnobWrite, mixKnobRead) <- setKnob "mix" (linSpan 0 1) 0.5++	let knobGuis = ver [mixKnobGui, preFxKnobGui, postFxKnobGui]++	mapGuiSource (\gs -> hor [knobGuis, sca 12 gs]) $ joinSource $ vlift3 (\(thr, delEvt) x sils -> do+		-- knobs	+		mixCoeffs <- tabSigs mixKnobWrite mixKnobRead x initMixVals+		preCoeffs <- tabSigs preFxKnobWrite preFxKnobRead x initPreVals+		postCoeffs <- tabSigs postFxKnobWrite postFxKnobRead x initPostVals++		refs <- mapM (const $ newSERef (1 :: Sig)) ids+		delRefs <- mapM (const $ newSERef (0 :: Sig)) ids+		zipWithM_ (setSilencer refs) silencer sils+		at smallRoom2 $ sum $ zipWith3 (f delEvt thr x) (zip3 times ids repeatFades) (zip5 mixCoeffs preFx preCoeffs postFx postCoeffs) $ zip3 delRefs refs instrs) throughDel sw sil+	where+		(tapControl, fadeControl, delControl, throughControl) = getControls (loopControl spec)++		dt = 60 / dtBpm ++		times = take len $ times' ++ repeat 1++		postFx = take len $ loopPostfx spec ++ repeat return+		preFx = take len $ loopPrefx spec ++ repeat return+		repeatFades = loopRepeatFades spec ++ repeat 1++		len = length ids+		initMixVals = take len $ loopMixVal spec ++ repeat 0.5+		initPreVals = take len $ loopPrefxVal spec ++ repeat 0.5+		initPostVals = take len $ loopPostfxVal spec ++ repeat 0.5++		silencer +			| null (loopFades spec) = fmap return ids+			| otherwise               = loopFades spec++		initInstr = loopInitInstr spec++		ids = [0 .. length instrs - 1]+		through = throughControl+		delete = delControl++		throughDel = hlift2' 6 1 (\a b -> (a, b)) through delete+		sw = tapControl (fmap show ids) initInstr		 +		sil = hlifts id $ zipWith (\f n -> f (show n)) fadeControl [0 .. length silencer - 1]++		maxDel = 3++		f delEvt thr x (t, n, repeatFadeWeight) (mixCoeff, preFx, preCoeff, postFx, postCoeff) (delRef, silRef, instr) = do+			silVal <- readSERef silRef	+			runEvt delEvt $ \_ -> do+				a <- readSERef delRef+				when1 isCurrent $ writeSERef delRef (ifB (a + 1 <* maxDel) (a + 1) 0)+			delVal <- readSERef delRef+			echoSig <- playSf 0++			let d0 = delVal ==* 0+			    d1 = delVal ==* 1+			    d2 = delVal ==* 2++			let playEcho dId = mul (smooth 0.05 $ ifB dId 1 0) $ mul (smooth 0.1 silVal) $ at (echo (dt * t) (ifB dId repeatFadeWeight 0)) $ ifB dId echoSig 0++			mul mixCoeff $ mixAt postCoeff postFx $ sum [ sum $ fmap playEcho [d0, d1, d2]+				, playSf 1]+			where +				playSf thrVal = mixAt preCoeff preFx $ playInstr (isCurrent &&* thr ==* thrVal) instr+				isCurrent = x ==* (sig $ int n)++		setSilencer refs silIds evt = runEvt evt $ \v -> +			mapM_ (\ref -> writeSERef ref $ sig v) $ fmap (refs !! ) silIds++tabSigs :: Output Sig -> Input Sig -> Sig -> [Sig] -> SE [Sig]+tabSigs writeWidget readWidget switch initVals = do	+	refs <- mapM newGlobalSERef initVals	++	vs <- mapM readSERef refs+	runEvt (changedE [switch]) $ \_ -> do+		mapM_  (\(v, x) -> when1 (x ==* switch) $ writeWidget v) $ zip vs $ fmap (sig . int) [0 .. length initVals - 1]++	forM_ (zip [0..] refs) $ \(n, ref) -> do+		when1 ((sig $ int n) ==* switch) $ writeSERef ref readWidget++	return vs
src/Csound/Air/Seg.hs view
@@ -48,9 +48,13 @@  type instance DurOf (Seg a) = Tick -instance Sigs a => Compose (Seg a) where+instance Sigs a => Melody (Seg a) where 	mel = sflow++instance Sigs a => Harmony (Seg a) where	 	har = spar++instance Sigs a => Compose (Seg a) where  instance Sigs a => Delay (Seg a) where 	del = sdel
src/Csound/Air/Wave.hs view
@@ -5,7 +5,7 @@     osc, oscBy, saw, isaw, pulse, sqr, pw, tri, ramp, blosc,      -- * Unipolar-    unipolar, bipolar, on, uon, uosc, uoscBy, usaw, uisaw, upulse, usqr, upw, utri, uramp, ublosc,+    unipolar, bipolar, uosc, uoscBy, usaw, uisaw, upulse, usqr, upw, utri, uramp, ublosc,      -- * Noise     rndh, urndh, rndi, urndi, white, pink,@@ -97,21 +97,6 @@ -- | Unipolar triangle wave with ram factor. uramp :: Sig -> Sig -> Sig uramp duty cps = unipolar $ ramp duty cps----- rescaling---- | Rescaling of the bipolar signal (-1, 1) -> (a, b)--- --- > on a b biSig-on :: SigSpace a => Sig -> Sig -> a -> a-on a b x = uon a b $ mapSig unipolar x ---- | Rescaling of the unipolar signal (0, 1) -> (a, b)--- --- > on a b uniSig-uon :: SigSpace a => Sig -> Sig -> a -> a-uon a b = mapSig (\x -> a + (b - a) * x)   -------------------------------------------------------------------------- -- noise
src/Csound/Control/Evt.hs view
@@ -6,7 +6,7 @@     boolToEvt, evtToBool, sigToEvt, evtToSig, stepper,     filterE, filterSE, accumSE, accumE, filterAccumE, filterAccumSE, -    Snap, snapshot, snaps, sync, syncBpm, +    Snap, snapshot, snaps, snaps2, sync, syncBpm,           -- * Opcodes     metroE, impulseE, changedE, triggerE, loadbang, impulse,@@ -92,6 +92,12 @@ -- | Splits a toggle event stream on on-events and off-events. splitToggle :: Evt D -> (Evt D, Evt D) splitToggle = swap . partitionE (==* 0)++-- | Constructs an event stream that contains pairs from the+-- given pair of signals. Events happens when any signal changes.+snaps2 :: Sig2 -> Evt (D, D)+snaps2 (x, y) = snapshot const (x, y) trigger+    where trigger = sigToEvt $ changed [x, y]  ---------------------------------------------------------------------- -- higher level evt-funs
src/Csound/Control/Gui.hs view
@@ -1,4 +1,9 @@-{-# Language TypeSynonymInstances, FlexibleInstances #-}+{-# Language +    TypeSynonymInstances, +    FlexibleInstances, +    MultiParamTypeClasses, +    FlexibleContexts, +    TypeFamilies #-} -- | GUI (Graphical User Interface) elements are handy to change  -- the parameters of the sound in real time. It includes sliders,  -- knobs, rollers, buttons and other widgets. @@ -51,9 +56,10 @@     Gui,      Widget, Input, Output, Inner,     Sink, Source, Display, SinkSource,-    widget, sink, source, display, sinkSource,+    widget, sink, source, display, sinkSource, sinkSlice, sourceSlice,     mapSource, mapGuiSource,      mhor, mver, msca,+    joinSource,      -- * Panels     panel, win, panels, panelBy,@@ -66,10 +72,13 @@      -- * Lifters     -- | An easy way to combine visuals for sound sources.+    hlifts, vlifts,      lift1, hlift2, vlift2, hlift3, vlift3, hlift4, vlift4, hlift5, vlift5,      -- ** Lifters with visual scaling+    hlifts', vlifts',+     hlift2', vlift2', hlift3', vlift3', hlift4', vlift4', hlift5', vlift5' ) where @@ -80,7 +89,23 @@ import Csound.Control.Gui.Layout import Csound.Control.Gui.Props import Csound.Control.Gui.Widget+import Csound.SigSpace +instance SigSpace a => SigSpace (Source a) where+    mapSig f = mapSource (mapSig f)++instance (At Sig (SE Sig) a) => At Sig (SE Sig) (Source a) where+    type AtOut Sig (SE Sig) (Source a) = Source (AtOut Sig (SE Sig) a)+    at f a = mapSource (at f) a++instance (At Sig2 Sig2 a) => At Sig2 Sig2 (Source a) where+    type AtOut Sig2 Sig2 (Source a) = Source (AtOut Sig2 Sig2 a)+    at f a = mapSource (at f) a++instance (At Sig2 (SE Sig2) a) => At Sig2 (SE Sig2) (Source a) where+    type AtOut Sig2 (SE Sig2) (Source a) = Source (AtOut Sig2 (SE Sig2) a)+    at f a = mapSource (at f) a+ -- | Creates a window with the given name, size and content -- -- > win name (width, height) gui@@ -90,8 +115,43 @@ keyWin :: String -> (Int, Int) -> Gui -> SE () keyWin name (x, y) = keyPanelBy name (Just $ Rect 0 0 x y) +-- | Hides the SE inside Source.+joinSource :: Source (SE a) -> Source a+joinSource a = do+    (g, mv) <- a+    v <- mv+    return (g, v)+ ---------------------------------------------------------------------------------- -- easy grouppings for GUIs++-- | Groups a list of Source-widgets. The visuals are horizontally aligned.+hlifts :: ([a] -> b) -> [Source a] -> Source b+hlifts = genLifts hor++-- | Groups a list of Source-widgets. The visuals are vertically aligned.+vlifts :: ([a] -> b) -> [Source a] -> Source b+vlifts = genLifts ver++-- | Groups a list of Source-widgets. The visuals are horizontally aligned. +-- It uses the list of proportions.+hlifts' :: [Double] -> ([a] -> b) -> [Source a] -> Source b+hlifts' props = genLifts (applyProportionsToList props hor)++-- | Groups a list of Source-widgets. The visuals are vertically aligned.+-- It uses the list of proportions.+vlifts' :: [Double] -> ([a] -> b) -> [Source a] -> Source b+vlifts' props = genLifts (applyProportionsToList props ver)++applyProportionsToList :: [Double] -> ([Gui] -> Gui) -> [Gui] -> Gui+applyProportionsToList props f as = f $ zipWith sca (props ++ repeat 1) as++genLifts :: ([Gui] -> Gui) -> ([a] -> b) -> [Source a] -> Source b+genLifts gf f as = fmap phi $ sequence as+    where +        phi xs = (gf gs, f vs)+            where (gs, vs) = unzip xs+  -- | The shortcut for @mapSource@. lift1 :: (a -> b) -> Source a -> Source b
src/Csound/Control/Gui/Widget.hs view
@@ -21,6 +21,7 @@     butBank1, butBankSig1,      radioButton, matrixButton, funnyRadio, funnyMatrix,     setNumeric, meter,+    setKnob, setSlider,     setToggle, setToggleSig,     -- * Transformers     setTitle,@@ -35,8 +36,19 @@     -- | Widgets for sample and hold functions     hnumbers, vnumbers, +    -- * Range widgets+    Range,+    rangeKnob, rangeSlider, rangeKnobSig, rangeSliderSig,+    rangeJoy, rangeJoy2, rangeJoySig,+     -- * The 2D matrix of widgets-    knobPad, togglePad, buttonPad, genPad+    knobPad, togglePad, buttonPad, genPad,++    -- * External control++    -- | The widgets can be controlled with external signals/event streams+    button', toggle', toggleSig', knob', slider', uknob', uslider',+    hradio', vradio', hradioSig', vradioSig' ) where  import Control.Monad@@ -48,7 +60,9 @@ import Csound.Typed.Gui import Csound.Typed.Types import Csound.Control.SE-import Csound.Control.Evt(listAt, Tick)+import Csound.SigSpace(uon)+import Csound.Control.Evt(listAt, Tick, snaps2, dropE, devt, loadbang, evtToSig)+import Csound.Typed.Opcode(changed)  -------------------------------------------------------------------- -- aux widgets@@ -133,21 +147,21 @@  -- | Exponential slider (usefull for exploring frequencies or decibels).  ----- > xknob min max initVal+-- > xknob (min, max) initVal -- -- The value belongs to the interval [min, max]. -- The last argument is for initial value.-xslider :: Double -> Double -> Double -> Source Sig-xslider a b initVal = slider "" (expSpan a b) initVal+xslider :: Range Double -> Double -> Source Sig+xslider (a, b) initVal = slider "" (expSpan a b) initVal  -- | Exponential knob (usefull for exploring frequencies or decibels).  ----- > xknob min max initVal+-- > xknob (min, max) initVal -- -- The value belongs to the interval [min, max]. -- The last argument is for initial value.-xknob :: Double -> Double -> Double -> Source Sig-xknob a b initVal = knob "" (expSpan a b) initVal+xknob :: Range Double -> Double -> Source Sig+xknob (a, b) initVal = knob "" (expSpan a b) initVal  -- | Unit linear joystick. ujoy :: (Double, Double) -> Source (Sig, Sig)@@ -278,3 +292,193 @@     return (gcat guis, res)     where                 ids = fmap (sig . int) [0 .. length names - 1]++++-- | Pair of minimum and maximum values.+type Range a = (a, a)++-- | Creates a knob that outputs only integers in the given range.+-- It produces a signal of integer values.+--+-- > rangeKnobSig (min, max) initVal +rangeKnobSig :: Range Int -> Int -> Source Sig+rangeKnobSig = rangeSig1 uknob++-- | Creates a slider that outputs only integers in the given range.+-- It produces a signal of integer values.+--+-- > rangeSliderSig (min, max) initVal +rangeSliderSig :: Range Int -> Int -> Source Sig+rangeSliderSig = rangeSig1 uslider++-- | Creates a knob that outputs only integers in the given range.+-- It produces an event stream of integer values. It can be used with+-- list access functions @listAt@, @atTuple@, @atArg@.+--+-- > rangeKnob needInit (min, max) initVal+--+-- The first argument is a boolean. If it's true than the initial value+-- is put in the output stream. If it\s False the initial value is skipped.+rangeKnob :: Bool -> Range Int -> Int -> Source (Evt D)+rangeKnob = rangeEvt1 uknob++-- | Creates a slider that outputs only integers in the given range.+-- It produces an event stream of integer values. It can be used with+-- list access functions @listAt@, @atTuple@, @atArg@.+--+-- > rangeSlider needInit (min, max) initVal+--+-- The first argument is a boolean. If it's true than the initial value+-- is put in the output stream. If it\s False the initial value is skipped.+rangeSlider :: Bool -> Range Int -> Int -> Source (Evt D)+rangeSlider = rangeEvt1 uslider++rangeSig1 :: (Double -> Source Sig) -> Range Int -> Int -> Source Sig+rangeSig1 widget range initVal = mapSource (fromRelative range) $ widget $ toRelativeInitVal range initVal++rangeEvt1 :: (Double -> Source Sig) -> Bool -> Range Int -> Int -> Source (Evt D)+rangeEvt1 widget isInit range initVal = mapSource (addInit . snaps) $ rangeSig1 widget range initVal+    where+        addInit+            | isInit    = ((devt (int initVal) loadbang) <> )+            | otherwise = id++-- | 2d range range slider. Outputs a pair of event streams. +-- Each stream  contains changes in the given direction (Ox or Oy).+--+-- > rangeJoy needsInit rangeX rangeY (initX, initY)+--+-- The first argument is a boolean. If it's true than the initial value+-- is put in the output stream. If it\s False the initial value is skipped.+rangeJoy :: Bool -> Range Int -> Range Int -> (Int, Int) -> Source (Evt D, Evt D)+rangeJoy isInit rangeX rangeY initVals = mapSource (addInit . f) $ rangeJoySig rangeX rangeY initVals+    where +        f (x, y) = (snaps x, snaps y)           +        addInit+            | isInit    = id+            | otherwise = \(a, b) -> (dropE 1 a, dropE 1 b)++-- | 2d range range slider. It produces a single event stream. +-- The event fires when any signal changes.+--+-- > rangeJoy2 needsInit rangeX rangeY (initX, initY)+--+-- The first argument is a boolean. If it's true than the initial value+-- is put in the output stream. If it\s False the initial value is skipped.+rangeJoy2 :: Bool -> Range Int -> Range Int -> (Int, Int) -> Source (Evt (D, D))+rangeJoy2 isInit rangeX rangeY initVals = mapSource (addInit . snaps2) $ rangeJoySig rangeX rangeY initVals+    where+        addInit+            | isInit    = id+            | otherwise = dropE 1++-- | 2d range range slider. It produces the pair of integer signals+rangeJoySig :: Range Int -> Range Int -> (Int, Int) -> Source (Sig, Sig)+rangeJoySig rangeX rangeY (initValX, initValY) = mapSource f $ +    ujoy (toRelativeInitVal rangeX initValX, toRelativeInitVal rangeY initValY)+    where f (x, y) = (fromRelative rangeX x, fromRelative rangeY y)++toRelativeInitVal :: Range Int -> Int -> Double+toRelativeInitVal (kmin, kmax) initVal = (fromIntegral $ initVal - kmin) / (fromIntegral $ (kmax - 1) - kmin) ++fromRelative :: Range Int -> Sig -> Sig+fromRelative (kmin, kmax) = floor' . uon (f kmin) (f kmax - 0.01)+    where f = sig . int+++------------------------------------------------------------+-- external control of widgets++-- | It's like simple @button@, but it can be controlled with external control.+-- The first argument is for external control.+button' :: Tick -> String -> Source Tick+button' ctrl name = mapSource (mappend ctrl) $ button name++-- | It's like simple @toggle@, but it can be controlled with external control.+-- The first argument is for external control.+toggle' :: Evt D -> String -> Bool -> Source (Evt D)+toggle' ctrl name initVal = source $ do+    (gui, output, input) <- setToggle name initVal+    output ctrl+    return $ (gui, mappend ctrl input)++toggleSig' :: Sig -> String -> Bool -> Source Sig+toggleSig' ctrl name initVal = +    ctrlSig (if initVal then 1 else 0) ctrl $ setToggleSig name initVal++-- | It's like simple @uknob@, but it can be controlled with external control.+-- The first argument is for external control.+uknob' :: Sig -> Double -> Source Sig   +uknob' ctrl initVal = ctrlSig (double initVal) ctrl $ setKnob "" uspan initVal ++-- | It's like simple @uslider@, but it can be controlled with external control.+-- The first argument is for external control.+uslider' :: Sig -> Double -> Source Sig +uslider' ctrl initVal = ctrlSig (double initVal) ctrl $ setSlider "" uspan initVal ++-- | It's like simple @knob@, but it can be controlled with external control.+-- The first argument is for external control.+knob' :: Sig -> String -> ValSpan -> Double -> Source Sig+knob' ctrl name span initVal = ctrlSig (double initVal) ctrl $ setKnob name span initVal++-- | It's like simple @slider@, but it can be controlled with external control.+-- The first argument is for external control.+slider' :: Sig -> String -> ValSpan -> Double -> Source Sig+slider' ctrl name span initVal = ctrlSig (double initVal) ctrl $ setSlider name span initVal++-- | It's like simple @hradioSig@, but it can be controlled with external control.+-- The first argument is for external control.+hradioSig' :: Sig -> [String] -> Int -> Source Sig+hradioSig' = radioGroupSig' hor ++-- | It's like simple @vradioSig@, but it can be controlled with external control.+-- The first argument is for external control.+vradioSig' :: Sig -> [String] -> Int -> Source Sig+vradioSig' = radioGroupSig' ver++-- | It's like simple @hradio@, but it can be controlled with external control.+-- The first argument is for external control.+hradio' :: Evt D -> [String] -> Int -> Source (Evt D) +hradio' = radioGroup' hor ++-- | It's like simple @vradio@, but it can be controlled with external control.+-- The first argument is for external control.+vradio' :: Evt D -> [String] -> Int -> Source (Evt D)+vradio' = radioGroup' ver++radioGroup'  :: ([Gui] -> Gui) -> Evt D -> [String] -> Int -> Source (Evt D)+radioGroup' gcat ctrl names initVal =  mapSource snaps $ radioGroupSig' gcat (evtToSig (int initVal) ctrl) names initVal++radioGroupSig'  :: ([Gui] -> Gui) -> Sig -> [String] -> Int -> Source Sig+radioGroupSig' gcat ctrl names initVal = source $ do+    (guis, writes, reads) <- fmap unzip3 $ mapM (\(i, tag) -> flip setToggleSig (i == initVal) tag) $ zip [0 ..] names+    curRef <- newGlobalSERef (sig $ int initVal)   ++    when1 (changed [ctrl] ==* 1) $ writeSERef curRef ctrl++    current <- readSERef curRef    +    zipWithM_ (\w i -> w $ ifB (current ==* i) 1 0) writes ids+    zipWithM_ (\r i -> runEvt (snaps r) $ \x -> do              +        when1 (sig x ==* 1) $ do+            writeSERef curRef i+        when1 (sig x ==* 0 &&* current ==* i) $ do+           writeSERef curRef i    +        ) reads ids   ++    res <- readSERef curRef+    return (gcat guis, res)+    where        +        ids = fmap (sig . int) [0 .. length names - 1]+++ctrlSig :: D -> Sig -> SinkSource Sig -> Source Sig+ctrlSig initVal ctrl v = source $ do+    (gui, output, input) <- v+    ref <- newGlobalSERef (sig initVal)+    when1 (changed [ctrl] ==* 1) $ writeSERef ref ctrl  +    when1 (changed [input] ==* 1) $ writeSERef ref input    +    res <- readSERef ref+    output res+    return (gui, res)+    
src/Csound/Control/Instr.hs view
@@ -1,4 +1,4 @@-{-# Language TypeFamilies, FlexibleContexts, FlexibleInstances #-}+{-# Language TypeFamilies, FlexibleContexts, FlexibleInstances, ScopedTypeVariables #-} -- | We can convert notes to sound signals with instruments.  -- An instrument is a function: --@@ -87,7 +87,7 @@     withDur,      -- ** Misc-    alwaysOn,+    alwaysOn, playWhen,      -- * Overload     -- | Converters to make it easier a construction of the instruments.@@ -143,6 +143,16 @@             res <- instr x             runEvt offEvt $ const $ turnoff             return res++-- | Transforms an instrument from always on to conditional one. +-- The routput instrument plays only when condition is true otherwise+-- it produces silence.+playWhen :: forall a b. Sigs a => BoolSig -> (b -> SE a) -> (b -> SE a)+playWhen onSig instr msg = do+    ref <- newSERef (0 :: a)+    writeSERef ref 0+    when1 onSig $ writeSERef ref =<< instr msg+    readSERef ref  ------------------------------------------------------------------------- -------------------------------------------------------------------------
src/Csound/SigSpace.hs view
@@ -5,7 +5,7 @@         FlexibleInstances,          FlexibleContexts #-} module Csound.SigSpace(-    SigSpace(..), BindSig(..), mul, At(..), bat,+    SigSpace(..), BindSig(..), mul, on, uon, At(..), mixAt, bat,     cfd, cfd4, cfds, cfdSpec, cfdSpec4, cfdsSpec,      wsum         ) where@@ -15,7 +15,6 @@  import Csound.Typed import Csound.Types-import Csound.Control.Gui(Source, mapSource) import Csound.Typed.Opcode(pvscross, pvscale, pvsmix, balance)  -- | A class for easy way to process the outputs of the instruments.@@ -30,6 +29,21 @@ mul :: SigSpace a => Sig -> a -> a mul k = mapSig (k * ) +-- rescaling++-- | Rescaling of the bipolar signal (-1, 1) -> (a, b)+-- +-- > on a b biSig+on :: SigSpace a => Sig -> Sig -> a -> a+on a b x = uon a b $ mapSig unipolar x +    where unipolar a = 0.5 + 0.5 * a++-- | Rescaling of the unipolar signal (0, 1) -> (a, b)+-- +-- > on a b uniSig+uon :: SigSpace a => Sig -> Sig -> a -> a+uon a b = mapSig (\x -> a + (b - a) * x) + -- | Crossfade. -- -- > cfd coeff sig1 sig2@@ -111,10 +125,6 @@ instance SigSpace (SE (Sig, Sig, Sig, Sig)) where mapSig  f = fmap (mapSig f) instance BindSig  (SE (Sig, Sig, Sig, Sig)) where bindSig f = fmap (bindSig f) -instance SigSpace a => SigSpace (Source a) where-    mapSig f = mapSource (mapSig f)-- ----------------------------------------------------- -- numeric instances @@ -298,9 +308,16 @@     type AtOut a b c :: *     at :: (a -> b) -> c -> AtOut a b c +-- | It applies an effect and balances the processed signal by original one. bat :: At Sig a b => (Sig -> a) -> b -> AtOut Sig a b bat f = at (\x -> mapSig ( `balance` x) $ f x) +-- | It applies an effect and mixes the processed signal with original one.+-- The first argument is for proportion of dry/wet (original/processed).+-- It's like @at@ but it allows to balance processed signal with original one.+mixAt :: (At a b c, c ~ AtOut a b c, SigSpace c, Num c) => Sig -> (a -> b) -> c -> c+mixAt k f a = cfd k a (at f a)+ instance SigSpace a => At Sig Sig a where     type AtOut Sig Sig a = a     at f a = mapSig f a@@ -361,10 +378,6 @@  ---------------------------------------------------------    -instance (At Sig (SE Sig) a) => At Sig (SE Sig) (Source a) where-    type AtOut Sig (SE Sig) (Source a) = Source (AtOut Sig (SE Sig) a)-    at f a = mapSource (at f) a- ---------------------------------------------------------    -- Sig2 -> Sig2 @@ -406,12 +419,3 @@     at f a = f =<< a  ---------------------------------------------------------   --instance (At Sig2 Sig2 a) => At Sig2 Sig2 (Source a) where-    type AtOut Sig2 Sig2 (Source a) = Source (AtOut Sig2 Sig2 a)-    at f a = mapSource (at f) a--instance (At Sig2 (SE Sig2) a) => At Sig2 (SE Sig2) (Source a) where-    type AtOut Sig2 (SE Sig2) (Source a) = Source (AtOut Sig2 (SE Sig2) a)-    at f a = mapSource (at f) a-