Csound
Csound is the music and audio signal processing language developed by MIT's Barry Vercoe. Csound will provide audio services for the XO computer.
Csound is both a programming language and a sound synthesis engine. Csound, as included in the OLPC project, can be used by Activities or directly by children and teachers. It can be accessed in a variety of ways. In the XO platform, two basic ways are provided:
- Through the Python programming environment: eg. programmed in Activities.
- Through its 'classic' command-line frontend, directly invoking it from the Terminal activity.
The version currently being shipped in all XO builds is 5.07, but with 5.08 having been recently released (see [1]), we expect to upgrade to this version in future releases. Further information about Csound can be found on its official website: http://csounds.com/.
Csound code and CSD files
Csound code is most commonly written in the Unified Csound File format (CSD). This uses XML-like tags to contain the different code elements in sections. Two of these are required: orchestra (<CsInstruments>) and score (<CsScore>) contained within the <CsoundSynthesizer> tags. Here is a trivial instrument and score:
<CsoundSynthesizer> <CsInstruments> instr 1 a1 oscili p4, p5, 1 out a1 endin </CsInstruments> <CsScore> f1 0 16384 10 1 i1 0 1 10000 440 e </CsScore> </CsoundSynthesizer>
This will give you a nice 1-second sinewave beep.
Orchestra and Score
Csound is loosely based on the concept of an Orchestra, made up of Instruments, and a Score, made up of events, function table definitions etc.. Instruments contain the synthesis/processing code and the score the parameters to run these. In practice, you might not need a score, because realtime events (from MIDI, from Python or from other Csound instruments), so in that case an empty or minimal one will do. Instruments are written using a variety of opcodes (there are over 1000 of these), which are interconnected using audio signal (a-), control signal (k-), spectral signal(f-), initialisation (i-) and string (S-) variables. A slightly more interesting example shows some of these in operation:
<CsoundSynthesizer> <CsInstruments> instr 1 idur = p3 iamp = p4 ifrq = cpspch(p5) kenv expon 1, idur, 0.01 asig oscili kenv*iamp, ifrq, 1 out asig endin </CsInstruments> <CsScore> f1 0 16384 10 1 i1 0 1 8000 8.00 i1 + 1 12000 8.04 i1 + 1 16000 8.07 i1 + 2 24000 9.00 e </CsScore> </CsoundSynthesizer>
What you should hear is an arpeggio of 'ping' sounds, a bit like a chime or tuning fork, which is much more interesting than our previous attempt. You will note that the envelope signal generated by the opcode 'expon' is a control (k-) signal and the sound produced by the 'oscili' opcode (an oscillator) is an audio signal. The parameters for the instrument are held in initialisation (i-) variables. The instrument is run 4 times (there are 4 i-statements in the score) in a sequential manner (the '+' makes the start times of events aligned with the end times of previous events). The frequency is notated in octave.pitch-class format in the score (last parameter field, 5, in each event) and translated to Hz in the instrument code.
MIDI playback
Csound can play back MIDI files, as well as realtime MIDI events (say from a keyboard or a sequencer). All you need is Csound code that understands MIDI. For MIDI file playback, the compilation option -F <your-midi-file> is used.
Here is a version of the ping instrument used above, adapted for simple MIDI input (listening on MIDI channel 1).
<CsoundSynthesizer> <CsInstruments> instr 1 idec = 1 iamp ampmidi 32767 kfrq cpsmidib 2 kenv expsegr 1, idec, 0.1, 0.1, 0.01 asig oscili kenv*iamp, kfrq, 1 out asig endin </CsInstruments> <CsScore> f0 36000 f1 0 16384 10 1 </CsScore> </CsoundSynthesizer>
In this case, we just need to do the following simple alterations: add opcodes for using MIDI NOTE data (frequency, amplitude) and a release-sensing envelope generator; remove the not required score events; and include a 'f0 36000' line to keep Csound listening for realtime events for 36000 seconds.
A more generic (and complex) example is shown below: a General MIDI (GM) soundfont synthesizer for playing GM files. This is give a good example of how flexible Csound can be, doing almost anything you would like in terms of sound synthesis. The code is based on two Csound instruments: one that parses raw MIDI data and another one that actually plays it.
File: GM_example.csd |
<CsoundSynthesizer> <CsInstruments> ichn = 1 lp1: massign ichn, 0 loop_le ichn, 1, 16, lp1 pgmassign 0, 0 gisf sfload "gmgsBank1.sf2" sfpassign 0, gisf /* this instrument parses MIDI input to trigger the GM soundfont synthesis instrument (instr 10 */ instr 1 idkit = 317 /* drum-kit preset */ tableiw idkit, 9, 1 irel = 0.5 /* release envelope */ ipg = 1 ivol = 2 ipan = 3 nxt: kst, kch, kd1, kd2 midiin if (kst != 0) then kch = kch - 1 if (kst == 144 && kd2 != 0) then ; note on kpg table kch, ipg /* instrument identifier is 10.[chn][note] */ kinst = 10 + kd1/100000 + kch/100 if kch == 9 then /* exclusive identifiers */ if kpg == idkit+7 then krel = 2 /* add extra release time for orch perc*/ else krel = 0.5 endif if (kd1 == 29 || kd1 == 30) then ; EXC7 kinst = 10.97 elseif (kd1 == 42 || kd1 == 44 || kd1 == 46 || kd1 == 49) then ; EXC1 kinst = 10.91 elseif (kd1 == 71 || kd1 == 72) then ; EXC2 kinst = 10.92 elseif (kd1 == 73 || kd1 == 74) then ; EXC3 kinst = 10.93 elseif (kd1 == 78 || kd1 == 79) then ; EXC4 kinst = 10.94 elseif (kd1 == 80 || kd1 == 81) then ; EXC5 kinst = 10.95 elseif (kd1 == 86 || kd1 == 87) then ; EXC6 kinst = 10.96 endif else krel = 0.5 endif event "i", kinst, 0, -1, kd1, kd2, kpg, kch,krel elseif (kst == 128 || (kst == 144 && kd2 == 0)) then ; note off kpg table kch, ipg kinst = 10 + kd1/100000 + kch/100 if kch == 9 then if (kd1 == 29 || kd1 == 30) then ; EXC7 kinst = 10.97 elseif (kd1 == 42 || kd1 == 44 || kd1 == 46 || kd1 == 49) then ; EXC1 kinst = 10.91 elseif (kd1 == 71 || kd1 == 72) then ; EXC2 kinst = 10.92 elseif (kd1 == 73 || kd1 == 74) then ; EXC3 kinst = 10.93 elseif (kd1 == 78 || kd1 == 79) then ; EXC4 kinst = 10.94 elseif (kd1 == 80 || kd1 == 81) then ; EXC5 kinst = 10.95 elseif (kd1 == 86 || kd1 == 87) then ; EXC6 kinst = 10.96 endif else kpg = 0 endif event "i", -kinst, 0, 1 elseif (kst == 192) then /* program change msgs */ if kch == 9 then kpg = idkit if kd1 == 8 then kpg = idkit+1 elseif kd1 == 16 then kpg = idkit+2 elseif kd1 == 24 then kpg = idkit+3 elseif kd1 == 25 then kpg = idkit+4 elseif kd1 == 32 then kpg = idkit+5 elseif kd1 == 40 then kpg = idkit+6 elseif kd1 == 48 then kpg = idkit+7 endif else kpg = kd1 endif tablew kpg, kch, ipg elseif (kst == 176 && kd1 == 11) then /* volume msgs */ tablew kd2, kch, ivol elseif (kst == 176 && kd1 == 7) then /* pan msgs */ tablew kd2, kch, ipan endif kgoto nxt endif endin /* this is the GM soundfont synthesizer instrument */ instr 10 kenv linenr 1,0.001,p8,0.001 iamp table p5, 5 a1, a2 sfplay p5, p4, iamp,1, p6 kv table p7, 2 kvol tablei kv, 5 kpan table p7, 3 kpan = (kpan - 64)/128 outs a1*kvol*(0.5-kpan/2)*kenv, a2*kvol*(0.5+kpan/2)*kenv endin </CsInstruments> <CsScore> /* program preset (memory) table */ f1 0 16 -2 0 0 0 0 0 0 0 0 226 0 0 0 0 0 0 0 /* velocity (memory) table */ f2 0 16 -2 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 /* pan (memory) table */ f3 0 16 -2 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 f5 0 128 5 0.1 128 1 /* velocity mapping: less nuanced */ f6 0 128 5 0.01 128 1 /* velocity mapping: more nuanced */ i 1 0 360000 e </CsScore> </CsoundSynthesizer> |
The above example is not very typical of MIDI usage in Csound, as it handles MIDI data at its lowest level. Much simpler examples of how MIDI can be used by Csound exist. However the example is a good demonstration of how a universally-existing standard such as GM can be handled by Csound.
Csound activities
Tam Tam uses Csound, but you would never know it as its interface is designed to wrap the Csound engine with a child-friendly look and feel. This excellent grouo of Activities allows kids to make sounds, make music, jam, record and transform their voices in an intuitive way. TamTam Edit allows students to patch together Csound's opcodes (modules) and teaches them all about signals, synthesis, and synthesizers. TamTam Activities demonstrate well how the power of Csound can be harnessed in the XO platform. For more information see:
http://wiki.laptop.org/go/Tamtam
You can see a number of activities developed by Greg for 542, mostly uploaded here:
http://csounds.com/GregCsoundActivities.zip
Pippy uses Csound to help teach children the Python programming language and to build XO Activities. Instructions for playing Csound in Pippy can be found in[2].
http://wiki.laptop.org/go/Pippy
Step is a simple 8-note step sequencer that children will use to play music and record their own loops for use in other sample-based activities. Step uses csndsugui.
http://www.thumbuki.com/xo/step.activity.zip
Funny Talk is an activity that children can use to record their voices with the built-in microphone, and process them with effects such as reverb, echo, chorus, etc. Funny Talk allows a child to save their manipulated voices as soundfiles so that they can be used in other musical activities. Funny Talk uses csndsugui.
http://www.thumbuki.com/xo/funnytalk.activity.zip
csndsugui
As you can see from some of the examples above, it is possible to use csndsugui for fast Activity development. It is basically Python toolkit for the development of Csound-based audio and music applications under sugar and GTK. The code, plus examples and documentation, can be found in:
http://dev.laptop.org/git/activities/csndsugui
Tutorials
See Csound tutorials for a wiki introduction to using Csound for music development.
Sample Code
- A simple Python project using Csound to create an audible system load monitor using the standard Python Csound binding
- TamTam uses a custom C++ wrapper around Csound and has a very large sound library available
- Activity example shows a complete Python and Csound code for a simple Activity.