say we have a patch like this:
[phasor~] |
[sig~ 1] [osc~ 20] [*~ 200] | | | [+~ 5] [osc~] [sig~ 10] [osc~] | ______| | _______| | | | | [*~] [*~] | _____________| | | [+~] |
| [*~ 2] |/ [dac 1]so we build an acyclic dependency graph like this, branching wherever a signal line splits or merges:
[dac] |
| 0 |/ 1 |
2 3 |\ |
4 5 6 7in this case the edge 2-4 is the partial chain [sig~ 1]--[+~ 5], edge 2-5 is the partial chain [osc~ 20]--[osc~], and so on.
so: we need a queue of partial chains, represented by edges of the dependency tree, and a collection of worker threads which pulls partial chains off the queue and processes them.
using the example above, we push edges 2-4, 2-5, 3-6, and 3-7 on to our process queue and process them in parallel. once both 2-4 and 2-5 have been processed, ie all dependencies for for node 2 have been satisfied, we can push 1-2 on to our process queue. once both 3-6 and 3-7 have been processed, we can push 1-3 on to our process queue. once both 1-2 and 1-3 have been processed, we push [dac]-1 and 0-1 on to our queue. once 0-1 is done we push [dac]-0 on to our queue.
the only bits of shared memory here are the partial chain queue and the buffers at each node where splitting or merging has to happen.
does this make sense?
more or less: both pd and nova compile the dsp graph to a chain (topological sorted graph), which is then executed by a rate-monotonic scheduler driven by the audio hardware. this is done for performance reasons (especially caching!) ... afaict, the performance benefits over a dynamic scheduling are quite significant ... for a dual-processor architecture, maintaining a process queue is probably too much of an overhead ...
and of course you instead of using shared memory, the target port would have to fetch the data from the source ports in order in order to avoid locks ...
tim
-- tim@klingt.org ICQ: 96771783 http://tim.klingt.org
The aim of education is the knowledge, not of facts, but of values William S. Burroughs