|
RTcmix Instruments
|
by R. Luke DuBois, with some judicious plagiarism from Charles Dodge, Curtis Roads, Paul Lansky, Perry Cook, Doug Scott, and, bien sûr, Brad Garton, Dave Topper, with revisions by Chris Bailey.
a couple of notes:
the syntax notes in the instruments are by no means definitive, especially for the makegens. feel free too experiment using different gen types. the example scores are all taken from Brad's cmix distribution in cmix/insts.
also, my grasp of calculus is limited (read virtually nonexistent), so some of these equations are a bit iffy, IMHO : ).
standard C comment syntax is used so that you can cut and paste from your browser into a MINC score or C file. pretty slick, huh? These scores all make use
of the new "load()" directive, so that they may be run simply by saying
CMIX < scorefile
for RTcmix instruments, or
cmix < scorefile
for non-RTcmix instruments.
the instrument pages read best linearly, so the instrument descriptions tend to get more and more terse towards the bottom of the document.
have fun!
am/AM
AM takes an input soundfile and modulates its amplitude according to an oscillator which is defined by function tables 1 (amplitude envelope) and 2 (waveform). The frequency of the modulation is determined by p4 of the AM() command. The frequency of the modulation as well as the oscillator setup will vary the modulation from a slight tremelo all the way to a full-blown artifact-full sound.
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1...) /* amplitude envelope of the output where tn and an are time/amplitude pairs */
makegen(2, 10, 1000, p0, p1...) /* waveform of the modulating oscillator where pn is the amplitude of successive harmonics in the spectra */
AM(outskip, inskip, duration, amp, frequency, inchan, spread)
in comment form:
/* am -- amplitude modulate an input signal
*
* p0 = output skip
* p1 = input skip
* p2 = duration
* p3 = amplitude
* p4 = AM modulator frequency (hz)
* p5 = input channal [optional]
* p6 = stereo spread <0-1> [optional]
* assumes function table 1 is the amplitude envelope
* function table 2 is the AM modulator waveform
*
*/
An example score:
rtsetparams(44100, 1)
load("AM")
rtinput("/sndh/bob.dole.mono")
makegen(1, 24, 1000, 0,0, 2,1, 5,1, 7,0)
makegen(2, 10, 1000, 1)
AM(0, 0, 7, 1, 14)
AM(8, 0, 7, 1, 187)
Another score, taking input from the ADC:
rtsetparams(44100, 1, 256)
load("AM")
rtinput("AUDIO")
makegen(1, 24, 1000, 0,0, 2,1, 5,1, 7,0)
makegen(2, 10, 1000, 1)
AM(0, 0, 7, 1, 14)
AM(8, 0, 7, 1, 187)
A third score, featuring a looping structure:
rtsetparams(44100, 2, 256)
load("AM")
rtinput("AUDIO", "MIC", 2)
makegen(1, 24, 1000, 0,0, 0.1,1, 0.2,1, 0.3,0)
makegen(2, 10, 1000, 1)
for(start = 0; start < 15.0; start = start + 0.1) {
freq = random() * 400.0
AM(start, 0, 0.3, 1, freq, 0, random())
}
aminst/AMINST
amplitude modulation: a type of modulation where a carrier signal (of frequency fc and mean amplitude a) is varied by a modulator signal (of frequency fm and modulation index I) such that two sidebands are produced of frequency fc ± fm and amplitude of a-I/2. the result depends on the modulator frequency: a modulator of frequency less than 10Hz will result in a tremelo effect based on the amplitude of the modulator signal. if the modulator is between 10Hz and a frequency where the sidebands are still within critical band of the center frequency, the sound will have an amplitude proportional to the averave amplitude of the modulator. at higher frequencies, the sidebands will be perceptible. (adapted from Dodge and Jerse, 1985).
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1...) /* amplitude envelope of the carrier */
makegen(2, 24, 1000, t0, a0, t1, a1...) /* amplitude envelope of the modulator */
makegen(3, 10, 1000, p0, p1...) /* spectrum of the carrier */
makegen(4, 10, 1000, p0, p1...) /* spectrum of the modulator */
AMINST(outskip, duration, amp, fc, fm, spread)
in comment form:
/* aminst -- amplitude modulation synthesis
*
* p0 = start
* p1 = duration
* p2 = amplitude
* p3 = carrier frequency (hz)
* p4 = modulator frequency (hz)
* p5 = stereo spread <0-1> [optional]
* assumes function table 1 is the amplitude envelope
* assumes function table 2 is the modulation envelope
* function table 3 is the carrier waveform
* function table 4 is the modulator waveform
*
*/
An example score:
rtsetparams(44100, 1)
load("AMINST")
makegen(1, 24, 1000, 0,0, 0.1,1, 3.4,1, 3.5,0)
makegen(2, 24, 1000, 0,0, 1,1, 2,0)
makegen(3, 10, 1000, 1)
makegen(4, 10, 1000, 1)
AMINST(0, 3.5, 10000, 178, 315)
makegen(1, 24, 1000, 0,1, 1,0)
makegen(2, 24, 1000, 0,1, 1.0,0.2, 3.4,0)
AMINST(3.9, 3.4, 10000, cpspch(8.00), cpspch(8.02))
clar/CLAR
CLAR is a physical modelling algorithm for a clarinet. physical modelling is a synthesis paradigm (developed by Perry Cook) whereby the computer synthesizes sound not according to the spectrum of the desired output, but rather based on a description of the physical process which makes the sound (to whit: a violin's physical model would include a system describing the physics of a vibrating string, coupled with a quantified description of the effects of bow pressure, string vibrato, etc.). physical modelling instruments, therefore, are simulated and controlled by expert systems describing cause-and-effect relationships of specific performance actions on corresponding acoustic results. (adapted from Cook, 1992, 1995).
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1...) /* amplitude of the noise (breath pressure) injected into the wind model in time/amplitude pairs */
makegen(2, 24, 1000, t0, a0, t1, a1...) /* amplitude of the overall output note */
CLAR(outskip, duration, noiseamp, length1, length2, amp, d2gain, spread)
in comment form:
/* clar -- Perry Cook's clarinet physical model
*
* p0 = start
* p1 = dur
* p2 = noise amp
* p3 = length1
* p4 = length2
* p5 = output amp
* p6 = d2 gain
* p7 = stereo spread (0-1)
* function slot 1 is the noise amp envelope
* function slot 2 is the output amp envelope
*
*/
An example score:
rtsetparams(22050, 1)
load("CLAR")
makegen(1, 24, 1000, 0, 1, 1, 1)
makegen(2, 24, 1000, 0, 1, 1, 1)
CLAR(0, 1, 0.02, 78, 31, 7000, 0)
CLAR(1, 1, 0.02, 35, 4, 7000, 0)
CLAR(2, 1, 0.02, 35, 9, 7000, 0)
CLAR(3, 1, 0.02, 51, 20, 7000, 0.5)
Another score, featuring a looping structure:
rtsetparams(22050, 1)
load("CLAR")
makegen(1, 24, 1000, 0, 1, 1, 1)
makegen(2, 24, 1000, 0, 1, 1, 1)
d2 = 0
for (start = 0; start < 10; start = start + 0.5) {
CLAR(start, 0.5, 0.02, 69, 34, 7000, d2)
d2 = d2 + 0.05
}
combit/COMBIT
a comb filter is a short feedbacking delay line of delay time t which, when applied to an incoming signal, causes the sound to ring at frequency 1/t for an amount of time which decays exponentially proportional to the percentage of feedback. (adapted from Roads, 1997). COMBIT takes an input soundfile and makes it ring at the frequency specified in p4 of the instrument, with a decay time in seconds of p5. the efficacy of the comb filter is dependent on the amount of that frequency already present in the incoming signal (thus, a very low filter frequency applied to a high-pitched soundfile will not ring as well as it would applied to a low-sounding signal).
Syntax:
setline(t0,a0,t1,a1...) /* sets the envelope of the output sound in time/amplitude pairs */
COMBIT(inskip, outskip, duration, amplitude, pitch, reverb, inchan, spread)
in comment form:
/* combit -- comb filter instrument
*
* p0 = output skip
* p1 = input skip
* p2 = input duration
* p3 = amplitude multiplier
* p4 = pitch (cps)
* p5 = reverb time
* p6 = input channel [optional]
* p7 = stereo spread [optional]
*
*/
An example score:
rtsetparams(44100, 2)
load("COMBIT")
rtinput("/sndh/bob.dole.mono")
COMBIT(0, 0, 3.5, 0.08, cpspch(7.09), .5, 0, 0)
COMBIT(0.2, 0, 3.5, 0.08, cpspch(7.07), .5, 0, 1)
Another score, using a looping structure:
rtsetparams(44100, 2)
load("COMBIT")
rtinput("/sndh/bob.dole.mono")
dur = 0.1
setline(0,0, 0.1,1, 1,0)
reset(1000)
for (outsk = 0; outsk < 14.0; outsk = outsk + 0.1) {
insk = random() * 7.0
pitch = random() * 500 + 100
COMBIT(outsk, insk, dur, 0.1, pitch, .5, 0, random());
}
A third score, taking input from the ADC:
rtsetparams(44100, 2, 1024)
load("COMBIT")
rtinput("AUDIO")
COMBIT(0, 0, 3.5, 0.08, cpspch(7.09), .5, 0, 0)
COMBIT(0.2, 0, 3.5, 0.08, cpspch(7.07), .5, 0, 1)
fir/FIR
fir does a finite impulse response filter on a soundfile according to the filter coefficients passed to the instrument. the filter is non-recursive, so only input samples are passed through the coefficients, in the form:
yn = anxn ± an-1xn-1... ± an-xxn-x
Syntax:
FIR(outskip, inskip, duration, coefficient1, coefficient2...) /* up to 99 coefficients can be specified */
in comment form:
/* fir: simple fir filter instrument
*
* p0 = outsk
* p1 = insk
* p2 = dur
* p3 = total number of coefficients
* p4... the coefficients (up to 99 fir coefficients)
*
* (no amplitude control, does channel 0 of both input and output only)
*
*/
An example score:
input("bob.dole.snd")
output("bob.dole.filtered.snd")
FIR(0, 0, 3.5, 2, 0.5, 0.1)
fminst/FMINST
frequency modulation: a type of distortion synthesis where one waveform (the carrier) of frequency fc is modulated by another waveform (the modulator) with frequency fm and modulation index I (defined by the maximum amplitude deviation of the modulator oscillator divided by its frequency). the resultant sound consists of the carrier frequency as well as a number of sidebands of frequencies fc ± kfm, where k is an integer series increasing from 0 (the carrier frequency). the amplitude of the sidebands over time is determined by a bessel function of the first kind Jk(I). negative frequencies are possible, resulting in a 180° out-of-phase sideband at the absolute value of that frequency. negative amplitudes are also possible, resulting in a reversal of phase at that sideband. (paraphrased from Dodge and Jerse, 1985).
FM has traditionally been considered a computationally efficient method to create complex, time-varying spectra using just two oscillators. a very low modulation index and/or frequency will result in vibrato on the carrier signal. as the modulation increases, the spectrum will become increasingly richer. FMINST provides for a time-varying index of modulation based on gen3 and p4 and p5 of the instrument (which define the index curve, its low point, and its high point, respectively).
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1...) /* amplitude envelope of the output signal, in time/amplitude pairs */
makegen(2, 10, 1000, p0, p1...) /* spectrum of the carrier oscillator */
makegen(3, 24, 1000, t0, a0, t1, a1...) /* envelope of the modulation index, in time/amplitude pairs */
FMINST(outskip, duration, amplitude, fc, fm, indexlow, indexhi, spread)
in comment form:
/* p0 = start; p1 = dur; p2 = amplitude; p3 = pitch of carrier (hz or oct.pc);
p4 = pitch of modulator (hz or oct.pc); p5 = fm index low point;
p6 = fm index high point; p7 = stereo spread (0-1)
function slot 1 is the amp, slot 2 is oscillator waveform;
slot 3 is index guide /*
An example score:
rtsetparams(44100, 1)
load("FMINST")
makegen(1, 24, 1000, 0, 0, 3.5,1, 7,0)
makegen(2, 10, 1000, 1)
makegen(3, 24, 1000, 0,1, 7,0)
FMINST(0, 7, 20000, 8.00, 179, 0, 10)
Another score, showing different index envelopes:
rtsetparams(44100, 2
load("FMINST")
makegen(1, 24, 1000, 0, 0, 3.5,1, 7,0)
makegen(2, 10, 1000, 1)
makegen(3, 24, 1000, 0, 0, 5,1, 7, 0)
FMINST(0, 7, 10000, 8.00, 179, 0, 10, 0.1)
makegen(3, 24, 1000, 0,1, 7,0)
FMINST(3.5, 7, 10000, 8.07, 179, 0, 10, 0.9)
A third score, featuring a looping structure:
rtsetparams(22050, 1)
load("FMINST")
print_off()
makegen(1, 7, 1000, 0, 500, 1, 500, 0)
makegen(2, 10, 1000, 1)
makegen(3, 24, 1000, 0,1, 2,0)
nfms = 1
for (start = 0; start < 60; start = start + 1.5) {
freq = 8.00
for (n = 0; n < nfms; n = n + 1) {
FMINST(start, 1.5, 1000, freq, 179, 0, 10)
freq = freq + 0.02
}
nfms = nfms + 1
}
iir/IIR
IIR sets up an infinite impulse response (or recursive) filter with center frequency, bandwidth, and amplitude boost defined in triplets by the setup() command. IIR can take as its input a soundfile (INPUTSIG), white noise (NOISE), a pulse train (PULSE), or a buzzing signal (BUZZ). IIR filters are excited based on previous output samples as well as previous input samples, so that they can ring down infinitely using the equation:
   y(n)=a0x(n)-b1y(n-1)-b2y(n-2)...bNy(n-N)
where y is an output sample at time n, x is an input sample, and a0 and bN are filter coefficients that are determined by the shape of the filter desired. (blatantly stolen from Dodge and Jerse, 1985). the number of coefficients used based on past output samples is called the number of poles in the filter. IIR uses a standard 4-pole filter equation. at least, that's what we'd like you to think.
Syntax:
for all variations:
setup(f0, bw0, a0, f1, bw1, a1...) /* defines the filter in center frequency/bandwidth/relative amplitude triplets -- up to 64 peaks can be defined in a single call */
makegen(1, 24, 1000, t0, a0, t1, a1...) /* defines the envelope of the output signal in time/amplitude pairs */
for inputsig():
INPUTSIG(outskip, inskip, duration, amplitude, inchan, spread)
for noise():
NOISE(outskip, duration, amplitude, spread)
for buzz():
makegen(2, 10, 1000, 1) /* sine wave */
BUZZ(outskip, duration, amplitude, pitch, spread)
for pulse():
PULSE(outskip, duration, amplitude, pitch, spread)
in comment form:
/* iir -- creates an iir filter with up to 64 resonance peaks, specifiable
* center frequency and bandwidth for each peak
*
* subcommands:
*
* setup()
* p0 = center frequency 1 (hertz or oct.pc)
* p1 = bandwidth 1 (or multiplier of cf if negative)
* p2 = relative amplitude 1
*
*
* inputsig()
* p0 = output skip
* p1 = input skip
* p2 = duration
* p3 = amplitude multiplier
* p4 = input channel (0 or 1)
* p5 = stereo spread (0-1) [optional]
* assumes function table 1 is the amplitude envelope
*
* noise()
* p0 = start
* p1 = duration
* p2 = amplitude
* p3 = stereo spread (0-1) [optional]
* assumes function table 1 is the amplitude envelope
*
* buzzit()
* p0 = start
* p1 = duration
* p2 = amplitude
* p3 = pitch (hz or oct.pc)
* p4 = stereo spread (0-1) [optional]
* assumes function table 1 is the amplitude envelope
* assumes function table 2 is a sine wave
*
* pulseit()
* p0 = start
* p1 = duration
* p2 = amplitude
* p3 = pitch (hz or oct.pc)
* p4 = stereo spread (0-1) [optional]
* assumes function table 1 is the amplitude envelope
*
*/
An example score using inputsig():
rtsetparams(44100, 1
load("IIR")
rtinput("/sndh/bob.dole.mono.snd")
makegen(1, 24, 1000, 0, 0, 1,1, 5,1, 7,0)
setup(149.0, 25.0, 1.0, 1415.0, 100.0, 0.8)
INPUTSIG(0, 0, 7, 0.3, 0)
setup(9.0, 25.0, 1.0, 10.0, 100.0, 0.8)
INPUTSIG(8, 0, 7, 0.15, 0)
Another score, using noise():
rtsetparams(44100, 2)
load("IIR")
makegen(1, 24, 1000, 0,0, 0.1,1, 0.2,0)
start = 0
for(pc = 0; pc < 0.25; pc = pc + 0.01) {
setup(8.00 + pc, 1.0, 1.0)
NOISE(start, 0.2, 5000, random())
start = start + 0.1
}
A third score, using buzz() and pulse():
rtsetparams(44100, 2)
load("IIR")
makegen(1, 24, 1000, 0,1, 0.1,0)
makegen(2, 10, 1000, 1)
pitch = 134.0
for(start = 0; start < 7.8; start = start + 0.1) {
setup((random()*2000.0) + 300.0, -0.5, 1)
BUZZ(start, 0.1, 4000, pitch, random())
BUZZ(start, 0.1, 4000, pitch + 2.5, random())
/* pitch = pitch + 0.5 */
}
for(start = 7.8; start < 15; start = start + 0.1) {
setup((random()*2000.0) + 200.0, -0.5, 1)
PULSE(start, 0.1, 8000, pitch, random())
PULSE(start, 0.1, 8000, pitch + 2.5, random())
pitch = pitch - 0.5
}
metaflute/METAFLUTE
METAFLUTE is another physical modelling instrument (see CLAR, above), designed to simulate a flute performance. METAFLUTE has several variants: a simple flute model (SFLUTE), a model with pitch-bending (BSFLUTE), and a model with envelope-defined vibrato curves (VSFLUTE). LSFLUTE does the same thing as SFLUTE, but
without reinitializing the internal buffers, allowing you to get legato and
slurred-note effects -- just like a REAL flute!
Syntax:
for everybody:
makegen(1, 24, 1000, t0, a0, t1, a1...) /* amplitude of the noise (breath pressure) injected into the wind model in time/amplitude pairs */
makegen(2, 24, 1000, t0, a0, t1, a1...) /* amplitude of the overall output note */
for sflute():
SFLUTE(outskip, duration, noiseamp, length1, length2, amp, spread, deleteflag)
for bsflute():
makegen(3, 7, 1000, a0, g0, a1, g1...aN) /* pitch curve for length one, where aN and aN+1 are amplitudes and gN is the number of points in the curve to interpolate between them (the sum of the g values cannot exceed the number allocated in p2, in this case 1000) */
makegen(4, 7, 1000, a0, g0, a1, g1...aN) /* pitch curve for length two */
BSFLUTE(outskip, duration, noisamp, length1low, length1high, length2low, length2high, amp, spread, deleteflag)
for vsflute():
makegen(3, 10, 1000, p0, p1...) /* vibrato function for length one, defining a waveform with partial amplitudes pN */
makegen(4, 10, 1000, p0, p1...) /* vibrato function for length two, defining a waveform with partial amplitudes pN */
VSFLUTE(outskip, duration, noisamp, length1low, length1high, length2low, length2high, amp, vibrato1low, vibrato1high, vibrato2low, vibrato2high, spread, deleteflag)
for lsflute():
LSFLUTE(outskip, duration, noiseamp, length1, length2, amp, spread)
One comment about the last optional p-field for SFLUTE, BSFLUTE, and VSFLUTE (the
"deleteflag"): Generally you can safely let this default to "0". However, the METAFLUTE instrument
allocates memory for some of the delay lines it uses, and if you generate huge numbers of notes
from an interactive application you can cause a serious memory drain on the poor computer.
Setting this optional p-field to "1" will tell METAFLUTE to free this memory after every note, and
will allow you to create billions and billions of notes. A setting of "1" will
not allow you to use the LSFLUTE legato-flute following
that particular note, though... because the sound buffer memory is freed,
LSFLUTE will not have any sound to work with.
Now the scores in comment form:
/* sflute -- Perry Cook's flute physical model
*
* p0 = start
* p1 = dur
* p2 = noise amp
* p3 = length1
* p4 = length2
* p5 = amp multiplier
* p6 = stereo spread (0-1)
* function slot 1 is the noise amp envelope
* function slot 2 is the output amp envelope
*
*/
An example score for sflute():
rtsetparams(22050, 1
load("METAFLUTE")
reset(2000)
makegen(1, 24, 1000, 0,1, 1.5,1)
makegen(2, 24, 1000, 0,0, 0.05,1, 1.49,1, 1.5,0)
SFLUTE(0, 1.5, 0.1, 20, 14, 10000)
SFLUTE(1.5, 1.5, 0.1, 20, 11, 10000)
Another score, for bsflute():
rtsetparams(22050, 1)
load("METAFLUTE")
makegen(1, 7, 1000, 1, 1000, 1)
makegen(2, 7, 1000, 1, 1000, 1)
makegen(3, 7, 1000, 0, 500, 1, 500, 0)
makegen(4, 7, 1000, 0, 1000, 1)
BSFLUTE(0, 1.5, 0.1, 20,25, 14,19, 10000)
a third score, for vsflute():
rtsetparams(22050, 1)
load("METAFLUTE")
makegen(1, 7, 1000, 1, 1000, 1)
makegen(2, 7, 1000, 1, 1000, 1)
makegen(3, 10, 1000, 1)
makegen(4, 10, 1000, 1)
VSFLUTE(0, 3.5, 0.1, 30,31, 15,19, 7000, 1.0,4.0, 1.0,5.0)
VSFLUTE(4, 3.5, 0.1, 24,25, 15,21, 7000, 4.0,7.0, 3.0,5.0)
mix/MIX
MIX is the oldest and simplest of the cmix family of instruments. It takes an input file and, well, mixes it to an output file. Since you can change the input file as you go, you can use it to mix a bunch of files together. Because of its panning syntax, MIX is basically outdated, and normally you will want to
use the STEREO instrument. But, we include it here mainly for historical reasons.
(There is one minor use for MIX: to extract one channel of a file, without the other channel, using the
"-1" panning argument. See below for an example.)
The trickiest part of MIX is the way it handles p4-pN (the channel mix matrix). Thus:
The next (up to 4) arguments are the numbers of the output channel in which to place the input channel as determined by its order in the series. In other words the series, 0 1 1 0 would indicate that you are placing input channel 0 in output channel 0, input channel 1 in output channel 1, input channel 2 in output channel 1, and input channel 3 in output channel 0. If you specify an incorrect number of channels the program will barf. If you want to skip over an input channel simply put a -1 in that field. (quoted from Lansky, 1987).
Note that the panning arguments must be either 0 or 1, you cannot use decimal fractions. You can use them with the STEREO instrument.
Also note that the sample scores have no "load()" directive. MIX is the main
object ("mix" for disk-based cmix fills the parallel role), and thus does
not need to be dynamically-loaded. It is 'always there'. Always.
Syntax:
setline(t0,a0,t1,a1...) /* the amplitude envelope of the output sound in time/amplitude pairs */
MIX(outskip, inskip, duration, amplitude, where_to_put_channel_0, where_to_put_channel_1, ... channelN) /* the duration field, if negative, specifies an absolute endtime in the output soundfile */
Now the scores in comment form:
/* p0 = start_time_in_output; p1 = input_skip; p2 = duration (if negative, endtime); p3 = amp;
p4-n = channel mix matrix;
Note: Don't use makegen slot 1. It is being used by the "setline" envelope generator. */
An example score:
rtsetparams(44100, 2)
rtinput("/sndh/bob.dole.mono.snd")
setline(0,0, 1, 1)
MIX(0, 0, 7.0, 1, 0, 0)
setline(0, 1, 1, 0)
MIX(0.1, 0, 7.0, 1, 1, 1)
A second example, using a looping structure and random numbers for panning:
rtsetparams(44100, 2)
rtinput("/snd/pablo1.snd")
setline(0,0, .1, 1, 2,0)
reset(44100)
dur = 1;
for(outsk = 0; outsk < 14.0; outsk = outsk + dur)
{
insk = random() * 7.0
dur = random() * 0.2
if (random() > 0.5) ch1 = 0
else ch1 = 1
if (random() > 0.5) ch2 = 0
else ch2 = 1
MIX(outsk, insk, dur, 1, ch1, ch2)
}
A third score, using the ADC:
rtsetparams(44100, 2)
rtinput("AUDIO", "MIC", 2)
setline(0,0, 1, 1)
MIX(0, 0, 5, 1, 0, 0)
setline(0, 1, 1, 0)
MIX(0.1, 0, 5, 1, 1, 1)
A fourth score, which will extract only channel 1 from a stereo file, putting it into
a mono file:
rtsetparams(44100, 1)
/* note the 1-channel argument */
rtinput("hum_de_dum.aiff")
rtoutput("hum_de_mono.aiff")
setline(0,1, 1, 1)
MIX(0, 0, 6, 1, -1, 0)
/* "skips over" channel 0. Writes input-channel 1 into output-channel 0
(the only available one, as this is a mono output file.)
multicomb/MULTICOMB
MULTICOMB takes an input file and runs it through four comb filters. funny thing is, you can only specify the upper and lower range of the filters -- the actual frequencies are chosen randomly (insert insane laughter from Brad here). MULTICOMB works great in stereo, as the filters are spread across a two-channel output field automatically.
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1) /* the amplitude envelope of the output signal in time/amplitude pairs */
MULTICOMB(outskip, inskip, duration, amplitude, comblow, combhigh, reverb)
in comment form:
/* multicomb -- 4 simultaneous comb filters randomly chosen within
* a specified range (spread across a stereo field)
* p0 = output skip
* p1 = input skip
* p2 = output duration
* p3 = amplitude multiplier
* p4 = comb frequency range bottom
* p5 = comb frequency range top
* p6 = reverb time
* assumes function table 1 is the amplitude envelope
*
*/
An example score:
rtsetparams(44100, 2)
load("MULTICOMB")
rtinput("/sndh/bob.dole.mono.snd")
reset(20000)
makegen(1, 24, 1000, 0,0, 0.5,1, 4.0,1, 4.3,0)
MULTICOMB(0, 0, 4.3, 0.02, cpspch(6.02), cpspch(9.05), 1)
Another score:
rtsetparams(44100, 2)
load("MULTICOMB")
rtinput("/sndh/bob.dole.mono.snd")
reset(20000)
makegen(1, 24, 1000, 0,0, 0.5,1, 8.6,1, 8.7,0, 8.8,0)
MULTICOMB(0, 0, 8.8, 0.01, cpspch(7.02), cpspch(8.05), 5)
Another example, using the ADC:
rtsetparams(22050, 2, 256
load("MULTICOMB")
rtinput("AUDIO")
reset(20000)
srand(87)
makegen(1, 24, 1000, 0,0, 1,1, 3,1, 5,0)
for(start = 0; start < 30; start = start + 2.5) {
low = random() * 500.0 + 50.0
hi = low + (random() * 300.0)
MULTICOMB(start, 0, 5, 0.01, low, hi, 2.5)
}
sculpt/SCULPT
SCULPT is an instrument which does a time-based resynthesis of frequency / amplitude pairs that have been parsed into makegens. this is useful if you want to do a quick resynthesis of output from, oh, say, AudioSculpt, et vous n'avez pas de CSOUND. ou quelque chose comme ça. inspired by Stanko Juzbasic, wherever he may be.
Syntax:
makegen(1, 10, 1000, p0, p1...) /* waveform for the resynthesis, usually a sine wave */
makegen(2, 24, 1000, t0, a0, t1, a1...) /* amplitude curve for the output signal in time/amplitude pairs */
infile("filename", fileno) /* reads in a space/tab/return delimited set of numbers to use as data -- fileno is the number assigned to the file (note -- input and output soundfiles are habitually assigned to filenumbers 0 and 1, so watch out) */
makegen(-3, 2, points, fileno) /* reads the first points numbers from open data file fileno into a makegen for frequency positions */
infile("filename", fileno+1)
makegen(-4, 2, points, fileno+1) /* does the same thing for amplitude positions which correspond to the frequencies in makegen 3 */
if you're feeling masochistic, you can also fill the gen tables manually:
makegen(3, 2, points, 0) /* 0 in fileno means look on the line below */
freq0, freq1... freqN */ N must equal the number of points-1 */
makegen(4, 2, points, 0)
amp0, amp1... ampN */ same for amplitude values */
SCULPT(outskip, pointdur, amplitude, numpoints, spread) /* pointdur is the lenght of each point in the gens */
in comment form:
/* sculpt: instrument for tracking audiosculpt data placed in makegens
*
* p0 = start time
* p1 = duration of each point
* p2 = overall amplitude
* p3 = number of points
* p4 = stereo spread (0-1)
* function slot 1 is waveform, slot 2 is overall amp envelope
* function slot 3 is frequency points, slot 4 is amplitude points
*/
An example score:
rtsetparams(44100, 1)
load("SCULPT")
makegen(1, 10, 1000, 1)
makegen(2, 24, 1000, 0, 1, 1, 1)
makegen(3, 2, 10, 0)
149.0 159.0 169.0 179.0 189.0 199.0 214.0 215.0 234.0 314.0
makegen(4, 2, 10, 0)
0.0 -7.0 -10.0 -3.0 0.0 -10.0 -20.0 -15.0 -2.1 -1.1
SCULPT(0, 0.5, 10, 10)
stereo/STEREO
STEREO is pretty much like MIX (see above). It takes an input file(s) and writes it to the output. This isn't very exciting by itself, of course, but it can get quite interesting when you start working algorithmically, and are mixing numerous different input files together. As in MIX, the p-fields for stereo-panning are the stereo spread for the left channel and the right channel of the input file, respectively (i.e. if p4 is set to 0, the left channel of the input file will be panned hard left; if set to 1, it will be panned hard right, if set to 0.5, it will be panned center). In this instrument, you
can use decimal fractions in the panning argument. Thus you can send either channel to anywhere in the stereo space.
Syntax:
setline(t0,a0,t1,a1...) /* the amplitude envelope of the output sound in time/amplitude pairs */
STEREO(output_start_time, input_skip, duration, amplitude, where_to_put_input_from_channel_0, where_to_put_input_from_channel_1, ... channelN) /* the duration field, if negative, specifies an absolute endtime in the output soundfile */
in comment form:
/* p0 = start_time_in_output; p1 = input_skip; p2 = dur (normal) OR if - (negative) , endtime; p3 = amp;
p4-n = channel mix matrix
Note: Don't use makegen slot 1, as it's being used by the setline envelope generator. */
An example score:
rtsetparams(44100, 2)
load("STEREO")
rtinput("/sndh/bob.dole.mono.snd")
setline(0,0, 1, 1, 1.1, 0)
STEREO(0, 0, 3.5, 0.7, 0.5, 0.5)
setline(0,0, 0.1, 1, 1, 0)
STEREO(2, 0, 3.5, 0.7, 0.1, 0.1)
Another score, featuring a looping structure:
rtsetparams(44100, 2)
load("STEREO")
rtinput("/sndsq/pablo1.snd")
setline(0,0, .1, 1, 2,0)
reset(44100)
dur = 1;
for(outsk = 0; outsk < 10.0; outsk = outsk + dur) {
insk = random() * 7.0
dur = random() * 0.2
STEREO(insk, outsk, dur, 1, random(), -1)
}
strum/STRUM
STRUM generates plucked-string sounds based on a neat hack developed by Kevin Karplus and Alex Strong. the k-s plucked-string algorithm is a subtractive synthesis system featuring a burst of white noise, a recirculating delay line, a lowpass filter, an allpass filter, and some serious math involving things like the letter sigma which i won't talk about here. (see Roads, 1997).
The basic idea is that a burst of noise is pushed through a delay line, which splits its output, sending one half as output and the rest of it back into itself after going through a lowpass and allpass filter setup. The result is a burst of rich sound that gradually loses its higher harmonics as it decays (as does, funnily enough, a plucked string). A number of simple additions to the instrument design have fine tuned the algorithm so that you can get some pretty realistic (or decidedly weird) effects along the lines of amp-driven guitars or tremelo-picked mandolins.
STRUM, like METAFLUTE, has a few sub-instruments inside of it. The basic instrument, START(), is your generic dry plucked string synthesis. When placed after START() commands, BEND() adds string bending, and FRET() emulates, er, two-hand tapping (?). START1() and its friends, BEND1(), FRET1(), add amplifier distortion, and VSTART1() and VFRET1(), in turn, add vibrato to that.
Syntax:
The syntax for strum is a bit of a mess, but here goes:
regular plucked strings (sounding most like mandolin or guitar:
START(outskip, duration, pitch, funddecay, nyquistdecay, amplitude, squish, stereo-pan, deleteflag)
A couple of notes on some of these:
- Specifying duration: This involves 3 of the parameters: duration, nyquistdecay, and funddecay (fundamental decay.) These can be explained most simply by thinking about a plucked string's behavior. After you pluck it, the sound decays. The higher partials decay, first, and on downward, until, finally, the fundamental frequency decays to 0. You can specify exactly how this happens with the nyquist-decay and fundamental-decay parameters. These are specified in seconds. (Remember that nyquist is the highest possible frequency for a given sampling rate, in our case 22050 Hz.) Thus nyquist-decay controls the decay rate of the highest, fastest-decaying partials of the sound. Fundamental-decay, then, controls the decay rate of the lowest, slowest-decaying partial. Now, here's the tricky part: if you want a given pluck to ring out for its full decay-time, you just make sure that funddecay and duration are equal. Consider that to be a default setting. If you want to "cut-short" the decay-time of a pluck, then you can make duration shorter than the funddecay. Things get even more complicated with BEND and FRET, but I'll [try to] explain below.
- squish: This parameter tells how "squishy" is the item being used to pluck the string. Values generally range from .000001 to 10, though any can be tried, you never know what might happen. Generally, the lower the value, the harder the plucking object. The higher, the more "fleshy."
- deleteflag: the last optional p-field for START, (and START1, and VSTART1):
Generally you can safely let this default to "0", or leave it out. However,
the STRUM instrument allocates memory for some of the delay lines it uses,
and if you generate huge numbers of notes from an interactive application
you can cause a serious memory drain on the poor computer. Setting this
optional p-field to "1" will tell STRUM to free this memory after every
note, and will allow you to create billions and billions of notes. A
setting of "1" will disable any future FRETs or BENDs on that particular
note, though... because the memory is freed, FRET or BEND will not have
any sound to work with.
BEND(start, duration, pitch0, pitch1, glissfunc, funddecay, nyquistdecay, updatefreq, stereo_position) /* important note -- will only work after a START() command */
Now for the parameters with "issues" in BEND:
- pitch0, pitch1, glissfunc: Glissfunc is the slot number of a makegen that you create. That makegen should be a curve describing the way you want the bending to occur. The curve is, of course, made of time-value pairs. A "value" of 0 in the curve corresponds to pitch0 in the BEND comman. A "value" of 1 corresponds to pitch1. Thus, assuming you have specified the following makegen:
makegen(8, 24, 10000, 0,0, 1,1, 2,.2, 3,.8, 4,.5, 7,.5, 9,1, 13, 1)
The instrument will interpret this as: "Begin at pitch0, go to pitch1, go almost to pitch0, go almost to pitch1, go right in between them, hang out there for a while, then go to pitch1 and hang out there 'till the end." (Note that since this makegen is in slot 8, you would assign a value of 8 to the glissfunc parameter.)
Which pitch is higher makes no difference. It only matters which comes first and second in your BEND command. A curve going from 0 to 1 thus could go up, or it could go down, depending on pitch0 and pitch1. This means that normally, if your gliss-curve starts at 0, then pitch0 should be the same as the last pitch specified (either in a preceding START command, or the last pitch reached in a BEND command (You can string BENDs together to get a kind of sitar-like articulation.)) If it's not, the sudden jump is going to cause a lot of noise (which you may find useful sometimes.)
- Duration issues, again: Remember that a BEND must come after a START. Therefore, the "duration" at issue here is the duration of the original START note. Any BEND stuff must happen within the specified duration of the original START. Normally, the following table can give you the appropriate values for the durational parameters for a given BEND command, in relation to its "parent" START command:
- BENDstart= somewhere within the duration of the original START.
- BENDdur= STARTdur - (BENDstart - STARTstart)
- BENDfunddecay= BENDdur
- BENDnyqdecay= STARTnyqdecay - (BENDstart - STARTstart)
If you want to have a string of BENDS, well . . . . you get the idea. Remember, it's a physical model of a plucked string that decays, so, figure it out logically from that perspective.
- updatefreq: This is a parameter telling how often to "update" the frequency of the string as it's glissing. Generally values like 2000 seem to work pretty well (if it's too small, you get clicking and other nastiness.)
FRET(start, duration, pitch, funddecay, nyquistdecay, spread) /* the pitch field is the pitch that alternates with the one specified in the preceding START() command */
Similar duration constraints to those listed above apply to this as well. It's a bit simpler, though, as there are no gliss-curves to deal with.
guitars with feedback:
START1(outskip, duration, pitch, funddecay, nyquistdecay, distortiongain, feedbackgain, feedbackpitch, cleanlevel, distortionlevel, amplitude, squish, spread, deleteflag)
BEND1(start, duration, pitch0, pitch1, glissfunc, funddecay, nyquistdecay, distortiongain, feedbackgain, feedbackpitch, cleanlevel, distortionlevel, amplitude, updatefreq, spread)
FRET1(start, duration, pitch, funddecay, nyquistdecay, distortiongain, feedbackgain, feedbackpitch, cleanlevel, distortionlevel, amplitude, spread)
guitars with vibrato and feedback:
for VSTART1 and VFRET1 only:
makegen(1, 10, 1000, p0, p1...) /* waveform for the vibrato */
makegen(2, 24, 1000, t0, a0, t1, a1...) /* envelope for the vibrato, in time/amplitude pairs */
VSTART1(outskip, duration, pitch, funddecay, nyquistdecay, distortiongain, feedbackgain, feedbackpitch, cleanlevel, distortionlevel, amplitude, squish, lowvibratorange, hivibratorange, vibratodepth, randomseed, updatefreq, spread, deleteflag)
VFRET1(outskip, duration, pitch, funddecay, nyquistdecay, distortiongain, feedbackgain, feedbackpitch, cleanlevel, distortionlevel, amplitude, lowvibratorange, hivibratorange, vibratodepth, randomseed, updatefreq, spread)
in comment form:
/* START:
p0 = start; p1 = dur; p2 = pitch (oct.pc); p3 = fundamental decay time
p4 = nyquist decay time; p5 = amp, p6 = squish; p7 = stereo spread [optional]
p8 = flag for deleting pluck arrays (used by FRET, BEND, etc.) [optional]
BEND:
p0 = start; p1 = dur; p2 = pitch0 (oct.pc); p3 = pitch1 (oct.pc);
p4 = gliss function; p5 = fundamental decay time; p6 = nyquist decay time;
p7 = update times/sec; p8 = stereo spread [optional]
FRET:
p0 = start; p1 = dur; p2 = pitch(oct.pc); p3 = fundamental decay time;
p4 = nyquist decay time; p5 = stereo spread [optional]
START1:
p0 = start; p1 = dur; p2 = pitch (oct.pc); p3 = fundamental decay time
p4 = nyquist decay time; p5 = distortion gain; p6 = feedback gain
p7 = feedback pitch (oct.pc); p8 = clean signal level
p9 = distortion signal level; p10 = amp; p11 = squish
p12 = stereo spread [optional]
p13 = flag for deleting pluck arrays (used by FRET1, BEND1, etc.) [optional]
BEND1:
p0 = start; p1 = dur; p2 = pitch0 (oct.pc); p3 = pitch1 (oct.pc)
p4 = gliss function #; p5 = fundamental decay time
p6 = nyquist decay time; p7 = distortion gain; p8 = feedback gain
p9 = feedback pitch (oct.pc); p10 = clean signal level
p11 = distortion signal level; p12 = amp; p13 = update gliss nsamples
p14 = stereo spread [optional]
FRET1:
p0 = start; p1 = dur; p2 = pitch (oct.pc); p3 = fundamental decay time
p4 = nyquist decay time; p5 = distortion gain; p6 = feedback gain
p7 = feedback pitch (oct.pc); p8 = clean signal level
p9 = distortion signal level; p10 = amp; p11 = stereo spread [optional]
VSTART1:
p0 = start; p1 = dur; p2 = pitch (oct.pc); p3 = fundamental decay time
p4 = nyquist decay time; p5 = distortion gain; p6 = feedback gain
p7 = feedback pitch (oct.pc); p8 = clean signal level
p9 = distortion signal level; p10 = amp; p11 = squish
p12 = low vibrato freq range; p13 = hi vibrato freq range
p14 = vibrato freq depth (expressed in cps); p15 = random seed value
p16 = pitch update (default 200/sec)
p17 = stereo spread [optional]
p18 = flag for deleting pluck arrays (used by FRET1, BEND1, etc.) [optional]
assumes makegen 1 is the vibrato function and makegen 2 is the
vibrato amplitude envelope
VFRET1:
p0 = start; p1 = dur; p2 = pitch (oct.pc); p3 = fundamental decay time
p4 = nyquist decay time; p5 = distortion gain; p6 = feedback gain
p7 = feedback pitch (oct.pc); p8 = clean signal level
p9 = distortion signal level; p10 = amp;
p11 = low vibrato freq range; p12 = hi vibrato freq range
p13 = vibrato freq depth (expressed in cps); p14 = random seed value
p15 = pitch update (default 200/sec)
p16 = stereo spread [optional]
assumes makegen 1 is the vibrato function and makegen 2 is the
vibrato amplitude envelope
*/
An example score:
rtsetparams(44100, 2)
load("STRUM")
makegen(1, 2, 7, 0)
7.00 7.02 7.05 7.07 7.10 8.00 8.07
srand(0.314)
for (st = 0; st < 15; st = st + 0.1) {
pind = random() * 7
pitch = sampfunc(1, pind)
START(st, 1.0, pitch, 1.0, 0.1, 10000.0, 1, random())
}
Another score:
rtsetparams(44100, 2)
load("STRUM")
makegen(1, 2, 7, 0)
7.00 7.02 7.05 7.07 7.10 8.00 8.07
srand(0.314)
for (st = 0; st < 15; st = st + 0.2) {
pind = random() * 7
pitch = sampfunc(1, pind)
stereo = random()
START(st, 0.05, pitch, 1.0, 0.1, 10000, 1, stereo)
FRET(st+0.05, 0.05, pitch+0.07, 1.0, 0.1, stereo)
FRET(st+0.1, 0.05, pitch+0.04, 1.0, 0.1, stereo)
FRET(st+0.15, 0.05, pitch+0.02, 1.0, 0.1, stereo)
}
A third score:
rtsetparams(44100, 1)
load("STRUM")
START1(0, 4, 6.08, 1, 1, 10, 0.05, 7.00, 0, 1, 10000, 2)
makegen(1, 24, 1000, 0, 0, 1, 1, 2, 0)
BEND1(4, 4, 6.08, 7.00, 1, 1, 1, 10, 0.05, 7.00, 0, 1, 10000, 100)
trans/TRANS
trans is a simple non-windowed soundfile transposer which simply resamples the soundfile to play it higher or lower.
Syntax:
TRANS(outskip, inskip, duration, transposition_interval, amplitude) /* where p3 is in relative 8ve.pc notation */
in comment form:
/* TRANS - transpose a mono input signal using cubic spline interpolation
p0 = output start time
p1 = input start time
p2 = output duration (time to end if negative)
p3 = amplitude multiplier
p4 = interval of transposition, in octave.pc
p5 = input channel [optional, default is 0]
p6 = percent to left [optional, default is .5]
Processes only one channel at a time.
Assumes function table 1 is amplitude curve for the note.
You can call setline for this.
*/
An example score:
rtsetparams(44100, 2)
load("TRANS")
rtinput("/sndh/bob.dole.mono.snd")
rtoutput("/sndh/bob.dole.trans.snd")
TRANS(0, 0.2, 3.5, 1, .07,)
TRANS(4.0, 0.5, 3.5, 1, -.07)
wavetable/WAVETABLE
WAVETABLE is an additive synthesis instrument. This means that it basically computes a bunch of sine waves and adds them up. While this means that your wavetabled sounds will have neither the harmonic richness of FMINST() or the time-varying spectra of STRUM(), well, er...
ahem. WAVETABLE. learn it. love it. worship it. it could save your life some day.
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1...) /* time-amplitude pairs defining the envelope of the resultant sound */
makegen(2, 10, 1000, p0, p1...) /* defines the spectrum of the synthesized note, where p0 is the fundamental, followed by successive overtones */
WAVETABLE(outskip, duration, amplitude, frequency, spread)
in comment form:
/* wavetable: a simple instrument
*
* p0=start_time
* p1=duration
* p2=amplitude
* p3=frequency or oct.pc
* p4=stereo spread (0-1)
* function slot 1 is amp envelope, slot 2 is waveform
*/
An example score:
rtsetparams(44100, 1)
load("WAVETABLE")
makegen(1, 7, 1000, 0, 50, 1, 900, 1, 50, 0)
makegen(2, 10, 1000, 1, 0.3, 0.2)
start = 0.0
freq = 149.0
for (i = 0; i < 40; i = i+1) {
WAVETABLE(start, 40-start, 500, freq)
start = start + 1.0
freq = freq + 25
}
Another score:
rtsetparams(44100,2)
load("WAVETABLE")
/* uncomment the following line to get rid of all the screen output */
/* print_off() */
makegen(1, 24, 1000, 0,0, 0.01,1, 0.1,0.2, 0.4, 0)
makegen(2, 10, 1000, 1, 0.3, 0.2)
reset(20000)
start = 0.0
freq = 149.0
for (i = 0; i < 100; i = i+1) {
WAVETABLE(start, 0.4, 5000, freq, 0)
WAVETABLE(start+random()*0.07, 0.4, 5000, freq+random()*2, 1)
start = start + 0.1
makegen(1, 10, 1000, 1, random(), random(), random(), random(), random()
, random())
}
A third score:
rtsetparams(22050, 2)
load("WAVETABLE")
print_off()
makegen(1, 24, 1000, 0, 1, 950, 0)
makegen(2, 10, 1000, 1, 0.3, 0.2)
srand(0.35)
for (start = 0; start < 7; start = start + 0.14) {
freq = random() * 200 + 35
for (i = 0; i < 3; i = i+1) {
WAVETABLE(start, 0.4, 1500, freq, 0)
WAVETABLE(start+random()*0.1, 0.4, 1500, freq+(random()*7), 1)
if (start > 3.5) {
makegen(1, 10, 1000, 1, random(), random(),random(),rand
om(),random(),random(),random(),random(),random(),random(),random())
}
freq = freq + 125
}
}
waveshape/WAVESHAPE
waveshaping: a type of distortion synthesis wherein an input waveform is modified by a transfer function to produce an output signal. thus, an input signal, x, puts out an output signal, y, by passing through a function defined as y = f(x). so:
f(x) = x2 will exponentially expand the amplitude of the incoming waveform. (Dodge and Jerse, 1985).
other useful transfer functions to use are waveforms and Chebyshev polynomial equations, which can output pre-defined harmonic spectra.
WAVESHAPE(), the command in WAVESHAPE, uses a makegen to define its transfer function. the makegen essentially draws a graph with input samples coming in on the x axis and output samples going out the y axis.
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1...) /* the amplitude of the output in time/amplitude pairs */
makegen(2, 10, 1000, p0, p1...) /* the incoming waveform defined by the relative amplitude of its partials */
makegen(3, 7, 1000, a0, g0, a1, g1...aN) /* transfer function for the waveshaper, where aN and aN+1 are amplitudes and gN is the number of points in the curve to interpolate between them (the sum of the g values cannot exceed the number allocated in p2, in this case 1000) */
makegen(4, 24, 1000, t0, a0, t1, a1...) /* the index envelope of the waveshaper, allowing the waveshaping to increase and decrease over time */
WAVESHAPE(outskip, duration, pitch, indexlow, indexhigh, amplitude, spread)
in comment form:
/* waveshaping instrument
* p0 = start
* p1 = duration
* p2 = pitch (hz or oct.pc)
* p3 = index low point
* p4 = index high point
* p5 = amp
* p6 = stereo spread (0-1)
* function slot 1 is amp envelope
* slot 2 is waveform to be shaped (generally sine)
* slot 3 is the transfer function
* slot 4 is the index envelope
*/
An example score:
rtsetparams(44100, 1)
load("WAVESHAPE")
makegen(1, 24, 1000, 0,0, 3.5,1, 7,0)
makegen(2, 10, 1000, 1)
makegen(3, 7, 1000, -0.7, 200, -0.5, 300, 0, 300, 0.5, 200, 0.7)
makegen(4, 24, 1000, 0,0, 3.5,1, 7,0)
WAVESHAPE(0, 7, 7.02, 0, 1, 10000)
WAVESHAPE(0, 7, 7.021, 0, 1, 10000)
Another score. note that makegen 3 uses gen number 17, which creates a Chebyshev polynomial for defining harmonics:
rtsetparams(44100, 2)
load("WAVESHAPE")
makegen(1, 24, 1000, 0,0, 3.5,1, 7,0)
makegen(2, 10, 1000, 1)
makegen(3, 17, 1000, 0.9, 0.3, -0.2, 0.6, -0.7)
makegen(4, 24, 1000, 0,0, 3.5,1, 7,0)
WAVESHAPE(0, 7, 7.02, 0, 1, 9000, 0.99)
makegen(2, 24, 1000, 0,0, 1.5,1, 7,0)
makegen(4, 24, 1000, 0,1, 7,0)
WAVESHAPE(4, 7, 6.091, 0, 1, 10000, 0.01)
del1/DEL1
DEL1 is a simple, non-regenerating delay instrument which takes an input soundfile and mixes it with a delayed copy of itself with an optional difference in amplitude. sounds are placed in a stereo field.
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1) /* amplitude envelope in time/amplitude pairs */
DEL1(outskip, inskip, duration, amplitude, delaytime, delayamp, inchan)
in comment form:
/* del1: single delay instrument
* into stereo output
*
* p0 = output start time
* p1 = input start time
* p2 = duration
* p3 = amplitude multiplier
* p4 = delay time
* p5 = delay amplitude multiplier
* p6 = input channel number
* assumes function slot 1 is the amplitude envelope
*/
An example score:
rtsetparams(44100, 2)
load("DEL1")
rtinput("/sndh/bob.dole.mono.snd")
makegen(1, 24, 1000, 0,0, 0.5,1, 3.5,1, 7,0)
DEL1(0, 0, 7, 1, .14)
makegen(1, 24, 1000, 0,0, 0.1,1, 1.5,0.21, 3.5,1, 7,0)
Another score, taking input from the ADC:
rtsetparams(44100, 2, 512)
load("DEL1")
rtinput("AUDIO", "MIC")
makegen(1, 24, 1000, 0,0, 1,1, 16,1, 17,0)
DEL1(0, 0, 17, 1, 4.3, 1)
delay/DELAY
DELAY is a simple, regenerating delay instrument. it has parameters for regeneration (amount of feedback) and for ring-down time, so that the delay decays naturally.
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1) /* amplitude envelope in time/amplitude pairs */
DELAY(outskip, inskip, duration, amplitude, delaytime, regeneration, ringdown, inchan, spread) /* regeneration should be less than 1 */
in comment form:
/* delay: regenerating delay instrument
*
* p0 = output start time
* p1 = input start time
* p2 = input duration
* p3 = amplitude multiplier
* p4 = delay time
* p5 = regeneration multiplier (< 1!)
* p6 = ring-down duration
* p7 = input channel number
* p8 = stereo spread (0-1)
* assumes function slot 1 is the amplitude envelope
*/
An example score:
rtsetparams(44100, 1)
load("DELAY")
rtinput("/sndgr/bob.dole.mono")
makegen(1, 24, 1000, 0,0, 0.5,1, 3.5,1, 7,0)
DELAY(0, 0, 7, 0.7, .14, 0.7, 3.5)
makegen(1, 24, 1000, 0,0, 0.1,1, 1.5,0.21, 3.5,1, 7,0)
DELAY(3.5, 0, 7, 1, 1.4, 0.3, 5)
Another score, taking input from the ADC:
rtsetparams(44100, 2, 512)
load("DELAY")
rtinput("AUDIO", "MIC")
makegen(1, 24, 1000, 0,1, 100,1)
DELAY(0, 0, 14, 1.0, .078, 0.8, 3.5, 0, 0.1)
DELAY(7, 0, 10, 1, .415, 0.5, 3, 0, 0.9)
A third score:
rtsetparams(44100, 2)
load("DELAY")
rtinput("/snd/pablo1.snd")
makegen(1, 24, 1000, 0,0, 0.5,1, 3.5,1, 7,0)
DELAY(0, 0, 7, 0.5, .14, 0.7, 3.5, 0, 0.1)
makegen(1, 24, 1000, 0,0, 0.1,1, 1.5,0.21, 3.5,1, 7,0)
DELAY(3.5, 0, 7, 1, 1.4, 0.3, 5, 1, 0.9)
panecho/PANECHO
PANECHO is a more complex stereo delay instrument than DELAY. PANECHO takes an input signal and "ping-pongs" the delays between the left and right channels.
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1) /* amplitude envelope in time/amplitude pairs */
PANECHO(outskip, inskip, duration, amplitude, delaytime, delayamp, regeneration, ringdown, inchan) /* regeneration should be less than 1 */
in comment form:
/* panecho: stereo panning delay instrument
*
* p0 = output start time
* p1 = input start time
* p2 = duration
* p3 = amplitude multiplier
* p4 = channel 0 delay time
* p5 = channel 1 delay time
* p6 = regeneration multiplier (< 1!)
* p7 = ring-down duration
* p8 = input channel number
* assumes function slot 1 is the amplitude envelope
*/
An example score:
rtsetparams(44100, 2)
load("PANECHO")
rtinput("/sndgr/bob.dole.mono")
makegen(1, 24, 1000, 0,0, 0.5,1, 3.5,1, 7,0)
PANECHO(0, 0, 7, 1, .14, 0.069, .7, 3.5)
makegen(1, 24, 1000, 0,0, 0.1,1, 1.5,0.21, 3.5,1, 7,0)
PANECHO(4.9, 0, 7, 1, 3.14, 0.5, 0.35, 9.5)
Another score, taking input from the ADC:
rtsetparams(44100, 2)
load("PANECHO")
rtinput("AUDIO", "MIC")
makegen(1, 24, 1000, 0,1, 100, 1)
PANECHO(0, 0, 14, 1.0, 5.14, 1.14, .7, 9.5)
PANECHO(10, 0, 7, 1.0, 1.14, 0.14, .7, 3.5)
A third score, featuring a looping structure:
rtsetparams(22050, 2)
load("PANECHO")
rtinput("/sndh/bob.dole.mono.snd")
makegen(1, 24, 1000, 0,0, 0.5,1, 3.5,1, 7,0)
PANECHO(0, 0, 7, 0.8, .14, 0.14, .7, 3.5)
makegen(1, 24, 1000, 0,0, 1.5,1, 3.5,1, 7,0)
PANECHO(4.9, 0, 7, 0.8, .514, 0.05, 0.95, 3.4, 0)
convolve
convolution: the process of multiplying two FFT's (one derived from a source sound and another derived from a sound used as an impulse response). the result is a blend of the two sounds, and is an algorithm used frequently in cross-synthesis and reverb simulation. the convolve instrument takes two soundfiles as input, performs an FFT on them both, and then uses a fast convolution algorithm to multiply the two FFT's, using a weighted moving average. the impulse response FFT is flipped back-to-front, with each frame of its FFT multiplying a corresponding frame of the source FFT. the result is then integrated, resulting in the frequency specta of the two signals being multiplied.
true convolution requires a serious amount of processing power, and convolve will run fairly slowly if you use large files. if you use a small impulse response, this will save time.
Syntax:
input("source_soundfile")
input("impulse_response_soundfile", 2) /* note that you open two soundfiles */
output("output_soundfile")
setwindow(0, d, t0, a0, t1, a1...) /* defines the FFT window for the source soundfile - d is the size of the window in seconds, and tN and aN are time/amplitude pairs defining the window envelope */
setwindow(1, d, t0, a0, t1, a1...) /* defines the FFT window for the impulse response file */
convolve(outskip, source_duration, source_inskip, impulse_number, impulse_duration, impulse_inskip, gain, i, dry, spread) /* impulse_number is the file number of the impulse response file (usually set to two, depending on your input() call, i is an invert flag, where the two soundfiles are switched, and dry is a number between 0 and 1 setting the amount of original source signal to be present in the output */
in comment form:
/* source window (2nd arg is duration)
setwindow(0, dur, time1, amp1, time2, amp2...)
impulse window (2nd arg is duration)
setwindow(1, dur, time1, amp1, time2, amp2...) */
/* convolve
*
* p0 = output skip
* p1 = source input skip
* p2 = output duration
* p3 = impulse file number (p1 on the input() command)
* p4 = impulse window number (p0 on the setwindow() command)
* p5 = impulse input skip
* p6 = amplitude multiplier
* p7 = invert flag (0 or 1, swaps the imp + src, I think)
* -- usually "0"
* p8 = "dry" (usually 0)
* p9 = outpan (0-1)
*
*/
An example score:
load("convolve")
input("/sndh/bob.dole.mono.snd")
output("/sndh/moderate.snd")
input("/sndh/clinton.blabs.snd", 2)
setwindow(0, 0.2, 0,0, 20,1, 80,1, 100,0)
setwindow(1, 0.2, 0,0, 20,1, 80,1, 100,0)
outsk = 0.0
srcinsk = 0.0
impinsk = 0.0
for(i = 0; i < 30; i = i + 1) { /* 0.1 skips means 3 seconds done */
convolve(outsk, srcinsk, 0.1, 2, 1, impinsk, 1, 0, 0, 0.5)
outsk = outsk + 0.1
srcinsk = srcinsk + 0.1
impinsk = impinsk + 0.1
}
Another score, using an FFT window the size of the entire file (will take a long time to compute):
load("convolve")
input("/sndh/luke/source.snd")
input("/sndh/luke/impulse.snd",2)
output("/sndh/luke/convolve.snd")
/* impulse response que */
outskip = 0
src_dur = dur[0] /* set the FFT size to the entire file */
src_inskip = 0
imp_num = 2
imp_dur = dur[2] /* set the FFT size to the entire file - must be smaller than the source */
imp_inskip = 0
gain = .5
i = 0
dry = 0
outpan = .5
/* optional window functions (0) src, (1) impulse.
args = [1] function # , [2] dur, setline args */
setwindow(0,src_dur,0,0,20,1,95,1,100,0)
setwindow(1,imp_dur,0,0,20,1,95,1,100,0)
convolve(outskip,src_inskip,src_dur,imp_num,imp_dur,imp_inskip,gain,i,dry,outpan)
flange
flanging is a dsp procedure whereby a sound is delayed according to an lfo, producing a whooshing effect.
Syntax:
makegen(1,10,512,1) /* lfo cycle for the flanger */
flange(outskip, inskip, duration, amp, frequency, regeneration, delay, inchan, spread) /* regeneration must be less than 1, delay is in seconds */
in comment form:
/* flange -- a stereo flanger instrument
*
* p0 = output skip
* p1 = input skip
* p2 = input duration
* p3 = amplitude multiplier
* p4 = flange frequency (hertz)
* p5 = flange regeneration (<1)
* p6 = flange delay (seconds)
* p7 = input channel [optional]
* p8 = stereo spread (0-1) [optional]
* assumes function table 1 is the flange cycle
* output file must be stereo (for now)
*
*/
An example score:
load("flange")
input("/sndh/bob.dole.mono.snd")
output("/sndh/bob.dole.flanged.snd")
setline(0,0, 1,1, 4,1, 5,0)
makegen(1,10,512,1)
flange(0, 0, 5, 1, .5, .7, .05, 0, 0)
flange(1, 0, 5, 1, .9, .7, .05, 1, 1)
gravy
gravy takes a soundfile, cuts it into frames, and then transposes and/or stretches those frames. the result is a sort of false 'vocoding', whereby a sound can be stretched and transposed independently of its original duration and pitch.
Syntax:
makegen(1, 7, 512, 0, 512, 1) /* function one describes the 'bevel' function of the windows (how the frames are shaped) */
gravy(outskip, inskip, duration, windowsize, amp, lengthmult, transp, inchan, spread) /* window size is in seconds, transposition is in 8ve.pc */
in comment form:
/* gravy -- a time and pitch-shifting instrument
* (modified 11/89 by D.S. to use parabolic interpolation)
*
* p0 = output skip
* p1 = input skip
* p2 = duration (on input)
* p3 = window size (in seconds)
* p4 = amplitude multiplier
* p5 = length multiplier (of original)
* p6 = transposition interval (oct.pc)
* p7 = input channel [optional]
* p8 = stereo spread (0-1) [optional]
* assumes function table 1 contains the window envelope
*
*/
An example score:
load("gravy")
input("/sndh/bob.dole.mono.snd")
output("/sndh/bob.dole.gravy.snd")
makegen(1, 25, 1000, 1)
gravy(0, 0, 2.5, 0.1, 0.2, 3.0, 0.00, 0, 0.5)
gravy(0, 0, 2.5, 0.1, 0.2, 3.0, 0.02, 0, .9)
gravy(0, 0, 2.5, 0.1, 0.2, 3.0, -0.03, 0, 0.01)
Another score, taking input from the ADC:
load("gravy")
input("/sndh/bob.dole.mono.snd")
output("/sndh/bob.dole.gravy.snd")
makegen(1, 25, 1000, 1)
gravy(1, 0, 7.0, 0.1, 0.2, 0.7, -0.04, 1, 0.5)
gravy(1, 0, 7.0, 0.1, 0.2, 0.7, -0.09, 0, .4)
gravy(1, 0, 7.0, 0.1, 0.2, 0.7, -0.03, 0, 0.61)
lpc
lpc (linear predictive coding) is a compression algorithm used for resynthesizing sounds based on datasets derived from a statistical analysis of the amplitude curve and fundamental frequency of a soundfile. the datasets are then used as filter response curves which can be used to predict the samples in-between the key frames of data in the analysis.
the cmix lpc package includes a number of routines: lpc creates a dataset from a soundfile using the linear prediction algorithm. stabilize removes any obvious irregularities from the dataset. ptrack performs a rudimentary tracking of the fundamental frequency of the soundfile. merge combines the ptrack and lpc datasets into one. lpcplot and pchplot are interactive terminal-based programs to view and modify any mistakes (and there are often quite a few) in the datasets. finally, lpcplay, which is the only real cmix instrument in the group, takes the datasets and resynthesizes sounds based on them.
lpc has several advantages over a larger fft-based analysis/resynthesis of a soundfile, though it also has many limitations. lpc resynthesizes sounds using a serious amount of interpolation based on prediction, so the datasets it uses are comparatively small (hence its use in audio compression technologies like sony's minidisc). in addition, cmix lpc creates lpc and pitch-tracking datasets independently, so that you can do some interesting cross-synthesis by merging datasets created from different sounds. the downside is that lpc is a very lossy compression method, so a lot of nuance is lost and a lot of errors created when analysing a sound, and the resynthesis (unless heavily tweaked) always has artifacts.
NOTE: At present, the lpc instruments do not exist as DSOs, therefore they
must be called by their actual name (lpcplay < lpc.sco) and do not make use of the "load()" directive in the scorefile.
Syntax:
to create an lpc dataset (.lpc file):
lpc -o lpc_anal_file -p #poles -f framesize [-i inskip] [-d duration] soundfile
to stabilize a dataset:
stabilize lpc_anal_file #poles
to do a pitch track (.pch file):
ptrack -rsampling_rate -fframe_size -iinterframe_offset -hhigh_pitch_estimate -llow_pitch_estimate -sinksip -dduration -opch_anal_file soundfile
(you can also try ptrack -q to run this interactively)
to merge the datasets:
merge -a lpc_anal_file -n #poles -p pch_anal_file -l lpc_starting_frame -s pch_starting_frame -e pch_end_frame
(-q runs this interactively as well)
to resynthesize the sounds:
output("output.snd")
dataset("lpcdataset.lpc", #poles)
lpcstuff(threshhold, random_amplitude_factor, unvoiced_rate(optional), rise(optional), decay(optional))
lpcplay(outskip, duration, pitch, starting_frame, end_frame, amplitude, warp, resonator_centerfreq, resonator_bandwidth, [frame1, pitch1, frame2, pitch2...]) /* the resonator values are optional */
in comment form:
/* lpcplay -- lpc resynthesis instrument
*
* p0 = output skip
* p1 = duration
* p2 = pitch
* p3 = frame1
* p4 = frame2
* p5 = amp
* p6 = warp
* p7 = resonbw
* p8=resoncf
* p9--> pitchcurves
*
*/
An example score:
output("test.snd")
float frames;
frames = dataset("test.lpc", 24)
lpcstuff(.001, .003, 0)
lpcplay(0, 6, 0, 1, frames, 1, 0, 0, 0)
move
move is doug scott's moving sound simulation instrument, which simulates the acoustic space of a room and let's the user define the trajectory of a soundfile moving through space within the room, relative to the listener's position. the instrument has optional parameters for microphone placement and the computation of inter-aural delays. room simulation in cmix is still a fairly computation-intensive procedure, so smaller files and simpler trajectories will work much better. the input file in move must
be mono, and the output file must be stereo.
Syntax:
(taken from doug scott's documentation)
to define an acoustic space:
space (dist_to_front, dist_to_right, -dist_to_back, -dist_to_left, height, abs_fact, rvbtime)
space is the setup call for the room in which the sound will appear. Since the listener (YOU) is at point (0,0) coordinate-wise, the locations of the 4 walls are specified like in an x,y coordinate system:
y
|
-x---0---x
|
-y
Therefore the distance to the back and left walls must be specified as negative. All, including height, are in feet. Abs_fac is a number between 0 (min) and 10 (max) that determines how reflective the walls are. Rvbtime is the approximate length of reve
rb in seconds (max depends on roomsize).
to setup microphones:
mikes(mike_angle, pattern_factor) /* optionally this... */
mikes_off() /* or this */
mikes is an optional setup call for times when you wish to simulate microphone recording (most of the time, actually). The arguments are mike_angle, which is the angle *each* microphone makes with a line drawn between them (i.e., 45 puts them at a 90 degree angle FROM EACH OTHER). pattern_factor is a value between 0 and one; 0 produces an omnidirectional mike, 1 produces a hypocardioid pattern, 0.5 produced the familiar cardioid pattern. If this call is left out, the pattern will be omnidirectional.
mikes_off() is used following a previous call to mikes(), in order to cancel mike mode in the event that you wish to use binaural mode (see below), or default to omnidirectional.
to define a trajectory for a soundfile:
path(time0,distance0,angle0, time1,distance1,angle1, ..., timeN,distN,angleN)
or:
cpath(time0,xcoord0,ycoord0, time1,xcoord1,ycoord1, ..., timeN,xcoordN,ycoordN)
or even something like this:
makegen(-1, 9, 1024, 1, 30, 0) /* x dimension = 1 +- 30 ft sine */
makegen(-2, 9, 1024, 1, 20, 30) /* y dimension = 1 +- 20 ft sine 30 deg. */
cparam(1, 2) /* combined, these produce a 20 x 30 foot elliptical path */
Path allows you to specify the trajectory of the sound source as triplets
representing relative time (as in setline), distance (in feet), and angle (in
degrees).
0.0 source
| /
| /
| /
| /
|/
you
Be sure to stay inside bounds of the room (it may take a bit of trigonometry
[or guessing] to do that).
If you prefer cartesian coordinates, use cpath instead, entering triplets of
time, x coordinate (left-right), y coordinate (front-back).
source
|
|
|
|
| (y dist.)
|
(x dist.) |
you-------------
Cparam allows you to parametrically specify the changes in x and y location as a function of time. For example, to have your sound move in a 50 foot circle, once over the course of the sound, create two gen functions as shown in the example, one with 0 degrees phase (sine) and one with 90 degrees phase (cosine). If the harmonic number is set to numbers above 1, the sound will cycle back and forth in that dimension (x or y) a number of times equal to the harmonic number. The amplitude of the functions represents the displacement (plus and minus) in feet on either side of the center line. Be sure to use the negative slot numbers to avoid rescaling the values (see manpage for makegen).
to control update times:
threshold(reset_distance)
Threshold allows you to determine how often the program updates the location
of the source. A typical value is 0.01 (feet). Smaller values give somewhat
smoother results at the cost of run time (which can go as high as 600 to 1!!).
and finally:
move (outskip, inskip, dur, amp, dist_between_mikes, rvb_amp)
Move has its first 3 args the same as mix, etc.
amp: amplitude factor for input signal (done before any of the processing).
dist_between_mikes: remember that this simulates a stereo image. Your 'mikes' should be anywhere from 1 to, say, 10 feet apart depending on the size of the room. If set to less than 1 foot (< 1.0), and if mikes() has not been called (or mikes_off() has been called), the program will be in binaural mode, which simulates the filtering effects of human ears. This mode is substantially slower, but produces dramatic results when listened to through headphones.
The last number is a global amp factor that affects all reflections and reverb
equally, but not the direct signal. This is usually set to 1.0.
in comment form:
/* move -- doug scott's room simulator with moving sound sources
*
* space (dist_to_front, dist_to_right, -dist_to_back, -dist_to_left, height, abs_fact, rvbtime)
*
* mikes(mike_angle, pattern_factor)
* mikes_off()
*
* path(time0,distance0,angle0, time1,distance1,angle1, ..., timeN,distN,angleN)
* or:
* cpath(time0,xcoord0,ycoord0, time1,xcoord1,ycoord1, ..., timeN,xcoordN,ycoordN)
* or:
* makegen(-1, 9, 1024, 1, 30, 0)
* makegen(-2, 9, 1024, 1, 20, 30)
* cparam(1, 2)
*
* threshold(reset_distance)
*
* move (outskip, inskip, dur, amp, dist_between_mikes, rvb_amp)
*
*/
An example score:
load("move")
input("/sndh/bob.dole.snd")
output("/sndh/bob.dole.bigroom.snd")
space(50, 50, -750, -80, 25, 1, 3)
mikes_off()
path(0, 25, 0, 3, 15, 90)
move(0, 0, 5, 1, 0, 1)
mrotate
mrotate is a disk-based instrument that does 'tape-head' style pitch-shifting (similar to the gliss() function in rt). the instrument windows a soundfile and then transposes the windows according to the curve set in makegen 3.
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1...) /* amplitude curve for the output signal */
makegen(2, 25, 1000, 1) /* sets a hamming window function for the windowing of the signal */
makegen(3, 24, 1000, t0, a0, t1, a1...) /* curve for the transposition function */
mrotate(outskip, inskip, duration, amp, pitch_shift_0, pitch_shift_1, windowsize, inchan, spread) /* the two pitch_shift fields are in 8ve.pc, positive or negative, defining the transposition of the input signal when makegen 3 is at 0 and 1, respectively
*/
in comment form:
/* mrotate -- a pitch-shifting instrument based upon the idea
* of old rotating tape-head pitch shifters
*
* p0 = output skip
* p1 = input skip
* p2 = duration
* p3 = amplitude multiplier
* p4 = pitch shift up or down (oct.pc) when function table 3 is 0
* p5 = pitch shift up or down (oct.pc) when function table 3 is 1
* p6 = window size
* p7 = input channel number
* p8 = stereo spread (0-1) [optional]
* assumes function table 1 is the amplitude envelope
* assumes function table 2 is the window envelope
*
* assumes function table 3 is the pitch shift envelope
*
*/
An example score:
load("mrotate")
input("/sndh/bob.dole.mono.snd")
output("/sndh/bob.dole.rotate.snd")
makegen(1, 24, 1000, 0,0, 1,1, 7.0,1, 7.8,0)
makegen(2, 25, 1000, 1) /* hanning window */
makegen(3, 7, 1000, 0, 500, 1, 500, 0)
mrotate(0, 0, 7.8, 1, -0.07, 0.09, 0.14)
A second score:
load("mrotate")
input("/sndh/bob.dole.mono.snd")
output("/sndh/bob.dole.rotate.snd")
makegen(1, 24, 1000, 0,0, 1,1, 7.0,1, 7.8,0)
makegen(2, 25, 1000, 1) /* hanning window */
makegen(3, 7, 1000, 0, 500, 1, 500, 0)
mrotate(0, 0, 7.8, 1, -0.07, 0.09, 0.14, 0, 0)
mrotate(0, 0, 7.8, 1, 0.07, -0.09, 0.15, 0, 1)
noise
noise outputs full-spectrum white noise to a soundfile.
Syntax:
noise(outskip, duration, amplitude)
in comment form:
/* noise -- makes noise, duh.
*
* p0 = outskip
* p1 = duration
* p2 = amplitude
*
*/
An example score:
load("noise")
output("noise.snd")
noise(0, 7, 1000)
place
place is doug scott's room simulation cmix instrument. it places a sound in a room of your design and simulates the acoustic resonances of the room. like move, place is a fairly slow program, and the input file must be mono with the output file stereo.<
br>
Syntax:
taken from doug scott's documentation.
mikes(mike_angle, pattern_factor) /* optionally this... */
mikes_off() /* or this */
mikes is an optional setup call for times when you wish to simulate microphone recording (most of the time, actually). The arguments are mike_angle, which is the angle *each* microphone makes with a line drawn between them (i.e., 45 puts them at a 90 degree angle FROM EACH OTHER). pattern_factor is a value between 0 and one; 0 produces an omnidirectional mike, 1 produces a hypocardioid pattern, 0.5 produced the familiar cardioid pattern. If this call is left out, the pattern will be omnidirectional.
mikes_off() is used following a previous call to mikes(), in order to cancel mike mode in the event that you wish to use binaural mode (see below), or default to omnidirectional.
space (dist_to_front, dist_to_right, -dist_to_back, -dist_to_left, height, abs_fact, rvbtime)
space is the setup call for the room in which the sound will appear. Since the listener (YOU) is at point (0,0) coordinate-wise, the locations of the 4 walls are specified like in an x,y coordinate system:
y
|
-x---0---x
|
-y
Therefore the distance to the back and left walls must be specified as negative. All, including height, are in feet. abs_fac is a number between 0 (min) and 10 (max) that determines how reflective the walls are. rvbtime is the approximate length of reverb in seconds (max depends on roomsize).
place (inskip, outskip, dur, amp, distance_to_sound, angle_of_sound, dist_between_mikes, 1.0)
Place has its first 3 args the same as mix, etc.
Location of source is most easily specified in terms of distance and angle:
0.0 source
| /
| /
| /
| /
|/
you
in feet and degrees, respectively. Be sure to stay inside bounds of the room (it may take a bit of trigonometry [or guessing] to do that). By setting the dist_between_mikes negative, you may enter this as an (x, y) pair instead.
amp: amplitude factor for input signal (done before any of the processing).
dist_between_mikes: remember that this simulates a stereo image. Your 'mikes' should be anywhere from 1 to, say, 10 feet apart depending on the size of the room. If entered negative, this acts as a flag saying that the coordinates are entered as cartesian (x, y) rather than polar (distance, angle).
The last number is a global amp factor that affects all reflections and reverb equally, but not the direct signal. This is usually set to 1.0.
in comment form:
/* place -- doug scott's room simulation instrument
*
* space (dist_to_front, dist_to_right, -dist_to_back, -dist_to_left, height, abs_fact, rvbtime)
*
* mikes(mike_angle, pattern_factor)
* mikes_off()
*
* place(outskip, inskip, dur, amp, distance_to_sound, angle_of_sound, dist_between_mikes, 1.0)
*
*/
An example score:
load("place")
input("/sndgr/blah.snd")
output("/sndgr/blah.place.snd")
space(400,400,-400,-400,400,8.,10.)
place(0,0,14.3,1,10,20,-1,1.)
pvoc
phase vocoding: a resynthesis technique developed by J. Moorer whereby a sound is anylized through a filter bank with additional computation of phase deviation from each of the channels of the vocoder (sort of an expanded fourier transform). the data discerned from the analysis allows for realistic time-independent transposition and, by corollary, pitch-independent time-stretching of a soundfile, with much fewer resynthesis artifacts than would normally be possible. (from Dodge and Jerse, 1997).<
br>
the cmix pvoc instrument (a replacement for the earlier cmixpv instrument) uses a standard fft analysis with additional phase computation, allowing the user to specify fft parameters and time- and pitch-shifting in terms of multiples of the original sound
.
Syntax:
pvoc(outskip, duration, inskip, inchan, fftsize, windowsize, readin, putout, pitchmult, npoles) /* readin and putout are the number of samples read into the vocoder versus the number put out, pitchmult allows transposition, and npoles is habitually set to
0 */
p5 (window size) is a tricky parameter to gauge, and if tweaked correctly it will cut down significantly on the amount of artifacts present in the vocoded signal. for rough sounds such as speech it should be between half and one times the fft size, though for purer sounds you can get away with up to four times the fft size.
in comment form:
/* pvoc -- cmix phase vocoder
*
* p0 = outskip
* p1 = inskip
* p2 = duration
* p3 = input channel
* p4 = fft size
* p5 = window size
* p6 = # samples read in
* p7 = # samples put out
* p8 = pitch multiplier
* p9 = npoles
*/
An example score:
load("pvoc")
input("/sndgr/bob.dole.snd")
output("/sndgr/bob.dole.stretch.snd")
pvoc(0, 0, 50, 0, 1024, 2056, 150, 100, 0)
Another score:
load("pvoc")
input("/sndgr/bob.dole.snd")
output("/sndgr/bob.dole.pvoc.snd")
pvoc(0, 0, 3.5, 0, 1024, 2048, 100, 100, 0.9)
rotate
the rotate instrument simulates the functionality of a vari-speed tape recorder, allowing for sample playback at different transposition levels. unlike mrotate, rotate only allows for a static transposition level.
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1...) /* amplitude curve in time/amp pairs */
makegen(2, 25, 1000, window) /* a hanning (1) or hamming (0) window for the windowing of the sound */
rotate(outskip, inskip, duration, amplitude, pitch_shift, window_size, inchan, spread) /* pitch_shift is in positive/negative 8ve.pc, and window_size, importantly, is in seconds, not samples */
in comment form:
/* rotate -- a pitch-shifting instrument based upon the idea
* of old rotating tape-head pitch shifters
*
* p0 = output skip
* p1 = input skip
* p2 = duration
* p3 = amplitude multiplier
* p4 = pitch shift up or down (oct.pc)
* p5 = window size IN SECONDS!!!!!!!!!!!!!!!!!!!
* p6 = input channel number
* p7 = stereo spread (0-1) [optional]
* assumes function table 1 is the amplitude envelope
* assumes function table 2 is the window envelope
*
*
*/
An example score:
load("rotate")
input("/sndh/bob.dole.mono.snd")
output("/sndh/rotate.snd")
makegen(1, 24, 1000, 0,0, 1,1, 8,1, 8.7,0)
makegen(2, 25, 1000, 1) /* hanning window */
rotate(0, 0, 8.7, 0.2, 0, 0.1)
rotate(0, 0, 8.7, 0.2, 0.02, 0.11)
rotate(0, 0, 8.7, 0.2, 0.07, 0.14)
rotate(0, 0, 8.7, 0.2, -0.03, 0.09)
Another score:
load("rotate")
input("/sndh/bob.dole.mono.snd")
output("/sndh/rotate.snd")
makegen(1, 24, 1000, 0,0, 1,1, 8,1, 8.7,0)
makegen(2, 25, 1000, 1) /* hanning window */
rotate(0, 0, 8.7, 0.2, 0, 0.1, 0, 0.5)
rotate(0, 0, 8.7, 0.2, 1.00, 0.11, 0, 0)
rotate(0, 0, 8.7, 0.2, -1.07, 0.14, 1, 0.99)
A third score, demonstrating different window types:
load("rotate")
input("/sndh/bob.dole.mono.snd")
output("/sndh/rotate.snd")
makegen(1, 24, 1000, 0,0, 1,1, 8,1, 8.7,0)
makegen(2, 25, 1000, 1) /* hanning window */
rotate(0, 0, 3.4, 0.2, 1, 0.1)
makegen(2, 25, 1000, 2) /* hamming window */
rotate(0, 3.5, 3.4, 0.2, 1, 0.1)
sgran
granular synthesis: synthesis involving the systematic ordering of very small sample fragments, called grains, which when organised together can create a wide variety of synthesis effects.
sgran, or stochastic granular synthesis, is a methodology developed by Mara Helmuth to manipulate grains using stochastic probabilities. as a result, sgran has a lot of p-fields, so pay attention.
Syntax:
for FM granular synthesis:
makegen(1, 24, 1000, t0, a0, t1, a1...) /* envelope of the grain in time / amplitude pairs */
makegen(2, 24, 1000, t0, a0, t1, a1...) /* shape of change in the grain density */
makegen(3, 24, 1000, t0, a0, t1, a1...) /* shape of change in the grain duration */
makegen(4, 24, 1000, t0, a0, t1, a1...) /* shape of change in the grain location */
makegen(5, 24, 1000, t0, a0, t1, a1...) /* shape of change in the carrier frequency (usually static) */
makegen(6, 10, 1000, p0, p1...) /* waveform of the grain */
makegen(7, 24, 1000, t0, a0, t1, a1...) /* shape of the modulation index */
sgran(outskip, duration, amplitude, start_grain_rate, end_grain_rate,
    low, average, hi, tightness [rate variation - beginning],
    low, average, hi, tightness [rate variation - emd],
    low, average, hi, tightness [grain duration - beginning],
    low, average, hi, tightness [grain duration - end],
    low, average, hi, tightness [grain location - beginning],
    low, average, hi, tightness [grain location - end],
    low, average, hi, tightness [pitch band - beginning],
    low, average, hi, tightness [pitch band - end])
/* tightness must be < 1. if p29 < 0 then noise is the input */
in comment form:
/*
sgran:
0 start time of group
1 duration of group
2 amplitude
3 beginning grain rate
4 ending grain rate
amount of variation in rate: (percentage of grain rate)
5-8 beg: lo, average, hi, tightness (0-1, is 0-100%)
9-12 end: lo, average, hi, tightness (0-1, is 0-100%)
average duration:
13-16 starting lo, average, hi, tightness
17-20 ending lo, average, hi, tightness
location:
21-24 starting lo, average, hi, tightness
25-28 ending lo, average, hi, tightness
pitch band AS:
29-32 starting lo, average, hi, tightness
if p29 < 0, noise is the input
33-36 ending lo, average, hi, tightness
input type 0=AS 1=FM 2=SAM
* * *
functions: (stt variation changes are linear)
1 grain envelope
shape of change:
2 grain density
3 grain duration
4 grain location
AS-band
5 shape of change: frequency (usually linear for all shapes)
6 waveform
FM
5 shape of change: carrier frequency
6 shape of change: c:m ratio
7 shape of change: mi
*/
An example score:
load("sgran")
output("ttt.snd")
makegen(1, 7, 1000, 0, 500, 1, 500, 0)
makegen(2, 7, 1000, 0, 50, 1, 950, 0)
makegen(3, 7, 1000, 1, 400, 0.1, 600, 0.4)
makegen(4, 7, 1000, 0, 400, 0.1, 600, 0.9)
makegen(5, 7, 1000, 0, 1000, 1)
makegen(6, 10, 1000, 1, 0.1, 0.3)
makegen(7, 7, 1000, 1, 1000, 0)
sgran(0, 3.5, 3000, 0.1, 0.005,
0, 0.5, 0.9, 0.2,
0.9, 0.5, 0.1, 0.7,
0.9, 0.2, 0.9, 0.5,
0.9, 0.5, 0.1, 0.7,
0.1, 0.7, 0.9, 0.2,
0.5, 0.9, 0.2, 0.9,
200, 900, 500, 0.1,
2000, 1000, 1500, 0.5)
vwavetable
vwavetable is the wavetable instrument with additional parameters for vibrato (change in pitch over time).
Syntax:
makegen(1, 10, 1000, p0, p1...) /* amplitudes of the partials in the waveform */
makegen(2, 24, 1000, t0, a0, t1, a1...) /* envelope of the sound in time/amp pairs */
makegen(3, 10, 1000, p0...) /* waveform of the vibrato function */
vwavetable(outskip, duration, pitch, amplitude, vibrato_rate_lo, vibrato_rate_hi, vibrato_depth, spread) /* vibrato_depth is a percentage number */
in comment form:
/* vwavetable -- a vibrato wavetable sythesis instrument
*
* p0 = start
* p1 = duration
* p2 = pitch (oct.pc or hz)
* p3 = amplitude
* p4 = vibrato rate low
* p5 = vibrato rate high
* p6 = vibrato depth (percentage)
* p7 = stereo spread [optional]
* assumes function table 1 is the synthesis waveform
* assumes function table 2 is the amplitude envelope
* assumes function table 3 is the vibrato waveform
*
*/
An example score:
load("vwavetable")
output("ttt.snd")
makegen(1, 10, 1000, 1, 0, 0.3, 0, 0.1, 0, 0.05)
makegen(2, 24, 1000, 0,0, 0.5,1, 3.4,1, 3.5,0)
makegen(3, 10, 1000, 1)
fplot(3) /* view the vibrato wave */
vwavetable(0, 3.5, 8.02, 10000, 4, 7, 1)
vwavetable(4.0, 3.5, 8.04, 10000, 4, 7, 10)
wah
wah is an instrument that runs a soundfile through a sweeping filter that can be defined by a tracking function.
Syntax:
makegen(1, 24, t0, a0, t1, a1...) /* tracking function for the filter between its low and high boundary frequencies */
wah(outskip, inskip, duration, freq_lo, freq_hi, bandwidth)
in comment form:
/* wah - a sweeping wah filter
*
* p0 = outskip
* p1 = inskip
* p2 = duration
* p3 = lo wah freq
* p4 = hi wah freq (hz)
* p5 = bandwidth
*
* function 1 will be the 'tracking' function for the filter
*
*/
An example score:
load("wah")
input("/sndh/bob.dole.snd")
output("/sndh/bob.dole.wah.snd")
makegen(1, 7, 1000, 0, 100, 1, 100, 0, 100, 1, 100, 0, 100, 1, 100, 0, 400, 1)
wah(0, 0, 15, 100, 1000, 20)
wahwah
wahwah is a slightly different wah filter implementation, with the filter sweeping automatically according to a frequency parameter and a waveform.
Syntax:
makegen(1, 10, 1000, p0...) /* waveform of the wah sweep */
wahwah(outskip, inskip, duration, freq_lo, freq_hi, bandwidth, wah_frequency)
in comment form:
/* wahwah - a periodic sweeping filter
*
* p0 = outskip
* p1 = inskip
* p2 = duration
* p3 = lo wah freq
* p4 = hi wah freq (hz)
* p5 = bandwidth
* p6=wah frequency
*
* function 1 should be some periodic function for the wah
*
*/
An example score:
load("wahwah")
input("/sndh/bob.dole.mono.snd")
output("/sndh/bob.dole.wahwah.snd")
makegen(1, 10, 1000, 1)
wahwahwah(0, 0, 15, 400, 3500, 5, 8)
wow
the wow instrument frequency modulates an input soundfile, in the same way that fminst applies fm to a waveform. the result varies from vibrato to a sideband-rich sound.
Syntax:
makegen(1, 24, 1000, t0, a0, t1, a1...) /* amplitude curve of the note */
makegen(2, 10, 1000, p0, p1...) /* waveform of the modulator */
wow(outskip, inskip, duration, amplitude, modulation_index, modulation_frequency, inchan, spread) /* see fminst, above, for a description of these parameters */
in comment form:
/* wow -- apply fm to an input soundfile
*
* p0 = output skip
* p1 = input skip
* p2 = duration
* p3 = amplitude
* p4 = modulator depth (index)
* p5 = modulator frequency (hz)
* p6 = input channel [optional]
* p7 = stereo spread <0-1> [optional]
* assumes function table 1 is the amplitude envelope
* function table 2 is modulator waveform
*
*/
An example score:
load("wow")
input("/sndgr/bob.dole.mono")
output("/sndgr/tryit.snd")
makegen(1, 24, 1000, 0,0, 1,1, 7,1, 8,0)
makegen(2, 10, 1000, 1)
wow(0, 0, 8, 1, 1, 4, 0, 0.5)
numtest
numtest is a debugging instrument which writes a number to a soundfile for a specific amount of time.
Syntax:
numtest(outskip, duration, number)
in comment form:
/* numtest: write a single number repeatedly into a soundfile
*
* p0=start_time
* p1=duration
* p2=the number
*/
An example score:
output("ttt.snd")
numtest(0, 10, 10000)
that's all, folks.