Msg from Server upon PlayBuf completion?


#1

Hi again. Not trying to spam the forum with questions, but I’m struggling with this one.

Basically I want the server to send me a message when a sample is done playing and include some info (like node number, buffer number and some user-defined variables). The syntax for [Done.kr] looks expensive and awkward. Is there another way?

I’m using 3.7 so I dont think I have access to the easy “Done.freeself” syntax, though I hope I’m wrong on this

edit: Just found NodeWatcher, though its a bit confusing at first. Could this be it?

Thanks,

Ross


#2

Maybe you can keep track of the variables, and use onFree? It’s basically a simpler interface to NodeWatcher.


#3

If you want to send a custom message, SendReply with a trigger that fires on completion is the way to go. Done.kr detects whether some other unit has finished, so:

b = Buffer.alloc(s, 44100, 2);

OSCdef(\demo, { |msg|
	[
		["path", "node ID", "reply ID", "value" /* can have more values */],
		msg
	].flop.do { |pair| "%: %\n".postf(*pair) };
}, '/sampleDone', s.addr);

a = { |bufnum|
	var sig = PlayBuf.ar(2, bufnum),
	doneTrig = Done.kr(sig);
	// [0]: little trick, doneTrig is actually 2 channels; only need 1
	// if it's mono, leave out '[0]'
	SendReply.kr(doneTrig[0], '/sampleDone', [bufnum]);
	FreeSelf.kr(doneTrig);
	sig
}.play(args: [bufnum: b]);

Well… this works in 3.10. I seem to remember in some older versions, Done might not work on multichannel PlayBuf. That was fixed at some point, but I don’t remember if this was before or after 3.7.

Btw, is there a particular reason why you can’t use 3.10? 3.7 is pretty old, and in my experience, 3.10 is a lot more stable than versions from a couple of years ago.

Done.freeSelf isn’t relevant to this question, btw.

hjh


#4

Holy crap, thanks so much to you both.

Im using 3.7 because I’m a sucker I guess, the download page made it seem like SuperNova is pretty important, though obviously I’m not using it if I’m still grappling with stuff like this. I feel like I may need it eventually though if I want to create a sampling system with a lot of polyphony and effects- seems like it could be difficult to realize i need SN later and downgrade back. Hopefully I’m wrong? For now I’ll upgrade.

Thanks so much for the detailed example, I never would have put that together. I’m confused by the ending though: [bufnum: b] ---- doesen’t b point to a buffer itself? I would expect b.bufnum… not saying your wrong of course, just not sure how that all comes together

also… could you please explain the scoping brackets in the OSCDef? Obviously they’re for the flop function, but I don’t understand the relevance of the flop.
copying this in now and messing with it, thanks again

EDIT: I got it to accept my code, but its not doing anything. Take a look?

OSCdef(\demo, { |msg| // Unchanged from original
[
[“path”, “node ID”, “reply ID”, “value”, “value_2” /* can have more values */],
msg
].flop.do { |pair| “%: %\n”.postf(*pair) };
}, ‘/sampleDone’, s.addr);

( // my synthdef
SynthDef(\play_samp, {
arg index, buf, vol, play_len, attack, sustain, release, sel_start, sel_end, rev, start_pos, speed;
var sig, env, doneTrig;

env = vol*EnvGen.kr(Env.new([0, 1, 1, 0], [attack, sustain, release]), doneAction:2);
  doneTrig = Done.kr(env);

SendReply.kr(doneTrig, ‘/sampleDone’, [index, val_2]);

sig = env*PlayBuf.ar(1, buf, 1, startPos:start_pos);
Out.ar(0, sig!2);
}).add;
)

what confuses me most about your [working] code is the lone ‘sig’ on the last line- I dont understand why the system doesent throw it back without a semicolon, and I’m guessing mine isnt working because its lacking this. Does it have to do with being a SynthDef?

Thank you


#5

First: Could I ask you to use backticks for code blocks? The website replaced all of your quotes with curved begin/end quotes. So I pasted your code into SC and it doesn’t recognize the strings as strings, and then it takes extra time (4 find/replace cycles!) to make your code runnable.

Code != text, and code != quoted material.

```
code here
```

In your code: it’s a subtle problem, but Done works with UGens that have a done flag. EnvGen has a done flag. But env is not an EnvGen. It’s a *.

env = EnvGen.kr(...);
level = vol * env;
doneTrig = Done.kr(env);

I’m gonna be a bit opinionated and say that I don’t think supernova is that important. Also, it has a few nasty bugs (and those bugs are beyond me to fix, because supernova’s C++ style is extremely advanced, and they’re not getting a lot of attention from other developers either… so you could say, in terms of maintenance effort, other developers don’t really feel supernova is that important either).

I used it successfully in one composition. Then, a few months later, I tried to use it in a live set and encountered 1/ frequent crashes during a section transition, 2/ Ringz sporadically producing garbage output (which didn’t happen in scsynth), and a couple of other issues that I forget now.

So, forgive me, but my opinion of supernova is rather low. Don’t let that hold you back from upgrading.

Thanks so much for the detailed example, I never would have put that together. I’m confused by the ending though: [bufnum: b] ---- doesen’t b point to a buffer itself? I would expect b.bufnum… not saying your wrong of course, just not sure how that all comes together

That’s a good question – you’re paying attention!

As a convenience, many objects can convert themselves into an OSC-friendly representation using asControlInput. Buffer has:

	asControlInput { ^this.bufnum }

If you’re really curious, the execution flow is:

  1. Synth processes its argument list with asOSCArgArray.
  2. Each element in the argument array does asOSCArgEmbeddedArray.
  3. There are a few special cases for asOSCArgEmbeddedArray, but almost everything, including Buffer objects, go through Object’s method:
    	asOSCArgEmbeddedArray { | array| ^array.add(this.asControlInput) }
    
    … and that’s where the buffer gets converted into its bufnum.

could you please explain the scoping brackets in the OSCDef? Obviously they’re for the flop function, but I don’t understand the relevance of the flop.

flop interleaves elements from several arrays.

So I built an array that contains two arrays:

  1. An array of names.
  2. An array of values.

flop turns those into an array of pairs: [ [ name0, value0 ], [ name1, value1 ], ... ]. Then it’s easy to iterate over the list of pairs and print them out in a way that makes sense to people.

hjh