[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/