Over a year ago, when I first tried the OLPC/Sugar software, I was fascinated by the activities in TamTam applications. Had any of them been available in my time, I may even have liked attending school.
The TamTam activity builds on top of the Csound framework to allow children to explore sounds and music. As I explored the Csound tutorial by Michel Gogins, I came across his comment, “Of all the languages I have used, both in my career as a programmer and in my career as an algorithmic composer, Python has been by far the easiest and most productive language to learn and to use.”
Gogins also writes, “Csound must be considered as one of the most powerful musical instruments ever created.” Hence, the motivation for this article. We will explore how to create noise and, we hope, you will go on to compose music :-) In the current state of the world, we need even more music.
To know a bit about the people behind the code, go to: www.csounds.com/journal/2006spring/meetTheCsound5Developers.html.
You will need to install the following packages: csound and csound-python.
Csound requires an XML-like configuration file with three sections. Create a minimal file, tutorial.csd:
<CsoundSynthesizer> <CsOptions> </CsOptions> <CsInstruments> </CsInstruments> <CsScore> </CsScore> </CsoundSynthesizer>
You will be satisfied with the default options. The instruments section is where we define the ‘orchestra’, which comprises all the instruments that will be used to create our musical masterpiece. These are the same as the contents of
myfile.orc in the beginner’s articles in www.csounds.com/journal/articleIndex.html.
The score section will contain a list of instructions for the instruments in the orchestra. These are the same as the contents of
myfile.sco, mentioned in the articles mentioned earlier.
Create the same simple instrument as in the beginners’ introduction:
<CsInstruments> sr=44100 ; Sample Rate kr=22050 ; Control Rate ksmps=2 ; sr/kr As far as I know this is always the case nchnls=2 ; 1=mono, 2=stereo, 4=quad instr 1 ; Instrument 1 begins here aout oscil 10000, 440, 1 ; An oscillator outs aout, aout ; Output the results to a stereo sound file endin ; Instrument 1 ends here </CsInstruments>
The first four lines have header information, which controls the output format. The remaining lines are the definition of the instrument, which is a simple oscillator operating at a frequency of 440Hz and a volume of 10000, about a third of the maximum. (Volume is represented as a 16-bit integer.) The third parameter to the oscil command/opcode identifies the waveform table to be used in the score given below. The oscillator is given a variable name
aout. The same sound is passed to both the channels.
Now, add the score:
<CsScore> f 1 0 16384 10 1 ; table #, start time, the size, generator, parameter i 1 0 1 ; instrument #, start time, duration </CsScore>
f is the waveform table, which is available at the start of performance with 16,384 samples. The generator value 10 with parameter 1 corresponds to a sine wave in Csound.
i line is an instrument event with the instrument number, the start time and the duration in seconds as the parameters.
You can run the following script, get a wave file and play it:
$ csound -Wo tutorial.wav tutorial.cs $ aplay tutorial.wav
Controlling Csound using Python
Write the following code in
tutorial.py. This is pretty useless as all it does is replace the command line for executing Csound. But have patience.
# Import the Csound API extension module. import csnd # Create an instance of Csound. csound = csnd.CppSound() # Enable Csound to print console messages csound.setPythonMessageCallback() # Load the tutorial piece created earlier. csound.load(‘tutorial.csd’) # Set the Csound command for off-line rendering. csound.setCommand(‘csound -Wo tutorial.wav temp.orc temp.sco’) # Export the .orc and .sco file for performance csound.exportForPerformance() # Actually run the performance. csound.perform()
We will now add code to generate the score algorithmically. However, our current instrument is pretty hopeless. So, you will need to refine the instrument in
tutorial.csd as follows:
instr 1 iamp = p4 ifqc = p5 itabl1 = p6 aout oscil iamp, ifqc, itabl1 outs aout, aout endin
The new oscillator uses the amplitude, frequency and waveform table reference as parameters. The variables in Csound have a strict format reminiscent of Fortran. Local variables start with the letters ‘i’, ‘k’ or ‘a’. A variable starting with the letter ‘i’ is initialised to a value when the instrument is started, and does not usually change. The letter ‘a’ indicates an audio rate variable and the letter ‘k’ indicates a control rate variable.
There are also some special ‘p’ variables or parameters that send values from the score to the orchestra—p1, p2 and p3 are the instrument’s number, start time and their duration. The variables p4, p5, p6, etc, are flexible. They are used here for amplitude, frequency and the waveform table.
Now, add a call to
add_score to the
tutorial.py as follows:
csound.setCommand(‘csound -Wo tutorial.wav temp.orc temp.sco’) add_score(csound) # Export the .orc and .sco file for performance
Now, code an
def add_score(csound): sarega = [130.8, 146.8, 164.8, 174.6, 195.0, 220.0, 246.9, 261.6] for time in range(8): csound.addNote(1, time, 1, 8000 , sarega[time], 1)
Your instrument will play the notes. Let us improve the instrument and put an envelope in each event. Modify the instrument definition in
tutorial.csd as follows:
instr 1 iamp = p4 ifqc = p5 itabl1 = p6 kamp linseg 0, .2, 1, .2, .8, p3-.5, .8, .2, 0 aout oscil iamp, ifqc, itabl1 outs aout*kamp, aout*kamp endin
You can define an envelope using the opcode
linseg, which represents the starting amplitude followed by pairs of time intervals and the amplitude at the end of the interval.
The control variable
kamp starts with 0, rises to 1 in .2 seconds, then drops to .8 in the next .2 seconds, retaining that value until .2 seconds before the end. In the last .2 seconds, the value drops from .8 to 0. As you can imagine, an instrument can be programmed to generate pretty complex sounds for each event. You can get an idea of the programming possibilities by playing two frequencies close to each other. Replace the
add_score method in the
def add_score(csound): sarega = [130.8, 146.8, 164.8, 174.6, 195.0, 220.0, 246.9, 261.6] for time in range(8): csound.addNote(1, time, 1, 8000 , sarega[time], 1) csound.addNote(1, time, 1, 8000 , sarega[time] + 5, 1)
Not surprisingly, you should hear beats.
Musicians do not work with frequencies. They work with octaves. So, let us define another instrument that uses a converter opcode to convert a number into a frequency. The whole number represents the octave, and the decimal part the semitone. So, at the instruments section in
tutorial.csd, add the following:
instr 2 iamp = p4 ifqc = cpspch(p5) itabl1 = p6 kamp linseg 0, .2, 1, .2, .8, p3-.5, .8, .2, 0 asigl oscil iamp, ifqc*.999, itabl1 asigr oscil iamp, ifqc*1.001, itabl1 outs asigl*kamp, asigr*kamp endin
Notice that the definition has a different oscillator definition for the right and left channels. In the score section, include a second waveform table:
f2 0 16384 10 1 .5 .3333
This table is also a sine wave but includes the first and second harmonics with amplitudes that are a half and a third of the primary wave.
Now, modify the
add_score method in
tutorial.py to use both instruments:
def add_score(csound): sarega = [130.8, 146.8, 164.8, 174.6, 195.0, 220.0, 246.9, 261.6] pitch = [8.00, 8.02, 8.04, 8.05, 8.07, 8.08, 8.11, 9.00] for time in range(8): csound.addNote(1, time, 1, 8000 , sarega[time], 1) csound.addNote(2, time, 2, 8000, pitch[time], 1)
The second instrument plays the same tones but at an octave higher. It also uses the second waveform table. You can explore various programming possibilities—like varying amplitudes, varying durations and varying the relative start time of instruments.
As you would have noticed, there is no constraint on the size of the orchestra you can single-handedly create. You can find some simple drum instruments at www.csounds.com/ezine/autumn1999/synthesis/index.html. So go ahead, try them and, may be, create a synthetic tabla!
Next month, we will explore playing around Soundfonts and Csound to create sounds.