Eastman Csound Tutorial

NEXT CHAPTER (Chapter 2) -- Table of Contents CHAPTER 1 -- CHAPTER 2 -- CHAPTER 3 -- CHAPTER 4 -- CHAPTER 5 -- CHAPTER 6 APPENDIX 1 -- APPENDIX 2

Chapter 1: Basics

1. Introduction

This tutorial provides an introduction to Csound. The reader also should have in his/her possession a Csound Reference Manual, and should consult the pertinent sections [indicated within square brackets] of this manual while reading the tutorial material covered here.

This tutorial covers only a small fraction of the audio signal generating and processing resources that are available within Csound. However, the resources we will discuss are among the most fundamental elements of computer music generation. Additionally, they are quite powerful and extensible (you can get a lot of mileage out of these things), and also will be used to illustrate the logic and syntactical conventions of Csound. An understanding of these conventions will enable you to begin constructing your own instrument algorithms, and to figure out how to use the myriad of resources in Csound that are not covered here.

Distributions of Csound periodically are updated by a volunteer team of Csound users currently led by John ffitch, and we install new versions at Eastman as they become available. New versions often contain a few bugs. ECMC users should check the helpfile csound for a list of known bugs in our current version of Csound, and advise one of our staff members if you stumble across any new ones.

Computer systems make music by computing samples (numbers that represent the amplitude of a sound at evenly spaced time intervals). In MIDI systems, MIDI controllers and/or a general purpose microcomputer send out control signals to special-purpose hardware circuits (oscillators, envelope generators, and the like), each optimized to perform one task as efficiently as possible. These sound generating and processing hardware circuits may exist in an external box -- a synthesizer or sampler (it's hard to tell the two apart these days) or "effects box," such as the K2000, Wavestation SR or PCM70 in the ECMC MIDI studio) -- or else in a sound card attached to the computer buss.

In software (or "direct") synthesis systems, by contrast, a computer CPU itself, running a program loaded into RAM, computes and processes the sound samples. If the computer is fast enough, and the signal generating algorithm is simple enough, and the score is not too complex, this can be done in real time, and the samples can be passed directly to digital-to-analog converters for immediate audition. However, software synthesis is inherently slower than hardware synthesis, and often the time required to compute the samples exceeds the duration of the sounds. Most often, therefore, the samples are first computed and written to a disk file, which can be played at the completion of the compile job.

Some hybrid sound synthesis systems, such as Turbosynth (an entry-level synthesis system marketed by Digidesign for Macintosh computers) and Kyma (a far more powerful system marketed by Symbolic Sound Corporation for Windows and Mac platforms) attempt to combine the flexibility of software procedures with the speed of hardware synthesis. The user interface allows greater flexibility in connecting processing devices than is generally available in fixed architecure hardware-based systems, and the system uses additional DSP or sound card hardware to relieve the CPU of repetitive operations and to compute the samples. For some types of operations such systems work quite well. However, they tend to offer less flexibility than fully software-based systems, and less speed than hardware systems, or else (as with the Kyma system) are quite expensive.

With fully software-based music programs, such as Csound, Princeton's CMIX, and several commercial programs at recently have been introduced for PCs and Macs (see the April 1998 issue of Electronic Musician, pp. 68 ff. for examples) the synthesis or sound processing architecture is not fixed. One is not limited, for exam- ple, to a particular number of simultaneous polyphonic "voices," or to only types of certain processing algorithms. Rather, users can construct and implement their own signal generating, processing and "effects" algorithms by "patching together" various procedures from a library of available utility programs and sub-routines, called unit generators (or opcodes) in Csound, using only those procedures that are needed, and calling as many as will fit in computer memory at once. Thus, if we want a hundred oscillators or filters for some application, and our computer has sufficient RAM, we can create them with a hundred calls to an oscillator or filter unit generator. The values we supply to these oscillators or filters can be arbitrarily complex, involving a mixture of many simultaneous control signals created by other unit generators.

Currently, Csound is the most widely used software synthesis system. Compiled public domain versions are available for all of the major computer operating system platforms -- various flavors of Unix (SGI, Linux, Sparc and generic Unix), several Windows ports, Macintosh (PowerPC and 68xxx) and even Atari -- and can be downloaded at no cost over the internet via a web browser or ftp from http://mitpress.mit.edu/e-books/csound/frontpage.html (the Csound Front Page) and mirror sites. Csound thus provides us with an avenue to study and put to creative use music synthesis and sound processing procedures apart from the limitations of particular hardware and software systems. Often, the knowledge gained from this process is directly applicable to other types of computer music systems as well.

In this tutorial, then, our primary goal will be not to transform you into Csound wizzards, but rather to use the tools of Csound to examine various types of computer music resources and procedures. Those already familiar with various MIDI synthesis techniques will find many familiar concepts within this tutorial and within Csound. Many of the unit generators in Csound have hardware counterparts in synthesizers, samplers, mixing consoles, and outboard gear. However, the implementation of these procedures presented here will likely be new, and may at times seem more complicated.

1.1. Orchestra and Score Files

Csound requires that the user supply two input files - an orchestra file and a score file - which, together, define a signal processing algorithm and all of the data needed for the compilation of output samples.

A Csound orchestra file is a user-written computer program, written according to the syntactical conventions of the Csound "language," that defines one or more instruments - audio signal processing algorithms. This program provides the Csound compiler with a step-by-step series of instructions, and some of the necessary argument values, required for the computation of each output sample. Designing an instrument algorithm bears certain similarities to patch editing on a MIDI synth, except that we usually begin with a "blank page" (or from an "init" state), rather than with certain pre-defined operations determined by the hardware architecture of the synth.

Some instrument algorithms or modules (sub-routines within an algorithm) generate audio signals from scratch, by sampling a synthetic waveform, such as a sinusoid, or else a digitized acoustic sound, such as a violin tone. Other instrument algorithms or modules process such signals. Eastman Csound Library instruments sf, rev and delays, which some of you may already have used, are examples of Csound instrument algorithms that produce no sound themselves, but rather process audio signals from other sources, adding reverberation, echos, spectral modifications (EQ) or other types of sound modifications.

A score file provides values (such as pitch and duration) that vary from note to note. These argument variables for each note are specified in the form of parameter fields (p1, p2, p3 and so on). Additionally, the score file provides any required function definitions, from which Csound creates tables of numbers used to generate or process sounds. The numbers within a function table may represent an audio waveshape, such as a sinusoid or a sawtooth wave, or a digitized acoustic sound. Other types of tables are used to represent "control" or "performance" elements, such as the amplitude envelope, or the time varying vibrato shape or width, within a tone. In still other cases a function table merely provides us with a convenient way to input a complete series of numbers in a single operation. We will return to score parameter fields and function definitions shortly.

Up to this point, ECMC users have been using the Eastman Csound Library instruments, for which score11 score templates have been provided. Throughout this tutorial, we will continue to use the score11 preprocessor to simplify the creation of our actual Csound score files. (Non-ECMC users can refer to the online Appendix, which includes Csound score file compilations for all of the score11 examples in this tutorial.) These Csound score files (called sout, short for "score output" file, by score11) look much like the MIDI controller event list files produced by MIDI sequencers such as Logic, Cubase, Performer, Cakewalk or Vision. When creating simple one or two note test score files for a new instrument algorithm, however, you might wish to bypass score11 and type in your Csound score file directly.

Csound also provides alternative ways to generate score files. With certain unit generators one can use standard type 0 MIDI files created with a sequencer program, or with an interactive program such as MAX, or use real-time MIDI controller input, to make music with Csound, and only a skeletal score file is required. The ECMC midiins algorithms illustrate this type of MIDI inplementation.) Advanced users may wish to explore the resources of the SCOT score translator, or the CSCORE score generating program, both of which are documented in the Csound reference manual. Other advanced users write their own score generating programs, or employ spreadsheet programs for particular applications.

