
There are SEVERE problems with the input code I sent earlier. I may
have jumped the gun on that one.
Working on it now. Sorry!
-Mike
On Wed, Aug 5, 2009 at 12:55 PM, mike clemow
I'm sorry, folks. I accidentally hit "send" there. **slaps forehead**
Basically, what I forgot to say was that using this method of enveloping signals for granular synthesis puts almost all of the heavy lifting on the UGens, which makes it perform really, really well in realtime. I was able to achieve well over a thousand grains-per-second with this method in realtime without overloading ChucK. And that's specifying the parameters of each grain individually on a per-grain basis in code!
The best part is that the envelope can be tailored to be any shape because it's all done with wavetable coefficients! That means that you aren't limited to triangle, or ADSR shaped envelopes, which makes a HUGE difference to the spectral properties of granular synthesis.
To make the long story short, I'd love to hear your feedback on these classes, especially if you find them helpful, useful, improvable, etc.
ChucK on!
_Mike
On Wed, Aug 5, 2009 at 12:49 PM, mike clemow
wrote: Dear Chuckists,
With the exception of a protracted discussion about garbage collection (of which I have yet to read the conclusion), things have been generally "all quiet on the ChucKian front" this summer. Nevertheless, I know that there are those of you who are still busy digging into this and that project with ChucK. I myself have been working (predictably, doggedly, stubbornly) on more granular synthesis stuff and wanted to share some recent classes that I find helpful to me in general (i.e. not just for granular synthesis).
Part 1: INPUT
I find that environments like Processing, SC, etc have very easy-to-use input calls like MouseX.kr etc, that easily bring the ability to add some interaction to your code, without having to set up a HidMsg, Hid pair and an event responder. Sometimes you just want mouse input and want it right now. I wanted to automate the process a little so that I could save some time by just telling ChucK to add the boiler plate listener for the mouse, keyboard, or a joystick in a separate thread and make the data available. With the MouseInput class, for instance, you can just do this:
MouseInput mi; spork ~ mi.listen(); me.yield();
while(true) { mi => now; <<< mi.deltaX, mi.deltaY, mi.wheelDeltaX, mi.wheelDeltaY, mi.buttonDown, mi.buttonUp >>>; me.yield(); }
I find this easier to use. Maybe you will too. There's one for Keyboard input and joystick input too. I'm sure they can be improved, so please share any ideas you have.
Part 2: WAVETABLES AS ENVELOPES
Concept: A positive, unipolar wavetable can be used as a cheap, flexible alternative to envelope UGens by driving it with a Phasor and multiplying its output with your signal. The CurveEnvelope class:
// // CurveTable Envelope //
class CurveEnvelope { // members and default params Phasor drive => CurveTable curvetable => Gain multiplier; 3 => multiplier.op; // this is what makes the CurveTable an envelope! 0. => multiplier.gain; // we use this to gait the output, so start at 0.
UGen source, out;
0 => drive.op; // stop the driver for now
dac @=> out; 1. => float gain; 1::second => dur length; [0., 0., 0., 1., 1., 0., 2., 0.] => curvetable.coefs; // triangle window
// methods fun void setEnvelopeCoefs( float _coefs[] ) { _coefs => curvetable.coefs; }
fun void connectSource( UGen src ) { src @=> source; }
fun void connectOutput( UGen destination ) { destination @=> out; }
fun void trigger() { source => multiplier => out; // connect things gain => multiplier.gain; // open gait 1 => drive.op; 0. => drive.phase; // reset driver to beginning of envelope curve 1. / (length / second) => drive.freq; // calculate speed of driver in Hz length => now; // let it happen... 0. => multiplier.gain; // close gait 0 => drive.op; source =< multiplier =< out; // disconnect things } }
USAGE:
CurveEnvelope ce; SinOsc s; ce.connectSource( s ); ce.connectOutput( dac ); ce.trigger();
TriOsc t; ce.connectSource( t ); ce.connectOutput( dac ); ce.trigger(); <<< "done" >>>;