Csound is an open-source audio programming language for sound synthesis and music composition. Though its historical use score-driven, more recently it has been used for interactive audio in real-time contexts. Csound is one of the four main languages supported by Bela, thanks to the contributions of Bernt Isak Wærstad, Alex Hofmann, Victor Lazarini, and Bela developer Guilio Moro.
This page is adapted from a Bela and Csound tutorial written by Bernt Isak and Alex Hofmann, and provides an introduction to coding interactive Bela projects with Csound.
Table of contents
- What is Csound?
- Writing a Csound instrument
- Csound and Bela
- Projects made with Csound and Bela
What is Csound?
Csound is an open source audio software and programming language for sound synthesis and composition. It was developed by Barry Vercoe at MIT Media Lab in 1986, but its roots go all the way back to the Music III Software developed by Max Matthews in 1961.
Today Csound is developed by a group of core developers with a wider community of volunteers contributing. One of the main principles in Csound development is to guarantee backwards compatibility, meaning that Csound source files written decades ago will still run on the latest Csound release.
Although Csound has a strong tradition as a tool for composing electro-acoustic pieces and traditionally has been used in a non-interactive, score-driven context, nowadays it is mostly used in a real-time context. Csound can run on various different hardware and software platforms including all major operating systems, including Android and iOS. Csound can also be called through other programming languages such as Python, Lua, C/C++, Java, and is supported by the Bela platform.
Writing a Csound instrument
Csound documents are simple text documents starting with the XML type tag
<CsoundSynthesizer> and are then structured into 3 sections:
<CsoundSynthesizer> <CsOptions> </CsOptions> <CsInstruments> </CsInstruments> <CsScore> </CsScore> </CsoundSynthesizer>
The fun starts in the
<CsInstruments> section, where we start defining instruments (or setting up patches). An new instrument is defined between the
endin lines (see example below). Instruments are built by combining signal processing modules called opcodes. There are thousands of opcodes available for different kinds of oscillators, filters, envelopes, delays, reverbs, sample manipulation tools and so on. The Csound Reference Manual provides more information and examples for each available opcode.
A simple instrument
Here we will start right into writing a first simple instrument which uses a pink noise generator, a simple sine oscillator, two LFOs and an opcode for stereo panning. The output of an opcode is assigned to a variable; for example
aNoise is the holder for the audio signal generated by the
Csound has specific variable types for the data to hold. The first letter of a variable name sets the type: in this case,
aNoise expects an a-rate, or audio, signal. Other types you will often find are k-rate (control rate) signals (which are updated less frequently to save computing power), and i-rate signals, which can only be set once when the instrument is instantiated.
In the CsScore section instruments can be called by their name or number. In this case
instr 1 is called 4 times with different settings for p4 and p5. This is the most straight forward way to run instruments, although other options like triggering by MIDI events and triggering live-events from within other instruments is worth checking out.
<CsoundSynthesizer> <CsOptions> -odac -iadc </CsOptions> <CsInstruments> sr = 44100 ksmps = 8 nchnls = 2 0dbfs = 1.0 instr 1 aNoise pinker ; pink noise aSin poscil 0.4, p4 ; sine oscillator aLFO1 lfo 0.7, p5, 3 ; LFO - square (unipolar) aLFO2 lfo 0.7, .3, 2 ; LFO - square (bipolar) aSig = (aLFO1 * aNoise) + (aLFO2 * aSin) ; crazy mixing aSigL, aSigR pan2 aSig, aLFO1-aLFO2 ; insane panning outs aSigL, aSigR ; stereo output endin </CsInstruments> <CsScore> ;Ins St Dur sinFq lfoFq i1 0 2 250 2 i1 + 2 50 10 i1 + 2 1500 .5 i1 + 1 50 10 </CsScore> </CsoundSynthesizer>
Csound and Bela
Running Csound on Bela came from the COSMO-project (Csound On Stage: Music Operator), a project devoted to making hardware and software frameworks for making embedded, standalone Csound instruments to use on stage. The COSMO team originally worked with Raspberry Pis but this always required some custom hardware (to achieve better sound quality, acceptably low latency, and individual controller inputs). These music-specific hardware requirements are already present on Bela.
Csound is now fully supported in the Bela IDE. To create a new, blank Csoun project, go to the
Project Explorer tab, click
New project, and select
Csound as the project type. Then, give your project a name, and click
Bela inputs and outputs in Csound
To communicate with the analog channels on the Bela, we’ll use the Csound channel system.
The analog input channels are named
analogIn7, and analog output channels are
analogOut7. To read values, we use the chnget opcode, and to write values we’ll use the chnset opcode. (Note that these are a-rate channels, so a downsampling is needed if you want to use the input values as k-rate control signals.)
;------------------------------------------------------ ; Simple AM synth with analoge in and out ;------------------------------------------------------ instr 1 ; Analog in 0 controls carrier frequency aCarFreq chnget "analogIn0" aCarFreq = (aCarFreq * 1000) + 50 kCarFreq = k(aCarFreq) ; downsampling from a-rate to k-rate ; Analog in 1 controls modulator frequency aModFreq chnget "analogIn1" aModFreq *= 100 kModFreq = k(aModFreq) ; Analog in 2 controls modulator amount aAM_vol init 1 aAM_vol chnget "analogIn2" ; Modulator aMod oscil aAM_vol*0.5, kModFreq aMod += 0.5 ; Carrier with envelope kEnv adsr 0.1, 0, 0.8, 0.3 aCar poscil 0.8*kEnv, kCarFreq aOut = aCar * aMod ; Set LED to blink in time ; with modulation frequency chnset aMod, "analogOut0" outs aOut, aOut endin
Building a simple effect processor using the COSMO DSP Library
The cosmo-dsp repository is a library of ready-made audio effects, such as Reverb, Delay, Distortion, Filters and so on. All effects are set up as independent modules that can be combined to a custom setup of effects. To make it as plug and play as possible, all arguments are also normalized (0-1) and scaled properly inside the effect so that the user can use them immediately.
To use one of the readymade effects, you first need to download the file containing the desired effect, place it with your csd file and include it using an
The name and a quick explanation of the arguments can be found in the header of each
.udo file in the COSMO dsp-library (e.g.
Since all arguments are normalized, we can directly use the analogIn values to control the paramters of the effect. Here is a complete example of a Reverb effect where the dry/wet mix is controlled by a potentiometer connected to the first analog in of a Bela system:
<CsoundSynthesizer> <CsOptions> -m0d </CsOptions> <CsInstruments> ksmps = 16 0dbfs = 1 nchnls = 2 #include "../DSP-Library/Effects/Reverb.udo" instr 1 aL, aR ins aPot0 chnget "analogIn0" kMix = k(aPot0) ; Reverb arguments: decay, cutoff, mix aL, aR Reverb aL, aR, 0.9, 0.5, kMix outs aL, aR endin </CsInstruments> <CsScore> i1 0 86400 </CsScore> </CsoundSynthesizer>
The same approach applies to any of the other effects found at https://github.com/cosmoproject/cosmo-dsp/tree/master/DSP-Library/Effects. What’s more, you can combine them in any order.
Building a MIDI controlled synthesizer
One advantage of Csound is that it’s really quick to write a MIDI synthesizer. This comes in very handy in combination with Bela - just connect any class-compliant MIDI keyboard to Bela’s USB port, load a Csound instrument, and use your MIDI keyboard to play your Csound project like a synth.
<CsOptions> you can select the MIDI device you’d like to use to control Csound. By default the MIDI channel defines the instrument number that’s called for each pressed key, but this can be changed by setting massign.
To avoid CPU overload by triggering too many voices in parallel, the maxalloc option allows to restrict the maximum number of voices. In this example, it’s set to 4 voices:
<CsoundSynthesizer> <CsOptions> -Mhw:1,0,0 -+rtmidi=NULL --daemon </CsOptions> <CsInstruments> ; Initialize global variables. sr = 44100 ksmps = 8 nchnls = 2 0dbfs = 1 seed 0 ; init random function maxalloc 1, 4 ; restrict to maximum 4 voices ;------------------------------------------------------ ; Instrument will be played by MIDI notes on Channel 1 ;------------------------------------------------------ instr 1 iFreq cpsmidi iAmp ampmidi 0.3 ; Three detuned sawtooth oscillators aOut1 = vco2(iAmp, iFreq) aOut2 = vco2(iAmp, iFreq*1.004) aOut3 = vco2(iAmp, iFreq*0.995) ; Envelope aOut = aOut1 + aOut2*0.5 + aOut3*0.5 aEnv linsegr 0, 0.01, 0.1, 0.2, 0 ; Filter LFO and envelope kLFO = lfo(50, 1.2, 0) aFiltEnv linsegr 100, 1.2, 1000, 0.2, 0 ; Korg35 resonant low-pass filter aOut = K35_lpf(aOut, aFiltEnv+kLFO, 9.4, 0, 1) ; Voice panning iPan random 0.2, 0.8; aOutL, aOutR pan2 aOut, iPan ; Output outs aOutL*aEnv, aOutR*aEnv endin </CsInstruments> <CsScore> </CsScore> </CsoundSynthesizer>
Good programming practices for Csound on Bela
In a real-time audio system like Bela, accessing hardware other than the audio device should be avoided (printing to console, reading writing to harddisk, etc). In Csound, printing and other console messages can be suppressed by adding
-m0d to the
<CsOptions> section. Loading files from disk should also be avoided (for instance, loading audio files with
diskin2), and should instead be loaded into memory with function table generators (see examples below). Using
reinit to re-initialize i-rate variables should also be avoided as this can cause a mode switch, which normally leads to problems with real-time performance.
Below is an example of how to load and playback a file from memory using function table and the
loscil opcode (see https://csound.com/docs/manual/loscil.html for a thorough explanation):
;------------------------------------------------------ ; Playback of a stereo sound file (looping) ;------------------------------------------------------ instr 1 iftable = 1 asigL, asigR loscil .8, 1, iftable, 1, 1 outs asigL, asigR endin </CsInstruments> <CsScore> i1 0 86400 f1 0 0 1 "soundfile.wav" 0 0 0 </CsScore>
Projects made with Csound and Bela
Augmented Tenor-Saxophone (COSMO)
Based on the effects collection in the COSMO library, [Alex Hofmann]((https://iwk.mdw.ac.at/alex-hofmann/) built a Tenor-Saxophone with integrated live electronics. Inside the bell of the instrument he mounted a Bela unit,with speaker and microphone, all powered by a regular 5V mobile phone charging battery. On Bela a Csound patch is running that processes his playing in real time, either by adding modulation effects or by live-sampling and playback.
The structure of the saxophone part of the 12 minute performance was chosen by an algorithm, which randlomly picks voice samples with instructions out of three categories (tempo, dynamics, tonal material). Verbal instructions such as “Fast, loud, three tones!” give cues to the player but are also hearabel for the audience. Furthermore, this setup allows the performer to move freely on stage or even walk into the audience, as all live-electronic parts are inside the saxophone. A full version of a 12 minute performance with this augmented Tenor-Saxophone at the Linux Audio Conference 2018 can be found here.
A video with excerpts from a performance with the augmented Tenor-Saxophone at the Linux Audio Conference 2018:
Trampeklang is an interactive sound installation for kids commisioned by Oslo Philharmonic Orchestra. It was designed and built by Bernt Isak Wærstad and Peter Baden using custom built wooden platforms with velostat material for pressure sensing and Csound for triggering and playback of different sounds (from a sound back chosen by the operator). Everything in this installation ran on Bela.
A short video showing Trampeklang in use during Oslo Philaharmonic kid’s day:
Electroacoustic guitar (COSMO)
Bernt Isak Wærstad used DIY electronics and custom processing software written in Csound (COSMO) combined with an acoustic guitar to create a new electroacoustic instrument, extending the traditional guitar and exploring the cross-sections between electronic and acoustic timbres. The instrument was first used for a concert at the MultiNO festival in Oslo in January 2018 and have later been presented through a performance at the NIME conference at Virginia Tech in June 2018.
The Half-Physler is a hybrid acoustic-virtual instrument. A physical model of a tube resonator is running on a Bela Mini, whereas a clarinet reed with a bending sensor together with an actuator is used as the excitation mechanism similar to real single-reed instruments. The physical model is provided as an opcode for Csound. The performer can control the coupling between the reed and the virtual tube by pressing the reed against the shaker. A slider and potentiometers on the 3D printed enclosure allow to shape the tube-resonator in a way beyond the possibilities with real acoustic instruments, such as morphing a cylinder into a cone.
The Half-Physler was developed at the Department of Music Acoustics at the University of Music and Performing Arts Vienna.