Your assignment is to write one or more scores that do these things:
Tables across notes
Tables created with maketable normally are used to control some parameter that changes during the course of a single note. We've been using amplitude envelope tables in this way. But what if you have a long series of notes, and you want to make continuous dynamic changes across the entire duration of the series? Here is a technique you can use. Of course, you can adapt this technique to control any parameter, even ones that cannot change during the course of a note (such as its start time).
peakamp = 20000
note_env = maketable("line", 1000, 0,0, 1,1, 2,1, 3,0)
total_env = maketable("line", table_length = 1000, 0,1, 1,0, 2,1)
for (start = 0; start < totdur; start += incr) {
freq = irand(261, 440)
pan = irand(0, 1)
index = (start / totdur) * table_length
thisamp = samptable(total_env, index)
WAVETABLE(start, dur, thisamp * peakamp * note_env, freq, pan)
}
The samptable function takes a sample of a table at a particular index. The index can be a decimal number, in which case samptable interpolates between two adjacent table values. The trick is to calculate the index as a percentage of the table length. For example, if the table has 1000 values, and our loop is halfway through the total duration spanning all notes, then we want the table value that is at index 500 — or 50% of the way through the table. The expression "(start / totdur)" gives us a "percentage," between 0 and 1, that locates the current start time within the total duration. We multiply this expression by the table length to get the index for use by samptable.
The result, in this case, is that the series of notes begins at full volume, diminuendos to silence, and then crescendos to full volume at the end. (It would be better to use decibels or a curve table, instead of straight line segments and linear amplitude.)
Tempo changes
We've been writing all our timing information in terms of seconds. It would be nice to have the option of working in beats, with the ability to change tempos. This requires a few extra steps and a few new functions.
totbeats = 50
tempo(0, 200) // at beat 0, set tempo to 200 bpm
beat_incr = 0.5
dur = 0.1
control_rate(10000)
amp = 20000 * maketable("line", 1000, 0,0, 1,1, 4,0)
for (beat = 0; beat < totbeats; beat += beat_incr) {
start = tb(beat) // return time value (seconds) for beat
freq = irand(100, 1200)
pan = irand(0, 1)
WAVETABLE(start, dur, amp, freq, pan)
}
The tempo function sets tempo in terms of beat, bpm pairs. Above, we just set a static tempo, but you can create a tempo curve.
tempo(0,200, 5,200, 10,500)
This tempo would start at 200 bpm, begin an accellerando after five beats, and end with a tempo of 500 bpm. You can also have instantaneous tempo changes by giving two beat, bpm pairs for the same beat.
tempo(0,90, 8,90, 8,180, 20,180, 20,90)
This tempo suddenly enters double time at the eighth beat, and returns abruptly to the initial tempo after twelve beats of double time.
Use the tb function to retrieve a time value from a given beat value. (Read tb as "time from beat.") To make use of the tempo information, we construct our loop in terms of beats, rather than seconds, converting from the current beat to its value in seconds before passing this to the instrument. You might also want to express duration in terms of beats.
Routing audio between instruments
You can process the audio output of one instrument by another. Of course, the second instrument must be one that is capable of processing audio, such as DELAY, MULTEQ or FREEVERB. Moreover, it must be an instrument that does not require future input to process a current sample. (In DSP lingo, it requires that the instrument be a causal filter.) This requirement rules out TRANS, since, for any upward transposition, it consumes more than one input sample for every output sample. Most other instruments that have an inskip or input start time parameter after the start time will work.
As in a typical hardware mixer, you connect instruments using buses. In RTcmix, these are called "aux," although the comparison with aux buses in a mixer is somewhat misleading. You set up the connections using the bus_config function before calling the instruments.
bus_config("WAVETABLE", "aux 0-1 out")
bus_config("FREEVERB", "aux 0-1 in", "out 0-1")
This routes stereo output from WAVETABLE into FREEVERB's stereo input; FREEVERB sends its output to the outside world.
The next (incomplete) score example illustrates a few more wrinkles.
bus_config("STEREO", "in 0", "aux 0-1 out")
bus_config("DELAY", "aux 0-1 in", "out 0-1")
incr = 0.5
dur = incr * 2
for (start = 0; start < totdur; start += incr) {
STEREO(start, inskip, dur, amp, pan)
}
inskip = 0 // inskip must be zero for aux bus readers
DELAY(0, inskip, totdur, amp, deltime, fdbck, rngdur, inchan=0, pan=1)
DELAY(0, inskip, totdur, amp, deltime, fdbck, rngdur, inchan=1, pan=0)
Here are some crucial things to keep in mind while working with buses.
You can have a chain comprising more than one processing instrument. (See "docs/sample_scores/longchain.sco" in the rtcmix application folder.) Read more about the RTcmix bus scheme on the bus_config help page at rtcmix.org.
-John Gibson