The Important GEN Routines

The purpose of Csound’s GEN routines is to generate or load data that will be stored in function tables. The term “functions” may be a bit misleading to knowledgeable programmers, as the tables don’t store functions; they store data. Once created, a table can be read or edited by the table family of opcodes, which are discussed in the next section of this chapter. Currently, Csound provides about 40 GEN routines, some of which you’ll be likely to use only if you know a fair amount about mathematics. Others are more broadly useful in everyday synthesis operations.

The f-Statement

GEN routines can be invoked in two ways. The original mechanism provided by Csound for this purpose utilized an f-statement in the score. For example:


  f 1 0 8192 10 1

If you look up the syntax of the f-statement in the manual, the meaning of this code should be fairly clear. It has five parameters (p1 through p5). p1 is the number by which the table will be used in the orchestra, and should usually be unique. You can create several tables with the same number if you like, but only the most recently created of them will exist in memory. p2 is the time in the score at which the table will be created. Often this is 0—that is, the table is created before the score plays—but you can easily replace one table with another at a later point in the score by using the same value for p1.

p3 is the size of the table to be created, in data words. At present, Csound is available in 32-bit and 64-bit versions, so the actual size of a given table in bytes will be twice as large in the latter case, even though the number of points in the table is the same. You don’t need to worry about this when creating the table; just give it a size. You do need to be aware, however, that some Csound operations require a table of a size that is a power of 2 or a power of 2 plus 1. This is true with simple waveforms like the sine wave created in the example above. 8192 is 2 to the 13th power. The extra point that may be added at the end (the table above could have been created with a size of 8193) is a guard point. In fact, a table created with a size of 8192 also has a guard point: Its actual size is 8193 data words. But the data in the guard point may be different, depending on which size you specify in your code. (The manual page on the f-statement explains how the two ways of specifying table size differ with respect to the guard point.) The guard point is needed with opcodes such as oscili and tablei, which derive their output using a process of interpolation between points in the table.


image

Note The reason why waveform tables have guard points is efficiency. It’s faster to calculate the interpolation when an opcode reaches the last point of the table if there’s a guard point, because the code doesn’t have to accommodate the special case where it’s interpolating between the last point in the table and the first one.


If you want to create a table with a size that’s not a power of 2 or a power of 2 plus 1, you must specify its size as a negative number. If you forget to do this, your .csd file will compile, but you’ll get an error message at run time if any instruments try to use the table, because it won’t actually exist.

Tables containing samples loaded from the hard drive can be given a size of 0, which tells Csound to determine the size of the table at run time based on the size of the file. Such tables will work with some opcodes, but not with others.

Returning to the syntax of the f-statement, p4 is the number of the GEN routine. This, too, can be negative, and the minus sign has a very specific meaning. When you use a positive integer to specify the GEN routine, the table will be rescaled after it is created, so that its data falls within the range −1 to +1. (See the “Post-Normalization” sidebar.) When the number of the GEN routine is negative, however, rescaling is omitted. This is useful for things like tables of frequencies that are used to construct microtonal scales.

The meanings of the other parameters in an f-statement (p5 and following) depend on the specific GEN routine. For details, you’ll need to consult the manual page for the specific GEN routine you’re using.


image

Post-Normalization When we construct tables that will be used as audio waveforms, or for certain other purposes such as envelope contours, we normally want the wave data to have a range of ±1. Csound’s GEN routines take care of this chore for us: After the data in the table is generated, it is normalized (increased or reduced in amplitude as needed) so that it fits neatly within this range.

Some types of data should not be normalized, however. If we’re writing a sequence of note pitches in octave/pitch-class format (perhaps a series that begins 8.00 8.02 8.04 7.11), the very last thing we want is to have Csound reduce these values to fit within a smaller range. We can defeat the normalization feature if we need to by making the number of the GEN routine negative.


The ftgen Opcode Family

