[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [sc-users] Notes and observations from a large SC project
On 29 Jul 2009, at 01:42, scott wrote:
Can you be more specific about what you'd like server side? Some
things are already in place, like trace and dumpTree.
trace and dumpTree provide most of what is needed. As I mentioned
when talking about trace below, getting that info as an object (even
just as a string that could be parsed) would make it a whole lot
more useful.
We've had it in mind to make query return an event. Just couldn't
quite decide a format! Trace could do something similar.
Regarding server execution order, there's currently no way I know of
to debug exactly what order each osc message is being processed in.
It's easy enough to figure it out with simple sets of messages, but
when you're sending multiple bundles, spread between many classes,
it becomes tougher. dumpOSC gets part of the way there, but when you
care about the order things are actually executed (not sent),
there's no solution I know of.
Hmm. Well ultimately with flexibility comes responsibility, and it
comes down to bookkeeping I suppose. They execute either in the order
they arrive, or according to their timestamps if bundled. When
asynchronous actions complete (as oppose to execute) is another matter
of course, but if you want that flexibility, I'm not sure of an easy
way around it. Since most commands are synchronous though this is
usually pretty straightforward.
Theoretically one might have a more complicated server side scheduler
which operated like a Routine, waiting on completion of some things.
This would not really be different than what we have now with sync.
There are simple paradigmatic ways of getting things done. But are
you concerned with node order or asynchronous actions?
The first can be dealt with with targets and add actions. Groups
can also be helpful. If you're really concerned wrap things in a
bundle to guarantee order. e.g. s.bind({thing1; thing2; ...});
The latter can be dealt with using sync as you said. Perhaps it's
that it's not clear which things are asynchronous?
Mainly asych actions. Bundling is useful, but it doesn't guarantee
order for asynchronous actions.
s.makeBundle(nil, {
m = { Out.kr( 100, [100,200,300] ) }.play;
n = { |a,b,c| Mix( SinOsc.ar( [a,b,c] ) ) }.play;
n.map( \a, 100 );
n.map( \b, 101 );
n.map( \b, 102 );
});
Fails. You can split it into two bundles to get it to work again:
s.makeBundle(1-0.1, {
m = { Out.kr( 100, [100,200,300] ) }.play;
n = { |a,b,c| Mix( SinOsc.ar( [a,b,c] ) ) }.play;
});
s.makeBundle(1, {
n.map( \a, 100 );
n.map( \b, 101 );
n.map( \b, 102 );
});
But it stops working if you embed that code into a bundle:
s.makeBundle(nil, {
s.makeBundle(1-0.1, {
m = { Out.kr( 100, [100,200,300] ) }.play;
n = { |a,b,c| Mix( SinOsc.ar( [a,b,c] ) ) }.play;
});
s.makeBundle(1, {
n.map( \a, 100 );
n.map( \b, 101 );
n.map( \b, 102 );
});
})
We ran into this a lot - we would build a class that abstracted a
bunch of synths/busses/etc, test it, and get it initializing just
fine. But later, if we tried to initialize it inside
another .makeBundle()
s.makeBundle(nil, {
spatializer.play();
someSynth.play( spatializer );
})
It would stop working again. Debugging, at that point, got very
difficult.
completion messages can be used sometimes, but (a) not everything
has these, and (b) sequencing 7 or 8 steps like this is difficult.
Ultimately, it would have best for us to separate all our major
initialization steps with s.sync()'s, and then made sure all
initializations happened inside a Routine. One major reason I was
hesitant about this was that it seemed like it would be difficult
when using multiple servers on diff. machines - but it looks like
BroadcastServer supports sync'ing to multiple servers appropriately.
Perhaps, then, the solution is some more detailed docs/examples for
Server.sync, and more explicit documentation about which server
actions are synchronous vs asynchronous.
I see what's happening, and I agree it's counterintuitive in your
example. Here's one solution:
s.makeBundle(nil, {
m = { Out.kr( 100, [100,200,300] ) }.play;
n = { |a,b,c| Mix( SinOsc.ar( [a,b,c] ) ) }.play;
s.sync;
n.map( \a, 100 );
n.map( \b, 101 );
n.map( \b, 102 );
});
The asynchronous bit is loading the SynthDefs for the two synths. You
are right that it is good practice to do as much initialisation (esp
async) as possible at the start in a Routine. This can often require
only one sync at the end. The above problem could be avoided by
predefining your defs. That approach is not necessary, of course, but
it's built into how the server works, def first then synth. This is an
efficiency tradeoff.
Another way would be this:
s.makeBundle(nil, {
m = { Out.kr( 100, [100,200,300] ) }.play;
n = { |a,b,c| Mix( SinOsc.ar( [a,b,c] ) ) }.play(args: [\a,
\c100, \b, \c101, \c, \c102]);
});
Map on creation. In that version you don't even really need the bundle.
S.
- Scott
_______________________________________________
sc-users mailing list
info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: https://listarc.bham.ac.uk/marchives/sc-users/
search: https://listarc.bham.ac.uk/lists/sc-users/search/
_______________________________________________
sc-users mailing list
info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: https://listarc.bham.ac.uk/marchives/sc-users/
search: https://listarc.bham.ac.uk/lists/sc-users/search/