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