Since the version 4.2.0 there are many widgets tageted at real-time performance. They should make it easy to mix and process audio live.
It's assumed that the library csound-sampler is installed.
We can start and stop samples with function sim.
module Main where
import Csound.Base
import Csound.Sam
a1 = infSig1 $ osc 220
a2 = infSig1 $ osc 330
main = dac $ mul 0.5 $ lift1 (runSam 120) $ sim 4 [("220", a1), ("330", a2)]~~~For simplicity we use pure sine waves but we can use samples with cool sounds instead.
The first argument for sim (it's 4 in the example above)
is responsible for syncronization. The samples are started only
on every n'th beat.
we can toggle between samples with the function tog.
The example is the same but write tog in place of sim.
With tog only one sample is going to be played.
The widget live resembles the session view of the Ableton.
the samples are arranged in matrix. We can start all samples
in the row by the single click of the mouse and we can toggle samples
within each column. Let's look at the example:
module Main where
import Csound.Base
import Csound.Sam
b1 = infSig1 $ sqr 220
b2 = infSig1 $ sqr 330
b3 = infSig1 $ sqr 440
c1 = infSig1 $ tri 220
c2 = infSig1 $ tri 330
c3 = infSig1 $ tri 440
main = dac $ mul 0.3 $ lift1 (runSam 120) $
live 4 ["triangle", "square"]
[ c1, b1
, c2, b3
, c3, b3]the function live takes in the number of beats for syncronization,
the names for columns and the list of samples. The number of columns
in the matrix is defined with the length of list of the column names.
We can mix several stereo signals together with the widget mixer.
mixer :: Sigs a => [(String, SE a)] -> Source aMixer takes in the list of pairs. The first element of the pair is the name of the instrument and the second element is the actual signal.
Let's balance the sound of the chord:
main = dac $ do
(g, res) <- mixer $ fmap (\x -> mixMono (show x) (osc $ sig $ int x)) [220, 330, 440]
win "mixer" (600, 300) g
return $ mul 0.5 $ resNote the function win. It constructs the window with the given name, size and content.
The function mixMono is usefull for mixing mono signals.
We can use mixer with functions sim and tog:
a1 = infSig1 $ osc 220
a2 = infSig1 $ osc 330
run = runSam 120
main = dac $ do
(g1, sam1) <- tog 4 [("220", a1), ("330", a2)]
(g2, sam2) <- sim 4 [("220", a1), ("330", a2)]
(g3, res) <- mixer [("tog", run sam1), ("sim", run sam2)]
win "main" (600, 400) $ ver [sca 0.6 $ hor [g1, g2], g3]
return resThere are many widgets to process stereo signals. The sound processing function is a function of the type:
type Fx = a -> SE aTo be truly interesting the sound processing function should depend on parameters which control the behavior of the effect:
Sigs a => Sig -> Sig -> ... -> Sig -> Fx aWe can create a visual representation of this type
with fxBox:
fxBox :: FxUI a => String -> ([Sig] -> Fx a) -> Bool -> [(String, Double)] -> Source (Fx a)
fxBox name fx isOn args = ...It expects the name of the widget, the sound processing function the flag that turns on the widget (is it active at the start time) and the list of arguments. The result contains the widget and fx-function. The FX-processing function takes in a list of signal arguments, each argument in the list is going to be represented with a slider. Names for the sliders are taken fron te last argument.
There are many predefined widgets that implement typical effects (reverbs, distortion, chorus, flanger etc).
module Main where
import Csound.Base
import Csound.Sam
main = dac $ do
(gui, fx) <- fxHor
[ uiFilter False 0.5 0.5 0.5
, uiChorus False 0.5 0.5 0.5 0.5
, uiPhaser False 0.5 0.5 0.5 0.5
, uiReverb True 0.5 0.5
, uiGain 0.5
]
win "main" (900, 300) gui
fx $ fromMono $ saw 110We can group the fx-widgets with functions fxHor, fxVer and fxSca.
They group widgets horizontaly, verticaly and scale the widgets.
There are many more widgets to consider you can find them in the modules
Csound.Air.Live and Csound.Air.Fx.FxBox.
Let's look at the types of the functions fxHor and fxVer to see what's going on:
fxHor, fxVer :: [Source (Fx a)] -> Source (Fx a)So with those functions we stuck the visual representations in the line and compose
the FX-functions in the list. Also there is a function fxGrid. We can create a matrix
of Fx-widgets with it:
fxGrid :: Int -> [Source (Fx a)] -> Source (Fx a)The first argument is a number of cells per row.