Dynamics Control and Panning

Because Csound uses floating-point audio internally, the signal level can rise to astronomical levels—far beyond anything that your output hardware (or your ears) can hope to deal with. In order to prevent clipping and have a pleasant listening experience, you’ll often want to employ one or more techniques for controlling the audio signal level. Appropriate tools for the job are the balance and compress opcodes, which are useful for designing individual instruments. In addition, I find it useful to set up i-time or k-rate level controls in the orchestra header, so that I have quick access to what is essentially a mixing console. For instance, the header might include code like this:


  giMasterVolume = 1.0
  giBassVolume = 1.0
  giSnareVolume = 1.0

Then, in the bass instrument, I would do something like this:


  iamp = p4 * giMasterVolume * giBassVolume

If, while developing a piece of music, I find that the mix as a whole is clipping, I can adjust everything downward by setting giMasterVolume = 0.95 or whatever. Likewise, I can adjust all instances of the bass instrument downward from one easy-to-find parameter, without having to edit the score or hunt through the orchestra for the bass instrument. (The same results can be achieved using the Mixer opcodes, as explained earlier in this chapter.)

balance

The most basic opcode for controlling the signal level within an instrument is balance. balance compares a signal to a reference signal. The output of balance is the same as the main input signal, but adjusted up or down in level so that it doesn’t exceed the level of the reference signal. balance doesn’t always do a perfect job of this; it does some averaging, so shorter peaks may slip through without being entirely squashed. So you’ll still need to use your ears and check the messages in the output console for indications of clipping.

I usually use balance by creating a dummy sine wave (a wave I’m not using for anything else) as its comparison input. Here’s an example that illustrates the technique:


  0dbfs = 1

  instr 1
  iCos ftgen 0, 0, 8192, 11, 1
  iSine ftgen 0, 0, 8192, 10, 1
  ifreq = p4

  ; generate a tone, and process it through a resonant filter:
  asig gbuzz 100, ifreq, 75, 1, 0.9, iCos
  ifiltrise = p3 * 0.01
  ifiltdecay = p3 * 0.99
  kfiltenv linseg 2500, ifiltrise, 3700, ifiltdecay, 800
  afilt rezzy asig, kfiltenv, 85

  ; generate a reference tone, and adjust the filter output to match the
  ; level of the reference:
  icomplevel = 0.2
  asine oscil icomplevel, 500, iSine
  abal balance afilt, asine
  aout linen abal, 0.01, p3, 0.1
  outs aout, aout
  endin

  </CsInstruments>
  <CsScore>

  i1 0 1 100
  i1 +. 125
  i1 +. 150

As usual, this orchestra has 0dbfs = 1, but the careless programmer has given the signal from gbuzz (the oscillator we’re listening to) an amplitude of 100. The filter (rezzy) is happy to process this signal, but the result—the signal in afilt—will be much too loud. A comparison signal is created by an oscil playing a 500-Hz sine wave, and afilt is passed through balance, giving us a new output signal called abal. This is then enveloped using linen and sent to the output. You’ll note that the level of asine is set to 0.2, yet the output level of the signal is about 0.9. There’s no clipping, which is good, but balance doesn’t always reduce a signal to the expected level, so creating an i-time argument (named icomplevel in the code above) to control the level of the comparison signal makes the code easy to read.

You can control the output more crudely and drastically with the limit opcode. In the example above, replace the balance line with this code:


  abal limit afilt, -0.9, 0.9

The output signal will be reported by the console as having a perfectly even level of 0.9, but you’ll still hear lots of clipping, because clipping the signal is what limit does. Once in a while this may be the effect you want, but it’s important to understand that limit is not a high-end soft-knee compressor/limiter: It just performs a simple mathematical operation. Rather than processing audio through limit, you’re more likely to want to use it to limit the range of control signals. That’s what it’s mainly designed for. For good-sounding limiting, use compress.

compress

The compress opcode implements a soft-knee sidechain compressor with standard envelope attack and release settings and an adjustable threshold. The first thing to note about this opcode is that as of Csound 5.13, the opcode assumes 0dbfs = 32768, which was the maximum signal level in early, 16-bit versions of Csound. I’m told this requirement will disappear in the next release of Csound, so if you’re using 5.14 or later, you shouldn’t need to worry about it.

For details on this opcode, you’ll need to consult the manual. But here’s an example to get you started. I set up my orchestra so that neither the synthesizer instrument nor the reverb uses outs to send the final signal to Csound’s audio output. Instead, they use global variables to send to an output processor “instrument” whose sole purpose is to apply compress. Because this .csd file has 0dbfs=1.0 in its orchestra header, the output processor has to do a little extra math on the input and output of compress. And because the signal is stereo, I needed a compress on each channel.

