Wanna generate more waveforms which is the combination of Sine Wave Harmonice easily? Sure! It's very easy with Gen10.
( see http://chuck.cs.princeton.edu/doc/program/ugen_full.html#GenX
http://chuck.cs.princeton.edu/doc/program/ugen_full.html#Gen10 )
This way of creating an oscillator is derived from the table-lookup mechanism dated back to some very classic audio programming languages such as MUSIC-N and Csound. I remember practicing Csound and starting to learn how to use Gen 10 to create a table (array) containing this kind of waveform: "harmonic partials with specified amplitudes" .. "composite waveforms made up of weighted sums of simple sinusoids", you can read more about Gen 10 in Csound at http://www.csounds.com/manual/html/GEN10.html, it feels very classic to me.
After creating a Gen10 and setting the coefficients (.coefs), the values in the table will be "normalized", so the range of the values in the table will always be in this range [-1, 1].
Let's start with the most simple wave form.. A pure sine wave!
Hear out a simple 220hz sine wave:
Phasor phase_generator => Gen10 signal => dac;
[1.0] => signal.coefs;
day => now;
So now, let me explain quickly. When a Gen is created, we can access the table in two ways:
[1] by using it as a function. by reading its .lookup(float), you can read the value from the table stored in the Gen at the specific phase. For example ..
Gen10 s;
[1.0] => s.coefs;
<<< .25 => s.lookup >>>;
This will output 1.000000 :(float), the value of sine at phase = .25 (90 degree or pi/2 radian).
(or you can use s.lookup(.25) as well.)
[2] by driving it by chucking in a signal. normally a signal in the range [-1, 1] .. but normally we can use Phasor (which has the output range [0, 1]). As in the above example which is playing the sine wave out, the example is (kinda) equivalent to SinOsc s => dac; day => now; (because SinOsc and Phasor both have the same initialized .freq at 220hz).
By driving it with chucking, we can easily use a Gen as an oscillator right away, and by altering the phasor's freq or doing Frequency Modulation (FM) or Phase Modulation (PM) with it, we can also turn a Gen into a FM/PMable oscillator right away.
Let me give an example for using Gen10 to create quite a basic sound: The Electric Organ. Normally, when we think of the electric organ sound, we think of it as the summation of sinusoid harmonic partials. Let's say, if we're playing a 440hz A note, the typical organ will let us mix more harmonics to shape the sound. We can adjust the amplitude of each harmonic by adjusting the drawbars. So we're adding up sine wave at 440hz, 440*2hz, 440*3hz, 440*4hz .. and so on. Yes, this is just like what we can do easily with Gen10!
Example: Randomizing each harmonic's amplitude, playing with the note C below middle C.
Phasor p => Gen10 organ => dac;
48 => Std.mtof => p.freq;
.5 => organ.gain;
float harmonics[8];
while(true)
{
1.0 => harmonics[0];
for(int i; i < 7; i++)
{
Std.rand2f(0, 2) => harmonics[i + 1];
}
harmonics => organ.coefs;
second => now;
}
Another Example: The same as above with added vibrato
Phasor p => Gen10 organ => dac;
48 => Std.mtof => p.freq;
.5 => organ.gain;
SinOsc lfo => p;
2 => p.sync; // set p's sync mode to FM to vibrate p's freq
6 => lfo.freq; // vibrato freq
2 => lfo.gain; // vibrato depth in hz
float harmonics[8];
while(true)
{
1.0 => harmonics[0];
for(int i; i < 7; i++)
{
Std.rand2f(0, 2) => harmonics[i + 1];
}
harmonics => organ.coefs;
second => now;
}
Example: Rotating the harmonic partials and the pitch also
Phasor p => Gen10 organ => NRev rev => dac;
.5 => organ.gain;
.04 => rev.mix;
SinOsc lfo => p;
2 => p.sync; // set p's sync mode to FM to vibrate p's freq
6 => lfo.freq; // vibrato freq
2 => lfo.gain; // vibrato depth in hz
float harmonics[8];
int seq;
while(true)
{
36 + seq % 12 * 2 => Std.mtof => p.freq;
for(int i; i < 8; i++)
{
.1 => harmonics[i];
}
1.0 => harmonics[seq % 8];
harmonics => organ.coefs;
second/8 => now;
seq++;
}
Example: Using a SinOsc to FM with a Gen10 sound
SinOsc p_fm => ADSR p_fm_env => Phasor p => Gen10 organ => dac;
2 => p.sync;
.5 => organ.gain;
p_fm_env.set(10::ms, 120::ms, .2, 10::ms); // set FM depth ADSR envelope
200 => p_fm_env.gain; // set maximum FM depth
36 => Std.mtof => p_fm.freq;
48 => Std.mtof => p.freq;
[1.0, 0, 0, .7, 0, 0, .4, 0, 0, .3] => organ.coefs; // set harmonic partial aplitudes
while(true)
{
p_fm_env.keyOn();
250::ms => now;
p_fm_env.keyOff();
250::ms => now;
}
Example: using a Gen10 to FM a Gen10
Phasor p_p_fm => Gen10 p_fm => ADSR p_fm_env => Phasor p => Gen10 organ => dac;
2 => p.sync;
.5 => organ.gain;
p_fm_env.set(10::ms, 160::ms, .1, 10::ms); // set FM depth ADSR envelope
400 => p_fm_env.gain; // set maximum FM depth
36 => Std.mtof => p_p_fm.freq;
48 => Std.mtof => p.freq;
[1.0, 0, 0, .7, 0, 0, .4, 0, 0, .3] => organ.coefs; // set harmonic partial aplitudes
float harmonics[8];
while(true)
{
for(int i; i < 8; i++)
{
0.0 => harmonics[i];
}
1.0 => harmonics[Std.rand2(1, 7)];
harmonics => p_fm.coefs;
p_fm_env.keyOn();
250::ms => now;
p_fm_env.keyOff();
250::ms => now;
}
I guess that's it for today. As an introduction to Gen10, I hope this can be one of the start point for ChucKers using GenX for the first time or finding general ideas on Gen10. Goodnight guys.
edit @ 19 May 2009 06:20:27 by aChucKaDay