1.2. Orchestra file headers

[ See the discussions of SYNTAX OF THE ORCHESTRA, ORCHESTRA STATEMENT TYPES and ORCHESTRA HEADER STATEMENTS> in the Csound reference manual ]

Every Csound orchestra must begin with a header, which establishes certain global values that are used by all instruments within the orchestra. Here is a sample Csound header:

sr=44100
kr=2205
ksmps=20
nchnls=1

1) The sr variable fixes the sampling rate (also called the audio-rate, or a-rate, in Csound). This determines how many samples per second will be calculated for each channel to represent sounds.

In the ECMC studios we currently use 44100 as a "universal," device-compatible, high quality sampling rate on all of our digital audio systems, from source recordings of acoustic sounds all the way through compact disc production. (However, we may be upgrading one or more of our systems in the near future to a 96 k sr, 24/32 bit format.)

For initial tests with Csound, however, lower sampling rates, such as 32000 or 22050, will compute more quickly and require only half as much disk space for output soundfiles. And if we run Csound in real time, sending the samples directly to the system DACs rather than writing them to a soundfile (by means of the ECMC csoundplay command, or its alias csp), lower sampling rates can enable us to employ more complex signal processing procedures, and to play more simultaneous "polyphonic" notes, before reaching the system throughput limitations.

Remember, however, that the highest frequency that can be represented digitally is one half the sampling rate, which is called the Nyquist frequency. If we attempt to create a sound that includes partial frequencies higher than the Nyquist, these higher frequencies will alias, or "fold over," according to the formula :

sr - freq

Thus, with the sampling rate set to 22050, a frequency of 12000 herz will actually be heard at 10050 Herz. And if we attempted to create a sine wave glissando between 20 Hz. and 22kHz., the resulting pitch would rise from 20 herz up to 11025 herz, but would then glissando back down to 50 herz.

Remember, too, that the "smoothing" filters built into all DACs, as well as the "anti-aliasing" low pass filters within ADCs, also serve to attenuate frequencies above approximately 38 of the sampling rate, reaching "total" attenuation (-60 dB) at around, or slightly below, the Nyquist frequency. With cheap converters, the rolloff is even less steep.

2) kr specifies a control rate. There are many types of subaudio control signals, such as vibrato and tremolo patterns, that do not need to be computed at the sampling rate to achieve a satisfactory resolution. To do so would waste processor (and user) time. For such operations our orchestra header above specifies a control rate of 2205 updates per second, a value we gen- erally recommend. Control rates typically vary between about 500 and 5000. However, the k-rate must divide evenly into the s-rate.

3) ksmps, an irksome but required part of Csound headers, is the ratio between the s-rate and the k-rate. Thus, in our example above, the ratio is 20 sample calculations for each calculation of control signals. In other words, every value computed at the control rate will be used for 20 successive audio samples, then updated (recomputed).

4) The final header variable, nchnls, determines the number of output audio channels. Use 1 for mono, and 2 for stereo.

The Eastman Csound Library macro SETUP presents the same information on a single line of code :

SETUP(44100,22050,1)