Instead of using f-statements in the score, you can invoke GEN routines using the opcodes ftgen, ftgenonce, and ftgentmp. The difference between the latter two is rather technical; for details, consult the manual page for ftgenonce. Basically, ftgenonce economizes on computer memory by checking to see whether an identical function table already exists. If so, the data in that table is used; no new table is created by the opcode. If some instrument is writing new data to the table during performance, and if some other instrument (or another event that uses the same instrument) is accessing the table, you’ll need to think carefully about whether to use ftgentmp or ftgenonce.

The arguments to ftgen and its siblings are very similar to those used with f-statements in the score, but with three differences, two of them rather trivial. First, the arguments to ftgen must be separated by commas. Second, the value for time of creation (p2) is ignored, as the table is created whenever ftgen runs. If it’s in the orchestra header, for instance, it will run when the performance starts. Third, you don’t need to specify a table number if you don’t want to. If you provide a p1 value of 0, Csound will automatically generate a unique table number. The automatically generated number is returned—that is, it’s an output value—when ftgen runs. For example, in place of the f statement in the previous section, we could do this:


  giSine ftgen 0, 0, 8192, 10, 1

At this point, the return value (giSine) is the number of the table. Because it’s a global variable, it can be used in any instrument in the orchestra in order to access the table. This is convenient because it makes the code easier to read, and because it eliminates the need to think about your table numbers.

Most often, you’ll invoke ftgen within the orchestra header, so its output will be a global value, as indicated by a name beginning with g-: giSine, for instance. ftgentmp is more often used within an instrument, and the table it creates exists only as long as the instrument is running. Because it’s local, a name beginning with i- would normally be used:


  iSine ftgentmp 0, 0, 8192, 10, 1

With this preamble out of the way, we’re ready to look at some GEN routines.

Sinusoids with GEN 09, 10, and 11

The sine wave is one of the basic building blocks of sound synthesis. Using GEN 10, we can create a waveform containing harmonically related sine waves of various amplitudes. For example:


  instr 1
  iamp = 0.5
  iWave ftgentmp 0, 0, 8192, 10, 1, 0.8, 0.6, 0.4, 0.2
  asig oscil iamp, 200, iWave
  outs asig, asig
  endin

Here, we have invoked GEN 10 using ftgentmp. The five values after the 10 (which is the GEN number) specify the relative strengths of the first five harmonics. The fundamental has a strength of 1, and the higher harmonics get progressively weaker. This will produce the tone of a very muted sawtooth wave. For a brighter sound that is still sawtooth-like, substitute this line:


  iWave ftgentmp 0, 0, 8192, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1

Now the wave has 10 sine harmonics of equal amplitude.


image

Sine Waves The sine wave (refer to Figure 7.1) is a mathematically defined entity and one of the most basic building blocks of sound synthesis. If you want to understand the technical definition, your best bet may be to go to the library and take out a good introductory book on trigonometry. Sine waves are explained in a number of articles online, but some of the articles use advanced math and others are rather eccentric.

In music synthesis, a sine wave produces a smooth, pure sound. It has no overtones. This makes it useful as a starting point for generating more complex sounds, for example in FM synthesis.

The easiest way to understand sine waves may be to imagine a freely rotating circle, with a dot at some point on the rim of the circle. As the circle rotates at a constant speed, the dot on the rim will move first upward and then downward, alternately. If we draw a diagram that shows the distance of the dot above or below the horizontal axis at the center of the circle as that distance changes over time, we have a diagram of a sine wave.


Because the tables created by GEN routines are rescaled unless we use a negative GEN number, the waveform created here can be weighted toward the higher harmonics without risk of overloading the audio output. Try replacing a few of the parameter values, along these lines:


  iWave ftgentmp 0, 0, 8192, 10, 0.5, 0, 3, 0.7, 0.6, 4.5, 0, 2.3, 0.2, 3.1

This is not necessarily the most interesting way to create tone colors, but even with something as simple as GEN 10 we have some useful options.

