> unfortunately, this is not a trivial issue.
>
> dynamically changing the signal graph is possible (actually, i had an
> implementation of that in nova). do the topological sorting in the
> background and you are fine.
>
> the tricky part are implicit dependencies. see this trivial patch:
> |adc~|
> |
> |send~ foo|
>
> |receive~ foo|
> |
> |dac~|
>
> it execution order is ambiguous. either (a) adc-send-receive-dac or
> (b) receive-dac-adc-send. the actual execution order depends on the
> implementation. the case (b) introduces one sample block of latency between
> send and receive, (a) doesn't introduce any latency.
> without the loss of generality, lets assume that the actual order of the dsp
> graph is (b). now you add a connection between adc~ and dac~. the
> topological sorting of the dsp graph may come to the execution order (a).
> adding the connection, you change the layout of the signal graph, changing
> the order of send~ and receive~ and therefore its semantics. you actually
> loose one sample block and therefore have an audio dropout.
>
> if there are any possibilities to circumvent this issue, i haven't found
> any. for special cases, it works, but whenever implicit dependencies have to
> be taken into account, things are getting very messy. if you want to have
> dynamically changing signal graphs, don't use max-like languages. it is not
> a problem of the implementation, it is a problem of the programming model in
> general! if you need dynamically changing signal graphs, you should use a
> system, that is designed for this use case.
The standard way of dealing with this problem is probably the same as
the way one deals with the analogous problem with delread~/delwrite~.
I attached a patch -- if you embed each of the object instances in
question within a subpatch and connect the subpatches in the order you
want, you'll force the execution order. This little patch is pretty
stupid because it looks like it ignores the reasons for needing to use
send~/receive~ in the first place (that is, because you're using
send~/receive~ AND a connection in the same place). However, I've
found it's not that bad if I'm using it in a really large patch, as
long as I keep things hierarchical and modular - the hierarchy can
help with forcing execution order cleanly, and making things modular
makes it easier to do more of it at once.
Doing it dynamically is a whole other issue, though (and the point of
this thread) -- if I really need a dynamic graph I'll usually use
supercollider instead, although sometimes you can fake it in Pd by
hard-coding and instantiating everything you need ahead of time if
it's simple enough, and then just switch~ing the correct possibility
on and the others off when appropriate; a waste of resources.
Matt