packages feed

csound-expression 3.0.1 → 3.1.0

raw patch · 21 files changed

+682/−83 lines, 21 filesdep ~csound-expression-typed

Dependency ranges changed: csound-expression-typed

Files

csound-expression.cabal view
@@ -1,5 +1,5 @@ Name:          csound-expression-Version:       3.0.1+Version:       3.1.0 Cabal-Version: >= 1.6 License:       BSD3 License-file:  LICENSE@@ -79,8 +79,17 @@      examples/Midi.hs     examples/Events.hs-    examples/Guis.hs+    examples/DubBass.hs +    examples/Gui/Button.hs      +    examples/Gui/Envelope.hs  +    examples/Gui/Harmonics.hs  +    examples/Gui/Osc.hs+    examples/Gui/EnvelopeAndHarmonics.hs  +    examples/Gui/Filter.hs    +    examples/Gui/Key.hs        +    examples/Gui/Waves.hs+ Homepage:        https://github.com/anton-k/csound-expression Bug-Reports:     https://github.com/anton-k/csound-expression/issues @@ -93,7 +102,7 @@   Ghc-Options:    -Wall   Build-Depends:         base >= 4, base < 5, process, data-default, Boolean >= 0.1.0,-        csound-expression-typed, csound-expression-opcodes+        csound-expression-typed >= 0.0.1, csound-expression-opcodes   Hs-Source-Dirs:      src/   Exposed-Modules:         Csound.Base@@ -111,11 +120,10 @@         Csound.Control.Instr         Csound.Control.SE ----        Csound.Gui---        Csound.Gui.Widget---        Csound.Gui.Props---        Csound.Gui.Layout+        Csound.Control.Gui+        Csound.Control.Gui.Widget+        Csound.Control.Gui.Props+        Csound.Control.Gui.Layout  --        Csound.LowLevel   Other-Modules:
+ examples/DubBass.hs view
@@ -0,0 +1,48 @@+module Main where++import Csound++wobbly :: Sig -> Sig -> Sig -> Sig+wobbly spb coeff cps = a2+    where+        a1 = mean [saw (cps * 1.005), sqr (cps * 0.495)]+        idivision = 1 / (coeff * spb)+        klfo = kr $ oscLins [0, 0.5, 1, 0.5, 0] idivision++        -- filter+        ibase = cps+        imod  = ibase * 9+        a2    = moogladder a1 (ibase + imod * klfo) 0.6++spb = double dspb+dspb = 0.45++instr (coeff, cps) = return $ wobbly (sig spb) (sig coeff) (sig $ cpspch cps)+++main = dac $ mix $ str (dspb * 2) $ sco instr $ melMap temp $ +    [ (2, 6.04)+    , (1/3, 7.04)+    , (2, 6.04)+    , (1/1.5, 7.07)+    +    , (2, 5.09)+    , (1, 6.09)+    , (1/1.5, 5.09)+    , (1/3, 6.11)++    , (1, 6.04)+    , (1/3, 7.04)+    , (2, 6.04)+    , (1/1.5, 7.07) +    +    , (2, 6.09)+    , (1, 7.09)+    , (1/1.5, 6.11)+    , (1/3, 6.07) +    +    , (2, 6.04)+    , (1/3, 7.04)+    , (2, 6.04)+    , (1/1.5, 7.07) ]+
+ examples/Gui/Button.hs view
@@ -0,0 +1,34 @@+-- | Simple buttons+module Button where++import Csound.Base++main = dac $ do    +    -- Let's create a toggle button with label "play".+    -- The toggle button emmits ones and zeros.+    (gbut1, evt1)   <- toggle "play"++    -- Let's create a plain button with label "Hi!".+    (gbut2, evt2)   <- button "Hi!"++    -- It splits the toggle button events on only ones and only zeros.+    let (evtOn, evtOff) = splitToggle evt1++    -- Let's use a standard method to create a master volume slider.+    (gvol, vol) <- masterVolume++    -- A simple instrument that plays a single note+    -- it fades in and out in 0.5 seconds.+    let instr cps _ = return $ fades 0.5 0.5 * osc cps++    -- Creates a window with our elements vertically aligned.+    panel $ ver [gvol, gbut1, gbut2]++    -- Plays a note while toggle button is 'on'.+    let sig1 = schedUntil (instr 440) evtOn evtOff+    -- Plays a note once.+        sig2 = sched (instr 330) $ withDur 0.2 $ fmap (const unit) evt2++    -- Sends the sum to the output scaled with given master volume.+    return $ vol * sum [sig1, sig2]+      
+ examples/Gui/Envelope.hs view
@@ -0,0 +1,30 @@+-- | An ADSR-envelope.+module Envelope where++import Csound.Base++-- We use `vdac` to activate the virtual midi keyboard.+-- We can use just `dac` if we have a hardware midi controller.+main = vdac $ do+    -- Creates an Attack-decay-sustain-release widget.+    -- We specify a label, time bounds for attack, decay and release+    -- and init values. It returns a gui-widget and the signal of+    -- the envelope.+    (genv, env) <- linAdsr "" (AdsrBound 1 1 3) (AdsrInit 0.1 0.5 0.5 0.1)+    +    -- Creates a master volume widget.+    (gvol, vol) <- masterVolume ++    -- A simple midi-instrument that plays a triangle wave with+    -- given amplitude envelope.+    let instr = onMsg $ \cps -> env * tri cps++    -- Let's place everything on window. Two elements+    -- are aligned vertically and the master volume slider is+    -- smaller than the envelope widget (we scale it by 0.25).+    panel $ ver [genv, sca 0.25 gvol]++    -- Triggers the midi instrument and scales+    -- the output by given master volume.+    return $ vol * midi instr+
+ examples/Gui/EnvelopeAndHarmonics.hs view
@@ -0,0 +1,28 @@+-- | Experiments with amplitude envelope and harmonics.+module EnvelopeAndHarmonics where++import Csound.Base++import Harmonics(harms)++main = vdac $ do+    -- Creates a bank of 15 sliders. We specify the label+    -- and initial values for slider (0 is minimum and 1 is maximum +    -- for each slider.+    (gharms, ks) <- sliderBank "harmonics" (1 : replicate 14 0)+    -- We create an Adsr envelope (see example Envelope.hs)+    (gadsr, env) <- linAdsr "amplitude envelope" (AdsrBound 1 1 3) (AdsrInit 0.1 0.1 0.5 0.1)+    -- Creates a master volume slider+    (gvol, vol)  <- masterVolume++    -- Places everything on window. Elements are aligned vertically.+    -- The volume slider is smaller than the ADSR-envelope. The element+    -- for harmonics is the biggest one. We alter the sizes with the function `sca`+    -- (it's short for scale)+    panel $ ver [sca 0.1 gvol, sca 0.25 gadsr, gharms]++    -- Let's create a simple instrument with the custom harmonics +    -- and amplitude envelope.+    let instr = onMsg $ \cps -> env * harms ks cps+    return $ vol * midi instr+
+ examples/Gui/Filter.hs view
@@ -0,0 +1,38 @@+-- | Development of the example Osc.hs (see it first). +-- Now oscillators are equipped with filter.+module Filter where++import Csound.Base++import Osc(OscInit(..), moogOscs)++data FilterInit = FilterInit +    { filterInitResonance :: Double     -- the Q+    , filterInitFreq      :: Double     -- the minimum of the center frequency+    , filterInitRange     :: Double }   -- center frequency range++-- | A moog like filter with ADSR-envelope for center frequency.+moogFilter :: String -> Sig -> FilterInit -> Source (Sig -> Sig)+moogFilter name env (FilterInit initQ initCfq initRange) = source $ do+    (gq, q) <- knob "resonance" uspan initQ +    (gcfq, cfq) <- knob "freq" (linSpan 0 1000) initCfq  +    (grange, range) <- knob "range" (linSpan 0 10000) initRange+    let cfqSig = cfq + env * range+    gui <- setTitle name $ hor [gq, gcfq, grange]+    return (gui, mlp cfqSig q)++adsrBound = AdsrBound 3 3 5+adsrInit  = AdsrInit  0.1 0.1 0.5 0.2++main = vdac $ do+    (gampEnv, ampEnv) <- linAdsr "amplitude" adsrBound adsrInit+    (gfiltEnv, filtEnv) <- linAdsr "filter" adsrBound adsrInit+    (goscs, oscs) <- moogOscs [OscInit 1 1 1, OscInit 0.5 2 2, OscInit 0.125 3 3]+    (gfilt, filt) <- moogFilter "" filtEnv (FilterInit 0.6 100 3000)+    (gvol, vol) <- masterVolume ++    let instr cps = vol * ampEnv * (filt $ oscs cps)+    let gui = hor [goscs, ver [gampEnv, gfiltEnv, gfilt], sca 0.1 gvol]+    panelBy "" (Just $ Rect 50 50 900 800) gui+    return $ midi $ onMsg instr+
+ examples/Gui/Harmonics.hs view
@@ -0,0 +1,22 @@+-- Experiments with harmonics.+module Harmonics where++import Csound.Base ++-- a sum of pure tones that form a hormanic series.+harms :: [Sig] -> Sig -> Sig+harms ks cps = sum $ zipWith f ks (fmap (sig . double) [1 .. ])+    where f k n = k * osc (n * cps)++main = vdac $ do+    -- Let's create a list of coefficients.+    (g, ks) <- sliderBank "Harmonics"  (1 : replicate 13 0)+    (gv, v) <- masterVolume+    -- A simple instrument that plays a harmonic series+    -- with the given coefficients.+    let instr = onMsg $ harms ks+    -- Places elements on window with vertical alignment.+    panel $ ver [g, sca 0.1 gv]+    -- Let's trigger the instrument with midi controller.+    return $ vol * midi instr+
+ examples/Gui/Key.hs view
@@ -0,0 +1,22 @@+-- | Keyboard events+module Main where++import Csound.Base++main = dac $ do     +    -- Creates a window that listens to keyboard events when in focus.+    keyPanel =<< box "hi"+    +    -- a pure tone instrument that plays a single frequency+    let instr x = const $ return $ osc x+    -- triggers the instrument with frequency on the give event stream+    -- and holds the note wile second stream is silent.+        asig cps evtOn evtOff = schedUntil (instr cps) evtOn evtOff+    +    return $ mean +        [ asig 330 (charOn 's') (charOff 's') +        , asig 440 (charOn 'a') (charOff 'a') ]+  +-- Due to inner limitation only one keyboard event can be +-- registered at one control cycle. So if you press +-- the two buttons at the same time only one event will be registered.
+ examples/Gui/Osc.hs view
@@ -0,0 +1,64 @@+-- | Simulates a moog-like oscillators.+-- We create a waveform from the sum of the three oscillators.+module Osc where++import Csound.Base+import Control.Monad++-- An oscillator+data OscInit = OscInit +    { oscInitVol   :: Double    -- volume+    , oscInitRange :: Int       -- integer scale for the frequency+    , oscInitWave  :: Int }     -- the waveform identifier+                                -- (0 - osc, 1 - triangle, 2 - square, 3 - saw)++-- A single moog oscillator.+-- It takes a title and initial values. Produces the waveform function.+moogOsc1 :: String -> OscInit -> Source (Sig -> Sig)+moogOsc1 name (OscInit initVol initRange initWave) = source $ do+    -- Creates a widget to chose between four classic waveforms+    (gf, f) <- classicWaves "" initWave+    +    -- A knob for a volume of the oscillator+    (gvol, vol) <- knob "vol" uspan initVol ++    -- A knob for a range of the oscillator (scaling of the frequency)+    -- It's the number of the harmonic.+    (grange, range) <- knob "range" (linSpan 1 10) (fromIntegral initRange)++    -- Creates a gui element with the given title and horizontal placement.+    gui <- setTitle name $ hor [setMaterial NoPlastic $ gf, gvol, grange]++    -- Creates a waveform+    let instr cps = vol * f (floor' range * cps) +    return (gui, instr)++-- A list of moog oscillators.+moogOscs :: [OscInit] -> Source (Sig -> Sig)+moogOscs xs = source $ do+    -- Creates a list of single moog oscillators+    (gfs, fs) <- fmap unzip $ zipWithM +        (\n initVal -> moogOsc1 ("osc" ++ show n) initVal) [1 ..] xs ++    -- The final waveform is the sum of all oscillators+    let instr cps = sum $ fmap ($ cps) fs +    -- Alligns all elements vertically+    let gui = ver gfs++    -- Creates a source widget.+    return (gui, instr)++main = vdac $ do+    -- Let's create a stack of three oscillators:+    (g, f) <- moogOscs [(OscInit 1 1 0), (OscInit 0.2 1 1), (OscInit 0 1 2)]+    -- Creates a master volume slider.+    (gvol, vol) <- masterVolume +    -- Creates an amplitude envelope (see Envelope.hs).+    (genv, env) <- linAdsr "amplitude envelope" (AdsrBound 3 3 5) (AdsrInit 0.1 0.5 0.5 0.5) +    +    -- Places all elements on window with given title and sizes.+    panelBy "" (Just $ Rect 50 50 600 600) (hor [ver [sca 0.25 genv, g], sca 0.1 gvol])++    -- Triggers the instrument with midi controller.+    return $ midi $ onMsg (mul (vol * env) . f)+
+ examples/Gui/Waves.hs view
@@ -0,0 +1,23 @@+-- | Plays standard waveforms: pure tone, triangle, square and sawtooth.+module Waves where++import Csound.Base++main = vdac $ do+    -- Creates a master volume slider.+    (gvol, vol) <- masterVolume++    -- We use a standard element to experiment with four classic waveforms.+    -- The return value of the widget is a function that takes a frequency+    -- and returns the signal.+    (gw, f) <- classicWaves "waves" 0++    -- Let's create a simple instrument that uses the waveform.+    let instr x = fades 0.1 0.1 * f x++    -- Places elements on window aligned horizontally.+    panel $ hor [sca 0.1 gvol, gw]++    -- Triggers the instrument with midi keyboard.+    return $ mul vol $ midi $ onMsg instr+
− examples/Guis.hs
@@ -1,61 +0,0 @@--- | Test for GUI-elements. Right now this example is a total mess and shouldn't work.--- see you in the next version...-module Main where--import qualified Data.Colour.Names as C--import Control.Applicative--import Csound.Base---unit = ValSpan (ValDiap 0 1) Linear--linenWidget :: Source Sig-linenWidget = do-    (g1, r1) <- slider unit 0.5-    (g2, r2) <- slider unit 0.5-    let out = liftA2 fun r1 r2        -    source (ver [g1, g2]) out-    where fun a b = linseg [0, a', 1, idur - a' - b', 1, b', 0]-                where a' = idur * ir a-                      b' = idur * ir b  --instr :: SE Sig -> D -> SE Sig-instr env cps = do-    e <- env-    return $ 0.5 * e * osc (sig cps)--pureTone () = 0.7 * osc 440 -    -u = fmap (props [SetSliderType Fill] . fst) $ slider unit 0.5-v = fmap fst $ knob unit 0.5-r = fmap fst $ roller unit 0.001 0.01-c1 = fmap fst $ count (ValDiap 0 10) 1 Nothing 2-c2 = fmap fst $ count (ValDiap 0 10) 1 (Just 2) 4-b = fmap (setLabel "push me" . fst) button-bb = fmap fst $ butBank 5 3-tb = fmap (setLabel "i'm the toggle" . fst) toggle -j = fmap fst $ joy unit unit (0.2, 0.2)--d = fmap (setBoxType BorderBox) $ box $ t ++ t ++ t-    where t = " Hello everybody, let's look at some cool text in the box "--f = setColors C.green C.magenta--main = dac $ do-    g1 <- u-    g2 <- u-    g3 <- u-    g4 <- r-    g5 <- c1 -    g6 <- c2-    g7 <- b-    g8 <- bb-    g9 <- d-    g10 <- j-    g11 <- tb--    let g = setTextColor C.azure $ hor [sca 3 $ sca 1.5 $ f $ ver [setLabel "Amplitude" g1, setLabel "Frequency" g2, hor [g5, g6]], setBorder ThinDown $ ver [g7, setTextColor C.azure $ ver [f $ setTextColor C.blue $ setButtonType RoundButton g11], sca 2 space ]]-   -    panel (ver [sca 4 g, hor [g7, g7]])
examples/Wind.hs view
@@ -68,5 +68,5 @@     ]  -- | Let's repeat everything 10 times and add the sustain for 2 seconds per note.-main = totem $ mix $ sustain 2 $ loop 3 windRes+main = dac $ mix $ sustain 2 $ loop 3 windRes 
src/Csound/Air.hs view
@@ -6,7 +6,7 @@     osc, oscBy, saw, isaw, pulse, sqr, tri, blosc,      -- ** Unipolar-    unipolar, bipolar, uosc, uoscBy, usaw, uisaw, upulse, usqr, utri, ublosc,+    unipolar, bipolar, on, uon, uosc, uoscBy, usaw, uisaw, upulse, usqr, utri, ublosc,      -- * Envelopes @@ -32,12 +32,21 @@     -- | Applies filter and balances the output by the input signal.     lpb, hpb, bpb, brb, blpb, bhpb, bbpb, bbrb, +    -- ** Specific filters+    mlp,+     -- * Patterns     mean, vibrate, randomPitch, chorus, resons, resonsBy, modes, dryWet,          -- ** List functions     odds, evens, +    -- * Widgets+    AdsrBound(..), AdsrInit(..),+    linAdsr, expAdsr, +    classicWaves,+    masterVolume, masterVolumeKnob,+     -- * Other     reverbsc1 @@ -47,7 +56,9 @@ import Data.Boolean  import Csound.Typed-import Csound.Typed.Opcode+import Csound.Typed.Opcode hiding (display)+import Csound.Typed.Gui+import Csound.Control.Gui(funnyRadio)  import Csound.Tab(sine) @@ -104,6 +115,20 @@ ublosc :: Tab -> Sig -> Sig ublosc tb = unipolar . blosc tb +-- rescaling++-- | Rescaling of the bipolar signal (-1, 1) -> (a, b)+-- +-- > on a b biSig+on :: Sig -> Sig -> Sig -> Sig+on a b x = uon a b $ unipolar x ++-- | Rescaling of the unipolar signal (0, 1) -> (a, b)+-- +-- > on a b uniSig+uon :: Sig -> Sig -> Sig -> Sig+uon a b x = a + (b - a) * x+ -------------------------------------------------------------------------- -- envelopes @@ -284,6 +309,12 @@ bbrb :: Sig -> Sig -> Sig -> Sig bbrb = balance2 bbr +-- | Moog's low-pass filter.+--+-- > mlp centerFrequency qResonance signal+mlp :: Sig -> Sig -> Sig -> Sig+mlp cf q asig = moogladder asig cf q+ -------------------------------------------------------------------------- -- patterns @@ -441,4 +472,57 @@ reverbsc1 :: Sig -> Sig -> Sig -> Sig reverbsc1 x k co = 0.5 * (a + b)     where (a, b) = ar2 $ reverbsc x x k co+++----------------------------------------------------------------------+-- Widgets++data AdsrBound = AdsrBound+    { attBound  :: Double+    , decBound  :: Double+    , relBound  :: Double }++data AdsrInit = AdsrInit+    { attInit   :: Double+    , decInit   :: Double+    , susInit   :: Double+    , relInit   :: Double }++expEps :: Fractional a => a+expEps = 0.00001++linAdsr :: String -> AdsrBound -> AdsrInit -> Source Sig+linAdsr = genAdsr $ \a d s r -> linsegr [0, a, 1, d, s] r 0++expAdsr :: String -> AdsrBound -> AdsrInit -> Source Sig+expAdsr = genAdsr $ \a d s r -> expsegr [double expEps, a, 1, d, s] r (double expEps)++genAdsr :: (D -> D -> D -> D -> Sig)+    -> String -> AdsrBound -> AdsrInit -> Source Sig+genAdsr mkAdsr name b inits = source $ do+    (gatt, att) <- knob "A" (linSpan expEps $ attBound b) (attInit inits)+    (gdec, dec) <- knob "D" (linSpan expEps $ decBound b) (decInit inits)+    (gsus, sus) <- knob "S" (linSpan expEps 1)       (susInit inits) +    (grel, rel) <- knob "R" (linSpan expEps $ relBound b) (relInit inits)+    let val   = mkAdsr (ir att) (ir dec) (ir sus) (ir rel)+    gui <- setTitle name $ hor [gatt, gdec, gsus, grel]+    return (gui, val)++-- | A widget with four standard waveforms: pure tone, triangle, square and sawtooth.+-- The last parameter is a default waveform (it's set at init time).+classicWaves :: String -> Int -> Source (Sig -> Sig)+classicWaves name initVal = funnyRadio name +    [ ("osc", osc)+    , ("tri", tri)+    , ("sqr", sqr)+    , ("saw", saw)]+    initVal++-- | Slider for master volume+masterVolume :: Source Sig+masterVolume = slider "master" uspan 0.5++-- | Knob for master volume+masterVolumeKnob :: Source Sig+masterVolumeKnob = knob "master" uspan 0.5 
src/Csound/Base.hs view
@@ -35,5 +35,5 @@ import Data.Default import Data.Monoid     -import Csound.Typed.Opcode+import Csound.Typed.Opcode hiding (button, display, space) 
src/Csound/Control.hs view
@@ -9,11 +9,15 @@     module Csound.Control.Evt,     -- * Instruments     -- | Invoking the instruments-    module Csound.Control.Instr+    module Csound.Control.Instr,+    -- * Gui+    -- | Interactive controllers+    module Csound.Control.Gui ) where  import Csound.Control.SE         import Csound.Control.Evt import Csound.Control.Instr+import Csound.Control.Gui  
src/Csound/Control/Evt.hs view
@@ -5,13 +5,14 @@     -- * Core functions     boolToEvt, evtToBool, sigToEvt, stepper,     filterE, filterSE, accumSE, accumE, filterAccumE, filterAccumSE,-    Snap, snapshot, snaps,++    Snap, snapshot, snaps, sync, syncBpm,           -- * Opcodes     metroE, changedE, triggerE,       -- * Higher-level event functions-    cycleE, iterateE, repeatE, appendE, mappendE,+    cycleE, iterateE, repeatE, appendE, mappendE, partitionE, splitToggle,     oneOf, freqOf, freqAccum,      randDs, randInts, randSkip, randSkipBy,      range, listAt,   @@ -19,23 +20,39 @@ ) where  import Data.Monoid-+import Data.Default import Data.Boolean+import Data.Tuple  import Csound.Typed import Csound.Typed.Opcode  -- | Behaves like 'Csound.Opcode.Basic.metro', but returns an event stream.-metroE :: Sig -> Evt ()+metroE :: Sig -> Evt Unit  metroE = sigToEvt . metro  -- | Behaves like 'Csound.Opcode.Basic.changed', but returns an event stream.-changedE :: [Sig] -> Evt ()+changedE :: [Sig] ->  Evt Unit changedE = sigToEvt . changed  -- | Behaves like 'Csound.Opcode.Basic.trigger', but returns an event stream.-triggerE :: Sig -> Sig -> Sig -> Evt ()+triggerE :: Sig -> Sig -> Sig -> Evt Unit  triggerE a1 a2 a3 = sigToEvt $ trigger a1 a2 a3++-- | the sync function but time is measured in beats per minute.+syncBpm :: (Default a, Tuple a) => D -> Evt a -> Evt a+syncBpm dt = sync (dt / 60)++-- | Splits event stream on two streams with predicate.+partitionE :: (a -> BoolD) -> Evt a -> (Evt a, Evt a)+partitionE p evts = (a, b)+    where +        a = filterE p          evts+        b = filterE (notB . p) evts++-- | Splits a toggle event stream on on-events and off-events.+splitToggle :: Evt D -> (Evt D, Evt D)+splitToggle = swap . partitionE (==* 0)  ---------------------------------------------------------------------- -- higher level evt-funs
+ src/Csound/Control/Gui.hs view
@@ -0,0 +1,70 @@+-- | 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. +--+-- A GUI element consists of two parts. They are view (how it looks)+-- and logic (what's going on with it). For example a slider can be+-- horizontal or vertical or green or yellow or small or big. It's the view +-- of the slider. And a slider can produce a continuous signal within the +-- given interval. It's a logic of the slider. +--+-- Let's talk about the view. The view is divided on two parts:+--+-- * where element is placed or Layout. +--+-- * all other  properties or just Properties. +--+-- The layout is defined with very simple functions. There are vertical and horizontal grouping +-- of the elements. We can scale the element within the group and include an empty+-- space in the group. Everything is aligned (see "Csound.Gui.Layout"). +-- Other properties include colors, fonts (size and type), borders, specific properties +-- of the widgets (see "Csound.Gui.Props").+--+-- Let's consider the logic. The logic consists of three parts:+--+-- * what is consumed ('Csound.Gui.Output')+--+-- * what is produced ('Csound.Gui.Input')+--+-- * what's going on inside ('Csound.Gui.Inner')+--+-- A widget can react on values, produce values or do something useful. +-- There are special types of widgets:+--+-- * 'Csound.Gui.Source'  - they produce values only+--+-- * 'Csound.Gui.Sink'    - they consume values only+--+-- * 'Csound.Gui.Display' - something is going on inside them (for example, it can show a "hello world" message)+-- +--+-- Widgets can be simple and compound. Simple widgets are primitive elements+-- (sliders, knobs, rollers, buttons). We have a special constructors that +-- produce simple widgets (see "Csound.Gui.Widget"). Compound widgets glue together+-- several widgets. That is the view contains several elements and all of them +-- involved in the logic of the widget.+--+--+module Csound.Control.Gui (+    -- * Gui+    Gui, +    Widget, Input, Output, Inner,+    Sink, Source, Display,+    widget, sink, source, display,+    +    -- * Panels+    panel, panels, panelBy,+    keyPanel, keyPanels, keyPanelBy,++    -- * Re-exports+    module Csound.Control.Gui.Layout,+    module Csound.Control.Gui.Props,+    module Csound.Control.Gui.Widget+) where++import Csound.Typed.Gui++import Csound.Control.Gui.Layout+import Csound.Control.Gui.Props+import Csound.Control.Gui.Widget+
+ src/Csound/Control/Gui/Layout.hs view
@@ -0,0 +1,18 @@+-- | The functions from this module specify the geometry +-- of the GUI-elements. They tell where to render the elements.+--+-- Every element is rectangular. To know where to place the element is +-- to know the parameters of the bounding rectangle. All rectangles are+-- relative and automatically aligned. +--+-- We have two functions for grouping. They construct horizontal and vertical+-- groups of the elements. Within the group we can change the relative size +-- of the rectangles (by scaling one side of the rectangle). In place of rectangle+-- we can put an empty space. +module Csound.Control.Gui.Layout (+    hor, ver, space, sca, horSca, verSca, +    padding, margin+) where++import Csound.Typed.Gui+
+ src/Csound/Control/Gui/Props.hs view
@@ -0,0 +1,22 @@+-- | Properties that specify the appearance of the GUI elements. +-- The specification is inspired by CSS. All properties+-- are set in the cascade manner. For example, if you want to change the font type+-- for all elements you should set this property only for the top-most GUI element.+-- If the property is set on the lower level it wins versus property that is set on the +-- higher level. +module Csound.Control.Gui.Props (+    -- * Properties+    props, forceProps,+    Prop(..), BorderType(..), Color,+    Rect(..), FontType(..), Emphasis(..), +    Material(..), Orient(..), ++    -- * Setters+    -- | Handy short-cuts for the function @props@.+    setBorder, setLabel, setMaterial, +    setColor1, setColor2, setColors, setTextColor,+    setFontSize, setFontType, setEmphasis, setOrient+) where++import Csound.Typed.Gui+
+ src/Csound/Control/Gui/Widget.hs view
@@ -0,0 +1,100 @@+-- | Primitive GUI elements.+--+-- There is a convention that constructors take only parameters that +-- specify the logic of the widget. The view is set for GUI-elements with +-- other functions.+module Csound.Control.Gui.Widget (+    -- * Common properties +    ValDiap(..), ValStep, ValScaleType(..), ValSpan(..),+    linSpan, expSpan, uspan, bspan, uspanExp,+    -- * Valuators+    count, countSig, joy, +    knob, KnobType(..), setKnobType,+    roller, +    slider, sliderBank, SliderType(..), setSliderType,+    numeric, TextType(..), setTextType,++    -- * Other widgets+    box, BoxType(..), setBoxType,+    button, ButtonType(..), setButtonType, +    toggle, butBank, toggleSig, butBankSig,+    butBank1, butBankSig1, +    radioButton, matrixButton, funnyRadio, funnyMatrix,+    value, meter,+    -- * Transformers+    setTitle,+    -- * Keyboard+    KeyEvt(..), Key(..), keyIn, charOn, charOff+) where++import Data.List(transpose)+import Data.Boolean++import Csound.Typed.Gui+import Csound.Typed.Types+import Csound.Control.Evt(listAt)++--------------------------------------------------------------------+-- aux widgets++readMatrix :: Int -> Int -> [a] -> [a]+readMatrix xn yn as = transp $ take (xn * yn) $ as ++ repeat (head as)+    where +        transp xs = concat $ transpose $ parts yn xn xs+        parts x y qs +            | x == 0    = []+            | otherwise = a : parts (x - 1) y b+            where (a, b) = splitAt y qs++-- | A radio button. It takes a list of values with labels.+radioButton :: Arg a => String -> [(String, a)] -> Int -> Source (Evt a)+radioButton title as initVal = source $ do+    (g, ind) <- butBank1 "" 1 (length as) (0, initVal)+    gnames   <- mapM box names+    let val = listAt vals ind    +    gui <- setTitle title $ padding 0 $ hor [sca 0.15 g, ver gnames]+    return (gui, val)+    where (names, vals) = unzip as++-- | A matrix of values.+matrixButton :: Arg a => String -> Int -> Int -> [a] -> (Int, Int) -> Source (Evt a)+matrixButton name xn yn vals initVal = source $ do+    (gui, ind) <- butBank1 name xn yn initVal+    let val = listAt allVals ind+    return (gui, val)+    where allVals = readMatrix xn yn vals++-- | Radio button that returns functions. Useful for picking a waveform or type of filter.+funnyRadio :: Tuple b => String -> [(String, a -> b)] -> Int -> Source (a -> b)+funnyRadio name as initVal = source $ do+    (gui, ind) <- radioButton name (zip names (fmap int [0 ..])) initVal+    contInd <- stepper (sig $ int initVal) $ fmap sig ind+    let instr x = guardedTuple (+                zipWith (\n f -> (contInd ==* (sig $ int n), f x)) [0 ..] funs+            ) (head funs x)+    return (gui, instr)+    where (names, funs) = unzip as++-- | Matrix of functional values.+funnyMatrix :: Tuple b => String -> Int -> Int -> [(a -> b)] -> (Int, Int) -> Source (a -> b)+funnyMatrix name xn yn funs initVal@(x0, y0) = source $ do+    (gui, ind) <- butBank1 name xn yn initVal+    contInd <- stepper flattenInitVal $ fmap sig ind+    let instr x = guardedTuple (+                zipWith (\n f -> (contInd ==* (sig $ int n), f x)) [0 ..] allFuns+            ) (head allFuns x)+    return (gui, instr)+    where +        allFuns = readMatrix xn yn funs+        flattenInitVal = sig $ int $ y0 + x0 * yn+++-- | Shortcut for press 'CharKey' events.+charOn :: Char -> Evt Unit+charOn  = keyIn . Press   . CharKey++-- | Shortcut for release 'CharKey' events.+charOff :: Char -> Evt Unit+charOff = keyIn . Release . CharKey++
src/Csound/Control/Instr.hs view
@@ -83,8 +83,8 @@     cpsmidi, ampmidi,      -- * Evt            -    trig, sched, schedHarp,-    trig_, sched_, +    trig, sched, schedHarp, schedUntil, schedToggle,+    trig_, sched_, schedUntil_,      trigBy, schedBy, schedHarpBy,     withDur, @@ -97,7 +97,7 @@ import Csound.Typed.Opcode import Csound.Control.Overload -import Csound.Control.Evt(metroE, repeatE)+import Csound.Control.Evt(metroE, repeatE, splitToggle)  -------------------------------------------------------------------------- -- midi@@ -129,4 +129,32 @@         dur   = double $ csdEventListDur notes          instr _ = mix_ notes+++-- | Invokes an instrument with first event stream and +-- holds the note until the second event stream is active.+schedUntil :: (Arg a, Sigs b) => (a -> SE b) -> Evt a -> Evt c -> b+schedUntil instr onEvt offEvt = sched instr' $ withDur (-1) onEvt+    where +        instr' x = do +            res <- instr x+            runEvt offEvt $ const $ turnoff+            return res++-- | Invokes an instrument with toggle event stream (1 stands for on and 0 stands for off).+schedToggle :: (Sigs b) => SE b -> Evt D -> b+schedToggle res evt = schedUntil instr on off+    where +        instr = const res+        (on, off) = splitToggle evt++-- | Invokes an instrument with first event stream and +-- holds the note until the second event stream is active.+schedUntil_ :: (Arg a) => (a -> SE ()) -> Evt a -> Evt c -> SE ()+schedUntil_ instr onEvt offEvt = sched_ instr' $ withDur (-1) onEvt+    where +        instr' x = do +            res <- instr x+            runEvt offEvt $ const $ turnoff+            return res