Object dependants & pub/sub

I’m trying to create a queue of Pbinds that will be triggered one after the other - so when (if) one finishes it will send a message that will start the next (if there is one)

Whether or not that’s a good idea - I’m trying to figure out how to use the depandants/changed/update features of Object - and I can’t find any examples.

I’m familiar with the pub/sub pattern in other languages, but SC’s implementation is eluding me. Are there any examples?

why not a Pseq of Pbinds ?

Pseq([ 
		Pbind(*[note:Pseq([ 1,2 ],2),dur:0.6] ),
		Pbind(*[note:Pseq([ 3,4 ])])
]).play
)```

because it needs to change dynamically - it’s event driven.

Think of it like a sequencer.

How about Pdefs? They have a condition method. And since it’s a pattern proxy you can update the code inside while things are running.

There is also Pfsm.

To @semiquaver’s point - I’m not sure I understand your objective, as the Pseq will play each Pbind through in series, and once a Pbind is finished, it will give control back to the Pseq, which will select the next Pbind, or finish playing.

I’m already using Pdefs (actually EventPatternProxy),and these are definitely interesting ideas - condition was new to me, and there are always lots of ways to do things in SuperCollider.

But over and above the way to solve this specific problem, I’d really like to understand how to use SC’s pub/sub. It’s a powerful pattern and it has wide application.

p = Pbind(\degree, Pseries(0, 1, 8), \dur, 0.5);

(
var watcher;

q = p.play;  // an EventStreamPlayer

// q, not p, because you're watching the *player* (not the pattern)
watcher = SimpleController(q)
.put(\stopped, {
	watcher.remove;  // mandatory cleanup
	"here is where you'd do whatever you need".postln;
});
)

hjh

I just took a shot at figuring out Object dependency… I agree it’s mad confusing.

It appears that the instance methods involved with dependency are primarily responsible for making global changes to Object.dependantsDictionary.

after thisProcess.recompile there are two dependants… s.boot will make a third.

‘update’ takes two arguments, yet ultimately does nothing with them…

doc.sccode.org/Search.html#update

http://doc.sccode.org/Classes/ObjectGui.html#-update

.changed calls .update

If you figure out those two, then you figure out the interface.

Godspeed.

aha! Thank you! This looks like what I need.

Still curious about what I’m missing the Object’s “update” method - it doesn’t seem to do anything.

right!
Object takes care of maintaining a Dictionary of IdentitySets - so any objects that use pub/sub can maintain a list, without every single object having the overhead - so far so reasonable, but update does nothing!

	update { arg theChanged, theChanger;	// respond to a change in a model
	}

are you supposed to override this? is it only usable in classes implement their own override?

It’s not really documented but yes, I believe that the idea is that you implement “update” for your own classes. At least, that’s how I’ve been using it.

Update is used if you want to implement your own subscriber. It is called on each of the object’s dependents, not on the object itself. When you are using something like SimpleController - that simple controller gets added to the object’s dependants and update is being called on the SimpleController instance (and update is implemented for SimpleController).

The Connection quark builds some abstractions on top of the changed/update functionality, and includes pub-sub.

// Quarks.install("Connection")

Pdef(\test1, Pbind(
	\degree, 0
));

Pdef(\test2, Pbind(
	\degree, 3
));

UpdateChannel(\test).connectTo(
    Pdef(\test1).methodSlot("play()"),
    Pdef(\test2).methodSlot("play()")
);

UpdateChannel(\test).changed()

// UpdateChannel(\test).releaseDependants();

Or with a named connections…

UpdateChannel(\test).connectToUnique(
    \patternConnections,
    Pdef(\test1).methodSlot("play()"),
    Pdef(\test2).methodSlot("play()")
);

// UpdateChannel(\test).connectToUnique(\patternConnections) // nothing objects to connect to, previous connections are freed

Yes, and yes.

update is an example of a “protocol” – a set of messages that are expected to behave consistently over a wide range of objects.

It’s quite common for a widespread protocol to implement no-op methods at the top level (see also Object:stop – you wouldn’t see stop {} and assume that stop is somehow undefined or meaningless elsewhere).

The meaning of this is, “objects may safely ignore this message without throwing an error.”

Object:update isn’t the ultimate destination of this message. E.g., SimpleController:update does use the arguments.

hjh

1 Like