With GEN 09, we have to give three values—the partial number, the strength, and the phase—for each partial. We have to call them partials at this point, not harmonics, because with GEN 09 the value for the partial number need not be an integer. In other words, GEN 09 lets us stack sine waves with arbitrary frequency relationships to one another. We could specify three partials with partial numbers 1, 1.37, and 1.944. This is less interesting than you might imagine, however, because the waveform will start over when the end of the table is reached. If you create such a wave and then use it in an oscil, you won’t hear three non-harmonically related partials— you’ll hear a buzzy tone with no apparent inharmonicity. The bright, buzzy quality of the sound will be caused by the abrupt discontinuity in the waveform when the end of the table is reached and the oscillator jumps back to the beginning. If you want to generate a tone containing nonharmonically-related partials, there are other ways to do it (using the adsynt2 opcode, for instance). GEN 09 is not the right choice for this type of tone.


image

Inharmonicity is out-of-tuneness. The word is generally used to refer to the sound of partials within a composite tone that are not harmonically related. If the partials are close to pure harmonic (whole-number) ratios, the composite tone has only a slight inharmonicity. The amount of inharmonicity, while not rigorously defined in a mathematical sense, is the aggregate distance of the partials from harmonically pure overtones—the amount of out-of-tuneness.


GEN 09 is useful, however, for creating a smooth curve that rises from −1 to +1, perhaps with some bumps along the way. Such a table can be useful in building a waveshaper. Here’s a simple example:


  instr 1
  iMap ftgentmp 0, 0, 8192, 9, 3.5, 1, 270
  iWave ftgentmp 0, 0, 8192, 10, 1
  kamp line 0.01, p3, 0.49
  asig oscil 1, 200, iWave
  atab tablei asig * kamp, iMap, 1, 0.5
  aout linen atab, 0.1, p3, 0.1
  outs atab, atab
  endin

GEN 09 is used, in the first line of the instrument, to create a table called iMap. The partial used is 3.5; to hear more overtones, try a higher value such as 7.5. This waveform starts with a phase value of 270 degrees, which is the bottom of the trough of a sine wave (refer to Figure 7.1). After generating a sine wave with oscil, we use the sine wave to read the iMap table using tablei, and the width of the sine wave’s swing through the table is controlled by a line value that increases from 0.01 to 0.49. The result is a tone that acquires more harmonics as the line rises. Not supremely interesting with a sine wave as the source, but with a sampled sound as the input from the oscil, the distortion will get more pungent.

GEN 11 creates a table containing one or more cosine waves rather than sine waves. The difference between a sine wave and a cosine wave is not audible, but it’s mathematically significant. Both are smooth curves that alternately rise above 0 and fall below 0. Assuming an amplitude of ±1, a sine wave starts with a value of 0, rises to 1, then slides down to −1, rises back to 0, and so on. A cosine wave starts at 1, slides down to −1, then rises to 1 again, and so on.

This difference—that a sine wave starts at 0, while a cosine wave starts at its maximum amplitude—is significant in Csound in at least two ways. First, a few opcodes, such as gbuzz, require cosine waves rather than sine waves as source data. Second, if you want to define a curve for some purpose, such as for an envelope segment or a waveshaper, you might want to use GEN 09 or GEN 11, and you’ll need to know where the curve starts.

The syntax of GEN 11 is:


  f # time size 11 nh [lh] [r]

In this prototype, nh is the number of harmonics requested, lh is the lowest harmonic, and r is a multiplier that is applied to the amplitudes of successively higher harmonics. The syntax of GEN 11 is efficient if you want to produce a tone that has a number of harmonically related partials. For instance:


  giCos ftgen 0, 0, 8192, 11, 7, 5, 1.2

This line of code produces a wavetable constructed additively using seven cosine waves, the lowest being the fifth harmonic, and the higher harmonics being somewhat louder than the lower ones.

Building Tables out of Segments

Sometimes we want to store the shape of a contour in a table, and we want to specify the shape of the contour ourselves rather than have it constructed automatically using sine waves. The basic tools for this are GEN 07 and GEN 27, both of which build tables using segments of straight lines. Such tables are very useful for creating modulation contours, such as amplitude envelopes. As far as I can determine, these two GEN routines give exactly the same result, but the syntax is different.

