Usage Notes
The technical description of waveshaping is that
an input signal, x, puts out an output signal, y, by
passing through a function defined as y = f(x).
So, for example,
f(x) = x2 will exponentially expand the amplitude of the incoming waveform (Dodge and Jerse, 1985).
What does this mean? Imagine a transfer function as a line drawn
on a cartesian coordinate system:
The x-axis is where the input values from the signal are located.
These are then mapped onto te y-axis -- the output values -- by mapping
from the x-axis to the transfer function curve and then over to the
y-axis:
Note that if the input value goes above or below a certain point on the
above graph, the output value will remain constant even if the input
value increases beyond that point (positive or negative). This simple
waveshaping distortion will result in "clipping" the input signal:
The "INDEXMIN" (p3) and "INDEXMAX" (p4) set the parameters for
how the lookup/transfer function works. In the above example, the
"INDEXMIN" was assumed to be 0.0 and the "INDEXMAX" was 1.0. This
will use the full range of the x-axis input values, i.e. the whole
transfer function. You may choose to use just a small portion of the
transfer function for doing the x-axis -> y-axis mapping by setting
these two values between 0.0 and 1.0.
The particular range of lookup values will also be determined by
the "INDEXENV" pfield control envelope (p9). It determines how much of the
range between p3 and p4 is used. Changing this dynamically can
alter the spectrum of the note through time. For example, a control
envelope that traveled from 0.0 to 1.0 back to 0.0 for the duration
of a note with a transfer function like the one pictured above will
gradually introduce distortion into the output wave and then
gradually reduce it. All timbres produced by WAVESHAPE
are harmonic spectra, however. No non-harmonic partials can
be generated by waveshaping.
p8 (the "TRANSFERFUNCTION") is a pfield reference to a table containing
the transfer function to be used. These are generally constructed
using the
maketable
scorefile command. Of special interest is the
maketable("cheby", ...)
option. Chebyshev polynomials can help design transfer functions with
particular harmonic characteristics.
The transfer-function process (called a "table lookup" by the way) also
imparts an amplitude to the signal as the "INDEXENV" travels between
0.0 and 1.0. Because this is primarily used for determining the
spectral character of the note, you may wish to use an independent
amplitude envelope (done using the pfield-control capabilities
of the "AMP" parameter, p5). To guarantee that a full output
results from the waveshaping, the optional "ampnormalize"
parameter (p10) can be set to 1 (this is the default, by the way).
To turn off this normalization, set it to 0. Why would you
want to turn this off? The amp normalization in this instrument can
cause clicks at the beginning and ending of notes if you don't
set your amplitude envelope.
Any waveform may be used as an input function. The waveform
table is specified in p7 ("WAVETABLE").
Be aware that
oct.pc format generally will not work as you expect for p3 (pitch)
if the pfield changes dynamically because of the 'mod 12' aspect of
the pitch-class (.pc) specification. Use direct frequency (hz) or
linear octaves instead.
WAVESHAPE can produce mono or stereo output.
Sample Scores
very basic:
rtsetparams(44100, 2)
load("WAVESHAPE")
ampenv = maketable("line", 1000, 0,0, 3.5,1, 7,0)
waveform = maketable("wave", 1000, "sine")
transferfunc = maketable("linebrk", 1000, -0.5, 300, -0.5, 200, 0, 200, 0.5, 300, 0.5)
indexfunc = maketable("line", 1000, 0,0, 3.5,1, 7,0)
WAVESHAPE(0, 7, 7.02, 0, 1, 20000*ampenv, 0.3, waveform, transferfunc, indexfunc)
WAVESHAPE(0, 7, 7.021, 0, 1, 20000*ampenv, 0.7, waveform, transferfunc, indexfunc)
slightly more advanced:
rtsetparams(44100, 2)
load("WAVESHAPE")
ampenv = maketable("line", 1000, 0,0, 3.5,1, 7,0)
waveform = maketable("wave", 1000, "sine")
transferfunc = maketable("cheby", 1000, 0.9, 0.3, -0.2, 0.6, -0.7)
indexfunc = maketable("line", 1000, 0,0, 3.5,1, 7,0)
WAVESHAPE(0, 7, 7.02, 0, 1, 20000*ampenv, 0.99, waveform, transferfunc, indexfunc)
ampenv = maketable("line", 1000, 0,0, 1.5,1, 7,0)
indexfunc = maketable("line", 1000, 0,1, 7,0)
WAVESHAPE(4, 7, 6.091, 0, 1, 20000*ampenv, 0.01, waveform, transferfunc, indexfunc)
See Also