packages feed

csound-expression-3.1.0: examples/Gui/Osc.hs

-- | 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)