Note that if you use this macro format, the value of ksmps is calculated and filled in automatically. The three arguments to the SETUP macro specify the sampling rate, the control rate, and the number of output channels. When using this macro format, make sure that the word SETUP is capitalized, and that there are no spaces between any of the characters. An orchestra file that uses any of the Eastman Csound Library macros, such as SETUP, must be processed by the Eastman utility m4orch (which can be abbreviated m4o). m4orch expands such macros into Csound code, and writes its output to a file named orch.orc (which can be abbreviated orc). This file should be used as your orchestra file input to Csound.

1.3. Audio, Control and Initialization Rates

[ See the discussion of CONSTANTS AND VARIABLES in the Csound reference manual, but do not worry about Global variables yet. ]

Csound instrument algorithms are constructed by patching together various unit generators, each of which performs a particular type of mathematical operation. The Csound reference manual describes these unit generators and other features of the compiler in a manner designed for quick reference by experienced users. It is unlikely that you will want to take this manual along to the beach for a relaxing read. The manual groups unit generators together by family and function. In this tutorial, we will look at the more commonly used operations. This will mean a lot of skipping around in the manual.

Before we examine these unit generators, we need to clarify a few basic things about the syntax with which one writes lines of Csound code. Reprinted below are the definitions for four Csound unit generators as they appear in the reference manual. The first two unit generators (oscil) create basic oscillators. The two concluding lines (rand) create white noise generators.

  output    unit generator  required arguments  optional arguments
("result")  ("opcode")
__________________________________________________________________
   kr       oscil           kamp , kcps , ifn   [, iphs]
   ar       oscil           xamp , kcps , ifn   [, iphs]
   kr       rand            kamp [, iseed]
   ar       rand            xamp [, iseed]

An oscillator or white noise generator can run either at the audio rate, if this signal will be heard as a sound, or else at the control rate, if the signal will instead control (modify) some characteristic of an audio signal created by some other unit generator. We determine the output rate by the output name (or "result") we supply. If this name begins with a k, the unit generator will run at the control rate; if the name begins with an a, the operation will be computed at the audio rate. We can choose any name we wish for these output names, so long as they begin with a k or an a.

If our oscillator will be producing a vibrato signal that modifies the pitch produced by another oscillator, for example, we might call the result kvibrato, or perhaps kvib, or k1, or, perversely, kKxg6w. If our white noise generator is producing audible noise, we might call the output anoise, or asignal, or asig, or a2.

To the right of the unit generator name, the arguments (input values) that it needs to perform its computations are listed. Each argument is separated by a comma. Blank spaces or tabs may be included between arguments for ease of reading.

Any argument beginning with an i is one for which a value will be established at the initialization (onset) of the note, and will not change during the note's duration. Any argument starting with a k can change values either at the control (k) rate, or else at the i rate. An argument that begins with an a is updated at the audio-rate. Finally, an argument beginning with an x can be given at the a-rate, at the k-rate, or as an initialization value. In other words, inputs to various mathematical operations may be specified only once per note, or change at either the control or audio rate. Some arguments must be specified at a certain rate, while with other arguments it is up to the user to select the appropriate update rate.

The oscil unit generator has three required arguments - an amplitude (amp) value, a frequency (cps) value, and a function number (fn). It is also possible, if we wish, to include a fourth argument (phs), which specifies where in the function table the oscillator should begin reading (more on this later).

If the oscillator is running at the control rate, the amplitude and frequency arguments can be either constant (i-rate) values, or else k-rate control signals, previously created by other unit generators. The function number argument is fixed (an i-rate value) for the duration of each note. (Normally, we cannot change waveshapes in the middle of a note.) However, the function table number can change from one note to the next. If the oscillator is running at the audio rate, its amplitude argument can be updated at any rate.

The white noise unit generator rand has only one required argument, which determines the amplitude of the noise band. If we run rand at the audio rate, we can update this amplitude value every sample (a-rate), every control period cycle (k-rate), or only once per note (i-rate). If rand is running at the k rate, audio rate amplitude updates are not possible.

1.4. A Simple Instrument Algorithm

See the discussion of INSTRUMENT BLOCK STATEMENTS in the Csound reference manual ]

We are now ready to start making some music, or at least some sound. So, without further ado, we present our first orchestra, which we would type into a file with a text editor such as vi. We will call this file first.orc:

sr= 44100
kr= 2205
ksmps= 20
nchnls= 1
instr 1
asound oscili 15000, 440, 1
out asound
endin

This is about as simple an orchestra as we could design. Savor it. In a couple of weeks, as you ponder the intricacies on lines 47 through 63 of some distant descendent of this little fellow, you may look back on these few pristine lines with almost unbearable nostalgia. But perhaps not. This orchestra also is so limited that it is highly unlikely you would ever want to use it, or to listen to its output for more than a couple of seconds.

Our orchestra includes a single instrument block, or algorithm. An instrument block consists of three things: A line identifying the number of the instrument block; the body of the instrument; and finally, the word endin, which signifies the end of this instrument block.

Here, we have given the instrument the auspicious number "1." Any number between 1 and 200 will do, but every instrument block within an orchestra must have a unique number.

The two line body of this instrument. can be translated as follows: Create an interpolating oscillator (oscili, a cousin of the basic oscil unit generator discussed above). Run this oscillator at the audio-rate, and write the results of its operations into a RAM memory location we will call asound. Give the oscillator a fixed amplitude of 15000 (on a scale of 0 to 32767). Make it sample a waveshape defined in our score by function table number 1. Set the output frequency to 440 herz. Then (out asound) write the output of RAM memory location asound to the output soundfile.

