Sampling Tutorial 4: Variable-length Wavetable
In this tutorial, we look at the wave~ object, which allows you to access buffer~ data as a wavetable for an oscillator. This allows you to load samples and use them as waveforms which are accessed based on playback frequency. You can use these wavetables to build sample-based oscillators for more complex synthesis patches.
Use any part of a buffer~ as a wavetable: wave~
As was shown in an earlier tutorial, the cycle~ object can samples of a buffer~ as a wavetable through which it reads repeatedly to play a periodically repeating tone. The wave~ object is an extension of that idea; it allows you to use any section of a buffer~ as a wavetable with detailed control of the endpoints.
The start and end points within the buffer~ are determined by the number or signal received in the middle and right inlets of the wave~ object. As a signal in the wave~ object's left inlet goes from to , wave~ sends out the contents of the buffer~ from the specified start point to the end point. The phasor~ object, ramping repeatedly from 0 to 1, is the obvious choice as an input signal for the left inlet of wave~.
In a standard implementation of wavetable synthesis, the wavetable (16K samples in the case of cycle~, or a section of any length in the case of wave~) would be one single cycle of a waveform, and the frequency of the cycle~ object (or the phasor~ driving the wave~) would determine the fundamental frequency of the tone. In the case of wave~, however, the wavetable could contain virtually anything (an entire spoken sentence, for example).
wave~ yields rather unpredictable results compared to some of the more traditional sound generation ideas presented so far, but with some experimentation you can find a great variety of timbres using wave~. In this tutorial patch, you will see some ways of reading the contents of a buffer~ with wave~.
Synthesis with a segment of sampled sound
The tutorial patch is designed to let you try three different ways of driving wave~ (labeled , , and ) with two different audio samples (labeled and ): with a repeating ramp signal (phasor~), a sinusoid (cycle~), or a single ramp (line~). The bottom part of the patcher is devoted to the basic implementation of wave~, and the upper part of the window contains the three methods of reading through the wavetable. First, let's look at the bottom half of the window.
Notice that the rate of the phasor~ often has no obvious relationship to the perceived pitch, because the contents of the wavetable do not represent a single cycle of a waveform. Furthermore, such rapid repetition of an arbitrarily selected segment of a complex sample has a very high likelihood of producing frequencies well in excess of the Nyquist rate, which will be folded back into the audible range in unpredictable ways.
This changes the contents of the wavetable (because wave~ now accesses a different buffer~), and sets the value of the ‘End time’ number box equal to the length of the file sacre.aiff. Notice an additional little programming trick - shown in the example below - employed to prevent the user from entering inappropriate start and end times for wave~.
Using wave~ as a transfer function
Take a look at the section of patcher logic labeled buffer~ object can also be used as a lookup table that can be accessed in different ways by other objects. In the next tutorial we'll look at this in a more traditional manner, but with the wave~ object you can generate interesting timbres by feeding a simple waveform into the object as an index value. To use wave~ in this way, we must scale and offset the incoming cycle~ so that it sends signal values from 0 to 1.. The
Play the segment as a note
Look at the third section of patcher logic at the top, labeled wave~ accepts any signal input in the rage 0 to 1, you can read through the wavetable just once by sending wave~ a ramp signal from 0 to 1 (or backward, from 1 to 0). Other objects such as play~ and groove~ are better suited for this purpose, but it is nevertheless possible with wave~.. Because
Changing the wavetable dynamically
The cycle~ object in the right part of the Patcher window is used to add a sinusoidal position change to the wavetable. As the cosine wave rises and falls, the start and end times of the wavetable increase and decrease. As a result, the wavetable is constantly shifting its position in the buffer~, in a sinusoidally varying manner. Sonically this produces a unique sort of vibrato, not of fundamental frequency but of timbre. The wavetable length and the rate at which it is being read stay the same, but the wavetable's contents are continually changing.
Any segment of the contents of a buffer~ can be used as a wavetable for the wave~ object. You can read through the wavetable by sending a signal to wave~ that goes from 0 to 1. So, by connecting the output of a phasor~ object to the input of wave~, you can read through the wavetable repeatedly at a sub-audio or audio rate. You can also scale and offset the output of a cycle~ object so that it is in the range 0 to 1, and use that as input to wave~. This treats the wavetable as a transfer function, and results in waveshaping synthesis. The position of the wavetable in the buffer~ can be varied dynamically - by adding a sinusoidal offset to the start and end times of wave~, for example - resulting in unique sorts of timbre modulation.
|buffer~||Store audio samples|
|phasor~||Generate sawtooth signals|
|wave~||Variable size wavetable|