I took a shot at optimizing a bit. the main patch looks good but in addosc there are a few little things (which may add up bc you have 224 of them):
[tabread~]
is taking a control-rate input. So, it isn't doing anything that [tabread]
couldn't do, and have it translated to a signal later down the graph instead. The difference is that [tabread~]
will still process the last input every sample whereas [tabread]
will only output when it gets a new message. (so you'll be doing about samplerate times fewer computations if you have a new input every second)
similarly [+~ ]
and [*~ ]
are more efficient if you use the versions with a control-rate right inlet bc the loops can be vectorized and maybe predicted better. (to do this supply them with a float argument).
generally the arithmetic objects are more efficient than the [expr~]
family. And, [expr~ 1 - $v1]
is also another case of not needing the signal version bc the input is control-rate (after changing it to [tabread]
). Instead you can change it to [1 $1(
going into a [- ]
. (tho in this case idk if it is actually better than [expr 1 - $f1]
bc we also have to process/send the list from the message box.. the main thing is making it control-rate tho)
The final little thing is replacing the division [/ 127]
in the adsr subpatch by multiplication with the reciprocal, bc processors are better at multiplying than dividing. You can do this any time you're dividing by a value that won't change.
hope it helps
addosc.pd
as for locality I think the only way is to use $0 in your arrays like you say.. you might consider making addvoice an abstraction as well. Then you could supply $0 as the argument, and inside supply it as the 2nd argument of [addosc]
with $1, which could then use it as $2 in the [tabread]
s to refer to the grandparent's $0
that way you'd only have to edit 28 [addosc]
s instead of 224