1.5. Oscil and Oscili

[ See the discussion of OSCIL and OSCILI in the Csound reference manual ]

The oscili unit generator in the example above requires a closer look, since oscillators are the most important components of many instruments. An oscillator is a signal generator, which often (but not always), it is used to create a periodic signal, in which some pattern is repeated many times. As noted earlier, Csound oscillators have three required input arguments - amplitude, frequency and function number - and an optional fourth argument (not used in the example above) specifying a starting phase at which the function is to be read.

Function Number (3rd oscillator argument) :

Digital oscillators cycle through a table of numbers (called a function, in Csound), which often represents one cycle of some waveform or shape. Practically any shape can be defined in a function definition, as we will see later, but a particularly common common waveshape is the sine wave. Functions are defined and numbered in the score. The third argument to oscil or oscili specifies the number of the score function to be read by the oscillator. Functions are created and loaded into memory at the beginning of a Csound soundfile compilation job, and unless one employs the -d option of the csound command, all functions within the score file are displayed near the beginning of the the sterr (standard error message) output of the Csound compilation job.

Starting Phase (optional 4th oscillator argument)

The optional fourth argument [iphs] specifies where the oscillator should begin reading within the table. The default, when the argument is left blank, is to begin at the beginning of the table. Valid arguments range between 0 and 1. . A value of .5 would cause the oscillator to begin reading half way (180 degrees) through the table; a value of .333 would cause reading to begin 1/3 of the way (120 degrees) into the table.

For a repetitive sine wave audio signal of, say, 440 herz, the starting phase makes no audible difference, and the argument can be omitted. However, if a control oscillator is creating a subaudio, five herz sine-wave vibrato sig- nal, beginning at a starting phase of .5 (half-way through the sine wave) would cause the resulting pitch first to be lowered, then raised, rather than the reverse.

The partials produced by most acoustic instruments are often not in phase, but these phase differences seem to make little audible difference. (This point has been studied and debated for many decades, however.) Phase differences DO become significant when mixing signals of the same or nearly same frequency (e.g. doubling a note between instruments, or combining direct and delayed signals).

Frequency (2nd oscillator argument) :

The second argument to an oscillator specifies the rate at which it must read through the function table. A value of 440, as in the example above, will cause the oscillator to read through the table ("wrap around") 440 times for each second of sound created.

An oscillator will almost never read every number within a single cycle function table in continuous succession. Rather, since both the sampling rate and the size of the function table are fixed, the oscillator will need to skip over several numbers within the table before taking each new sample reading in order to produce the correct frequency. This "skip" value is called the sampling increment.

In our example, with a sampling rate of 44100 and a requested frequency of 440 Herz, the oscillator will need to spit out 100.22727 samples to represent each cycle :

100.22727 samples per cycle * 440 cycles = 44100 samples per second

Csound function table sizes generally must be a power of two (exceptions are noted later), and a table size of 1 k (1024 numbers) is a typical length. To figure out the correct sampling increment, the oscillator employs the formula

                           table length   *   frequency
    sampling increment  =         sampling rate

or, in our example,

                            1024  * 440
    sampling increment   =     44100       =  10.21678

This means that our oscillator will read in the first number from the table, using it to compute the first output sample value, then skip the next ten numbers within the table, using the eleventh number to compute output sample 2, the 21st table number to compute output sample 3, and so on. On approximately every fifth output sample, the oscillator will skip eleven rather than ten numbers within the table.

Every frequency requires a unique sampling increment. However, none of this mathematical unpleasantness need concern the user; the oscillator takes care of all of this automatically.

1.5.1. Interpolating and Truncating Oscillators

This brings us to the difference between interpolating oscillators, such as the Csound oscili, and truncating (non-interpolating) oscillators, like oscil. With a sampling increment of 10.21678, the oscillator should find values at the following points in the table :

0 10.21678 20.43356 and so on

Obviously, there is no value at location 10.21678 in the table - only values at locations 10 and 11. Truncating oscillators (oscil) keep accurate track of the cumulative sampling increment, but, in the example above, return the values of table locations 0, 10, 20, 30 and so on. The interpolating oscili, by contrast, will take the time to compute the difference between the numbers in table locations 10 and 11, multiply this difference by .21678, and add the result to the number in table location 10. By interpolating between adjacent table locations for each input sample in this fashion, oscili will provide better resolution (representation) of the waveform, with less round-off error and thus less harmonic distortion. The price? Greater computation time for this particular unit generator, by at least a factor of two.

If our orchestra contains a single oscillator, the difference in computation time between oscil and oscili might be trivial. But if our orchestra includes several interpolating oscillators, and our score requires that many notes be computed simultaneously, the computation time difference becomes more substantial. For non-real-time synthesis of audio signals, oscili is often the better, or at least the safer, choice. For control signals, such as a 5 herz vibrato pattern, however, it is unlikely that the higher resolution would make much audible difference. We would probably use the faster oscil to create this signal, and would run this oscillator at the control rate rather than at the audio rate.

Note that by using very large table sizes - say, 4096 or 8192 points, rather than 1024 - to represent a waveform, round-off error can be reduced when truncating oscillators are used. This is the solution often employed in higher quality commercial digital synthesizers, and one we also employ when running Csound in real time. However, larger tables require more RAM. Such tradeoffs between computation time, memory space and signal resolution are encountered frequently in digital synthesis. The harsh, nasal timbres produced by many cheaper hardware synthesizers result from such factors: low sampling rates, and round-off errors produced when truncating oscillators read waveshapes stored in comparatively small tables.

