Eastman Csound Tutorial
END of this chapter -- Table of Contents CHAPTER 1 -- CHAPTER 2 -- CHAPTER 3 -- CHAPTER 4 -- CHAPTER 5 -- CHAPTER 6 APPENDIX 1 -- APPENDIX 2

Chapter 6

In this chapter we will look at

6.1 Preprocessing of orchestra and score files, illustrated primarily with the Unix m4 utility
6.2 Some final orc/sco/soundfile examples that illustrate additioanl unit generators
6.3 Quick pointers to some additional Csound resources
6.4 Where to go for more help and information

6.1. Using m4 to prepare orchestra and score files

At some point you likely will begrudge the tedium sometimes involved in preparing Csound orchestra and score files, and wish for shortcuts and more powerful, easier-to-use tools. Preprocessing programs sometimes can provide such tools. Aleck Brinkman's score11 program is one example of a pre-processor. Advanced Csound users sometimes write their own preprocessing procgrams to simplify repetitive, complex or irksome tasks.

Ultimately, the best source of preprocessing tools is a knowledge of a high level computer programming language such as C. This enables a user to write front-end utility programs, custom tailored to her specific requirements and preferences, which generate input used by other programs, such as Csound. Unix shells themselves provide many programming commands, similar to those of C, that can be patched together within an executable shell script file to facilitate some tasks. (For examples, you might look at a few local utility scripts in /usr/local/bin that you have already used, such as pitchshift, mko or runsfcompress.)

The rub, of course, is that programming languages have a learning curve of their own, and may require a digression from from making music into the less appealing realm (for most musicians) of computer programming techniques. Obviously, a survey of C or shell script programming syntax and procedures is beyond the scope of this tutorial, and also beyond the needs of beginning users.

Instead, to illustrate a few types of preprocessing techniques employed by many advanced users, we will survey some operations that can be performed with the Unix preprocessing program m4. While rather limited, and much less powerful than a full fledged programming environment such as C, m4 has relatively few syntactic conventions, and its tools can be put to use fairly quickly, "right out of the box."

A copy of the Unix documentation on m4 is available in the Linux studio. We will survey three types of m4 operations -- define, include and conditional statements -- which, once mastered, can sometimes simplify Csound orchestra and score file preparation. In addition, these operations also can provide us with some rudimentary computer-assisted algorithmic compositional tools.

Throughout this discussion, bear in mind the distinction between the standard Unix m4 preprocessor and ECMC utilities such as m4orch, m4expand and mko that incorporate m4 operations. It is more likely that ECMC users will want to use the Eastman utility programs, which require a slightly different (and, for most of our purposes, easier-to-use) syntax than "straight" m4. In particular, the ECMC utilities substitute left and right square bracket symbols

    [       and     ] 
     in place of the standard m4 quote symbols 
    '       and     ' 

All m4 operations are enclosed within balanced left and right parentheses:

    (       and     ) 
Arguments to these operations that are longer than a few characters, or that include newlines (carriage returns) or characters that can have a special meaning (such as parenthesis symbols) should be enclosed within balanced left and right square brackets:

    [       and     ] 

6.1.1. define statements

A define command is used to define a macro -- a (short) string of characters used to represent another (usually longer) string. A macro character string can consist of almost any combination of alphnumeric characters, but many users employ UPPER CASE characters so that occurrences of macros can be spotted quickly. In the following score file, macros N1, N2 and N3 are defined as particular pitch motives, while macros R1 and R2 are defined as rhythmic motives. These macros are then permuted in the score:

