Skip to content

Instantly share code, notes, and snippets.

@forrcaho
Last active January 5, 2019 02:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save forrcaho/21acdb25e05a8620f56dba591cd52ed5 to your computer and use it in GitHub Desktop.
Save forrcaho/21acdb25e05a8620f56dba591cd52ed5 to your computer and use it in GitHub Desktop.
Fixed Additive object: now a Chubgraph
class AdditivePartial extends SinOsc {
int partialNumber;
float baseFreq;
float noteAmplitude;
fun void init( int partialNumber, float baseFreq, float noteAmplitude )
{
0 => this.gain;
0 => this.freq;
partialNumber => this.partialNumber;
baseFreq => this.baseFreq;
noteAmplitude => this.noteAmplitude;
}
/*
The relative amplitude of the Nth partial, in a range from 0 to 1. Note that even though
noteAmplitude (the gain for the entire composite note) is passed in, we don't scale by that value
here. That is just provided so that louder notes can have a different timbre than quieter
ones (e.g. be brighter).
The default here gives the nth partial an ampitude of 1/2*n^2 with a small attack and decay
to avoid glitches.
*/
fun float partialAmplitude( dur timeLoc, dur duration )
{
0.5 * Math.pow(partialNumber, -2.0) => float maxGain;
0.1::second => dur fadeTime;
if (timeLoc < fadeTime) {
return maxGain * (timeLoc/fadeTime);
}
if (timeLoc > (duration - fadeTime)) {
return maxGain * ((duration - timeLoc)/fadeTime);
}
return maxGain;
}
/*
The frequency of the Nth partial, in Hz.
This base function returns the most common n * the base frequency for the nth partial.
*/
fun float partialFrequency(dur timeLoc, dur duration )
{
return baseFreq * partialNumber;
}
/*
This routine is sporked for each partial. It does not spork any partial that starts above MAX_FREQUENCY,
and drops any partial that exeeds MAX_FREQUENCY after it's started down to zero gain (which will only happen
when partialFrequency is overridden using a time-varying function that ascends above its starting value).
This method is not intended to be overridden.
*/
fun void play( dur duration )
{
8::samp => dur step;
now => time start;
now - start => dur timeLoc;
while (timeLoc < duration) {
this.partialFrequency(timeLoc, duration) => float frequency;
frequency => this.freq;
noteAmplitude * partialAmplitude(timeLoc, duration) => this.gain;
step => now;
now - start => timeLoc;
}
0 => this.gain;
}
}
class Additive extends Chubgraph {
float baseFreq;
float noteAmplitude;
10 => int numPartials;
AdditivePartial @ partial[numPartials];
/*
Creates and initializes an AdditivePartial
*/
fun AdditivePartial initPartial(int partialNumber)
{
new AdditivePartial @=> AdditivePartial ap;
ap.init(partialNumber, baseFreq, noteAmplitude);
ap => outlet;
return ap;
}
/*
Creates and initializes an Additive object for additive synthesis
*/
fun void init(float baseFreq, float noteAmplitude)
{
baseFreq => this.baseFreq;
noteAmplitude => this.noteAmplitude;
for (0 => int i; i < numPartials; i++) {
initPartial(i+1) @=> partial[i];
}
}
/*
Plays the additive for duration by sporking all the partials
*/
fun void play(dur duration)
{
for(0 => int i; i < numPartials; i++) {
spork ~ partial[i].play(duration);
}
duration => now;
}
}
new Additive @=> Additive a;
a.init(220.0, 0.1);
a => dac; // I thought that I'd have to connect this before the call to init(), but this works fine.
new Additive @=> Additive b;
b.init(275.0, 0.1);
b => dac;
spork ~ a.play(2::second);
0.5::second => now;
spork ~ b.play(2::second);
2::second => now;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment