Creating and reading custom wavetables

This is done by creating buffers, filling them with data and then using another ugen to read from them. Let's start with a look at buffers.

Buffer creation - method 1

/b_alloc - OSC style for using in sendMsg commands

The b_alloc command will allocate a zero filled buffer (i.e. empty) with the number of channels and samples specified by the user. It takes the arguments buffer number, number of samples and number of channels in that order.

Example:

s.sendMsg("/b_alloc", 0, 1024, 2);

will create a stereo buffer of 1024 samples as buffer number 0

To free it again, you can send a /b_free message:
s.sendMsg("/b_free", 0);
will free buffer number 0

Buffer creation - method 2

Buffer.alloc - similar to /b_alloc, but for use inside synths. It assigns buffer numbers automatically. It takes the server as an argument instead of the buffer number argument.

Example:

(
s = Server.local;
b = Buffer.alloc(s, 1024, 2);
)

will create a stereo buffer of 1024 samples in server "s". To free this buffer you would simply use

b.free;

***************************************************************

Filling buffers

There are a few predefined shapes you can fill a buffer with:

sine1 - fills a buffer with a series of sine wave partials. It takes an array of floats, the first float specifies the amplitude of the first partial, the second the amplitude of the second partial, and so on.

sine2 - similar to sine1, but each individual partial frequency is specified as well.

sine3 - similar to sine2, but you can also specify the starting phase.

cheby - fills a buffer with a series of chebyshev polynomials (defined as cheby(n)=amplitude*cos(n*acos(x)). It takes an array of floats - the first float specifies the amplitude for n=1, the second for n=2 etc.

There are three additional arguments which can be set to either true or false. These are (in order):

normalize - The peak amplitude of the wave is set to 1.0
wavetable - the buffer is written in wavetable format so it can be read by interpolating oscillators
clear - this will clear the buffer before adding new values. If set to false, the new partials will be summed with the existing ones.

Example - filling a wave table with a sine1 shape:

(
s = Server.local;
b = Buffer.alloc(s, 1024, 1);
b.sine1(1.0/[1,2,3,4,5,6,7,8,9], true, true, true);
)

b.free;

****************************
Using these wavetables in an oscillator

There are a few different ugens you can use to play back your custom wavetables:

Osc - interpolating wavetable oscillator
OscN - non-interpolating wavetable oscillator
VOsc - wavetable oscillator which can be swept smoothly across multiple wavetables. All wavetables must be the same size.
VOsc3 - same as VOsc, but with 3 oscillators

Example 1 - Osc
s = Server.local;
(
SynthDef("oscexample", {
var b;
b = Buffer.alloc(s, 1024, 1);
b.sine1(1.0/[1,0,2,0,3], true, true, true);
Out.ar(0, Osc.ar(0, 440));
}).writeDefFile;
s.sendSynthDef("oscexample");
)

s.sendMsg("/s_new", "oscexample", 1000, 1, 0);
s.sendMsg("/n_free", 1000);
b.free;

Example 2 - VOsc

(
SynthDef("voscexample", {
var b, c, d, e, x;
b = Buffer.alloc(s, 1024, 1);
c = Buffer.alloc(s, 1024, 1);
d = Buffer.alloc(s, 1024, 1);
e = Buffer.alloc(s, 1024, 1);
b.sine1(1.0/[0,1,0,2,0,3,0,4], true, true, true);
c.sine1(1.0/[1,0,2,0,3,0,4], true, true, true);
d.sine1(1.0/[1,2,3,4], true, true, true);
e.sine1(1.0/[0,0,0,0,1,2,3,4], true, true, true);
x = MouseX.kr(0,3);
x.postln;
Out.ar(0, VOsc.ar(0+x, 440));
}).writeDefFile;
s.sendSynthDef("voscexample");
)

s.sendMsg("/s_new", "voscexample", 1000, 1, 0);
s.sendMsg("/n_free", 1000);

(
b.free;
c.free;
d.free;
e.free;
)