When GEN 07 is used, the first data p-field (p5) is a value—the value of the first location in the table. The remaining fields alternately specify the lengths of the segments and the data values at the ends of those segments. The sum of the lengths of the segments will normally equal the size of the requested table.

When GEN 27 is used, again, alternating p-fields are used to define the values stored in the table— but in this case the values alternate with the points in the table at which that value is reached, rather than the lengths of the segments. An example may make this clearer. The following two f-statements construct the same table data:


  f1 0 256 7 0 63 1 1 -1 127 1 1 -1 64 0
  f2 0 256 27 0 0 63 1 64 -1 191 1 192 -1 256 0

In the first statement, using GEN 07, three segments are defined with lengths 63, 127, and 64. Two abrupt discontinuities—segments of 1 length—are also defined, where the table data jumps down from 1 to −1. The result is a rising ramp wave. In the second statement, using GEN 27, each segment is defined by its start and end points (0–63, 64–191, and 192–256 respectively).

Here is a simple instrument and score with which you can listen to and compare these tables:


  instr 1
  iWave ftgentmp 0, 0, 8192, 10, 1, 0.7, 0.4, 0.1
  kphase phasor 1
  ; replace with: kphase, 2, 1
  kramp tablei kphase, 1, 1
  asig oscil 0.7, 300 + (50 * kramp), iWave
  outs asig, asig
  endin
  </CsInstruments>
  <CsScore>

  f1 0 256 7 0 63 1 1 -1 127 1 1 -1 64 0
  f2 0 256 27 0 0 63 1 64 -1 191 1 192 -1 256 0

  i1 0 5

Try replacing 1 with 2 as the second argument to tablei. Sounds like a car alarm either way. I can’t hear the difference—can you?

GEN 16 and GEN 25 produce tables using variable curves. GEN 25 operates much like expseg: The curvature of the segments is exponential, and the breakpoints of the curve must all have the same sign (either positive or negative). GEN 16 produces only one curve between its start and end points, but the start and end points don’t have to be alike in sign, and the curve can be adjusted to have a slightly or radically convex or concave shape. The curvature produced by GEN 16 is handled exactly like the curvature produced by transeg.

Reading Audio Files

GEN 01 reads a mono or stereo. WAV or. AIFF file from your hard drive and stores the data in a table. GEN 49 does the same thing with .mp3 files. These files should be stored in the directory you define as the SSDIR or SFDIR in the Environment tab of the Configuration box in CsoundQt. Note, however, that in version 0.6 these settings are broken. If Csound can’t find the audio files, you may need to specify the full path from the root of your hard drive as part of the f-statement, like this:


  f1 0 1048576 1 
     “C:/Users/Jim Aikin/Documents/csound scores/samples/olive.aiff” 
     0 0 0

(The backslash is used for a line of code that is too long to fit conveniently on one line in the screen.) As you can see, spaces are allowed in directory and file names, and forward-slashes are used as separators in the file name string, not backslashes.

GEN 49 is a relatively recent addition to Csound—at this writing, it’s less than three years old. It didn’t work for me using Csound 5.13 in Windows 7, but it worked fine on my MacBook Pro. Here’s a test file I created, which played egyptian .mp3:


  instr 1
  aphas phasor 0.023
  asigL tablei aphas, 1, 1
  asigR tablei aphas, 2, 1
  aoutL linen asigL, 0.1, p3, 0.1
  aoutR linen asigR, 0.1, p3, 0.1
  outs aoutL, aoutR
  endin
  </CsInstruments>
  <CsScore>
  f1 0 2097152 49 “egyptian.mp3” 4 3
  f2 0 2097152 49 “egyptian.mp3” 4 4
  i1 0 60

