-
sr = 44100 kr = 4410 ksmps = 10 nchnls = 4
A Beginners Guide to
Csound
instr 1 ;;;; phase vocoder resynthesis and time-stretching ;;
read pv analysis over time and resynthesize ktime line p5, p3, p6 ;
inskip, dur, and outskip asig pvoc ktime, 1, p4, 0 ; read pvanal
(p4) over dur ;; apply amplitude envelope kenv expseg 0.001, p3*p9,
1, p3*p10, 1, p3*p11, 0.001 aout = asig * kenv ;; read panning
function table ktabler phasor 1/p3 ; pointer from 0-1 (over dur)
kpanx tablei ktabler*ftlen(p7), p7 ; read x coord as fn of time
kpany tablei ktabler*ftlen(p8), p8 ; read y coord as fn of time ;;
panning a1, a2, a3, a4 pan aout, kpanx, kpany, 17, 1, 0 ;; outputs
outq a1*p12, a2*p12, a3*p12, a4*p12 ; p12 is master gain
endin
instr 2 ;;;; granular synthesis from a soundfile
Christopher Watts, DMA
Director of the Newell Center for Arts Technology St. Lawrence
University
draft edition
2008 Christopher Watts
-
A Beginners Guide to Csound
Christopher Watts, DMA Director of the Newell Center for Arts
Technology
St. Lawrence University
-
i
A Beginners Guide to Csound
Table of Contents Introduction v Obtaining and Installing Csound
vii Chapter 1: Getting Started 1 The Orchestra File 1 Header
Statements Instrument Declarations The Score File 4 F-Statements
I-Statements E-Statement Chapter 2: Scorefile Variables 7 Replacing
Values with Variables 7 Converting Values 9 Chapter 3: Adding
Envelopes 11 Applying an Amplitude Envelope 11
The linen Opcode Creating More Complex Envelopes 12
Line Segments with linseg Linear versus Exponential Envelopes 14
Line Segments with expseg Multiple Envelopes 15 Chapter 4: Stereo
Panning 17 Placing Sound in the Stereo Field 17 Dynamic Panning
with Function Tables 19 Chapter 5: Synthesis 25 Additive Synthesis
25
Amplitude Modulation 26 Simple AM Ring Modulation Frequency
Modulation 28 Simple FM Implementing an Index of Modulation Adding
Complexity
-
A Beginners Guide to Csound
ii
Chapter 6: Acoustic Realism in Instrument Design 33
Fluctuations in Amplitude and Frequency 33 Tremolo Vibrato
Jitter Putting it all Together
Correlations Between Parameters 35 Timbre as a Function of
Loudness Envelope as a Function of Pitch Further Correlations
Chapter 7: MIDI control of Csound Instruments 39 Csound and MIDI
39 MIDI Opcodes 39 ampmidi and cpsmidi midictrl linenr pchbend
Chapter 8: Working with Sampled Sound 45 The soundin Opcode 45 The
diskin Opcode 47 About Environment Variables 48 Chapter 9: Reverb,
Delay, and Global Variables 53 The reverb2 and delay Opcodes 53
Global Variables 53 Chapter 10: Filters 59 Filtering Noise 59
The Q Factor 60 Moving Filters 61 Filter Banks 61 Chapter 11:
Synthesis-by-Analysis Techniques 67 Linear Predictive Coding (LPC)
67 lpanal
lpread and lpreson Manipulation in Resynthesis
Phase Vocoding 70 pvanal pvoc Manipulation in Resynthesis
-
iii
Phase Vocoder Cross-Synthesis Chapter 12: Programming Efficiency
and Style 79 Efficient Design 79 Style 81 More about the Csound
Document Format (csd) 82 Macros 84 Recommended Reading 91 Index
93
-
A Beginners Guide to Csound
iv
-
v
Introduction
About this Book Csound is a very powerful tool for creating and
processing sound. Because of its extremely flexible nature, many
find Csound difficult to learn; it can be especially overwhelming
at the beginning. This introduction to Csound is intended for the
individual who has some experience with commercial audio
applications such as MIDI sequencers and Digital Audio
Workstations, but little or no programming experience. It is hoped
that, by starting with the core concepts and gradually adding
complexity, newcomers to Csound may quickly overcome the
overwhelming feeling that such a deep program can often produce.
There are many excellent Csound resources available, and a list of
recommended ones can be found at the end of this document. This
beginners guide is by no means comprehensive! It simply introduces
some of the basic concepts, provides very simple example code, and
refers the reader to more authoritative sources. Enjoy.
Acknowledgements Special thanks to Dr. Stephen David Beck, who
took me through the beginner stage with Csound. Thanks to Mr.
Joshua Titus as well, who served as a willing guinea pig during the
initial preparation of these tutorials.
-
A Beginners Guide to Csound
vi
-
vii
Obtaining and Installing Csound
Getting Csound Csound is freely available for most major
platforms. Current versions compiled for your platform can be
downloaded from csound.sourceforge.net, as can source code. One of
the best Csound resources is www.csounds.com. Links are available
to download software, talk with other users, consult reference
materials and tutorials, and purchase resource materials such as
The Csound Book.
Installing Csound Because Csound is basically a compiled
language, it does not have a standard user interface. It can be run
from the command line, and many front ends have been developed for
those who prefer a point-and-click interface. Because of this,
installations of Csound can vary significantly. Each of the most
popular platforms will be discussed briefly below: Max OS X: At
present, the easiest way to run Csound on Mac OS X is to use
MacCsound by Matt Ingalls, available at csounds.com/matt/MacCsound.
An OS X version of Csound is also available for download on
sourceforge. With this version, it may be necessary to set some
environment variables read the installation instructions carefully.
Linux: Download the appropriate version for your system from
sourceforge. Install the package or copy the executable(s) into
/usr/bin, as appropriate. It may be necessary to set some
environment variables read the installation instructions carefully.
Windows NT/2000/XP: Csound can be run on Windows in a GUI or in
Console. Current versions can be downloaded from sourceforge.
CsoundAV, a variant that supports OpenGL video, is also available
at www.csounds.com/csoundav. Classic Mac OS: Mac OS 7-9 are no
longer officially supported. However, Csound 5.01 for classic Mac
OS is still available on sourceforge. Note that while installing
and running Csound on different platforms can vary significantly,
programming orchestra and score files is the same no matter what.
We will address this in the next section.
-
A Beginners Guide to Csound
viii
-
1
1
Getting Started Basic operations in Csound involve two files:
the orchestra and the score. These files can be created in any text
editor, but must be saved in plain text format and named with the
appropriate suffixes: .orc and .sco. For example, a project
entitled bad piece might consist of the files badpiece.orc and
badpiece.sco. Each of these two files has specific functions.
Generally speaking, the orchestra file describes the instruments to
be used, and the score file tells when and how they will be used.
Both the orchestra and score files must follow certain conventions
in order to be understood by Csound. We will outline these
conventions below:
The Orchestra File The orchestra file has two basic types of
statements: headers, which set basic parameters common to all
instruments, and instrument declarations, which describe the
processes the instruments will perform. Below is an example of a
very simple orchestra file:
sr = 44100 kr = 4410 ksmps = 10 nchnls = 1 instr 1 asig oscil
10000, 440, 1 ; an oscillator that generates a test tone asig out
asig ; send asig to the output endin
In your text editor, open a blank document and enter the text
above. Save your document as chap1.orc (it must be in plain text
format.) Note: Some Csound front ends, such as MacCsound, save both
the orchestra and score in one special file (called a Csound
document or .csd. See Chapter 13 for more about .csd.) If this is
the case, simply type your orchestra code into the front end
program in the appropriate place. Headers. The orchestra file
begins with four statements that tell Csound about the output we
wish to create: Sampling Rate. (sr) The Sampling Rate, as you
probably know, is the number of data points the computer will plot
on the audio waveform each second. It is measured in cycles per
second, or Hertz. CD-quality audio is recorded at a sampling rate
of 44,100 Hz. DVD-quality audio is recorded at a sampling rate of
96,000 Hz.
-
A Beginners Guide to Csound
2
Control Rate. (kr) Many operations in Csound do not need to be
calculated for every sample. They can be calculated a slower rate,
called the control rate. This is typically one-tenth of the
sampling rate. More on this later. Samples per Control Rate.
(ksmps) Csound requires this value to be stated in the headers.
Simply divide the sampling rate by the control rate (usually 10).
Number of Channels. (nchnls) This header tells Csound how many
channels of output to generate. For the sake of simplicity, we will
begin with a mono output. Instruments. The majority of the
orchestra file is made up of instrument declarations. Each
instrument describes a set of signal generators and/or signal
processors that performs a specific function whenever it receives
the appropriate commands from the score file (more on the score
file shortly). Below is the general format for instrument
declarations. Compare with the orchestra file above:
instrument number result opcode parameters, separated, by,
commas ; comments output result to be output ; comments
end of instrument declaration There are several important things
to remember about the syntax of an instrument declaration:
Instrument Number. The declaration must begin with instr # and end
with endin. Instruments are typically numbered in order. Csound
loads the instruments in numerical order, so occasionally it is
important to give one instrument a lower number than another.
Opcode. An opcode is a keyword that tells Csound to perform a
particular action. Each opcode has its own arguments, which follow
the opcode and are separated by commas. It is not necessary to
memorize the parameters, as they can be easily looked up in the
Csound Reference Manual
(http://www.csounds.com/manual/html/index.html). Result. Any opcode
that produces an output that can be routed to other opcodes must
have a labeled result (most opcodes fit this description.) These
result labels make it easy to pass signals (or simple values) from
one opcode to another. Result labels follow a very important
convention: a result will always begin with a letter indicating at
which rate the statement will operate. In our example, asig
indicates that the result value of oscil will be calculated at the
audio rate (a-rate), or once every sample. In other instances,
values may be calculated at the control rate (k-rate; once every
ten samples), or at the instrument rate (i-rate; once per
instrument call). Additionally, static values can be assigned that
are not adjustable at all. Output. out is one example of an opcode
that never has a result label. It is always the last opcode in the
chain, so its result does not need to be routed. Additionally, its
result is always calculated at the audio rate.
-
Chapter 1: Getting Started
3
Comment. Csound will ignore anything that appears to the right
of a semicolon, up to the end of that line. We use this feature to
enter comments that help us see whats going on in the program. Also
remember that Csound does not distinguish between spaces and tabs.
Use these to make your code look clean. oscil Each Csound opcode,
or keyword, has its own rules to follow. (It is not necessary to
memorize these they can be easily looked up.) The entry for oscil
in the Csound reference manual reads as follows:
kr oscil kamp, kfreq, ifn [, iphs] ar oscil xamp, xfreq, ifn [,
iphs]
From this entry, we can learn several important things. The
labels kr and ar tell us that the output of oscil can be calculated
at the control rate or the audio rate. Our oscil will run at the
audio rate, so we will examine the second line of the entry. oscil
has four variables, or arguments: xamp, xfreq, ifn, and iphs
(amplitude, frequency, function, and phase). The brackets [ ]
indicate that the final argument is optional. The letter i in ifn
and iphs indicates that these are instrument-rate variables, while
the x in xamp and xfreq indicates that the rate of these variables
is adjustable by the user. We will discuss this further in later
chapters. Next, we will examine these arguments and how they affect
the resultant sound. Amplitude is a measure of signal strength and
roughly corresponds with our perception of loudness. In a 16-bit
soundfile, this value can be any number between 0 and 32767. Any
number higher than 32767 will cause clipping to occur and result in
distortion, clicking, or both (Csound will report samples out of
range.) Frequency refers to the rate of periodicity of the
oscillator (measured in Hertz) and roughly corresponds with our
perception of pitch. The maximum value for this variable is the
Nyquist frequency, obtained by dividing the sampling rate by 2 (In
this case, 22050Hz.) Therefore, appropriate values for xfreq in
this instance will range from 0 to 22050. Remember that the outside
range of human hearing is 20 to 20,000Hz, and that the lowest and
highest notes on the piano are 27.5Hz and 4186Hz, respectively. The
third argument, ifn, allows us to control the waveform of the
oscillator. The waveform is the most significant factor in our
perception of timbre, or tone color. This can be anything from a
simple sinusoid to a complex sampled waveform. The waveform of an
oscil is provided in the score file. We will address this issue in
the section on score files below. The final argument, iphs, allows
the user to set the phase of the oscils waveform (Each cycle is
divided into 360 of phase.) As it is optional, we will leave it out
for the time being. The default value for iphs is 0. The Score
File
-
A Beginners Guide to Csound
4
For our purposes, there are three kinds of statements in a basic
score file: f-statements, which allow for the easy creation of
function tables, i-statements, which invoke instruments in the
orchestra file and supply them with needed parameters, and the
e-statement, which simply tells Csound that the end of the score
has been reached. Below is an example of a simple score file that
corresponds to the orchestra file seen in the previous section:
f1 0 8192 10 1 ; sine wave ;inst start dur i1 0 5 e
In your text editor, open a blank document and enter the text
above. Save your document as chap1.sco (it must be in plain text
format.) Note: Some Csound front ends, such as MacCsound, save both
the orchestra and score in one special file (usually called a
Csound document or .csd.) If this is the case, simply type your
orchestra code into the front end program in the appropriate place
and save as chap1.csd. F-Statements. An f-statement generates a
function table that Csound opcodes can look up to retrieve
information that changes over time. One of the most typical uses of
the f-statement is to generate a waveform for a signal generator
such as oscil. The basic syntax of an f-statement is as
follows:
f# init size gen# values separated by spaces or tabs
Csound has a number of GEN routines that take the values in an
f-statement and generate a function table according to a specific
formula. You will use a variety of GENs, depending on the
situation. It is not necessary to memorize how the various GEN
routines work you can look this information up easily in the
reference manual. In our example orchestra file, we had an oscil
that had the values 10000, 440, 1 as its parameters. The 1 in the
argument ifn means that Csound will load the information that it
finds in f-statement number 1 (f1) in the score and use that data
as the waveform for our oscil. We set this waveform as a sine wave
by using GEN 10:
f1 0 8192 10 1 ; sine wave f-statements are typically numbered
in order. The second value is the initialization time for the table
(in seconds). Normally, tables will be intitialized at the
beginning (time 0). The third value is the table size, or the
number of data points it will contain. Note that the size of a
function table must be equal to a power of two (2n; 2, 4, 8, 16,
32, 64, 128, 256, etc.), or a power of two plus one (2n+1; 3, 5, 9,
17, 33, 65, 129, 257, etc.) We will discuss the reasons for this in
a later chapter. The fourth value is the number of the GEN routine
that will be used to build the table. GEN 10 is a simple function
generator that uses sine waves in a harmonic series to build up
complex waveforms. Each value represents the relative amplitude of
a single harmonic. Since we have only the value 1 in our f-
-
Chapter 1: Getting Started
5
statement, GEN 10 will generate a sine wave at full strength on
the fundamental frequency (currently set to 440Hz in the orchestra)
with no overtones. I-Statements. Before we can hear anything, we
need an i-statement that calls our instrument and tells it what to
do. i-statements always begin with the following syntax:
i# start dur
If we increase the number of variables in our instrument, our
i-statement will get longer. For now, however, we only need these
three values to tell our instrument what to do. The first parameter
(called a p-field) tells Csound which instrument number to call.
The second p-field tells the instrument when to start, in seconds.
A value of 0 will cause the sound to start at the beginning of the
output file. The third p-field tells the instrument how long the
note should last, in seconds. Our i-statement calls instrument 1 at
time 0 and plays for 5 seconds. Note: It is always a good idea to
use a comment to label the p-fields in your i-statements.
E-Statement. Every score file needs an e-statement at the end. This
simply tells Csound that were done. Try running the program. If
youre using a front-end program, simply make sure the orc and sco
files are loaded in and click on the programs run button. The
program may ask you to name your output file (name it chap1.aiff)
and then it will run. If youre using a command line version of
Csound, open a shell, cd to the directory that contains your orc
and sco files, and type the following command:
csound A o chap1.aiff chap1.orc chap1.sco
When you play the output file, you should hear what sounds like
a typical test tone at 440 Hz (the A above middle C). Not very
exciting? Thats okay. The next few chapters will show you how to
take more control over your instruments and get more sophisticated
results.
; chap1.orc sr = 44100 kr = 4410 ksmps = 10 nchnls = 1 instr 1
asig oscil 10000, 440, 1 ; an oscillator that generates a test tone
asig out asig ; send asig to the output endin
-
A Beginners Guide to Csound
6
; chap1.sco f1 0 8192 10 1 ; sine wave ;instr start dur i1 0 5
e
-
7
2 Scorefile Variables
In moving from a very simple instrument like the one in Chapter
1 to a more sophisticated one, one of the first things we can do is
to move control of various parameters from the orchestra file into
the score file. This makes instruments more flexible and often
eliminates the need to write several very similar instruments. It
also creates a situation in which most of the editing work can be
done in the score file, and the orchestra file only has to be
edited occasionally. Replacing Values with Variables The first step
is replacing parameter values in the orchestra file with
variables:
instr 1 asig oscil 10000, 440, 1 out asig endin
becomes:
instr 1 asig oscil p4, p5, p6 out asig endin
Looking back at the i-statement in the score, remember that the
first three p-fields are always designated as instrument number,
start time, and duration:
;instr start dur i1 0 5
Once variables have been added to the orchestra file (p4, p5,
and p6), the i-statement simply becomes longer:
;instr start dur amp freq fn i1 0 5 10000 440 1
Naming Variables. Many Csound programmers like to take this
substitution scheme one step further in the orchestra file by
giving each variable a name:
instr 1 iamp = p4 ifreq = p5 ifn = p6
-
A Beginners Guide to Csound
8
asig oscil iamp, ifreq, ifn ; an oscillator that generates a
test tone asig out asig ; send asig to the output endin
Once again, the i at the beginning of these names designates
that these are i-rate variables, or that they are set only once for
each i-statement. Alternately, amp and freq could be calculated
more frequently if desired. We will see cases when this is
advantageous later. The convention of giving names to the variables
in the orchestra is optional, but many find that it makes the code
clearer in the long run. Each programmer develops his or her own
style as long as the syntax is correct, no errors will result.
Remember that the definition of the variable (iamp = p4) has to
come before the line that refers to the variable. Running this
orchestra and score file as they are now will result in a soundfile
identical to the one produced in Chapter 1. By moving control of
these parameters to the score, however, we have dramatically
increased the flexibility of the instrument. Add this i-statement
to the score file below the first one (but above the e):
i1 6 5 20000 10000 1 If you havent already done so, save this
orchestra and score as chap2.orc and chap2.sco and then run them.
The second note in our new sound file differs dramatically from the
first in loudness and in pitch. Controlling Timbre. To change the
timbre, we will need to change the function table. Add the
following f-statement to the score file:
f2 0 8192 10 1 0 .33 0 .2 0 .14 0 .11 ; square wave and change
the value of p6 (fn) in the second i-statement from 1 to 2. f2
contains odd harmonics with relative amplitudes in a ratio of 1:N,
where N is the number of the harmonic. The third harmonic has an
amplitude 1/3 of that of the fundamental; the fifth harmonic has an
amplitude 1/5 of that of the fundamental, etc. This creates a
waveform that approximates a square wave. It is quite different
from the timbre of the simple sine wave in f1. Here are some other
f-statements with GEN 10 for experimentation:
f3 0 8192 10 1 .11 .04 .02 .01 .008 ; triangle f4 0 8192 10 1 .5
.33 .25 .2 .16 .14 .12 .11 .1 .09 ; sawtooth
Simply add these f-statements to the score and set the value of
p6 to 3 or 4 in any i-statement.
-
Chapter 2: Score File Variables
9
Converting Values Working with Pitch Classes. Sometimes it is
beneficial to work with frequency in terms of pitch classes rather
than cycles per second. Csound contains opcodes that will convert
between cycles per second (cps) and the octave.pitchclass (pch)
format: x.yy. In this format, the number before the decimal point
indicates the octave, and the number after the decimal point
indicates the pitch class (i.e., 00=C, 06=F#, 09=A, etc.; 8.00 =
middle-C, 9.00 = C above middle-C, etc.) This conversion takes
place in the orchestra file:
ifreq = cpspch(p5) After changing the above line in the
orchestra file, values for p5 in all scorefile i-statements must be
changed to the octave.pitchclass format. To change the pitches of
our two i-statements to middle-C and the C# two octaves above, we
will change our i-statements to look like this:
i1 0 5 10000 8.00 1 i1 6 5 20000 10.01 2
The cpspch opcode receives the value of p5 and converts it to a
frequency before passing it on to the oscil. This makes it easy to
select specific pitches, but frequencies that fall between the
cracks of the equal-tempered system can no longer be used. Working
with Decibels. Likewise, it is often beneficial to work with
loudness in terms of decibels rather than raw amplitude values. The
opcode ampdb works in the same way as cpspch:
iamp = ampdb(p4)
We can now specify loudness in our i-statements (p4) in terms of
decibels:
i1 0 5 75 8.00 1 i1 6 5 90 10.01 2
These amplitude values will result in the second tone being
considerably louder than the first. Remember that small changes in
value will result in a very noticeable change in loudness (An
increase of 6dB will sound approximately twice as loud.) At the
beginning of this chapter, we had a simple Csound instrument that
could produce a sine wave. The only parameters under user control
were when the sound started and how long it lasted. We now have an
instrument that can be adjusted in a number of ways: amplitude,
frequency, and waveform. We can use these parameters to change the
loudness, pitch, and timbre of the resulting sound. We have also
learned how to deal with frequency and amplitude in terms of pitch
and loudness, which often makes more sense musically. In the next
several chapters, we will learn how to shape sound using envelopes,
as well as a simple technique for basic stereo panning.
-
A Beginners Guide to Csound
10
; chap2.orc sr = 44100 kr = 4410 ksmps = 10 nchnls = 1 instr 1
iamp = p4 ifreq = cpspch(p5) ifn = p6 asig oscil iamp, ifreq, ifn ;
an oscillator that generates a test tone asig out asig ; send asig
to the output endin ; chap2.sco f1 0 8192 10 1 ; sine f2 0 8192 10
1 0 .33 0 .2 0 .14 0 .11 ; square f3 0 8192 10 1 .11 .04 .02 .01
.008 ; triangle f4 0 8192 10 1 .5 .33 .25 .2 .16 .14 .12 .11 .1 .09
; sawtooth ;instr start dur amp freq fn i1 0 5 75 8.00 1 i1 6 5 90
10.02 2 e
-
11
3 Amplitude Envelopes
Up to this point, we have produced sounds that do not change
over time. One simple way that we can control the shape of a
synthesized sound is through the use of an amplitude envelope. In
its most basic form, an amplitude envelope provides a smooth fade
in at the beginning and a smooth fade out at the end. More
sophisticated shapes can also easily be applied. Applying an
Amplitude Envelope The linen opcode generates linear envelopes that
work well when applied to amplitude. The Csound reference manual
contains the following entry for linen:
kr linen kamp, irise, idur, idec ar linen xamp, irise, idur,
idec
We will use the linen opcode at the control rate (k-rate), so we
will examine the first line in the entry. linen has four arguments:
kamp, irise, idur, and idec (amplitude, rise time, duration time,
and decay time). We can see from the first letter of each argument
that the amplitude value is calculated at the control-rate, while
the other arguments are calculated at the note-rate (only once for
each i-statement). The amplitude argument sets the maximum
amplitude for the envelope (the portion of the sound that is not
being faded in or out). linen breaks the duration of a sound into
three parts: rise, sustain, and decay. The rise, duration, and
decay arguments are times (in seconds) for fade-in time, total
duration, and fade-out time portions of the sound. A value of 0 for
irise or idec will result in no fade in or out, respectively. To
use linen with an oscil, the code might look like this:
instr 1 kenv linen ampdb(p4), .2, 5, .2 asig oscil kenv,
cpspch(p5), p6 out asig endin
The result label chosen here for the linen is kenv, indicating
that it is a control-rate envelope. We are creating an amplitude
envelope, so the linen has to affect the amplitude of the oscil. We
plug the linen into the amplitude argument of the oscil by simply
typing its result in the slot instead of a value or a score
variable. Here is a simple score file to accompany the instrument
above:
-
A Beginners Guide to Csound
12
f1 0 8192 10 1 ; sine ;instr st dur amp pch fn i1 0 5 85 8.07 1
e
Move Control to the Score. The next step is to gain more control
over the envelope by moving values to the score file. We can create
new p-fields in the score file for rise time and decay time very
easily:
instr 1 kenv linen ampdb(p4), p7, p3, p8 asig oscil kenv,
cpspch(p5), p6 out asig endin
and
;instr st dur amp pch fn rise decay i1 0 5 85 8.07 1 .2 .2 e
p7 and p8 are now scorefile variables for controlling rise time
and decay time in seconds. Setting the value of idur to be equal to
p3 means that the duration of the envelope will always match the
duration of the note. Working with Percentages. In some instances,
it might be desirable to set the rise and decay times in terms of a
percentage of duration rather than an absolute time in seconds.
This is also easily accomplished:
instr 1 kenv linen ampdb(p4), (p3*p7), p3, (p3*p8) asig oscil
kenv, cpspch(p5), p6 out asig endin
Now the rise and decay times will be calculated by multiplying
the duration (p3) by a number specified in p7 or p8. Instead of
having rise and decay times of .2 seconds, the times will now be
20% of the duration of the note. As the duration increases, so will
the rise and decay times. Creating More Complex Envelopes The linen
opcode divides the duration into 3 parts. To created an envelope
that has more than three parts, we can use the linseg opcode: The
linseg Opcode. The manual entry for linseg reads as follows:
-
Chapter 3: Amplitude Envelopes
13
kr linseg ia, idur1, ib[, idur2, ic[...]] ar linseg ia, idur1,
ib[, idur2, ic[...]]
The line that linseg creates can have as many segments as
needed. The arguments ia, ib, etc. are the values (in this instance
they will relate to amplitude) and the arguments idur1, idur2, etc.
are the lengths of time between the values. Here is an example of a
simple linseg:
instr1 kline linseg 0, .2, 1, 2, .33, 7.5, 1, .3, 0 asig oscil
(ampdb(p4)*kline), cpspch(p5), p6 out asig endin
and
i1 0 10 85 1 In this case, the linseg generates an amplitude
envelope that fades in over .2 seconds, then drops to one-third
strength over one second, slowly builds back to full strength over
7.5 seconds, and fades out over .3 seconds. The amplitude values
are on a scale of 0-1, and these values are then multiplied by the
value of p4, which sets the overall loudness. Remember that Csound
calculates an amplitude value for each sample. We are controlling
the amplitude through multiplying that value by a number less than
1. A multiplier of .33, for example, cuts the signal strength to
one-third. This lowers the loudness considerably; signal strength
and loudness are not directly proportional. Also note that, because
the envelope is running at the control rate, the value of the
multiplier will only change every 10 samples. Working with
Percentages. In the previous example, the linseg segments are fixed
amounts of time. It is often convenient to define these times as
percentages of the total duration (p3) instead:
instr1 kline linseg 0, (p3*.1), 1, (p3*.2), .33, (p3*.6), 1,
(p3*.1), 0 asig oscil (ampdb(p4)*kline), cpspch(p5), p6 out asig
endin
The length of the first segment will now equal 10% of the note
duration; the second segment will have a length equal to 20% of the
note duration, and so on. Moving Control to the Score. Taking this
one step further, we can change these percentages to scorefile
variables by adding p-fields:
-
A Beginners Guide to Csound
14
instr1 kline linseg 0, (p3*p7), 1, (p3*p8), .33, (p3*p9), 1,
(p3*p10), 0 asig oscil (ampdb(p4)*kline), cpspch(p5), p6 out asig
endin
and
;instr st dur dB pch fn seg1 seg2 seg3 seg4 i1 0 10 85 8.07 1 .1
.2 .6 .1
As long as the values for p7-p10 add up to 1, the envelope will
have the same duration as the note, specified in p3. This allows
for the relative length of each segment to be easily adjusted in
the score. Changing the other arguments of linseg to scorefile
variables would allow the shape of the envelope to be controlled in
the score as well. Remember that any value in the orchestra can be
substituted with a p-field in the score.
instr1 kline linseg 0, (p3*p7), p8, (p3*p9), p10, (p3*p11), 12,
(p3*p13), 14 asig oscil (ampdb(p4)*kline), cpspch(p5), p6 out asig
endin
and
;instr st dur dB pch fn val1 time1 val2 time2 etc i1 0 10 85
8.07 1 0 .2 1 .6 etc.
Linear versus Exponential Envelopes The purpose of an amplitude
envelope is to vary the amplitude of a signal over time. Both linen
and linseg create linear changes: the change occurs at a steady
rate over the allotted time. It is also possible to create
exponential envelopes; that is, envelopes in which the rate of
change increases (or decreases) exponentially. The simplest way to
do this is with the expseg opcode. expseg. The arguments for expseg
are the same as those for linseg:
kr expseg ia, idur1, ib[, idur2, ic[...]] ar expseg ia, idur1,
ib[, idur2, ic[...]]
In order to hear the difference between linear and exponential
envelopes, we will create an example in which all other parameters
are the same:
-
Chapter 3: Amplitude Envelopes
15
instr 1 kenv linseg 0, p3*.9, 1, p3*.1, 0 asig oscil
(ampdb(p4)*kenv), cpspch(p5), p6 out asig endin instr 2 kenv expseg
0.00001, p3*.9, 1, p3*.1, 0.00001 asig oscil (ampdb(p4)*kenv),
cpspch(p5), p6 out asig endin
and
i1 0 5 85 8.00 1 i2 6 5 85 8.00 1 e
In this example, we can hear that the change occurs more
gradually at the beginning of the second note, but accelerates much
more rapidly toward the end of the note. Note that values for
expseg can never be 0; here we use a very small number to stand in
for zero. Multiple Envelopes In the example above, we have
constructed two instruments that have different envelope types but
are alike in every other respect. Here is a useful trick that can
be used to eliminate the need for two separate instruments in this
case: have Csound evaluate an expression.
instr 3 kenv1 linseg 0, p3*.98, 1, p3*.02, 0 kenv2 expseg
0.00001, p3*.98, 1, p3*.02, 0.00001 kenv = (p7 > 0 ? kenv2 :
kenv1) ; 0 for lin, 1 for exp asig oscil (ampdb(p4)*kenv),
cpspch(p5), p6 out asig endin
This instrument contains an expression labeled kenv that
evaluates p7. If p7 is greater than zero, it plugs the exponential
envelope generator (kenv2) into oscil. If not, it plugs in the
linear envelope generator (kenv1). Now we can choose which envelope
type to use by entering a 0 or 1 in p7.
;instr st dur dB pch fn env i3 0 5 85 8.00 1 0 i3 6 5 85 8.00 1
1 e
-
A Beginners Guide to Csound
16
; chap3.orc sr = 44100 kr = 4410 ksmsps= 10 nchnls = 1 instr 1
kenv linseg 0, p3*.9, 1, p3*.1, 0 asig oscil (ampdb(p4)*kenv),
cpspch(p5), p6 out asig endin instr 2 kenv expseg 0.00001, p3*.9,
1, p3*.1, 0.00001 asig oscil (ampdb(p4)*kenv), cpspch(p5), p6 out
asig endin instr 3 kenv1 linseg 0, p3*.98, 1, p3*.02, 0 kenv2
expseg 0.00001, p3*.98, 1, p3*.02, 0.00001 kenv = (p7 > 0 ?
kenv2 : kenv1) asig oscil (ampdb(p4)*kenv), cpspch(p5), p6 out asig
endin ; chap3.sco f1 0 8192 10 1 ;instr st dur dB pch fn env i1 0 5
85 8.00 1 i2 6 5 85 8.00 1 i3 12 5 85 8.00 1 0 i3 18 5 85 8.00 1 1
e
-
17
4 Stereo Panning
A simple way to add depth to a sound is to place it in the
stereo field. This chapter will present one way to implement a
stereo pan, and then expand on it. We will use a copy of instrument
3 from the previous chapter as a starting point. Placing Sound in
the Stereo Field Changing the orchestra from the previous chapter
from mono to stereo is a simple task:
sr = 44100 kr = 4410 ksmps= 10 nchnls = 2 instr 1 kenv1 linseg
0, p3*.98, 1, p3*.02, 0 kenv2 expseg 0.00001, p3*.98, 1, p3*.02,
0.00001 kenv = (p7 > 0 ? kenv2 : kenv1) asig oscil
(ampdb(p4)*kenv), cpspch(p5), p6 outs asig, asig endin
In the headers, the value for nchnls becomes 2. In the
instrument, out becomes outs, which has two arguments separated by
commas. At this point, both channels will contain the same signal
at the same amplitude. We can vary these amplitudes to implement a
stereo pan. A simple way to vary these amplitudes might be:
instr 1 kenv1 linseg 0, p3*.98, 1, p3*.02, 0 kenv2 expseg
0.00001, p3*.98, 1, p3*.02, 0.00001 kenv = (p7 > 0 ? kenv2 :
kenv1) asig oscil (ampdb(p4)*kenv), cpspch(p5), p6 outs asig*p8,
asig*(1-p8) ; p8 is a value from 0-1 endin
In this case, a value for p8 can be set that alters the
amplitudes of each channel to pan the sound. A value of 0 would
result in a full-strength signal in the right channel and no signal
in the left channel. A value of 1 would result in the reverse. A
value of .5 would result in equal strength in both channels.
Remember, however, that an increase in amplitude does not equal the
same increase in loudness. Therefore, the instrument above will not
always pan convincingly.
-
A Beginners Guide to Csound
18
An Alternate Use for Function Tables. In previous chapters, we
have used function tables (f-statements in the score) to store
waveform data for oscillators. Function tables have many other uses
as well, and we will encounter one of them here. Panning is
accomplished by varying the amplitude between the two speakers; a
stronger signal on the left channel will convey the impression that
the sound is originating from a location left of center. If
amplitude values are adjusted on a linear scale (as in the example
above), sounds placed in the center of the stereo field sound
softer than those placed slightly to the left or right. To
compensate for this, we will use 1/4 period of a sine wave instead
of a straight line to control our amplitude levels for panning. The
following f-statement will produce 1/4 period sine:
f2 0 4096 9 0.25 1 0 This function table uses GEN 9, a GEN
routine that allows the user to set the partial, signal strength,
and phase for any number of sine waves in harmonic or inharmonic
relationships. The f-statement above contains one partial sine wave
that is .25 cycle, with a signal strength of 1 and phase of 0. Be
sure to take a look at the graph of f2 when running Csound. table
and ftlen. In order to make use of the 1/4 sine in our panning
routine, we need a way to get that data from the score into the
orchestra file. The table opcode serves this purpose:
kr table kndx, ifn [, ixmode [, ixoff[, iwrap]]]
We will only concern ourselves with the first two arguments, as
the others are optional. The first argument, kndx, is the index (or
address) of a data point in the table. For example, a kndx value of
1 would retrieve the value of the first point in the table. If the
table has 4096 data points, a kndx value of 4096 would retrieve the
value of the last point in the table. The second argument, ifn, is
simply the number of the f-statement to which the table refers. Our
implementation of the table opcode will look something like
this:
kpanL table p8*ftlen(2), 2 kpanR table (1-p8)*ftlen(2), 2
This is less complicated than it may seem: there is a table for
each channel, and p8 is a pan value between 0 and 1 (0 = right, 1 =
left). In kpanL, the value for the first argument (kndx) is
calculated by multiplying p8 times the number of data points in
function table 2. ftlen is an opcode that reports the length of a
table in terms of how many data points it contains. If the value of
p8 is .25, Csound will multiply .25 times 4096 and retrieve the
value from data point number 1024. This value, which is a number
between 0 and 1, will be used later to adjust the amplitude of the
left channel. In kpanR, kdnx is determined by subtracting p8 from 1
and then multiplying by the length of f2. If the value of p8 is
.25, Csound will subtract 1 -.25 = .75 * 4096 = 3072. The value
stored in data
-
Chapter 4: Stereo Panning
19
point 3072 will then be retrieved, and later will be used to
adjust the amplitude of the right channel. Here is the code above
incorporated into the instrument:
instr 2 kenv1 linseg 0, p3*.98, 1, p3*.02, 0 kenv2 expseg
0.00001, p3*.98, 1, p3*.02, 0.00001 kenv = (p7 > 0 ? kenv2 :
kenv1) asig oscil (ampdb(p4)*kenv), cpspch(p5), p6 kpanL table
p8*ftlen(2), 2 kpanR table (1-p8)*ftlen(2), 2 outs asig*kpanL,
asig*kpanR endin
asig is multiplied by the values supplied by kpanL and kpanR to
adjust the amplitudes for panning. This will result in an
equal-powered pan that does not lose its oomph in the center of the
stereo field. (This will become more critical as we learn to move
sounds across the stereo field as they play.) Try it out with
various values for p8; a sample scorefile can be found below.
f1 0 8192 10 1 ; sine f2 0 4096 9 0.25 1 0 ; 1/4 sine ;inst st
dur dB pch fn env pan i2 0 1 80 8.00 1 1 0 i2 1 1 80 8.00 1 1 .1 i2
2 1 80 8.00 1 1 .2 i1 3 1 80 8.00 1 1 .3 i2 4 1 80 8.00 1 1 .4 i2 5
1 80 8.00 1 1 .5 i2 6 1 80 8.00 1 1 .6 i2 7 1 80 8.00 1 1 .7 i2 8 1
80 8.00 1 1 .8 i2 9 1 80 8.00 1 1 .9 i2 10 1 80 8.00 1 1 1 e
Active Panning We can take the panning routine above a step
further by moving the sound across the stereo field as it plays. To
do this, will use function tables in another new way: we will
create a table that has values moving from 0 to 1 back to 0 over
its length. GEN 7 works nicely for this purpose:
f3 0 256 7 0 128 1 128 0
-
A Beginners Guide to Csound
20
With GEN 7, we can specify values and how many points there are
in between; the GEN routine will fill in the points in between in a
linear fashion. The f-statement above moves from 0 to 1 and back
over its 256 data points. Once again, in order to use the data in
this table in our instrument, we need a way to get it into the
orchestra file. phasor and tablei. In the first part of this
chapter, we manipulated the kndx argument of table to get one
particular value out of the table. In this instance, we want to use
the entire table. The phasor opcode is a pointer from 0-1 that we
can use to read through the entire table over a particular length
of time:
kread phasor 1/p3 kpan tablei ktabler*ftlen(3), 3
kread will read through the entire table once over the duration
of any i-statement. The tablei opcode is similar to table, but it
has the added advantage of interpolating between data points, which
smooths out transitions. Whenever an interpolating opcode such as
tablei is used, its a good idea to add one extra data point to the
function tables used by that opcode. This guard point at the end of
the table will have the same value as the first point in the table,
and sometimes prevents errors.
f3 0 257 7 0 128 1 128 0 To add the above code to our
instrument, we will insert it before the pan routine and plug the
output of kpan into the index variables for kpanL and kpanR.
instr 3 ; amplitude envelope
kenv1 linseg 0, p3*.98, 1, p3*.02, 0 kenv2 expseg 0.00001,
p3*.98, 1, p3*.02, 0.00001 kenv = (p7 > 0 ? kenv2 : kenv1) ;
oscillator asig oscil (ampdb(p4)*kenv), cpspch(p5), p6 ; read
panning function table kread phasor 1/p3 kpan tablei
ktabler*ftlen(3), 3 ; apply an equal-powered pan kpanL table
kpan*ftlen(2), 2 kpanR table (1-kpan)*ftlen(2), 2
; outputs outs asig*kpanL, asig*kpanR endin
-
Chapter 4: Stereo Panning
21
Once an instrument begins to get lengthy, it may be helpful to
divide it up into sections based on their function, as above.
Remember that comments can be very helpful. Try this instrument out
with the following score:
f1 0 8192 10 1 ; sine f2 0 4096 9 0.25 1 0 ; 1/4 sine f3 0 257 7
0 128 1 128 0 ; pan table ;instr st dur dB pch fn env i3 0 10 85
7.07 1 0 e
One additional adjustment will give us greater flexibility:
; read panning function table kread phasor 1/p3 kpan tablei
ktabler*ftlen(p8), p8
Moving the function table number for panning to the score allows
us to create additional panning function tables and choose one for
each i-statement. Here are some additional f-statements for
panning. Look up any unfamiliar GEN routines in the reference
manual.
f4 0 3 2 0 0 f5 0 3 -2 .5 .5 f6 0 3 2 1 1 f7 0 17 2 1 1 1 0.9
0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1 0 0 0 0 f8 0 17 2 0 0 0 0.1 0.2 0.3
0.4 0.5 0.6 0.7 0.8 0.9 1 1 1 1 f9 0 257 5 0.001 128 1 128
0.001
(NOTE: The minus sign (-) in front of a GEN routine number
prevents Csound from normalizing the values in the table. This is
especially important in f5, above. Remove the minus sign and run
Csound to see why.)
-
A Beginners Guide to Csound
22
; chap4.orc sr = 44100 kr = 4410 ksmps= 10 nchnls = 2
instr 1 ; panning instrument that doesnt pan evenly kenv1 linseg
0, p3*.98, 1, p3*.02, 0 kenv2 expseg 0.00001, p3*.98, 1, p3*.02,
0.00001 kenv = (p7 > 0 ? kenv2 : kenv1) asig oscil
(ampdb(p4)*kenv), cpspch(p5), p6 outs asig*p8, asig*(1-p8) ; p8 =
pan (0-1) endin
instr 2 ; panning instrument with an equal-powered pan kenv1
linseg 0, p3*.98, 1, p3*.02, 0 kenv2 expseg 0.00001, p3*.98, 1,
p3*.02, 0.00001 kenv = (p7 > 0 ? kenv2 : kenv1) asig oscil
(ampdb(p4)*kenv), cpspch(p5), p6 kpanL table p8*ftlen(2), 2 ; p8 =
pan (0-1) kpanR table (1-p8)*ftlen(2), 2 outs asig*kpanL,
asig*kpanR endin
instr 3 ; actively panning instrument ; amplitude envelope kenv1
linseg 0, p3*.98, 1, p3*.02, 0 kenv2 expseg 0.00001, p3*.98, 1,
p3*.02, 0.00001 kenv = (p7 > 0 ? kenv2 : kenv1) ; oscillator
asig oscil (ampdb(p4)*kenv), cpspch(p5), p6 ; read panning function
table kread phasor 1/p3 kpan tablei kread*ftlen(p8), p8 ; p8 = pan
table number (3-9) ; calculate equal-powered pan kpanL table
kpan*ftlen(2), 2 kpanR table (1-kpan)*ftlen(2), 2 ; outputs outs
asig*kpanL, asig*kpanR endin
-
Chapter 4: Stereo Panning
23
; chap4.sco f1 0 8192 10 1 f2 0 4096 9 0.25 1 0 f3 0 257 7 0 128
1 128 0 f4 0 3 2 0 0 f5 0 3 -2 .5 .5 f6 0 3 2 1 1 f7 0 17 2 1 1 1
0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1 0 0 0 0 f8 0 17 2 0 0 0 0.1 0.2
0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1 1 1 f9 0 257 5 0.001 128 1 128
0.001 ;i1-2 st dur dB pch fn env pan i2 0 2 90 8.00 1 0 1 i2 2 2 90
8.00 1 0 .5 i2 4 2 90 8.00 1 0 0 ;i3 st dur dB pch fn env pantbl i3
6 10 85 7.07 1 0 3 i3 17 10 80 7.09 1 0 9 e
-
A Beginners Guide to Csound
24
-
25
5 Synthesis
Example instruments up to now have used simple waveforms (mostly
sinusoids) to create sound. In this chapter, we will take a first
look at several synthesis algorithms that allow us to create sounds
with richer spectra. For more detailed information about each
algorithm described below, the reader is referred to Computer
Music: Synthesis, Composition, and Performance by Charles Dodge and
Thomas A. Jerse. Additive Synthesis One of the most basic types of
synthesis algorithms is called additive synthesis or Fourier
synthesis. An instrument employing this type of algorithm builds a
complex spectrum with a series of simple oscillators. The outputs
of the individual oscillators are added together to create a more
complex waveform. The following instrument uses additive synthesis
to create a bell-like timbre:
instr 1 ; additive synthesis iamp = ampdb(p4) asig1 oscil iamp *
.56, cpspch(p5), 1 asig2 oscil iamp * .92, cpspch(p5 + 0.03), 1
asig3 oscil iamp * 1.19, cpspch(p5 + 0.07), 1 asig4 oscil iamp *
1.7, cpspch(p5 - 1.0), 1 asig5 oscil iamp * 2.0, cpspch(p5 + 1.0),
1 aadd = asig1 + asig2 + asig3 + asig4 + asig5 kenv line 1, p3, 0
aout = aadd * kenv out aout endin
In this example, each oscil generates a sine wave at a different
frequency and amplitude. These waves are in an unusual relationship
that approximates the overtone series of a bell. A simple amplitude
envelope is added at the end of the signal path using the line
opcode. In this case, line goes from 1 to 0 over the duration of
the note, creating a simple decay. Try this instrument with the
following score:
f1 0 8192 10 1 ;i1 st dur dB pch i1 0 1 75 8.09 i1 + . 75 8.07
i1 + . 75 8.05 i1 + 3 75 8.00 e
-
A Beginners Guide to Csound
26
Since, theoretically, any sound can be represented as the sum of
n sign waves, it should be possible to create any sound using
additive synthesis. But because each overtone must have its own
unit generator (such as oscil), this method is computationally
expensive. The rest of this chapter will present synthesis
algorithms that generate rich spectra with few unit generators.
Amplitude Modulation One way to alter the spectrum of an oscillator
is to modulate one of its inputs. A simple model for synthesis by
amplitude modulation uses the output of one oscillator (the
modulating oscillator) to modulate the amplitude of another (the
carrier oscillator).
instr 2 ; AM synthesis kmod oscil p6*p4, p7, 1 ; p6 = m (0-1) p7
= mod freq acarr oscil kmod+p4, p5, 1 ; p4 = amp p5 = carrier freq
out acarr endin
Lets take a look at this instrument from the bottom up: Carrier
Oscillator. The oscil labeled acarr is the carrier oscillator. Like
any oscil, it has arguments for amplitude, frequency, and function.
A constant amplitude value is set by p4, and this value then has
kmod added to it. Because kmod is a control-rate variable, the
amplitude value for the carrier oscillator can change every 10
samples. The frequency of the carrier is conventionally labeled fc.
Modulating Oscillator. The oscil labeled kmod is the modulating
oscillator. It is important to remember that its output is not
directly heard; rather, its effect on the carrier oscillator is
heard. Because of this, the amplitude and frequency arguments will
serve different functions. Changing the amplitude value of the
modulator will alter how much it affects the carrier. Changing the
frequency value will alter how often it affects the carrier. The
modulation frequency (fm) has a significant effect on timbre. For
convenience, the amplitude value of the modulator is usually
expressed relative to the amplitude of the carrier. That is, the
amplitude of the carrier (p4 above) is multiplied by a number
between 0 and 1 (p6 above) to determine how much the carrier will
be affected by the modulator. This value is called the modulation
index or m. When m = 0, the modulating oscillator is off and the
waveform of the carrier is heard unaltered (zero modulation). When
m = 1, the modulator is equal in amplitude to the unmodulated
carrier (100% modulation). To clarify, p4 in the example is the
amplitude value for the carrier. p5 is the frequency of the
carrier. p6 is the modulation index (m), a number between 0 and 1.
m is multiplied by p4 to determine the amplitude value of the
modulator. p7 is the modulation frequency. The output of the
modulator (kmod) is added to the amplitude value of the carrier
(p4). This causes the amplitude of the carrier to fluctuate, and
dramatically changes the timbre.
-
Chapter 5: Synthesis
27
Here is a sample score for use with instrument 2. Experiment
with each of the parameters to get a better feel for how they
affect the sound.
f1 0 8192 10 1 ;i2 st dur amp fc m fm i2 0 3 18000 1000 .7 8 i2
+ . . . . 15 i2 + . . . . 100 i2 + . . . . 10000 e
Ring Modulation A variation on AM synthesis, ring modulation
occurs when the output of the modulator is applied directly to the
amplitude of the carrier (no constant amplitude value is added).
This small change alters the relationships between several
parameters.
instr 3 ; ring modulation kmod oscil p4, p6, 1 ; p4 = amp p6 =
mod freq acarr oscil kmod, p5, 1 ; p5 = carrier freq out acarr
endin
The amplitude value for the modulator now serves as the overall
amplitude value, and there is no need for a modulation index.
Listen to the difference between an AM sound and a ring-modulated
sound with similar parameters:
;i2 st dur amp fc m fm i2 0 3 15000 1000 1 250 ;i3 st dur amp fc
fm i3 3 3 15000 1000 250 e
The ring-modulated sound seems to have a hole in the middle when
compared with the AM sound. This has to do with the types of
spectra produced by these two different algorithms. The AM example
above produces a spectrum with three components: the carrier
frequency and two equally spaced sidebands; one above and one below
the carrier. The amplitude of the sidebands is controlled by m, and
their distance from the carrier is controlled by fm. Ring
modulation produces the sidebands only; the carrier frequency is
not present in the spectrum at all. If a more complex waveform is
used, the resulting sound will have additional equally spaced
sidebands, but still no carrier present.
-
A Beginners Guide to Csound
28
Frequency Modulation Like AM synthesis, Frequency Modulation is
a means of generating rich spectra by modulating one of the
oscillators inputs with another oscillator. As the name suggests,
the frequency will be modulated rather than the amplitude.
instr 4 ; FM synthesis kmod oscil p6, p7, 1 ; p6 = d p7 = fm
acarr oscil p4, p5+kmod, 1 ; p4 = amp p5 = fc out acarr endin
In the example above, the output of kmod affects the frequency
of acarr. As in AM synthesis, the output of the modulator is added
to a constant value; in this case, the carrier frequency (fc). The
amplitude input for kmod (p6) controls the deviation (d), which is
a measure of the maximum frequency deviation caused by the
modulator. Use the scorefile below to test the effect of an
increasing deviation:
f1 0 8192 10 1 i4 st dur amp fc d fm i4 0 5 15000 800 10 10000
i4 + . . . 100 . i4 + . . . 1000 . e
Index of Modulation. In FM synthesis, the relationship between
the deviation and the modulation frequency is critical to the
resulting timbre. Because of this, it is often more convenient to
deal with the deviation in terms of an index. This index of
modulation (I) is defined as the ratio of deviation to modulation
frequency.
I = d/m As the value of I increases, the timbre becomes
brighter. Implementing I in the instrument above is a simple task.
We will use p6 for I instead of d; however, we still need a d value
to plug in to the amplitude input of kmod. If we solve the equation
for d, we get d = I*m. The code will look like this:
instr 5 ; FM synthesis with I kmod oscil p6*p7, p7, 1 ; p6 = I
p7 = fm acarr oscil p4, p5+kmod, 1 ; p4 = amp p5 = fc out acarr
endin
-
Chapter 5: Synthesis
29
Use the scorefile below to hear the effect of an increasing
index of modulation:
f1 0 8192 10 1 ;i5 st dur amp fc I fm i5 0 5 15000 800 1 2000 i5
+ . . . 5 . i5 + . . . 20 . e
Adding Complexity There are any number of ways to improve upon
the AM and FM instruments described above. Some of these involve
adding features we have already learned. Converters. Converters
such as ampdb and cpspch can be added to any of these instruments
in the usual way:
instr 6 ; AM synthesis kmod oscil p6*ampdb(p4), p7, 1 ; p6 = m
(0-1) acarr oscil kmod+ampdb(p4), cpspch(p5), 1 ; p7 = fm (in Hz)
out acarr ; p4 = amp (in dB) endin ; p5 = fc (in pch)
Note that, while it makes perfect sense to deal with amp in
decibels and c in pch, the amplitude and frequency inputs for the
modulating oscillator do not change amplitude and frequency
directly. Therefore, they will not be dealt with in dB or pch.
Amplitude Envelopes. Adding an envelope to one of these instruments
is also accomplished in the usual way:
instr 7 ; FM synthesis w/ amp env kmod oscil p6*p7, p7, 1 ; p6 =
I p7 = fm kenv linen ampdb(p4), p8, p3, p9 ; p4 = amp p8 = rise p9
= decay acarr oscil kenv, cpspch(p5)+kmod, 1 ; p5 = fc out acarr
endin
The order in which kmod and kenv appear in this instrument is
irrelevant; however, they both must appear above acarr, since it
references them in its arguments. Amplitude Envelopes and the
Modulating Oscillator. An amplitude envelope causes the amplitude
of an oscillator to change over time. Since the amplitude of the
modulating oscillator affects the spectrum of the sound rather than
the amplitude, applying an amplitude envelope to the modulating
oscillator will cause the spectrum to change over time. The
envelope is applied the in the same way:
-
A Beginners Guide to Csound
30
instr 8 ; time-varying FM ; modulator and env kenvm linen p6*p7,
p10, p3, p11 ; p6 = I p10 = rise p11 = decay kmod oscil kenvm, p7,
1 ; p7 = fm (Hz) ; carrier and env kenvc linen ampdb(p4), p8, p3,
p9 ; p4 = amp p8 = rise p9 = decay acarr oscil kenvc,
cpspch(p5)+kmod, 1 ; p5 = fc (pch) out acarr endin
Here is a scorefile to be used with instrument 8 above:
f1 0 8192 10 1 ;i8 st dur dB pch I fm risec decc risem decm i8 0
10 80 7.07 10 1000 .1 .1 5 5 e
The obvious drawback to this instrument is its 11 p-fields per
i-statement, which is a bit unwieldy. There is always a balance to
strike between ease-of-use and flexibility, and 11 p-fields is not
really unreasonable for a Csound instrument. A more complex
envelope using linseg or expseg can be used to control the changes
in spectrum over time in a more flexible manner. Note that this
will increase the number of p-fields. Review Chapter 3 if
necessary. You may also wish to add a panning routine to this
instrument, as discussed in Chapter 4 (dont forget to increase
nchnls to 2 in the orchestra headers).
-
Chapter 5: Synthesis
31
; chap5.orc instr 1 ; additive synthesis iamp = ampdb(p4) asig1
oscil iamp * .56, cpspch(p5), 1 asig2 oscil iamp * .92, cpspch(p5 +
0.03), 1 asig3 oscil iamp * 1.19, cpspch(p5 + 0.07), 1 asig4 oscil
iamp * 1.7, cpspch(p5 - 1.0), 1 asig5 oscil iamp * 2.0, cpspch(p5 +
1.0), 1 aadd = asig1 + asig2 + asig3 + asig4 + asig5 kenv line 1,
p3, 0 aout = aadd * kenv out aout endin instr 2 ; AM synthesis kmod
oscil p6*p4, p7, 1 ; p6 = m (0-1) p7 = mod freq acarr oscil
kmod+p4, p5, 1 ; p4 = amp p5 = carrier freq out acarr endin instr 3
; ring modulation kmod oscil p4, p6, 1 ; p4 = amp p6 = mod freq
acarr oscil kmod, p5, 1 ; p5 = carrier freq out acarr endin instr 4
; FM synthesis kmod oscil p6, p7, 1 ; p6 = d p7 = fm acarr oscil
p4, p5+kmod, 1 ; p4 = amp p5 = fc out acarr endin instr 5 ; FM
synthesis with I kmod oscil p6*p7, p7, 1 ; p6 = I p7 = fm acarr
oscil p4, p5+kmod, 1 ; p4 = amp p5 = fc out acarr endin instr 6 ;
AM synthesis kmod oscil p6*ampdb(p4), p7, 1 ; p6 = m (0-1) acarr
oscil kmod+ampdb(p4), cpspch(p5), 1 ; p7 = fm (in Hz) out acarr ;
p4 = amp (in dB) endin ; p5 = fc (in pch)
-
A Beginners Guide to Csound
32
instr 7 ; FM synthesis w/ amp env kmod oscil p6*p7, p7, 1 ; p6 =
I p7 = fm kenv linen ampdb(p4), p8, p3, p9 ; p4 = amp p8 = rise p9
= decay acarr oscil kenv, cpspch(p5)+kmod, 1 ; p5 = fc out acarr
endin
instr 8 ; time-varying FM ; modulator and env kenvm linen p6*p7,
p10, p3, p11 ; p6 = I p10 = rise p11 = decay kmod oscil kenvm, p7,
1 ; p7 = fm (Hz) ; carrier and env kenvc linen ampdb(p4), p8, p3,
p9 ; p4 = amp p8 = rise p9 = decay acarr oscil kenvc,
cpspch(p5)+kmod, 1 ; p5 = fc (pch) out acarr endin ; chap5.sco f1 0
8192 10 1 ;i1 st dur dB pch i1 0 3 75 8.00 ;i2 st dur amp fc m fm
i2 4 3 18000 1000 .7 100 ;i3 st dur amp fc fm i3 8 3 18000 1000 100
;i4 st dur amp fc d fm i4 12 5 15000 800 10 10000 ;i5 st dur amp fc
I fm i5 18 5 15000 800 2 10000 ;i6 st dur dB pch m fm i6 24 3 70
7.07 .5 800 ;i7 st dur dB pch I fm rise decay i7 28 5 75 7.00 1
1000 .3 .1 ;i8 st dur dB pch I fm risec decc risem decm i8 34 10 80
7.07 10 1000 .1 .1 5 5 e
-
33
6 Realism in Instrument Design
The mechanical construction of acoustic instruments results in a
number of subtle features that can be conspicuous by their absence
in synthesized sound. These features are often responsible for that
subjective quality we call expressivity. A few simple examples are
discussed below. For further information, the reader is directed to
Beck, Stephen David. Designing Acoustically Viable Instruments in
Csound. In The Csound Book, Richard Boulanger, ed. Cambridge, MA:
MIT Press, 2000. p.155-170. Fluctuations in Amplitude and Frequency
Tremolo. Tremolo is a technique used with many acoustic musical
instruments. Technically speaking, tremolo is a sub-audio
oscillation of amplitude. Tremolo can easily be applied using the
AM technique discussed in Chapter 5 with a large m (close to 1) and
a very small m (20).
instr 1 ; tremolo ktrem oscil p6*ampdb(p4), p7, 1 acarr oscil
ktrem+ampdb(p4), cpspch(p5), 1 out acarr endin
and f1 0 8192 10 1 ;i1 st dur dB pch m fm i1 0 5 80 8.00 .9 3
e
Note that if the modulation frequency (m) is increased to a
value above about 20Hz, the listener will perceive a change in
timbre rather than fluctuations in amplitude. Vibrato. Vibrato is
another technique used with many acoustic instruments. Most players
and singers use vibrato in a fairly constant manner. Technically
speaking, vibrato is a sub-audio oscillation of frequency. It can
easily be applied using the FM technique discussed in Chapter 5
with a relatively small d and a very small m. When using an FM
instrument to generate vibrato, the d controls the vibrato width
and m controls the vibrato rate. Vibrato width is conveniently
controlled by setting it as a percentage of the carrier frequency
(c).
-
A Beginners Guide to Csound
34
instr 2 ; vibrato kvib oscil p6*cpspch(p5), p7, 1 acarr oscil
ampdb(p4), kvib+cpspch(p5), 1 out acarr endin
and ;i2 st dur dB pch vwid vrate i2 6 5 80 8.02 .02 6
Note that if the modulation frequency (m) is increased to a
value above about 20Hz, the listener will perceive a change in
timbre rather than fluctuations in pitch. Jitter. Another common
feature of acoustic instruments is pitch jitter. As the player
sounds a steady tone, tiny random variances in pitch occur. This
can be accomplished in Csound using the randi opcode:
ar randi xamp, xcps[, iseed[, isize[, koffset]]]
randi is a random number generator that interpolates between
successive values. This will work well for varying pitch. xamp
controls the minimum and maximum values, while xcps controls how
often a new random number will be generated. Because randi
interpolates smoothly between values, the pitch will not jump
noticeably.
instr 3 ; pitch jitter ajit randi cpspch(p5)*.01, 10 acarr oscil
ampdb(p4), cpspch(p5)+ajit, 1 out acarr endin
The instrument above will vary in pitch by +/- 1%.
;i3 st dur dB pch i3 12 5 80 8.03
Putting It All Together. Each example above has applied one of
these principles to a simple sinusoid. The instrument below applies
all three techniques to an FM sound:
instr 4 ; FM instrument with tremolo, vibrato, and jitter ktrem
oscil p8*ampdb(p4), p9, 1 ; p8=trem d p9=trem rate kvib oscil
p10*cpspch(p5), p11, 1 ; p10=vib depth p11=vib rate ajit randi
cpspch(p5)*.02, 10 kmod oscil p6*p7, p7, 1 ; p6=I p7=fm acarr oscil
ktrem+ampdb(p4), kvib+ajit+kmod+cpspch(p5), 1 out acarr endin
-
Chapter 6: Realism in Instrument Design
35
;i4 st dur dB pch I fm tremd tremr vibd vibr i4 0 5 80 8.00 2
1800 .9 5 .02 10
Tremolo, vibrato, and jitter can each be used in subtle or
obvious ways. When used subtly, these techniques can bring warmth
and realism to a synthesized sound that may seem unconvincing
otherwise. These are only a few of the ways in which synthesized
sounds can be made more realistic. Correlations Between Parameters
Timbre as a Function of Loudness. In an acoustic instrument,
parameters of pitch, timbre, loudness, and envelope are tied to one
another in many ways. For example, timbre tends to brighten as the
instrument is played more loudly. The instrument below ties timbre
to loudness in a fairly straightforward way:
instr 5 ; FM with loudness-timbre correlation kmod oscil
(p4/60)*p6, p6, 1 ; p6 = fm kenv linen ampdb(p4), p7, p3, p8 ; p7 =
rise p8 = decay acarr oscil kenv, cpspch(p5)+kmod, 1 out acarr
endin
This instrument uses loudness (in dB) as a scaling factor for
the index of modulation (I). Louder sounds will have a higher I,
resulting in a brighter timbre.
;i5 st dur dB pch fm rise decay i5 0 2 60 8.00 800 .1 .1 i5 + .
66 . . . . i5 + . 72 . . . . i5 + . 78 . . . . i5 + . 84 . . .
.
Envelope as a Function of Pitch. Acoustic instruments use a
larger mass to produce lower pitches than higher ones (a
longer/thicker string, a longer air column, a larger resonating
body, etc.) Because of inertia, these lower pitches will have
slower attack and decay times than will higher pitches. Amplitude
envelopes can be constructed to reflect this tendency:
instr 6 ; FM with loudness-timbre and pitch-envelope correlation
kmod oscil (p4/60)*p6, p6, 1 ; p6 = fm kenv linen ampdb(p4),
(1/p5)*p3*.25, p3, (1/p5)*p3*.25 acarr oscil kenv, cpspch(p5)+kmod,
1 out acarr endin
In the example above, pitch (in oct.pch) is used as a scaling
factor to control what percentage of the duration will comprise
rise and decay time. For example, if the pitch is
-
A Beginners Guide to Csound
36
8.00, rise and decay time will each represent 1/8 of the
duration. If the duration is 10 seconds, rise will be 0.31 seconds
in length ((1/8.00) * 10 * .25 = 0.31). If the pitch is 5.00, rise
and decay will each be 1/5 of the duration. If the duration is 10
seconds, rise and decay will each be 0.5 seconds in length
((1/5.00) * 10 * .25 = 0.5). Further Correlations. Both of the
examples above are quite simplistic. There are much more
sophisticated ways of correlating these parameters. Additionally,
there are other correlations that make sense: pitch and timbre,
amplitude and envelope, etc. One elegant means of accomplishing
these correlations involves indexing tables (stored in
f-statements) to change one parameter in response to another.
Again, the reader is directed to Becks article on this subject in
The Csound Book.
-
Chapter 6: Realism in Instrument Design
37
; chap6.orc sr = 44100 kr = 4410 ksmps = 10 nchnls = 1 instr 1 ;
tremolo ktrem oscil p6*ampdb(p4), p7, 1 acarr oscil
ktrem+ampdb(p4), cpspch(p5), 1 out acarr endin instr 2 ; vibrato
kvib oscil p6*cpspch(p5), p7, 1 acarr oscil ampdb(p4),
kvib+cpspch(p5), 1 out acarr endin instr 3 ; pitch jitter ajit
randi cpspch(p5)*.01, 10 acarr oscil ampdb(p4), cpspch(p5)+ajit, 1
out acarr endin instr 4 ; FM instrument with tremolo, vibrato, and
jitter ktrem oscil p8*ampdb(p4), p9, 1 ; p8=trem d p9=trem rate
kvib oscil p10*cpspch(p5), p11, 1 ; p10=vib depth p11=vib rate ajit
randi cpspch(p5)*.02, 10 kmod oscil p6*p7, p7, 1 ; p6=I p7=fm acarr
oscil ktrem+ampdb(p4), kvib+ajit+kmod+cpspch(p5), 1 out acarr endin
instr 5 ; FM with loudness-timbre correlation kmod oscil
(p4/60)*p6, p6, 1 ; p6 = fm kenv linen ampdb(p4), p7, p3, p8 ; p7 =
rise p8 = decay acarr oscil kenv, cpspch(p5)+kmod, 1 out acarr
endin instr 6 ; FM with loudness-timbre and pitch-envelope
correlation kmod oscil (p4/60)*p6, p6, 1 ; p6 = fm kenv linen
ampdb(p4), (1/p5)*p3*.25, p3, (1/p5)*p3*.25 acarr oscil kenv,
cpspch(p5)+kmod, 1 out acarr endin
-
A Beginners Guide to Csound
38
; chap6.sco f1 0 8192 10 1 ;i1 st dur
-
39
7 Real-time Control with MIDI
In the previous chapters, we have instructed Csound to generate
a sound file as its output. It is also possible to send Csounds
output directly to the digital/analog converter (dac). In this
chapter we will use a MIDI controller to drive Csound instruments
in real time. Csound and MIDI Csound observes several conventions
for MIDI control. First, MIDI channels are assigned by instrument
number. For example, instrument 1 will receive information only on
MIDI channel 1. Since there are only 16 MIDI channels, any
instruments numbered above 16 will not be able to receive MIDI
data. Because MIDI messages are used to turn notes on and off,
there is no need for i-statements in the scorefile. (Any needed
f-statements will still be located in the score.) Without
i-statements, there is no indication of duration in the score.
Consequently, Csound will continue to run until it is stopped
manually. As long as Csound is running, instruments can receive
MIDI messages from the controller. If desired, the user can make
Csound exit automatically with a special f-statement in the
score:
f0 30 f0 is a special f-statement that specifies a length of
time in seconds. Once this time has elapsed, Csound will exit
automatically, and the instruments can no longer receive MIDI
messages. MIDI Opcodes ampmidi and cpsmidi. As you might imagine,
there are several opcodes for the handling and conversion of MIDI
information. Two of these are used in the instrument below:
sr = 44100 kr = 4410 ksmps = 10 nchnls = 1 instr 1 ; receives on
MIDI channel 1 ivel ampmidi 16000 ; convert velocity to amp between
0-16000) inote cpsmidi ; convert note number to a frequency asig
oscil ivel, inote, 1 out asig endin
-
A Beginners Guide to Csound
40
When a key is depressed on the MIDI controller, a MIDI message
called a note on is sent. A note on consists of two values: note
number and velocity. Each of these is a value between 0 and 127.
The note number indicates which key was depressed. The velocity
value is a measure of how rapidly the key was depressed (the key
goes down faster when the player is playing more loudly). The
cpsmidi opcode receives the note number and converts it to a
frequency (in Hz). The ampmidi opcode receives the velocity value
and converts it to an amplitude value. The scale for amplitudes is
determined by ampmidis argument. In this case, the velocity value
(0-127) will be converted to an amplitude value between 0 and
16,000. (Note that three notes played together with middle to high
velocity values will exceed the amplitude limit of 32767, causing
clipping and distortion.) When a depressed key on the MIDI
controller is released, a MIDI message called a note off is sent. A
note off message consists of two values as well: the note number
and a velocity of 0. The note off message will stop the Csound
instrument from sounding this note. Although there is no need for
i-statements with this instrument, a function table for the
waveform of oscil must be supplied. We also have the option of
supplying an f0 statement.
f0 60 ; run for 60 sec and exit f1 0 8192 10 1 ; sine for
oscil
Since there are no i-statements, an e-statement is not needed.
midictrl. There are a number of types of MIDI messages besides note
on and note off. The continuous controller message is one such
type. The midictrl opcode receives values from a specific
continuous controller:
instr 2 ; receives on MIDI channel 2 ivel ampmidi 10000 inote
cpsmidi kctrl midictrl 7 ; controller 7 is MIDI volume kvol = kctrl
* .007874 ; scale to a number between 0 and 1 asig oscil ivel,
inote, 1 out asig * kvol ; kvol is master volume control endin
In this instrument, midictrl receives information from
controller 7, which is usually used for volume. This value is
multiplied by .007874 to yield a number between 0 and 1 (1 / 127
.007874). asig is multiplied by the result, which attenuates the
signal if the slider is not in the maximum position.
-
Chapter 7: Real-time Control with MIDI
41
linenr. Csound contains an amplitude envelope opcode
specifically designed for use with MIDI-controlled instruments. The
linenr opcode behaves more or less like linen, with one major
difference: when using MIDI control, there is no way to specify the
duration of the envelope beforehand. linenr waits until the key is
released before beginning its decay phase.
kr linenr kamp, irise, idec, iatdec The final argument of linenr
allows the user to specify an attenuation factor for the decay,
which is reduced exponentially over the decay period. This value
must be positive and is typically on the order of .01.
instr 3 inote cpsmidi ivel ampmidi 10000 kvol midictrl 7 ;
controller 7 is MIDI volume kind midictrl 1 ; controller 1 is the
Mod wheel kmod oscil kind*900, 900, 1 ; mod index is controlled by
mod wheel kenv linenr 1, .1, 2, .01 ; slow decay after key is
released acarr oscil ivel*kenv, inote+kmod, 1 out acarr * kvol *
.0078125 endin
The instrument above uses linenr for an amplitude envelope. It
also has a second midictrl opcode that receives data from
controller 1 (the modulation wheel). This value is used as the
index of modulation (I) for the modulating oscillator in this FM
instrument. pchbend. Although it works in much the same way, the
pitch bend wheel is in its own class separate from the continuous
controllers. Data from the pitch bend wheel can be obtained with
the pchbend opcode. The instrument below uses data from the pitch
bend wheel to control stereo pan:
sr = 44100 kr = 4410 ksmps = 10 nchnls = 2 instr 1 inote cpsmidi
ivel ampmidi 10000 kvol midictrl 7 ; controller 7 is MIDI volume
kind midictrl 1 ; controller 1 is the Mod wheel kbend pchbend .5, 1
; scale pitch bend 0 - .5 - 1 kmod oscil kind*900*.0078125, 900, 1
; mod index controlled by mod wheel kenv linenr 1, .1, 2, .01 ;
slow decay after key is released
-
A Beginners Guide to Csound
42
acarr oscil ivel*kenv, inote+kmod, 1 kpanL table kbend*ftlen(2),
2 ; equal-power pan kpanR table (1-kbend)*ftlen(2), 2 outs acarr *
kvol * .0078125 * kpanL, acarr* kvol * .0078125 * kpanR endin
and
f0 60 f1 0 8192 10 1 f2 0 4096 9 .25 1 0
The two arguments for pchbend set the center value and the
maximum value. Note that this instrument cannot be in the same
orchestra as the previous instruments in this chapter, because
nchnls = 2. This chapter has only scratched the surface of Csounds
MIDI capabilities. For more information, the reader is directed to
Boulanger, Richard, ed. The Csound Book. Cambridge, MA: MIT Press,
2000. (The chapters on MIDI implementation can be found on the
accompanying CD-ROM.)
-
Chapter 7: Real-time Control with MIDI
43
; chap7.orc sr = 44100 kr = 4410 ksmps = 10 nchnls = 1 instr 1 ;
receives on MIDI channel 1 ivel ampmidi 16000 ; convert velocity to
amp between 0-16000) inote cpsmidi ; convert note number to a
frequency asig oscil ivel, inote, 1 out asig endin instr 2 ;
receives on MIDI channel 2 ivel ampmidi 10000 inote cpsmidi kctrl
midictrl 7 ; controller 7 is MIDI volume kvol = kctrl * .007874 ;
scale to a number between 0 and 1 asig oscil ivel, inote, 1 out
asig * kvol ; kvol is master volume control endin instr 3 inote
cpsmidi ivel ampmidi 10000 kvol midictrl 7 ; controller 7 is MIDI
volume kind midictrl 1 ; controller 1 is the Mod wheel kmod oscil
kind*900, 900, 1 ; mod index is controlled by mod wheel kenv linenr
1, .1, 2, .01 ; slow decay after key is released acarr oscil
ivel*kenv, inote+kmod, 1 out acarr * kvol * .0078125 endin ;
chap7.sco f0 60 f1 0 8192 10 1
-
A Beginners Guide to Csound
44
; chap7b.orc sr = 44100 kr = 4410 ksmps = 10 nchnls = 2 instr 1
inote cpsmidi ivel ampmidi 10000 kvol midictrl 7 ; controller 7 is
MIDI volume kind midictrl 1 ; controller 1 is the Mod wheel kbend
pchbend .5, 1 ; scale pitch bend 0 - .5 - 1 kmod oscil
kind*900*.0078125, 900, 1 ; mod index controlled by mod wheel kenv
linenr 1, .1, 2, .01 ; slow decay after key is released acarr oscil
ivel*kenv, inote+kmod, 1 kpanL table kbend*ftlen(2), 2 ;
equal-power pan kpanR table (1-kbend)*ftlen(2), 2 outs acarr * kvol
* .0078125 * kpanL, acarr* kvol * .0078125 * kpanR endin chap7b.sco
f0 60 f1 0 8192 10 1 f2 0 4096 9 .25 1 0
-
45
8 Working with Sampled Sound
Up to now we have relied on synthesis for generating all of the
sound used in our Csound instruments. In this chapter, we will
begin a study of working with sampled sound in Csound. soundin
There are a number of Csound opcodes for reading sound from a
soundfile. Of these, the most basic is soundin; it simply reads in
all or a portion of a soundfile.
sr = 44100 kr = 4410 ksmps = 10 nchnls = 2 instr 1 ; read in
specified portion of soundfile aleft, aright soundin 1 ; read file
soundin.1 outs aleft, aright endin
In the instrument above, the 1 used as an argument for soundin
tells the opcode to find and read the soundfile soundin.1. A value
of 2 would point to a file named soundin.2, and so forth. These
soundfiles should be located in the same directory with the Csound
code. (Alternately, they can be located in directories specified as
SFDIR or SSDIR. More on that at the end of this chapter.) Note
that, if the soundfile read by soundin is a stereo file, it must
have two results separated by a comma. The number of results for
soundin must always match the number of channels in the
soundfile.
;i1 st dur i1 0 10 e
The instrument above, used with this score, will simply read in
the first 10 seconds of soundin.1 (as specified in p3) and pass
this data along to the output file. Skiptime. The next example
instrument adds some flexibility to the one above:
instr 2 ; portion of soundfile with skip and gain aleft, aright
soundin p5, p6 ; p6 is skiptime
outs aleft * p4, aright * p4 ; p4 is master gain endin
-
A Beginners Guide to Csound
46
Instrument 2 moves the first argument of soundin to the score
and adds a second optional argument: skiptime. As its name
suggests, skiptime is the number of seconds that will be skipped at
the beginning of the file. If, for example, p3 is 10 and p6 is 4,
soundin will skip 0 4 and read in 4 14. Additionally, instrument 2
uses p4 as a multiplier to set a kind of master gain control. If p4
is 1, amplitudes in the output file will match those in the input
file. If p4 is less than 1, the amplitudes will be attenuated.
;i2 st dur gain file skip i2 0 10 .7 1 4
Envelopes. Instrument 3 reads a soundfile and applies a simple
amplitude envelope:
instr 3 ; read in soundfile and apply envelope aleft, aright
soundin p5, p6 ; p6 is skiptime kenv linen p4, p3 * .05, p3, p3 *
.1 ; p4 is master gain outs aleft * kenv, aright * kenv endin
and
;i3 st dur gain file skip i3 0 10 1 1 0
The values for rise time and decay time could easily be moved to
the scorefile to increase the usefulness of this instrument. Much
more complex envelopes can be created with linseg and expseg, as
seen in Chapter 3. Ring Modulation. Instrument 4 uses an oscil to
perform ring modulation with the input from a soundfile:
instr 4 ; ring modulation of a soundfile aleft, aright soundin
p5, p6 kmod oscil p7, p8, 1 ; p7=amp, p8=freq outs aleft * kmod *
p4, aright * kmod * p4 endin
and
f1 0 8192 10 1 ;i4 st dur gain file skip amp freq i4 0 10 .4 1
36 1 400
-
Chapter 8: Working with Sampled Sound
47
Multiplying one signal by another is often an effective way of
altering the source signal. diskin The diskin opcode is very
similar to soundin, but provides some additional flexibility:
ar1[, ar2] soundin ifilcode[, iskiptime[, iformat]] ar1[, ar2]
diskin ifilcode, kpitch[, iskiptime[, iwraparound[,
iformat]]] Pitch Adjustment. The second argument of diskin,
kpitch, allows the user to specify the pitch ratio between the
output file and the input file. A value of 2, for example, would
cause the output of diskin to be an octave higher than the input
file (a 2:1 ratio). As the output is an octave higher, it will also
be twice the tempo of the input file. A negative value for kpitch
causes diskin to read through the file backwards. A value of -.5
would cause diskin to read the file backwards and an octave lower
(and at half speed). Below is the series of instruments
demonstrated with soundin; they have been altered to make use of
the diskin opcode. Note that file names are still soundin.x, even
when the diskin opcode is used instead.
instr 1 ; read in specified portion of soundfile aleft, aright
diskin 1, 1 ; read file soundin.1 outs aleft, aright endin instr 2
; portion of soundfile with skip and gain aleft, aright diskin p5,
p6, p7 ; p6 is pitch, p7 = skip outs aleft * p4, aright * p4 ; p4
is master gain endin instr 3 ; read in soundfile and apply envelope
aleft, aright diskin p5, p6, p7 ; p6= pitch, p7 = skip kenv linen
p4, p3 * .05, p3, p3 * .1 ; p4 is master gain outs aleft * kenv,
aright * kenv endin instr 4 ; ring modulation of a soundfile aleft,
aright diskin p5, p6, p7 kmod oscil p8, p9, 1 ; p8=amp, p9=fm outs
aleft * kmod * p4, aright * kmod * p4 endin
The fact that kpitch is a k-rate variable means that the
playback pitch/speed can be varied during a single i-statement. The
instrument below uses an f-statement to control kpitch over the
duration a an i-statement:
-
A Beginners Guide to Csound
48
instr 5 ; pitch controlled by an f-statement kread phasor 1/p3
kpitch table kread * ftlen(p6), p6 aleft, aright diskin p5, kpitch,
p7 kenv linen p4, p3 * .05, p3, p3 * .1 outs aleft * kenv, aright *
kenv endin
The f-statement referenced in p6 will control the pitch of the
output. f-statements using GEN2 are convenient for this
purpose:
f2 0 4 -2 1 2 .5 1
GEN2 uses the values in the f-statement as the only points in
the table. Used with instrument 5, f2 above will cause diskin to
read the sample at normal speed for the first quarter of the
duration. It will read at double speed for the second quarter, half
speed for the third, and then read backwards at normal speed for
the last quarter of the duration. Any variety of GEN routines can
be used to generate function tables for this purpose. About
Environment Variables In an attempt to make file management a
little bit easier, Csound allows the user to set some environment
variables. SFDIR, SSDIR, and SADIR are environment variables that
tell Csound where to look for certain types of files, and where to
save files it generates. SFDIR, SSDIR, and SADIR stand for sound
file directory, sound sample directory, and sound analysis
directory, respectively. If a directory has been specified as
SFDIR, that directory is the default location for Csound to write
output soundfiles. If SFDIR has not been defined, the default
location is the current working directory. Csound looks for input
soundfiles in the current directory; if it cant find them there, it
will look in SSDIR and then SFDIR. If Csound does not find input
analysis files (such as those called by pvoc and lpread; see
chapter 12) in the current directory, it will look in SADIR.
Setting these environment variables gives you central locations to
store your input, output, and analysis files and prevents you from
having to give full paths in your code. The procedure for setting
the environment variables depends on your platform and the front
end you are using, if any. Check the documentation that came with
your Csound distribution. More information about environment
variables can be found in the reference manual under I. Overview:
The Csound Command: Csound Environment Variables.
-
Chapter 8: Working with Sampled Sound
49
; chap8.sco sr = 44100 kr = 4410 ksmps = 10 nchnls = 2 instr 1 ;
read in specified portion of soundfile aleft, aright soundin 1 ;
read file soundin.1 outs aleft, aright endin
instr 2 ; portion of soundfile with skip and gain aleft, aright
soundin p5, p6 ; p6 is skiptime outs aleft * p4, aright * p4 ; p4
is master gain endin instr 3 ; read in soundfile and apply envelope
aleft, aright soundin p5, p6 ; p6 is skiptime kenv linen p4, p3 *
.05, p3, p3 * .1 ; p4 is master gain outs aleft * kenv, aright *
kenv endin
instr 4 ; ring modulation of a soundfile aleft, aright soundin
p5, p6 kmod oscil p7, p8, 1 ; p7=amp, p8=freq outs aleft * kmod *
p4, aright * kmod * p4 endin
-
A Beginners Guide to Csound
50
;chap8.sco f1 0 8192 10 1 ;i1 st dur i1 0 10 ;i2 st dur gain
file skip i2 12 10 .7 1 4 ;i3 st dur gain file skip i3 24 10 1 1 0
;i4 st dur gain file skip amp freq i4 36 10 .4 1 36 1 400 e
-
Chapter 8: Working with Sampled Sound
51
; chap8b.orc sr = 44100 kr = 4410 ksmps = 10 nchnls = 2 instr 1
; read in specified portion of soundfile aleft, aright diskin 1, 1
; read file soundin.1 outs aleft, aright endin instr 2 ; portion of
soundfile with skip and gain aleft, aright diskin p5, p6, p7 ; p6
is pitch, p7 = skip outs aleft * p4, aright * p4 ; p4 is master
gain endin instr 3 ; read in soundfile and apply envelope aleft,
aright diskin p5, p6, p7 ; p6= pitch, p7 = skip kenv linen p4, p3 *
.05, p3, p3 * .1 ; p4 is master gain outs aleft * kenv, aright *
kenv endin instr 4 ; ring modulation of a soundfile aleft, aright
diskin p5, p6, p7 kmod oscil p8, p9, 1 ; p8=amp, p9=fm outs aleft *
kmod * p4, aright * kmod * p4 endin instr 5 ; pitch controlled by
an f-statement kread phasor 1/p3 kpitch table kread * ftlen(p6), p6
aleft, aright diskin p5, kpitch, p7 kenv linen p4, p3 * .05, p3, p3
* .1 outs aleft * kenv, aright * kenv endin
-
A Beginners Guide to Csound
52
; chap8b.sco f1 0 8192 10 1 f2 0 4 -2 1 2 .5 1 ;i1 st dur ;i2 st
dur gain file pitch skip ;i3 st dur gain file pitch skip ;i4 st dur
gain file pitch skip ampm fm ;i5 st dur gain file tbl skip e
-
53
9 Reverb, Delay, and Global Variables
Once a soundfile has been read into a Csound instrument, there
are any number of ways to manipulate the audio signal. Adding
effects such as reverb and delay is easily accomplished using
opcodes designed for these purposes:
ar reverb2 asig, ktime, khdif[, iskip] ar delay asig, idlt[,
iskip]
Either of these opcodes can simply be added to a signal path, as
below:
sr = 44100 kr = 4410 ksmps = 10 nchnls = 2 instr 1 ; add reverb
to a mono soundfile ain diskin p5, p6, p7 ; p9 = rev. time averb
reverb2 ain, p9, p10 ; p10=hdif aout = (ain * p4) + (averb * p8) ;
p4 = dry gain outs aout, aout ; p8 = rev. gain endin
and ;i1 st dur gain file pitch skip rgain rtime hdif i1 0 10 .6
1 1 0 .3 .4 1 e
Note that both the reverberated signal and the dry signal are
passed to the outputs. The gain controls for each will have to be
adjusted carefully; watch out for clipping. The third argument of
reverb2, khdif (high frequency diffusion), controls the manner in
which the reverberated signal decays. If the value is 0, all
frequencies will decay at the same speed. If the value is 1, the
high frequencies will decay more rapidly. Although there is nothing
wrong with the design of the instrument above, it is often both
more efficient and more convenient to set up a separate instrument
for reverberation. This is accomplished using global variables.
Global Variables In the code below, instrument 2 reads all or a
portion the soundfile from disk and routes it to the output file. A
global variable is used to pass the signal to instrument 3, where
reverb is applied and the reverberated signal is routed to the
output file.
-
A Beginners Guide to Csound
54
ga1 init 0 ; initialize global variable instr 2 ; read mono
soundfile ain diskin p5, p6, p7 ; p6= pitch, p7 = skip kenv linen
p4, p3 * .05, p3, p3 * .1 ; p4 is master gain ga1 = ga1 + ain ;
send ain to reverb outs ain * kenv, ain * kenv ; direct (dry)
outputs endin instr 3 ; global reverb kenv linen 1, .05 * p3, p3, 0
arev reverb2 ga1, p5, p6 ; p5= rev time. p6 = hdif averb = arev *
kenv * p4 ; p4= rel. amp of rev (0-1) outs averb, averb ga1 = 0 ;
reset global variable endin
The global variable ga1 is used to pass the signal from
instrument 2 to instrument 3. The g in the name indicates that it
is a global variable; the a indicates that it is an audio-rate
variable. We have something else unusual he