Library csound-expression allows csound code construction in functional way.
This module provides overview of the library.
For examples see sources, folder
- module CsoundExpr.Base
Csound-expression is csound code generator. Program
produces value of
Show. So that is the way to get csound code.
csd can be invoked to make value of
csd :: Flags -> Header -> EventList Dur SignalOut -> CsoundFile
String. It's pasted in place of csounds flags.
Headeris csound header declaration. See module CsoundExpr.Base.Header for more details.
EventListrepresents csound orchestra and score sections. This type comes from external library 'temporal-media' .
EventListcontains values with time marks. Value begins at some time and lasts for some time. Very much like csound notes, but there is one difference no need for p-field parameters, translator derives them from note structure encoded in values of type
EventListcan be constructed directly with functions of 'temporal-media' library, but better way is to use some front-end. Package 'temporal-music-notation'  provides higher level musical functionality for
Instruments are functions from some signal representation to signal.
Score (from 'temporal-music-notation' library) or
EventList (from 'temporal-media' library) is a
so to play on instrument means to apply instrument.
to container of its notes. Instrument can be made with opcodes.
Translator derives p-fields from instrument structure. There are only
two explicit p-fields
p3 in csound).
Signals / Types
Signals are represented with trees. Tree contains information about how signal was build.
There are five types for signals (CsoundExpr.Base.Types).
Arate is audio rate signal
Krate is control rate signal
Irate is init value
SignalOut is no output at all (it's produced by opcodes
like out, outs, xtratim)
There are two special types
(for opcodes that may produce several outputs,
(for opcodes that rely on number of appearances in csound code,
unirand, see CsoundExpr.Base.SideEffect)
Naming conventions : Opcodes are named after csound's counterparts usually. Some opcodes in csound can produce signals of different rates by request (oscil, linseg). Those opcodes are labelled with suffix. Suffix defines output rate of signal (oscilA, oscilK). Some opcodes in csound have unfixed number of inputs due to setup parameters, almost all of them. Those opcodes have first argument that is list of setup parameters.
oscilA :: (X a, X b) => [Irate] -> a -> b -> Irate -> Arate oscilK :: (K a, K b) => [Irate] -> a -> b -> Irate -> Krate
Imperative style csound code
Most of csound opcodes can be used in functional way. You can plug them in one another, and make expressions, but some of them behave like procedures and rely on order of execution in instrument. Module CsoundExpr.Base.Imperative provides functions to write imperative csound code.
outList - to sequence procedures
'(<=>)' - Assignment
Functional style :
exmpInstr :: Irate -> SignalOut exmpInstr pch = out $ oscilA  (num 1000) (cpspch pch) $ gen10 4096 
Imperative style :
exmpImper :: Irate -> SignalOut exmpImper pch = outList [ ir "amp" <=> num 1000, ir "cps" <=> cpspch pch, ir "ft" <=> gen10 4096 , ar "sig" <=> oscilA  (ir "amp") (ir "cps") (ir "ft"), out (ar "sig")]
User Defined opcodes
You can add your own opcodes to library, see CsoundExpr.Base.UserDefined
There are two ways to tell
csd to include instrument
in csound file. Instrument can be a part of
it can be midi instrument, then it should be mentioned
pgmassign function. If you want to
play midi-instr for some time
t, you can tell it
csd function by invoking
(toList $ ('temporal-music-notation')
in place of
f 0 n is always present in generated .csd file.
n is score's duration.
import Temporal.Music import CsoundExpr import CsoundExpr.Opcodes flags = "-odac -d -+rtmidi=virtual -M0" header = [massign  1 instrMidi] instrMidi :: SignalOut instrMidi = out $ oscilA  (num 5000) cpsmidi $ gen10 4096  res = csd flags header (rest 3600) -- play: requires tmp folder in current directory main = do playDac "tmp" "new" res
What can not be expressed
The major benefit and major problem of csound-expression is abscense of ids for p-fields, ftables, notes and instruments.
no ids for ... means ... no
p-fields/notes - opcodes that rely on p-fields or invoke instruments
ftables - k-rate ftables
instruments - convenient way to specify order of instruments
imperative program flow control
There is no program flow control opcodes (like if, then, goto). But you can use functional if/then from module CsoundExpr.Base.Boolean
I've decided to represent csound's S-rate with
Signal is represented with tree and it means i can't include
opcodes that produce Srate
Hack-way around (what somehow can be expressed)
Orchestra section is generated from
EventList. Different instruments
have different tree structure and one instrument's tree can't be
transformed into another one by replacing leaf-values only.
You can point to instrument by its structure. There is opcode in
CsoundExpr.Base.Header that specifies order of instruments by
list of notes.
instrOrder takes in list of notes, if instrument's
tree is equivalent to note it is placed in relation to list of notes.
There are ways to make mistake. Sometimes it's unpredictable.
In example below
q1 =/= q2
sco contains two instruments (one with
x, and another
osc x = oscilA  (num 1000) x $ gen10 4096  env = lineK 1 idur 0 q1 x = osc x <*> env q2 x = env <*> osc x sco1 = note 1 440 sco2 = note 1 $ cpspch 8.00 sco = fmap q1 $ sco1 +:+ sco2
I think maybe it's worthwhile to introduce some way of instrument id assignment.