The number after the file name in the f-statements is a skip time. Since my audio started several seconds into the file, I entered a 4 here. The last number specified the left channel of the stereo source file for f1 and the right channel for f2. I then read the data in these two tables using a pair of tablei opcodes, one for the left channel and one for the right channel, in the instrument. The value for the frequency of the phasor was derived empirically. In this instrument the phasor frequency determines the speed and therefore the pitch of the audio playback.

Your Own Data

Two GEN routines are especially useful when you know exactly what data you want to store in a table: GEN 02 and GEN 23. These routines are the tool of choice, for instance, when you want to create a complex tuning table and fill it with your own frequency values, or when you want to build a step sequencer.

With GEN 02, you enter the data by hand into the .csd file, either in the f-statement or in the call to the ftgen opcode. In either case, the data is transferred directly from the p-fields into the table. Don’t forget that the data will later be rescaled to a ±1 range unless you make the GEN number negative.

According to the manual, numeric values in a text file used by GEN 23 can be separated by spaces, tabs, newline characters, or commas. Words can be added to the file as comments and will be ignored when GEN 23 loads the file into a table.

Here is an example that loads values from a table created with GEN 02 in order to play an arpeggio within a single note event. In this example we’re using the table opcode rather than tablei, because there’s no need to interpolate between the data values in the table.


  instr 1
  iWave ftgentmp 0, 0, 8192, 10, 1, 0.7, 0.4, 0.1
  iPitchTable ftgentmp 0, 0, 8, -2, 300, 375, 450, 525, 600, 525, 450, 375
  kfreq init 300
  kstep init 0

  ktrig metro 8
  if ktrig == 1 then
    kfreq table kstep, iPitchTable
    kstep = kstep + 1
    if kstep > 7 then
      kstep = 0
    endif
  endif

  asig oscil 0.7, kfreq, iWave
  outs asig, asig
  endin

  </CsInstruments>
  <CsScore>
  i1 0 5

This instrument plays an arpeggio. The successive steps in the arpeggio are triggered by a metro, which outputs a value of 1 at a frequency of 8 Hz. Except when these pulses occur, the value of ktrig is 0. The first if-test encloses a block that runs only when ktrig is 1. In this situation, table reads from the table whose ID is iPitchTable, which was created by ftgentmp. The rest of that code block increments the value of the counter kstep. If we’ve reached the end of the table, kstep is set back to 0.

This arpeggio is implemented in a basic way, using actual frequency values. Also, the frequencies are in just intonation, which may not be what you want. Let’s edit this instrument slightly so it will use 12-note-per-octave equal temperament. We’ll use cpspch, which was introduced earlier in this chapter.


  instr 1
  iWave ftgentmp 0, 0, 8192, 10, 1, 0.7, 0.4, 0.1
  iPitchTable ftgentmp 0, 0, 8, -2, 8.00, 8.04, 8.07, 8.10, 9.00,
    8.10, 8.07, 8.04
  kfreq init 100
  kfreqval init 8.00
  kstep init 0

  ktrig metro 8
  if ktrig == 1 then
    kfreqval table kstep, iPitchTable
    kfreq = cpspch(kfreqval)
    kstep = kstep + 1
    if kstep > 7 then
      kstep = 0
    endif
  endif

  asig oscil 0.7, kfreq, iWave
  outs asig, asig
  endin

The table now contains data in octave/pitch-class format. We’ve introduced a new k-rate variable, kfreqval, which receives the data from the table in its original form. cpspch then converts this data into a frequency value that oscil can use.

To try out GEN 23, copy the eight data values from the iPitchTable ftgentmp above and paste them into a new text file in a text editor (not a word processor). Save this file to some suitable location and then replace the GEN 02 line with GEN 23. On my machine, the new code looks like this:


  iPitchTable ftgentmp 0, 0, 8, -23, 
    “C:/Users/Jim Aikin/My Documents/csound scores/arpeggio.txt”

The sound should be exactly the same as before. GEN 02 is more convenient if you only need to enter a few values, or if you want to keep all of your code in a single file. GEN 23 is more useful if you’re using an external program to write a large amount of data to a text file.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.239.44