from GJW on ChucK Discord Server:
Gain gl => Envelope el => dac.chan(0);
Gain gr => Envelope er => dac.chan(1);
SinOsc sL0 => gl; 440.0 => sL0.freq; 0.3 => sL0.gain;
SinOsc sL1 => gl; 880.0 => sL1.freq; 0.15 => sL1.gain;
SinOsc sR0 => gr; 440.0 => sR0.freq; 0.3 => sR0.gain;
// ... up to 32 partials per channel
0.0 => el.value; 1.0 => el.target; (fade/second) => el.time; el.keyOn();
0.0 => er.value; 1.0 => er.target; (fade/second) => er.time; er.keyOn();
(total - fade) => now;
0.0 => el.target; (fade/second) => el.time; el.keyOff();
fade => now;
One of these was generated and loaded as a shred every 1-3 seconds into a persistent VM (chuck --loop). Two shred slots alternated, overlapping their envelopes for crossfade. Each shred had up to 32 SinOsc objects + Gain + Envelope per stereo channel. When the shred finished and was removed, the UGen objects were never freed.
from GJW on ChucK Discord Server:
Gain gl => Envelope el => dac.chan(0);
Gain gr => Envelope er => dac.chan(1);
SinOsc sL0 => gl; 440.0 => sL0.freq; 0.3 => sL0.gain;
SinOsc sL1 => gl; 880.0 => sL1.freq; 0.15 => sL1.gain;
SinOsc sR0 => gr; 440.0 => sR0.freq; 0.3 => sR0.gain;
// ... up to 32 partials per channel
0.0 => el.value; 1.0 => el.target; (fade/second) => el.time; el.keyOn();
0.0 => er.value; 1.0 => er.target; (fade/second) => er.time; er.keyOn();
(total - fade) => now;
0.0 => el.target; (fade/second) => el.time; el.keyOff();
fade => now;
One of these was generated and loaded as a shred every 1-3 seconds into a persistent VM (chuck --loop). Two shred slots alternated, overlapping their envelopes for crossfade. Each shred had up to 32 SinOsc objects + Gain + Envelope per stereo channel. When the shred finished and was removed, the UGen objects were never freed.