Note that the synth output needs to be zeroed in the output processor instrument, because the synth instrument will be played polyphonically. There’s only one reverb, however, so its output, which is also arriving at the output instrument, simply overwrites whatever is in the bus rather than adding to it. Thus the reverb bus doesn’t need to be zeroed.


  instr 201; output compressor
  ainL = gaRevOutL + gaSynthOutL
  ainR = gaRevOutR + gaSynthOutR
  gaSynthOutL = 0
  gaSynthOutR = 0

  ; get rid of DC:
  ainL atone ainL, 10
  ainR atone ainR, 10

  ; boost (and later reduce) the level for Csound 5.13:
  ainL = ainL * 32768
  ainR = ainR * 32768
  aoutL compress ainL, ainL, 0, 60, 76, 2, 0.001, 0.05, 0.005
  aoutR compress ainR, ainR, 0, 60, 76, 2, 0.001, 0.05, 0.005
  aoutL = aoutL / 32768
  aoutR = aoutR / 32768

  outs aoutL, aoutR
  endin

The inputs are being used in both the first and second arguments to compress. The second input is the signal that is to be analyzed for purposes of deciding what to do with the signal at the first input. In other words, compress has a built-in sidechain input. Since we’re not using a second signal for sidechaining, this is how we tell compress to analyze our main signal.

The output processor above is designed for live use, so the final argument to compress is only 5 milliseconds (0.005 second). A larger value here might give a slightly smoother response, but it would also add latency to a MIDI keyboard performance, because the output of compress will always be delayed by this amount of time. 5ms seems a good compromise.

Because of the sidechain input, compress can also be used for ducking. Below is an instrument that illustrates this idea. You can substitute your own voice wave (or a drum loop sample, or whatever). The tone produced by gbuzz will duck during the amplitude peaks in the voice signal.


  instr 1
  iCos ftgen 0, 0, 8192, 11, 1
  iVoiceTable ftgen 0, 0, 524288, 1, “olive.aiff”, 0, 0, 0
  ibasefreq = 44100 / ftlen(iVoiceTable)

  ; play the voice signal:
  aphas phasor ibasefreq
  avoice tablei aphas, iVoiceTable, 1, 0, 1
  avoice = avoice * 0dbfs

  ; create a tone:
  abuzz gbuzz 0dbfs, 200, 75, 1, 0.9, iCos

  ; duck the tone in response to peaks in the voice signal:
  acomp compress abuzz, avoice, 0, 48, 60, 10, 0.005, 0.01, 0.05
  outs avoice, acomp
  endin

  </CsInstruments>
  <CsScore>

  i1 0 35

Note the use of the global variable 0dbfs to set the amplitudes of the two signals. Because this file does not have 0dbfs=1 in its orchestra header, this variable has the default value 32768.

Try changing the values for the attack and release parameters, and notice how the output changes.

pan and pan2

If you use Csound to generate stereo audio—probably the most common situation, in which the orchestra header specifies nchnls=2—you’ll often need a way to control the point in the stereo field at which a signal will be heard. The tool for this is pan2. Here is its prototype:


  a1, a2 pan2 asig, xp [, imode]

pan2 takes one audio input (called asig above) and produces left and right outputs. The latter are called a1 and a2 in the prototype, but I feel it’s less confusing in actual instrument code to name them something like aL and aR. The value sent to xp is the pan position and should be somewhere between 0 (hard left) and 1 (hard right).

By default, pan2 runs in equal-power mode, but there are two other options, as explained in the manual: linear and square-root-of-two.


image

In equal-power panning, a signal that is panned smoothly from the left speaker to the right or vice versa will sound equally loud at each point in the stereo field. With linear panning, the amplitude level will drop by 6 dB in the middle of the stereo field.


There are two or three basic ways to use the xp input. If you know that the pan position of the instrument will remain fixed throughout the score, you can set this argument to a constant. If various notes will be panned to various positions, you can set it from a p-field in the score; in this situation it will presumably be an i-time value, which will be a constant in any given note, but may change from one note to the next. Because this parameter can also be sent a changing k-rate value, you can easily modulate pan position from an envelope or LFO, like this:


  kpan lfo 0.5, 2
  kpan = kpan + 0.5
  aL, aR pan2 aout, kpan
  outs aL, aR

The raw signal from lfo is bipolar; that is, it will run from −0.5 to 0.5. We need to add 0.5 to it so it will vary from 0 to 1. This code will cause the LFO to pan whatever signal is in aout between the stereo outputs.

The pan opcode is more powerful. It’s designed for quadrophonic audio systems, in which four speakers are positioned at the corners of a square. In addition to specifying the X and Y coordinates of the apparent sound source within the square, the user has to create a table that defines the curve with which the amplitude will grow as the X or Y value increases.

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

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