Over a year ago, when I first tried the OLPC/Sugar software, I was fascinated by the TamTam activities. Had such activities been available in my time, I may even have liked 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 have 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 , see http://www.csounds.com/journal/2006spring/meetTheCsound5Developers.html. Getting StartedYou will need to install the following packages: csound csound-python Csound requires an xml-like configuration file with 3 sections. Create a minimal file, tutorial.csd: <CsoundSynthesizer> <CsOptions> </CsOptions> <CsInstruments> </CsInstruments> <CsScore> </CsScore> </CsoundSynthesizer> We will be satisfied with the default options. The instruments section is where we define the 'orchestra', that is all the instruments which will be used to create our musical masterpiece. These are the same as the contents of myfile.orc in the beginners articles in http://www.csounds.com/journal/articleIndex.html. The score section will contain a list of instructions for the instruments in our orchestra. These are same as the contents of myfile.sco mentioned in the above articles. Create the same simple instrument as in the beginners' introduction - http://www.csounds.com/ezine/winter1999/beginner/index.html <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 are the 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 16bit 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 16384 samples. The generator value 10 with parameter 1 corresponds to a sine wave in Csound. The i line is an instrument event with the instrument number, the start time and duration in seconds as the parameters. You can run this script, get a wave file and play it. $ csound -Wo tutorial.wav tutorial.cs $ aplay tutorial.wav Controlling Csound using PythonWrite 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". Variables starting with the letter "i" are initialized to a value when the instrument is started and do 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 which send values from the score to the orchestra – p1, p2 and p3 are the instrument's number, start time and the duration. The variables p4, p5, p6, etc. are flexible. They are used above for amplitude, frequency and the waveform table. Now, add a call to add_score 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 add_score method: 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)
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 envelop using the opcode linseg, which represents the starting amplitude followed by pairs of time interval and the amplitude at the end of the interval. The control variable kamp starts with 0, rises to 1 in .2 sec, then drop to .8 in next .2 sec, and retains that value until .2 sec before the end. In the last .2 sec, 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 tutorial.py with: 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 which uses a converter opcode to convert a number into a frequency. The whole number represents the octave and the decimal part the semitone. So, to 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 1st and 2nd harmonics with amplitudes 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) As you would have noticed, there is no constraints on the size of the orchestra you can single handedly create. You can find some simple drum instruments at http://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 with sounds using Soundfonts and Csound. |
Python For Friends >