Amplitude (1st oscillator argument) :

The tables of numbers for most sine wave and other synthetic audio functions are floating point values that range between -1. to +1. The amplitude argument to an oscillator specifies a multiplier for each number read in from the function table. On a 16-bit integer system, the output integer samples are scaled between 0 to +/- 32767. Thus, the number 15000 used in our example merely denotes a value within the acceptable range. It is impossible to say whether this value will be perceived as mezzo-piano, forte, or whatever. (Recall that timbre is often a more important factor in our perception of loudness than ampitude.)

In general, we try to create source signals at fairly hot levels, with a maximum amplitude peak somewhere between 15000 and 32000 for 16 bit signals, in order to take advantage of the full 16 bit signal resolution. Level and balance adjustments between different signals within a mix generally are accomplished during mixing operations, in the same manner that one users faders on a mixing console (or vitural faders in a sequencing or audio mixing program) when bouncing multiple tracks down to a stereo master. In creating source soundfiles, however, one must take care not to exceed a maximum amplitude of 32767 (for 16 bit samples) at any given point, or else severe distortion will result. The Csound sterr terminal output provides the error message "samples out of range" whenever the amplitude of a sample exceeds 32767. If several copies of an instrument are playing simultaneously (for example, a chord, or overlapping sustaining notes), be conservative in your initial amplitude arguments. These can always be increased on subsequent runs of the job if you find that the resulting total amplitude values are low.

In sum, we can paraphrase the three required arguments to an oscillator as three questions. These are:

(1) What is the intensity level of the signal? (amplitude);

(2) How many times per second, or at what rate, is the waveshape being produced? (frequency); and

(3) What is the time-varying waveshape of the signal? (function number, which points to a table of numbers that has been compiled and stored in RAM.)

Output statements: out, outs, outs1 and outs2

[ See the discussion of unit generators OUT and OUTS in the Csound reference manual ]

The statement out asound on the penultimate line of our sample orchestra file is called a 'standard out' statement. The out unit generator sends the current value of the RAM memory location we have called asound to an output buffer. Here it is added to any value (from other notes being played simultaneously by this instrument, or by other instruments within the orchestra) already in the buffer. Eventually, a group of a thousand or so samples within the buffer are written as successive samples to the disk soundfile, or, if Csound is being run in real time, toe system DACs.

Since our orchestra is monophonic, we don't have to worry about spatial localization. However, if we change our orchestra to stereo (by setting the header nchnls argument to 2), we must use unit generator outs (or else outs1 and outs2), rather than out, in order to specify stereo localization. The standard out statement might look like this:

outs a1, a1

This would send the signal at full amplitude to both output channels. If the standard out statement looked like this:

outs (.7*a1), (.3*a1)

or else like this :

outs1 .7*a1
outs2 .3*a1

70 % of the signal would be sent to the left channel, and 30 would be sent to the right.

1.6. Score files

[ Read the discussions of THE STANDARD NUMERIC SCORE and of
I STATEMENT (INSTRUMENT or NOTE STATEMENT) in the Csound reference manual ]

Our first.orc file provides a working, if trivial, instrument algorithm. Now we must tell this algorithm how many notes to play, what the durations of the notes should be, and what waveform the oscillator should read. We could create a score11 file like the following to create a sine wave table (f1, where the 1 corresponds to the function number we have told our oscillator to use), and then to specify a single note lasting three seconds:

Score11 input file:

  *f1 0 1024 10 1; <this line defines function number 1, a sine wave
  i1 0 0 1;        < instrument number 1 plays one note
  p3  3;           < the duration of this note is 3 beats
  end;

The resulting score11 output file sout, a Csound format score file, would look like this:

  f1 0 1024 10 1
  i1 0.000 3.000
  e

We are now ready to compile our soundfile with Csound :

   csound  first.orc  sout  or, on ECMC systems:    cs  first.orc  sout 

Alternatively, since our Csound score is so simple, we might find score11 superfluous, and instead type the three lines of the Csound score directly into a file. In this case, we might include Csound comments, which begin with a ; (rather than with a <):


  f1 0 1024 10 1  ; this line defines function number 1, a sine wave
  i1 0.000 3.000  ; instrument number 1 plays 1 note lasting 3 seconds
  e

We need not call this Csound score file "sout." Perhaps first.sco, or - yes! - evocative.sco would be more descriptive.

Note that the single I Statement line in our score has three parameters: p1 (i1) specifies which instrument within the orchestra file is to play this note; p2 (0.000) specifies the starting time of the note; and p3 (3.000) specifies the duration of the note.

1.7. Creating Function Table Definitions

[ See the discussion of F (FUNCTION TABLE) STATEMENT in the Csound reference manual ]

Our next major topic concerns function table definitions, which must be included in our score file whenever we employ one or more oscillators within our orchestra. Like I (note) statements, F (function) statements consist of a series of parameters (variables):


(p1) (p2) (p3) (p4) (p5)
 f1   0   1024  10   1  ; Csound score file function definition
 *f1  0   1024  10   1 ;  <score11 input file definition of the same function
Note that in score11 input files, the f must be preceded by an asterisk, a flag that tells score11 simply to reproduce the line as is, and must conclude with a semicolon.

The first parameter field (f1), specifies the number of the function, in this case 1, although 10, 125 or 1000 would do just as well. One cannot have two different functions within a score with the same number active at the same time. However, two or more oscillators can read simultaneously from the same function table.

The second p-field determines at what time the function will be created. In this case, the function is created at time '0,' that is, before the computation of samples begins.