define(N1,[c4/ e/ fs/])
define(N2,[b4/ as/ cs5/ e4/])
define(N3,[a5/ gs/ b/ c5/])
define(R1,[( 4=16*5)/ -8/ 4/])
define(R2,[16/ 32// 4./])
instr 1 0 9;
p3 rh R1 R2 R2 R1 R2;
p4 no N1 N2 N3
N2 N2 N1;

When this file is run through score11, the resulting sout file is :

       ----   i1   0.000   0.200   8.00    --- 
       |      i1   0.200   0.200   8.04       | N1
       |      i1   0.400   0.200   8.06     --
    R1 |      i1   0.600   0.200   8.11     --  (p4)
   (p2)|      i1   0.800   0.200   8.10       | N2
       |     ;i1   1.000   0.500   9.01<rest> |
       ---    i1   1.500   1.000   8.04     --
       ---    i1   2.500   0.250   9.09     --
       |      i1   2.750   0.125   9.08       | N3      
    R2 |      i1   2.875   0.125   9.11       |
       ---    i1   3.000   1.500   9.00    ---
       ---    i1   4.500   0.250   8.11    --- 
       |      i1   4.750   0.125   8.10       | N2 
    R2 |      i1   4.875   0.125   9.01       |
       ---    i1   5.000   1.500   8.04    ---
       ---    i1   6.500   0.200   8.11    ---
       |      i1   6.700   0.200   8.10       | N2 
       |      i1   6.900   0.200   9.01       |
    R1 |      i1   7.100   0.200   8.04    ---
       |      i1   7.300   0.200   8.00    ---
       |     ;i1   7.500   0.500   8.04<rest> | N1  
       ---    i1   8.000   1.000   8.06    --- 
       end of score%

On the ECMC Linux systems, all files submitted to score11 actually take a detour, and are first passed through m4orch for macro preprocessing. What score11 actually "sees" is the output of m4orch. Thus, it is not necessary to process score11 input files through m4orch yourself.

Of course, macro definitions must be defined before they can be used in a file. Usually, all macro definitions are placed at the very beginning of a file, as in the example above. Remember that what score11 "sees" is the expanded version of these macros. When using define macros, visualize the expanded output on each line, or else run the file through m4expand or m4expandsc :

m4expand filename

Do not put so many macros on one line of a score file that the line length of the expanded code will be too long (greater than 80 characters) for score11 to process.

Define statements and other m4 operations often result in the inclusion of newline characters and resulting blank lines which can result in gaping "holes" in the m4 output. Most of these blank lines can be suppressed by including the delete newline keyword dnl immediately (no blank spaces intervening) after the concluding ")" right parenthesis of the statement, like this:


Orchestra files containing such m4 macros must first be run manually through m4orch (m4o), which writes its output to file orch.orc (which can be abbreviated orc). Your Csound job should then have the following syntax :

csound (- options) orc sout

The following skeletal orchestra file :

define(SIMP,[instr 6])
define(OUTPUT,[out a1])
kamp expseg 1,p6,p5,p3-(p6+p7),p5,p7,1
a1 oscili kamp , cpspch(p4), 1

after being run through m4orch or mko would look like this :

instr 6
kamp expseg 1,p6,p5,p3-(p6+p7),p5,p7,1
a1 oscili kamp, cpspch(p4), 1
out a1

By itself, the example above is not all that useful, since the macro OUTPUT will always be expanded to out a1. However, ifelse and ifdef constructions can be included within macro definitions to provide alternative expansions, based upon some evaluation.

6.1.2. ifelse and ifdef constructions

ifelse conditionals have the following format :


This is interpreted : "If character string a is identical to string b, then return string c; if they are not identical, return string d." The following definition of OUTPUT is an ifelse construction that provides two alternative expansions, depending on whether the orchestra header specifies mono or stereo output:

define(OUTPUT,[ifelse(NCHNLS,1,[out a1],[outs sqrt(p10)*a1, sqrt(1-p10)*a1])])

It may be easier to follow the logic of this nasty looking line if we "explode" the arguments:

                ifelse  (a,      b, c,        d                                 )
define(OUTPUT, [ifelse (NCHNLS, 1, [out a1], [outs sqrt(p10)*a1, sqrt(1-p10)*a1])])

m4orch (or m4expand) "reads" this line as follows: "Define OUTPUT on the basis of the following comparison. If NCHNLS has been defined as 1 in the SETUP header macro, return out a1; otherwise (for stereo) return outs p10*a1,(1-p10)*a1.

With this definition of OUTPUT in place, our instrument algorithm can be used, without further editing, to create either mono or stereo soundfiles, simply by changing the NCHNLS (number of channels) argument in the SETUP header at the top of an orchestra file.

ifdef statements, too, return a string based on an evaluation. The simple form is :


which means : if a has already been defined, return value b. Otherwise, do nothing.
In many cases, b is another define statement.

More often, ifdef statements contain three arguments :


Here, if a has been defined, argument b is returned. If a has NOT been defined, argument c is returned. Arguments b and c may be define statements, ifelse constructions, or further (nested) ifdef operations. Consider the following ifdef statement:

ifdef([OUTPUT],,define(OUTPUT,[ifelse(NCHNLS,1,[out a1],
[outs p10 * a1,(1-p10) * a1])]))dnl

Here is how this complex statement is evaluated :

If OUTPUT has already been defined, use this previous definition. (Notice the blank second argument "b," indicated by ",,") If there is no current definition, however, provide one now, based on an evaluation of the NCHNLS argument in the SETUP header. If NCHNLS has been set to "1," define OUTPUT to be
out a1.
Otherwise (if NCHNLS = 2) define OUTPUT to be
outs p10 * a1,(1-p10) * a1

With this macro in place, we can use the default mono and stereo instrument outputs in creating most soundfiles. However, if we wish to include additional postprocessing, we can provide a new definition of OUTPUT, which will override these defaults. The new definition must precede the ifdef statement above.

The most common problem with nested constructions like the one above (other than their repugnant ugliness) is failure to balance left and right parentheses and square brackets. To illustrate the necessary balancing of the preceding example, we have labeled the four matching sets of parentheses "1" through "4" below, and the four sets of square brackets "W," "X," "Y" and "Z."

         1W       W        2        X      3       Y      Y
         ||       |        |        |      |       |      |
    ifdef([OUTPUT],,define(OUTPUT,[ifelse(NCHNLS,1,[out a1],
    [outs p10*a1,(1-p10)*a1])]))dnl
    |            |     |   |||||
    Z            4     4   Z3X21

6.1.3. include statements

Those with experience in such programming languages as C, or with Unix shell scripts, already will be familiar with include statements, which allow us to include the complete contents of one file at some point within another file. Includes are also possible within m4. Here is a sample orchestra file:


After this file is processed by m4orch, file orch.orc will include file flute.orc from the our current directory, and file strings.orc from subdirectory ins.

If you want to include files from directories that do NOT branch from your current working directory, you must include the complete path name for these files. The tilde sign (~) is a useful abbreviation for your home Unix directory.

If file flute.orc includes a macro output definition of the ifdef type previously discussed:

ifdef([OUTFLUTE],,define(OUTFLUTE,[ifelse(NCHNLS,1,[out a1],
[outs sqrt(p20)*a1, sqrt(1-p20)*a1])]))dnl

but you want to override the default output within this particular orchestra file, you could create a new output definition before the include call to flute.orc:

     define(OUTFLUTE,[ ; add a moving stereo pan
     kpan oscili p22-p21, 1/p3 , p23
     kpan = kpan+p21
     outs  sqrt(kpan)*a1, sqrt(1-kpan) * a1])dnl


If this output panning module works well, and you might wish to use it again, either with flute.orc or with other instrument algorithms, you could copy it to another file, and, perhaps, put this new file in a directory that contains only such post-processing modules of Csound code. In this case, we will observe the convention, and type our panning module code into a file called pan.defs. We will then place pan.defs in a directory called m4stuff.

     define(PAN,[ ; add a moving stereo pan
     kpan oscili p22-p21, 1/p3 , p23
     kpan = kpan+p21
     outs  sqrt(kpan)*a1, sqrt(1-kpan) * a1])dnl

Actually, we might wish to include macro definitions for several types of panning operations within this file, and give these definitions names such as PAN1, PAN2, RANDOMPAN, FASTPAN and so on. Now, we can append any of several types of panning operations, defined in our pan.defs file, to our flute algorithm:


Similar macro definitions can be useful in score preparation. Here, we will first create a file, called motives, that contains definitions for various rhythmic and pitch motives. A simple file of this type might look something like this:

     define(RH1,[4./16//2./ 32 * 4/])dnl
     define(RH2,[16// -2/  8*4/ 24 * 3/])dnl
A more usable file might contain 10 or more lengthy define statements, rather than only four short rhythmic and pitch "motives" as in the example above.

Now we can create several score files that that access these motives. One such score might look like this:

     i1 0 12;
     p3 rh RH1/-2/RH1;
     p4 no df3/ TREBLE / g5/bf4; 
     p5 mx 5 2000 1000/2 12000/ 5 12000 2000;

     i2 0 12;
     p3 rh RH2/8/32//RH2/-2;
     p4 no BASS/b3/f2/BASS;
     p5 1. 5000 12000;

These examples are merely illustrative, and hint at some of the many ways in which we can preprocess Csound orchestra and score files. Advanced users often employ such procedures not only to speed up score and orchestra file preparation, but also as compositional tools to derive a lot of mileage from a limited amount of initial source material. Synthesis and score generating algorithmic procedures thus can become modules that can be patched together in various configurations and combinations to permute, develop, vary and extend ideas, and which can enable us to go back and forth between "top down" and "bottom up" compositional approaches at various stages in the realization of a work.

Obviously, prepreprocessing procedures such as those we have surveyed above are not limited to our work with Csound, but rather can be applied as well to the creation of input files or data for other sound processing programs as well.

6.1.4 Macros recognized by Csound

Csound itself includes simple orchestra macros and score macros that permit the use of #define and #include statements within orchestra and score files. Here is a simple example. First we create a file of macro function definitions, which we will call defs, that we might use within several score files:

#  /* file of macro function definitions */
#define SINE # f1 0 1024 10 1.#
#define TRIANGLE # f31 0 64 7 -1. 32 1. 32 -1.#
#define SAW # f32 0 64 7 -1 64 1 #
#define SQUARE #f33 0 64 7 1. 16 1. 0 -1. 32 -1. 0 1. 16 1. #
Next we create a Csound score file that includes some of the macro definitions from file defs as well some additional macros unique to this score:

#include #/u/staff/allan/SEC1/defs#
#define RISEFALL # .005 .25#
f50 0 65 7 0 64 1.

  i31 0.000 1.200 100 6000 0.004 0.850 
  i31 0.119 0.924 130 6883 $RISEFALL
  i31 0.240 0.712 168 7897 $RISEFALL
  i31 0.982 2.000 60 22000 0.002 .350 
The score file above would be equivalent to this:

f 1 0 0 1024 1024 10 1.
f 31 0 0 64 64 7 -1. 32 1. 32 -1.
f 32 0 0 64 64 7 -1 64 1
f 33 0 0 64 64 7 1. 16 1. 0 -1. 32 -1. 0 1. 16 1.
f 50 0 0 65 65 7 0 64 1.
  i31 0.000 1.200 100 6000 0.004 0.850 
  i31 0.119 0.924 130 6883 0.005 0.250
  i31 0.240 0.712 168 7897 0.005 0.250
  i31 0.982 2.000 60 22000 0.002 .350 


6.2 Final orc/sco/soundfile examples

This section presents a few concluding orchestra/score11 file (and resulting /sflib/x soundfile) examples that illustrate some additional Csound opcodes and procedures that you may find useful.

- - - - - - - - - - - - - - - - - -
ex6-1 and ex6-2 : harmonizer examples using loscil and harmon

Orchestra file ex6-1 uses

Thus, from a given input tone (or more complex sound source), this instrument can produce three output tones, in exact rhythmic synchronization, at three new pitch levels.
;  #############################################################
;  orchestra file example ex6-1 : harmonizer   :   ECMC Csound Tutorial
;  #############################################################
; csound header
1 sr=44100
2 kr=2205
3 ksmps=20
4 nchnls=1

5 instr 1
6 ;----- SOUNDFILE INPUT --------------------
7 	ifunc = p4 ; gen1 function number of input soundfile
8 	iampscale = (p5 = 0 ? 1. : p5)  ; adjust input amplitude
9       irise = (p6 = 0 ? .001 : p6)   ; fade-in time
10 	idecay =( p7  = 0 ? .001 : p7)  ; fade-out time

11     ; loscil arguments
12     ibasepitch = (p8 < 13. ? cpspch(p8) : p8) ; base pitch of soundfile in pch or cps
13     ioutpitch = (p9 < 13. ? cpspch(p9) : p9) ; output pitch in pch or cps
14     ioutpitch = (p9 < 3 ? p9 * ibasepitch :ioutpitch) ; or as multiplier of basepitch

15  ; output amplitude envelope
16 kamp  expseg  .005 ,irise  , iampscale  , p3 - (irise + idecay) , iampscale , idecay , .005
17 asource  loscil3  kamp, ioutpitch, ifunc, ibasepitch

18 ;----- HARMONIZER --------------------
19 	imin init 0
20 	imin = (p10 < 1. ? p10 * ioutpitch : imin)
21 	imin = (p10 > 1. && p10 < 13. ? cpspch(p10) : imin)
22 	imin = (p10 > 13 ? p10 : imin)

23       ; max. freq. variance
24                      ; as % of output source pitch or in pch or cps
25 	imaxvar = (p11 < 1. ? p11 : p11 / ioutpitch)
26         imode = p12 ; if 0, iharm1 & iharm2 are ratios * ioutpitch
27                     ;  if 1, iharm1 & iharm2 are notes in pch or cps
28         iprd = p15  ; pitch analysis window size
29 iharm1 init p13
30 iharm2 init p14
31 if imode = 0 igoto doit
32 if p13 = 0 igoto harm2
33 	iharm1 = (p13 < 13. ? cpspch(p13) : p13)
34 harm2: if p14 = 0 igoto doit
35 	iharm2 = (p14 < 13. ? cpspch(p14) : p14)
36 doit:

37 aharm harmon asource, ioutpitch, imaxvar, iharm1, iharm2, imode, imin, iprd
38 ; print ioutpitch, imaxvar, iharm1, iharm2, imode, imin, iprd
39 ;----- SIGNAL OUTPUTS  {source/harmonizer mix} ---------------
40 out (p16 * asource) + (p17 * aharm)
41 endin
The important lines within this code are the calls to loscil3 on line 17 and to harmon on line 37.

Companion score11 input file ex6-1 represents an initial test of this instrument algorithm, creating three-part harmonies in succession from three sflib soundfiles all pitched at b3: a soprano tone (sflib/voice/sop1.b3), a violin tone (/sflib/string/vln.b3) and a trumpet tone (sflib/wind/trp.b3).

< Score file used to create "ex6-1" :
* f1 0 524288 -1 "/sflib/voice/sop1.b3" 0 0 0 ; < dur = 6.37
* f2 0 262144 -1 "/sflib/string/vln.b3" 0 0 0 ; < dur = 3.62
* f3 0 524288 -1 "/sflib/wind/trp.b3" 0 0 0 ; < dur = 6.31

i1 0 0 3;   < create 3 output "notes"
p3 4;               
du 303;        < each output note lasts 3 seconds
p4 nu 1/2/3;   < gen 1 func number of input soundfile : sop/vln/trp
< p5,6,7 : amplitude envelope
p5 nu .6/.4//;         < input amplitude multiplier
p6 0 ;         < optional fade-in time
p7 .2;         < optional fade-out time
p8 no b3;      < base pitch of input soundfile in pch or cps
p9 no b3//c4;      < output pitch in pch or cps

< harmonizer p-fields:
p10 no a3;  < iminfrq , in cps or as % of p9 base pitch
p11 .5;     < kmaxvar : fraction
p12  1;     < imode : if 0, p13 & p14 are ratios * p8 pitch
< IMPORTANT: p12 & p13 cannot BOTH be > p8
p13   no gs3;       < harmonizer output note or ratio 1
p14 no  cs4;         < harmonizer output note or ratio 2
p15 .04; < iprd : normally between .02 & .05
< source/harmopnizer output mix
p16 nu .5/0/.2;      < amp. multiplier for source signal output
p17 nu 1;          < amp. multiplier for harmonizer output
end;  <<<<<<<<<<<<<< end of ex6-1 score file >>>>>>>>>>>>>>

Within the opening SOUNDFILE INPUT section of this instrument algorithm (lines 6 through 17) we first define several initialization values, mostly be means of conditional evaluations of score p-fields 4 through 9, so that for each score11 input file we create for this instrument we can employ the most convenient of two or more alternative ways to set these parameter values.

6 ;----- SOUNDFILE INPUT --------------------
7 	ifunc = p4 ; gen1 function number of input soundfile
8 	iampscale = (p5 = 0 ? 1. : p5)  ; adjust input amplitude
9       irise = (p6 = 0 ? .001 : p6)   ; fade-in time
10 	idecay =( p7  = 0 ? .001 : p7)  ; fade-out time

11     ; loscil arguments
12     ibasepitch = (p8 < 13. ? cpspch(p8) : p8) ; base pitch of soundfile in pch or cps
13     ioutpitch = (p9 < 13. ? cpspch(p9) : p9) ; output pitch in pch or cps
14     ioutpitch = (p9 < 3 ? p9 * ibasepitch :ioutpitch) ; or as multiplier of basepitch
15  ; output amplitude envelope
16    kamp  expseg  .005 ,irise  , iampscale  , p3 - (irise + idecay) , iampscale , idecay , .005

With the iampscale init value derived from p5 we can scale (adjust) the amplitude of the input soundfile (since harmonization will increase the output amplitude, possibly resulting in clipping if we do not attenuate the input signal). The irise and idecay values derived from score p-fields 6 and 7 allow us to apply fade-ins and fade-outs to the input soundfiles within the output amplitude envelope created by expseg on line 16.

In order to transpose the pitch of a soundfile by resampling (a process that also will alter the duration of the sound), loscil3 must determine the ratio between the input and output frequencies. The ibasepitch (input pitch) conditional evaluation of p8, and the corresponding ioutpitch (output pitch) evaluation of p9, allow us to use either the score11 keyword notes in p8 and p9, which will output pch values less than 13., or else, if we prefer, provide these values in herz. (The latter method could be useful if we wish to pitch shift a soundfile by only a few herz.)

Harmonization: The harmon unit generator

     ar harmon asig, kestfrq, kmaxvar, kgenfreq1, kgenfreq2, imode, iminfrq, iprd
                 or, in ex6-1,
    aharm harmon asource, ioutpitch, imaxvar, iharm1, iharm2, imode, imin, iprd
can create either one or two pitch shifted copies of an input audio signal (which, in ex6-1, is the signal it receives from loscil3). However, only one of these copies can be pitched higher than the input signal, and only the copies (and not the input signal) are included in the audio output of harmon. Unlike loscil3, harmon performs time correction when pitch shifting. This can make the unit generator useful, apart from its typical "harmonization" applications, for pitch shifting a source sound without altering its duration, and for correcting the inaccurate pitch of a sound.

However, while the input pitch tracking within harmon (and within many of today's hardware harmonizers) generally is accurate, the audio input signal often suffers some degradation from the process of harmonization . (This is one of the reasons why harmonizers most often are used on "background," tracks in pop music.) This degradation may be just a little grunge, or may result in audible distortion or other artifacts. Input signals with wide vibratos or tremolos, or with complex timbres, or which lack a well-defined fundamental pitch, are especially prone to distortion.

To help the pitch tracking algorithm within harmon perform its rather complex task we must provide it with several arguments:

  1. An estimated center input pitch (called kestfrq), in herz, and provided in ex6-1 by the ioutpitch variable
  2. a maximum allowable variance from this pitch (kmaxvar), to help the pitch tracker cope with glissandi, vibratos and other pitch inflections. harmon requires that this value be expressed as a decimal fraction, where a value of .25 would indicate that the pitch can vary by +/- 25 % of the estimated center pitch value.
    The imaxvar conditional value in ex6-1 allows us to express this variance either in this fractional manner in p11, or else, should we prefer, in cps. (For example, a p11 value of 40 would specify that the input pitch does not drift by more than 40 herz from the estimated center pitch.)
  3. A minimum estimated frequency -- the lowest frequency that the pitch tracker might detect within the input signal.
    The imin variable in ex6-1 allows us to express this value in one of three ways within p10:
       --> if p10 is less than 1., it specifies a ratio between the lowest
       possible frequency and the estimated center frequency
       Example: A p10 value of .8 thus specifies .8 times the  ioutputpitch value 
       derived from p9 
       --> if p10  is between 1. and 13., we can use the score11 keyword notes to specify imin
            Example:  p10  no  a3
            (and a resulting Csound score value of 7.09) would set the imin value to 220 herz
       --> if p10 is greater than 13., we can specify this value directly in herz
  4. an analysis period (or window size), called irpd and generally set to between .02 and .05, which determines how frequently the pitch analysis will be updated

The remaining three arguments to harmon specify