A brief Introduction to Csound
Csound is a sound and music computing system which was originally developed by Barry Vercoe in 1985 at MIT Media Lab. Since the 90s, it has been developed by a group of core developers. A wider community of volunteers contribute examples, documentation, articles, and takes part in the Csound development with bug reports, feature requests and discussions with the core development team.
The Csound language is in the MUSIC N lineage of acoustic compilers developed by Max Mathews and colleagues at MIT in the 1960s. These compilers connect together low-level operational building blocks, called opcodes. The Csound language is compiled into an efficient set of signal-processing operations that are then performed by its audio engine. With over a 1300 such opcodes available to the programmer, Csound is a complete and very mature sound-synthesis language. But don’t let its historical importance fool you: it is still being actively developed and extended, making it a compilation and real-time performance tool that is arguably unrivalled in the breadth of its sound generation and processing capabilities.
the Csound compiler can be run
- From the command line, in which case the configurations of the signal processing operations and their controls are read from text files–often .csd, .orc and/or .sco files
- From its various frontends, many available through the csounds.com website.
- Through a high-level Csound Application Programming Interface (API) interface. We use the API through the Python language.
Although Csound has a strong tradition as a tool for composing electroacoustic pieces, it is used by composers, musicians and sound designers for any kind sound that can be made with the help of the computer. Csound has traditionally being used in a non-interactive score-driven context, but nowadays it is mostly used in in a real-time context. It can run on a host of different platforms including all major operating systems, Android and iOS as well as is a web browser. Csound can also be called through other programming languages such as Python, Lua, C/C++, Java, etc.
A basic overview of the Csound language
Instruments
The basic structuring unit in Csound is the instrument. This is used to hold a series of operators called unit generators that are defined in the Csound language by combinations of various opcodes. An instrument is a model of a sound-processing/generating object that Csound will instantiate any number of times necessary, according to the demands of a score. Here is an example of a very simple instrument definition as coded in a .csd file:
<CsoundSynthesizer>
<CsOptions>
-odac ; write output to built-in DAC
;-Wo "testy.wav" ; write output to file
</CsOptions>
<CsInstruments>
sr=48000 ; sampling rate
ksmps=32 ; number of samples in a audio processing buffer
nchnls=2 ; 2 output channels
0dbfs=1 ; set the maximum db value without distortion to 1
instr 1 ; the beginning the definition of an instrument
iamp = 0.5 ; line 2
icps = 440 ; line 3
asig oscili iamp, icps ; line 4
aout vco2 0.5, 220 ; line 5
;out(asig+aout)
outs asig, aout
endin ; the end of the definition of an instrument 1
</CsInstruments>
<CsScore>
i1 0 1 1 0.2 205
i1 0.75 0.5 0.3 500
i1 1.25 0.5 0.4 700
e
</CsScore]
</CsoundSynthesizer>
link to download this and other examples
Variable types
Csound has a number of variable types. These define not only the data content, but also the action time. When an instrument is run, there are two distinct action times:
- Initialisation time, a single pass through the code which is used to initialize variables and unit generators, and to execute code that is designed to run once per instance.
- Performance time, when instruments process signals, looping over the unit generator code. Performance time has three different time “frames”:
- Instance init time (i-time)
- control time (k-time)
- audio (sample))a-time) time..
In the example, the oscillator is allocated and its initialization routine is executed. At perf time, it produces the audio signal that is sent to the output.Signals can be of two types:
- Scalars, used for control operations (e.g. parameter automation)
- Vectors, for audio
Action times and the two types of signals yield three basic variable types, defined by the first letter of the variable names:
variable type | action time | data format |
i - instance, | init | scalar |
k - kontrol | performance | scalar |
a - audio | audio samples | vector |
Lines 2 and 3 in the above example will execute (once) at i-time, followed by the initialization of the oscillator (line 3).
At performance time, line 4 and 5 run in a loop for the required duration, filling and consuming audio signal vectors asig and aout and last lines will be run in a loop for the requested duration, filling and consuming audio signal vectors. The size of these vectors is determined by the system constant ksmps and defaults to 10. The sampling rate is also set by the constant sr and its default value is 44,100. A third quantity, the control rate (kr) is set to sr/ksamps, determining how often each control (scalar) variable is updated. This also determines the processing loop period (how often the processing code is repeated).
The scope of variables is local to a single instrument. Global variables for communicating variables, including audio buffers, can be created by attaching a ‘g’ to the start of the variable name (e.g. gi1, gkNew, or gasig).
Parameter Numbers
Instruments can contain external initialization arguments. These are identified by parameter numbers p1...pN.
The first three are set by default to
- p1 The instrument number,
- p2 The start time
- p3 The duration (in seconds, with −1 indicating indefinite duration).
The following arguments can be freely used by instruments. For instance:
instr 1
iamp = p4
icps = p5
asig = oscili, iamp, icps
out (asig)
endin
Control variables are used to make parameters change over time. For instance, we could use a trapezoidal envelope generator (linen) to shape the amplitude of our example instrument, cutting out the clicks at the beginning and end of sounds:
instr 1
idur = p3
endin
iamp = p4
icps = p5
ksig = linen iamp,0.1,idur,0.2
asig = oscili ksig, icps
out(asig)
With these three basic types, it is possible to start doing signal processing with Csound.
link to download examples
The Python Csound The API (ctcsound.py)
The Csound API provides complete access to the system, from configuration to code compilation and audio engine performance. It is based on a C/C++ set of functions and classes, but it has been wrapped for various languages. In the case of Python, there are two alternative packages that can be used, csnd6 and ctcsound. The former is only available for Python 2 and the latter can be used in both versions 2 and 3.
The ctcsound package/module provides full access to the Csound C API, in addition to a few extra components. It can be loaded with the command:
>>>import ctcsound
The ct refers to the fact that it is made with the python module ctypes. A typical use of the package involves the following steps:
- Creating a Csound object
- Setting up options to control the compiler and engine
- Compiling code
- Starting and running the audio engine
- Interacting with the compiled instruments
For example, the following code creates a Csound object, sets it to output audio to the soundcard, compiles some code and performs it:
code = '''
instr 1
endin
idur = p3
iamp = p4
icps = p5
ksig = linen(iamp,0.1,idur,0.2)
asig = oscili(ksig, icps)
out(asig)
schedule(1,0,1,0dbfs/3,440)
schedule(1,1,1,0dbfs/3, 550)
schedule(1,2,1,0dbfs/3, 660)
'''
cs = ctcsound.Csound()
cs.setOption('-odac')
cs.compileOrc(code)
cs.start()
cs.perform()
When running the Csound engine, it is often simpler to start a new thread for performance, so that the user can interact with it. For this purpose, we have the CsoundPerformanceThread class, which takes a Csound object and allows it to be played:
cs = ctcsound.Csound()
cs.setOption ('-odac')
cs.compileOrc (code)
cs.start()
perf = ctcsound.
CsoundPerformanceThread(cs.csound())
perf.play()
Methods for pausing, stopping and joining the thread are available (pause(), stop(), and join()). With Csound running in a separate thread, we can start new instruments running and set controls in them using methods of the Csound class. Both of the above examples (with and without threads) can be used to run the Csound code examples in this book, with Python as the host environment. In this case all we need to do is to replace the triple-quoted string in code by the program in question. We might also need to set other options, which we can do by calling setOption() more than once with the option as an argument.
Principle references
link to download examples
Csounds website: http://csounds.com/
Some Csound manuals:
- The Canonical Csound Reference Manual - cSounds.com
(all in one page - good for online searching/exploring. NB all opcode entries have csound code examples at the end of the page) - Some download versions: www.csounds.com/manual/
- Csound FLOSS manual: write.flossmanuals.net/csound/preface/
The most comprehensive ctcsound manual is accessed through the python help function
>>> help (ctcsound)
and the various class objects:
>>> help (ctcsound.Csound())
etc or read the module file ctcsound .py