If we were creating a long, complex soundfile, say, 40 seconds or so, and didn't need this particular function until halfway through, we could give it a starting time of 20. The table then would not be created until 20 beats into the soundfile. This might be elegant, but is rarely required, unless we don't have enough computer RAM to squeeze in everything that happens in the first 20 seconds. With today's computers, this is rarely a problem.

The third parameter (1024) determines how many numbers will be used to outline the desired shape. As discussed earlier, the higher the number, the greater of resolution, but the more memory space required to store the table. The table size must be either a power of 2, (2, 4, 8, 16, 32, 64, 128, 512, 1024, 2048, 4096, 8192 etc.) or else a power of two- plus-one (3, 5, 9, 17, 33, 65, 129, etc.).

=> If the function is going to read repetitively by an oscillator, then a power of two should be used.
=> If the function will be read only once per note, a power of two plus one is better. Examples of the latter case will be discussed in the section on envelopes.

The fourth p-field in the function definition statement is a call to a particular function generating program, which will actually calculate the numbers of the table and load them into RAM. These programs are called gen routines in Csound (and in many other music compilers as well, since they are all derived from programs of the same name originally written at Bell Labs in the 1960s). Our function table definition invokes gen10.

1.8. GEN Routines : gen10

[ See the discussion of GEN10 in the Csound reference manual. ]

gen10 creates a table that represents one cycle of an audio waveform consisting entirely of harmonic partials. By harmonic, we mean that every frequency component is an integer ratio - exactly twice the fundamental frequency, three times the fundamental, and so on. The relative amplitude of each harmonic is indicated, successively, in the remaining p-fields of the function definition. In our example sine wave function definition, only one additional p-field is included, specifying a value of 1. This means that the first partial (the fundamental) has a relative strength of 1, while the remaining harmonics all have a relative strength of 0. This will produce a sine wave.

Suppose we want to create a wave that consists of only odd numbered harmonics, all of equal intensity. Our function definition might now look something like this:

     function definition: *f1 0 1024 10 1 0 1 0 1 0 1 0 1 0 1;
              harmonics:                        1  2  3  4  5  6  7  8  9 10 11
               p-fields:    1    2    3     4   5  6  7  8  9 10 11 12 13 14 15

Here, harmonics 1,3,5,7,9 and 11 all have the same relative strength, while all even numbered partials are suppressed.

Of course, this likely would produce a rather unnatural timbre. It would be much more likely for the various harmonics to have different relative strengths :

*f1 0 512 10 1 0 .33 0 .2 0 .14 0 .11 0 .09;

This makes the fundamental stronger, and the higher odd partials progressively weaker. In fact, the function above would approximate a square wave, though with sloped sides, because the waveshape is band-limited in frequency. We have specified only odd harmonics 1, 3, 5, 7, 9 and 11. Additional, higher odd-numbered harmonics would be necessary to produce the right angles of a true square wave. As of this writing, function definitions, as well as Csound orchestra and score files, can include up to 150 p-fields (a limit that may soon be raised), so we could add many more harmonics if we so desired. However, we would have to be careful about using such a function to create high-pitched tones, especially at lower sampling rates, since the highest harmonics might exceed the Nyquist frequency and alias.

Example: With a sampling rate of 22050 and a pitch of 1000 Herz, any harmonic above number 11 would fold over.

(Although not required, it is generally good practice to give a value of 1 to the strongest partial -- which will not always be the fundamental -- and to scale the others accordingly, as numbers between 0 and 1.)

The time has finally come to put to use what we have learned so far, to experiment with some audio function definitions, and to create a couple of soundfiles which are available for your listening and dancing pleasure in the sflib/x directory. To do this, however, we must first upgrade our orchestra file, replacing some of constant values with score p-field variables, so that we can vary the oscillator's amplitude, frequency and function number arguments from note to note. Our revised orchestra file now looks like this:

;  #############################################################
; Soundfile examples  "ex1-1"  and  "ex1-2"
;  #############################################################

Orchestra file used to create these two soundfiles:
-------------------------------------------------------------------------
   sr= 44100
   kr = 2205
   ksmps = 20
   nchnls = 1

   instr 1
   asound  oscili  p5, p4 , p6
   out asound
   endin
-------------------------------------------------------------------------

Soundfile example ex1-1 in /sflib/x was created by means of the orchestra file above, and the following score11 file:

-------------------------------------------------------------------------
< Score11 file used to create soundfile example ex1-1 :
*f1 0 1024 10 1.;    < sine wave
*f2 0 1024 10 1. 0 .33 0 .2 0 .14 0 .11 0 .09; < odd harmonics
*f3 0 1024 10 0 .2 0 .4 0 .6 0 .8 0 1. 0 .8 0 .6 0 .4 0 .2 ; < even harmonics
 < function 4 includes harmonics 11 through 20
*f4 0 1024 10 0 0 0 0 0 0 0 0 0 0 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. ;
 < f5 = harmonics 1, 6, 11, 16, 21 , 26 , 31 ,36
*f5 0 1024 10 1 0 0 0 0   .8 0 0 0 0   .7 0 0 0 0   .6 0 0 0 0   .5 0 0 0 0
 .35 0 0 0 0   .2 0 0 0 0   .1;

i1 0 0 10;  < play 10 notes
p3 4;
du .95;
p4 nu 220 * 5 / 27.5 * 5 ;   < frequency :
                             <  5 notes at 220 hz, then 5 notes at 27.5 hz
