Hi again,
Rereading through this, it occurs to me some examples would be helpful.
the server-side triggers for the grains are the result of bandpass filters, lots of them:
SynthDef("filter", {|freq = 128, in = 16, on = 1, thresh = 0.0125, rq = 0.025|
var amp, rate, t0, t1, t2, bound;
//reads the amplitude of the result of a bandpass filter on incoming signal;
amp = Amplitude.kr(BPF.ar(InFeedback.ar(in), freq, rq));
//a retrigger rate for persistent bands, NOT 1/freq as i said above, but rather just freq (note audio rate)
rate = Impulse.ar(freq);
//define three scalable regions of amplitude. scalable, hence the weird recursive "bound*1.5" action
bound = thresh;
t0 = bound*1.5 > amp > bound;
bound = bound*1.5;
t1 = bound*1.5 > amp > bound;
bound = bound*1.5;
t2 = bound*1.5 > amp;
// tN = change of state , tN && rate = presence in state. (again note audio rate)
SendTrig.ar(t0 && rate, 0, freq);
SendTrig.ar(t1 && rate, 1, freq);
SendTrig.ar(t2 && rate, 2, freq);
}).send(s);
/* a lot of these are spread across the spectrum and contained in an array. */
a = (12, 12.2..135).midicps; //geometric spacing
b = a.collect({|x|
Synth.new("filter", [\freq, x]);
});
/* the OSCresponderNode. added only once.
c = OSCresponderNode(s.addr,'/tr',
{|time, responder, msg|
var frq, amp;
frq = msg[3];
amp = msg[2] + 1;
/* this part changes quite a lot, with new grain types and different destinations.*/
/* this paradigm made it really intuitive to substitute 's' for the result of iterating
through an array of available servers, for example. */
/* also note the scaling for translating amplitude state for 'real' amplitude*/
s.sendMsg("/s_new", "sine_subsample", -1, 0, 0, \freq, frq, \amp, amp/3);
}
).add;
/* and finally, the grain: */
SynthDef("sine_subsample",{ arg out=0, freq = 440, cyc = 8, amp = 3;
var sig, osc, offset, length, env, sd;
sd = SampleDur.ir;
length = cyc/freq;
env = EnvGen.kr(Env.sine(length), 1.0);
offset = (1-SubsampleOffset.ir) * sd;
Line.ar(1,0, length + offset, doneAction:2);
//amplitude is scaled way back because there's gonna be a lot of these
osc = FSinOsc.ar(freq, 0, 0.025*amp);
sig = DelayC.ar(env * osc, sd*4, offset);
//widest spread, done cheaply.
OffsetOut.ar(IRand(out, out+1), sig)
}).send(s);
/* one cycle grains, should be subsample accurate (as far as I can hear) . */
so this thing works for me in the sense that the filters trigger grains and with big enough grains, that underlying-subharmonic-amplitude-mod-thing goes away. but still it bugs me that i'm losing out on all that information. i've done so many modifications to and tests on this paradigm that i'm nearly positive it's OSCresponderNode's fault. is there a really simple, obvious and more efficient way of doing this?
-Joe
On Wed, May 7, 2008 at 6:36 AM, Joe Mariglio <
joe.mariglio@...> wrote:
Hi all,
I'm trying to trigger subsample accurate grains using OSCresponderNode, but I'm running into a rate limitation that ends up sounding like ring modulation, with the modulator frequency at a multiple of 44100/64, which also happens to be server's sample rate over blockSize. Nevertheless, I've determined it's not scsynth but rather OSCresponderNode itself which limits the response rate to this frequency.
I'm using the responder to trigger layers of synchronous grains whose trigger rate is the reciprocal of their frequency, ranging across the spectrum. the grains' amplitudes are the result of analysis happening on the server which sends these '/tr' messages back to the client for evaluation into "/s_new" messages. but alas! OSCresponderNode limits the rate at which these "/s_new" messages can be sent!
i'm thinking of maybe using the '/tr' messages as signals for change of amplitude state for each band, rather than to trigger the grains themselves, thus easing the load being placed on OSCresponderNode. in this hypothetical implementation, the '/tr' messages would trigger trains of particles using either patterns or routines, which are fast enough. however, i want to implement this on remote servers across a network so I'm unsure how to use the pattern paradigm for that.
I'm currently looking into using OSCresponderNode to toggle routines which will handle spawning the grains, but this is cumbersome. if it were on one machine i'd be using patterns i guess, but still the process would be quite annoying.
what's the deal with OSCresoponder's draconian rate limit and why will it not listen to reason? even if i use <server>.sendBundle(latency, [msg]) directly inside an OSCresponderNode, the distortion appears, whereas using sendBundle within a Routine seems just fine. le sigh.
JM
_______________________________________________
sc-users mailing list
sc-users@...
http://lists.create.ucsb.edu/mailman/listinfo/sc-users