c Sound Guide

103
5/26/2018 cSoundGuide-slidepdf.com http://slidepdf.com/reader/full/c-sound-guide 1/103  sr = 44100 kr = 4410 ksmps = 10 nchnls = 4 A Beginner’s 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

Transcript of c Sound Guide

  • 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