p5 15000;  < amplitude (constant here for all notes)
p6 nu 1 / 2 / 3 / 4 / 5;
end;
-------------------------------------------------------------------------

The Csound score file ("sout") produced by the above score11 file looks like this:

f1 0 1024 10 1.
f2 0 1024 10 1. 0 .33 0 .2 0 .14 0 .11 0 .09
f3 0 1024 10 0 .2 0 .4 0 .6 0 .8 0 1. 0 .8 0 .6 0 .4 0 .2
f4 0 1024 10 0 0 0 0 0 0 0 0 0 0 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
f5 0 1024 10 1 0 0 0 0 .8 0 0 0 0 .7 0 0 0 0 .6 0 0 0 0 .5 0 0 0 0 .35 0 0 0 0 .2 0 0 0 0 .1
  i1 0.000 3.800 220 15000 1
  i1 4.000 3.800 220 15000 2
  i1 8.000 3.800 220 15000 3
  i1 12.000 3.800 220 15000 4
  i1 16.000 3.800 220 15000 5
  i1 20.000 3.800 27.500 15000 1
  i1 24.000 3.800 27.500 15000 2
  i1 28.000 3.800 27.500 15000 3
  i1 32.000 3.800 27.500 15000 4
  i1 36.000 3.800 27.500 15000 5
end of score


Some questions to ponder on this example:

After experimenting with some isolated test tones in this fashion, we often can isolate some material that can be used to create a more intriguing musical gesture. Listen to and study the following example, which makes considerable use of random selection procedures. Three audio waveshape functions similar to f4 in the previous example are employed. The fundamental frequencies at the very end of the example are subaudio (see p4 below).

-------------------------------------------------------------------------
; Score11 file used to create soundfile example  ex1-2  :
 < function 1 includes harmonics 11 through 20 :
*f1 0 1024 10 0 0 0 0 0 0 0 0 0 0 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. ;
*f2 0 1024 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1. 1. 1. 1. 1.
  1. 1. 1.  ; < harmonics 21 thru 28
*f3 0 1024 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
   1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. ; < harmonics 30 thru 41

i1 0 8.5 ;  < play for 8.5 beats
p3 mo 4. .6 .15/  4.5 .15 .6;
du mx 8.5  301. 302. 304.;
rs 444;   < this reseed value produced better results than some others I tried
p4  mx 1. 20 50  72/ 6. 72 50  800  500 / 1.5 6. 8. 5.;
     < frequency : pitch gradually rises
p5 mx 4. 2000 4000 6000 8000/4.5 6000 8000 4000;  < amplitude
p6  se 8.5 1 2 3;  < audio function number : randomly selected here
end;
-------------------------------------------------------------------------

Appendix Csound score file examples : Chapter 1

Note that our long score11 function definition for f3 in the example above extends over two physical lines, but that these two line comprise only a single line of code (a score11 line does not end until a semicolon is reached). In Csound orchestra and score files, however, a newline character (produced by a carriage return) terminates a line of code, unless the newline is preceded by the backslash character \

1.8.1. gen9

[ See the discussion of GEN09 in the Csound reference manual ]

Function generator gen10, while relatively easy to use, is also somewhat limited. Its cousin, gen9, though more complicated to use, provides greater flexibility, enabling us to specify

(1) only the partials we want ;
(These partials can be either harmonic or inhar- monic, but the use of inharmonic partials requires a little trickery, discussed below.)
(2) the relative strength of each of these partials; and,
(3) the starting phase of each partial.

Each partial, then, requires three p-field arguments within the function table definition. Here is an example:

        f1 0 1024 9 1 .5 0 5. 1. 90 7. .35 180 11. .2 270;
(p-fields): 1    2    3    4  5   6   7  8   9    10  11    12    13   14    15   16

Here, we place a 9 in p4 to summon gen9 to create the table. The remaining p-fields can be roped off in groups of threes (p5-7, p8-10, p11-13 and p14-16). (Alternating italic and bold type are used above to differentiate these groups.) Within each of these groups, the first number is the frequency of the partial (as a multiplier of the fundamental) ; the second number is the relative amplitude strength ; and the third is the initial phase, expressed in degrees (0 to 360). Thus, this function will create a waveform that consists of harmonics 1, 5, 7 and 11, with relative amplitude intensities of .5, 1., .35 and .2. The fifth harmonic will be 90 degrees out of phase with the fundamental, the 7th partial 180 degrees out of phase, and the 11th partial 270 degrees out of phase.

It is unlikely that these phase relationships will make much, if any, audible difference. Note, too, that within gen9, the starting phase of individual partials is expressed in degrees - 0 to 360. By contrast , the optional phase argument to oscillators within an orchestra file, which specifies where the oscillator is to begin reading within the table, must be specified as a fraction between 0 and 1. It is easy to become confused over these two quite different usages of the word "phase." If no one in class asks for clarification on this point, we'll know that you didn't read this section.

One need not specify harmonic partials. Inharmonic frequency ratios are also possible, as in the following function:

*f1 0 1024 9 1. 1. 0 2.7 .5 0 5.4 .33 0 8.1 .12 0;

Here we create four partials, with frequencies (shown here in bold type) that will be, respectively, 1, 2.7, 5.4 and 8.1 times the base frequency we supply to the oscillator.

This looks fine on paper, but it will not give us the audible result we expect. Additional high frequency artifacts will be present, and the timbre will be buzzy rather than "pure." Why? Within the function table, which represents one cycle of this waveform, only the first partial (1) will be symmetrical, beginning and ending at the same phase point. The second partial will contain 2.7 cycles of a sine wave, the third partial 5.4 cycles, and the fourth partial 8.1 cycles. The fractional (.7, .4 and .1) cycle components at the ends of these three partials will result in a discontinuity between the end of the table and the beginning. Each time the oscillator wraps around the table, high frequency artifacts, or "clicks," will result from this asymmetric discontinuity.

This does not prevent us from creating inharmonic partials, but it does require some slight-of-hand within our function table definition and in the frequency input to our oscillator. Consider the orchestra and score11 files, reproduced below, used to create soundfile example ex1-3. The orchestra file is identical to our previous orchestra except for the oscillator frequency argument (shown here in boldface). Within the score11 file, the partial frequencies for both audio functions also are shown here in bold type.

;  #############################################################
; Soundfile example  ex1-3
;  #############################################################

Orchestra file used to create this soundfile:
-------------------------------------------------------------------------

     sr= 22050
     kr = 2205
     ksmps = 10
     nchnls = 1

     instr 1
     asound  oscili  p5, .1 * p4 , p6
     out asound
     endin
-------------------------------------------------------------------------

score11 file used to create this soundfile:

*f1 0 2048 9 10 .8 0  27 1. 0  54  .4 0  81  .2  0;  <  partials 1, 2.7 , 5.4 & 8.1
 < function 2 includes partials at approximately  2,  3,  9, 10, 16 and 17 times
 < the fundamental {which is missing}
*f2 0 2048 9 21 .4 0  29 .5 0  91 1. 0  100 .7 0  161  .2  0 170 .15 0;

i1 0 0 4;  < play 4 notes
p3  3.;
du .95;
p4  nu 55 / 261.6 ;   <  frequency : alternate between a1  &
c4 {middle c}
p5 nu 12000 / 7000;         < amplitude
p6 nu 1 // 2// ;  < audio function number
end;
-------------------------------------------------------------------------

Within the function definition of f1, we specify partial frequencies of 10, 27, 54 and 81. Within the orchestra file, we have modified the oscillator frequency argument, directing it to wrap around function tables at a rate one tenth the value specified in p4. Thus, for the first note in our score, where the oscillator frequency is set to 55 herz in p4, the oscillator actually will wrap around the table at a rate of only 5.5 cycles per second. The frequencies of the waveform will be 10, 27, 54 and 81 times this 5.5 herz base, or, respectively, 55, 148.5, 297 and 445.5 herz. The audible result, of course, will be identical to that produced by an oscillator wrapping around a table at 55 herz, with partial frequencies of 1., 2.7, 5.4 and 8.1, except that we have eliminated the discontinuity in the waveform.

The second function in our score, used for notes 3 and 4, specifies partial frequencies of 21, 29, 91, 100, 161 and 170, which actually become frequency ratios of 2.1 , 2.9 , 9.1, 10., 16.1 and 17. These partials are almost, but not quite, harmonic. Therefore, even with no fundamental specified, this spectrum will produce a clearly defined pitch at the phantom fundamental frequency, but with amplitude beating resulting from the slight inharmonicity.

Note, too, that because these two tables produce very complex waveshapes (since they include so many cycles of each partial), we have increased the table sizes from the customary 1024 to 2048. 4096 might produce even better audio quality.

Obtaining copies of the orchestra and score files examples

ECMC users can obtain copies of the orchestra and companion score files for all of the examples within this tutorial (such as ex1-1, ex1-2 and ex1-3 above) in either of two ways:

  1. If you are working in a shell window on one of the SGI systems:
    • To obtain a listing of available orchestra ("instrument") files from this tutorial, type: lsins
    • To copy one or more of these orchestra files into a file called orch.orc (which can be abbreviated simply as orc) within your current working Unix directory, use the ECMC mko ("make orchestra file") command:
      mko   filename(s)
      Example:  mko ex1-1
    • To obtain a listing of available score11 input files for the tutorial examples, type: lsex
    • To display one or more of these score11 input files, type
      getex   filename(s)
      Example:  getex  ex1-1
    • To copy one or more of these score11 input files into a file of your own, redirect the output:
      getex filename(s) > myfile
      For example, typing
      getex ex1-1 ex1-2 ex1-3 > chap1scores
      will copy the score11 input files for tutorial examples ex1-1, ex1-2 and ex1-3 into a file called chap1scores within your current working Unix directory.
  2. If you are using cecilia to run Csound you can access orchestra and Csound (not score11) score files for all of the examples in this tutorial, as well as for Eastman Csound Library algorithms, by selecting
    File > New > ESMTutorial
    and then selecting the desired orc/sco module. Please consult the ECMC help file cecilia for details on setting up your cecilia environment to include these ECMC tutorial modules, as well as modules from the Eastman Csound Library, such as marimba, samp and gran.

Assignment

1) Study and review the material in this chapter, and in the corresponding pages of the csound manual. Jot down any questions you have (before you forget them) and bring up these questions in the next class. Do this each week.

2) Using the examples within this chapter as initial models, create two or three simple Csound orchestra files, and a few brief scores for these orchestras to play. Your scores should include functions using gen9 and gen10. Compile soundfiles from these orchestra and score files and play these soundfiles (or else run Csound in real-time mode) and make sure that you are getting what you expect. Be adventurous.

Eastman Csound Tutorial: End of Chapter 1


NEXT CHAPTER (Chapter 2) -- Table of Contents CHAPTER 1 -- CHAPTER 2 -- CHAPTER 3 -- CHAPTER 4 -- CHAPTER 5 -- CHAPTER 6 APPENDIX 1 -- APPENDIX 2