Loadbang, patcherargs and pattr

Mattijs's icon

Hi maxppl,

I am currently working on a set of abstractions that during their initialization depend on the state of other objects. It has been said before that there is no guarantee for the initialization order, but since I need it so hard I'm nontheless trying to figure out the order of execution on load. I thought it might be interesting for you to have a look at the results of my little research and I would greatly appreciate any feedback and additions you may have.

For now, the initialization order looks like this:

1) load objects
2) execute loadbangs
    inside out, so loadbangs in a child patcher fire before loadbangs in its parent patcher
3) execute patcherargs and load stored values into pattr and output them
    no specified order

It is especially this last 'no specified order' that I coudn't live with for my project so I took a closer look at it. I found out that the order depends on the moment that max encounters an object when unfolding the object tree. The patch below illustrates this. You can save it and reload it, then look at the prints in the max window.

Max Patch
Copy patch and select New From Clipboard in Max.

In the text representation of the patch, the lines that define the loadbangs come first, then the patcherargs, then the pattrs. When I load this patch, the max windows says

loadbang: child
loadbang: parent
patcherargs: parent
patcherargs: child
pattr: parent
pattr: child

Now cut the subpatcher pattrTest and paste it back to the same location. When you look at this patch in text format, you'll see that the lines defining the pattrs have moved above the definition of the other two subpatchers. When I reload the patch, I get

loadbang: child
loadbang: parent
pattr: parent
pattr: child
patcherargs: parent
patcherargs: child

The same holds when you cut and paste the 'child' patcher in the patcherargsTest object. The prints then look like this:

loadbang: child
loadbang: parent
pattr: parent
pattr: child
patcherargs: child
patcherargs: parent

I believe this illustrates the way the initialization is currently ordered, although I assume something will be changed to this system in future releases. For now I will have to depend on this though so I can only hope the new system will match the way I use the current one as closely as possible ;)

Best,
Mattijs

Drsbaitso's icon

loadbang > uzi 999 > s loadorder > r loadorder > route X

that's how i "order" things at load time (or init, can't remember what we're calling it)...

Mattijs's icon

:) I see.

This evening (+1 GMT) I'll try to provide a neat example of a situation where you really need this loadbang, patcherargs and pattr behaviour.

Mattijs

Peter Castine's icon

On 25-Sep-2006, at 13:24, James Aldridge wrote:

> loadbang > uzi 999 > s loadorder > r loadorder > route X

A useful technique. I was wondering what you do when you have to
insert an event in the middle of an existing chain of events, then
the old BASIC trick of incrementing line numbers by 10 occured to me.
To insert between events 1 (10) and 2 (20) just use 15.

So I learned something useful from BASIC after all.

However, any defers or deferlows in the processing order may throw a
spanner in the works.

-- P.

-------------- http://www.bek.no/~pcastine/Litter/ -------------
Peter Castine +--> Litter Power & Litter Bundle for Jitter
Universal Binaries on the way
iCE: Sequencing, Recording &
Interface Building for |home | chez nous|
Max/MSP Extremely cool |bei uns | i nostri|
http://www.dspaudio.com/ http://www.castine.de

Trond Lossius's icon

Hi,

I know that the triggering of patcherargs is deferlowed, so it is
correct that it will execute after all loadbangs have gone of. I suspect
that pattr is the same. I would only use one patcherargs in a patch.
Also it is worth noting that patcherargs sens out the message "done"
from right outlet once it has finished dumping all that it is supposed
to. This can be used to ensure that the rest of the messages are sent in
proper order to where they are meant to go.

If you need to be 100% sure about sequence of triggering between many
objects, I would use one central loadbang and trigger. An alternative
solution would be to use a text file, xml or similar, read it in, and
then dump it one line at a time.

Best,
Trond

Mattijs Kneppers wrote:
> Hi maxppl,
>
> I am currently working on a set of abstractions that during their initialization depend on the state of other objects. It has been said before that there is no guarantee for the initialization order, but since I need it so hard I'm nontheless trying to figure out the order of execution on load. I thought it might be interesting for you to have a look at the results of my little research and I would greatly appreciate any feedback and additions you may have.
>
> For now, the initialization order looks like this:
>
> 1) load objects
> 2) execute loadbangs
>     inside out, so loadbangs in a child patcher fire before loadbangs in its parent patcher
> 3) execute patcherargs and load stored values into pattr and output them
>     no specified order
>
> It is especially this last 'no specified order' that I coudn't live with for my project so I took a closer look at it. I found out that the order depends on the moment that max encounters an object when unfolding the object tree. The patch below illustrates this. You can save it and reload it, then look at the prints in the max window.
>
> #P window setfont "Sans Serif" 9.;
> #P window linecount 1;
> #N vpatcher 119 228 427 423;
> #P window setfont "Sans Serif" 9.;
> #P newex 27 66 40 9109513 t parent;
> #P newex 27 89 66 9109513 print loadbang;
> #P newex 27 44 45 9109513 loadbang;
> #N vpatcher 25 70 221 262;
> #P window setfont "Sans Serif" 9.;
> #P newex 57 79 33 9109513 t child;
> #P newex 57 102 66 9109513 print loadbang;
> #P newex 57 57 45 9109513 loadbang;
> #P connect 0 0 2 0;
> #P connect 2 0 1 0;
> #P pop;
> #P newobj 80 44 35 9109513 p child;
> #P connect 1 0 3 0;
> #P connect 3 0 2 0;
> #P pop;
> #P newobj 22 36 71 9109513 p loadbangTest;
> #N vpatcher 119 228 427 423;
> #P window setfont "Sans Serif" 9.;
> #P newex 27 66 40 9109513 t parent;
> #P newex 27 89 78 9109513 print patcherargs;
> #P newex 27 44 57 9109513 patcherargs;
> #N vpatcher 25 70 221 262;
> #P window setfont "Sans Serif" 9.;
> #P newex 57 79 33 9109513 t child;
> #P newex 57 102 78 9109513 print patcherargs;
> #P newex 57 57 57 9109513 patcherargs;
> #P connect 0 0 2 0;
> #P connect 2 0 1 0;
> #P pop;
> #P newobj 123 44 35 9109513 p child;
> #P connect 1 0 3 0;
> #P connect 3 0 2 0;
> #P pop;
> #P newobj 22 58 83 9109513 p patcherargsTest;
> #N vpatcher 297 466 510 649;
> #P window setfont "Sans Serif" 9.;
> #P newex 21 69 40 9109513 t parent;
> #P newex 21 91 48 9109513 print pattr;
> #P message 63 47 36 9109513 value1;
> #P newex 21 47 40 9109513 pattr;
> #X prestore 1 0 value1;
> #P objectname u124000017;
> #N vpatcher 15 55 239 230;
> #P window setfont "Sans Serif" 9.;
> #P newex 50 72 33 9109513 t child;
> #P newex 50 94 48 9109513 print pattr;
> #P message 92 50 36 9109513 value1;
> #P newex 50 50 40 9109513 pattr;
> #X prestore 1 0 value1;
> #P objectname u196000018;
> #P connect 1 0 0 0;
> #P connect 0 0 3 0;
> #P connect 3 0 2 0;
> #P pop;
> #P newobj 123 75 35 9109513 p child;
> #P objectname "sub patch";
> #P connect 2 0 1 0;
> #P connect 1 0 4 0;
> #P connect 4 0 3 0;
> #P pop;
> #P newobj 22 80 53 9109513 p pattrTest;
> #P objectname pattrTest;
> #P window clipboard copycount 3;
>
> In the text representation of the patch, the lines that define the loadbangs come first, then the patcherargs, then the pattrs. When I load this patch, the max windows says
>
> loadbang: child
> loadbang: parent
> patcherargs: parent
> patcherargs: child
> pattr: parent
> pattr: child
>
> Now cut the subpatcher pattrTest and paste it back to the same location. When you look at this patch in text format, you'll see that the lines defining the pattrs have moved above the definition of the other two subpatchers. When I reload the patch, I get
>
> loadbang: child
> loadbang: parent
> pattr: parent
> pattr: child
> patcherargs: parent
> patcherargs: child
>
> The same holds when you cut and paste the 'child' patcher in the patcherargsTest object. The prints then look like this:
>
> loadbang: child
> loadbang: parent
> pattr: parent
> pattr: child
> patcherargs: child
> patcherargs: parent
>
> I believe this illustrates the way the initialization is currently ordered, although I assume something will be changed to this system in future releases. For now I will have to depend on this though so I can only hope the new system will match the way I use the current one as closely as possible ;)
>
> Best,
> Mattijs
> --
> http://www.samplemadness.nl/smadsteck
> SmadSteck - Interactive audiovisual sampling soft- and hardware
>
>

vade's icon

I just use something like loadbang -> bang first part of patch to
initialize, sends a bang when its done initing, which triggers a bang
to the next module, which notifies the next once its done loading,
etc. This way I can be certain of ordering within a module, and what
order the modules load in.

v a d e //

www.vade.info
abstrakt.vade.info

On Sep 25, 2006, at 8:20 AM, Peter Castine wrote:

> On 25-Sep-2006, at 13:24, James Aldridge wrote:
>
>> loadbang > uzi 999 > s loadorder > r loadorder > route X
>
> A useful technique. I was wondering what you do when you have to
> insert an event in the middle of an existing chain of events, then
> the old BASIC trick of incrementing line numbers by 10 occured to
> me. To insert between events 1 (10) and 2 (20) just use 15.
>
> So I learned something useful from BASIC after all.
>
> However, any defers or deferlows in the processing order may throw
> a spanner in the works.
>
> -- P.
>
> -------------- http://www.bek.no/~pcastine/Litter/ -------------
> Peter Castine +--> Litter Power & Litter Bundle for Jitter
> Universal Binaries on the way
> iCE: Sequencing, Recording &
> Interface Building for |home | chez nous|
> Max/MSP Extremely cool |bei uns | i nostri|
> http://www.dspaudio.com/ http://www.castine.de
>
>

Mattijs's icon

Quote: Trond Lossius wrote on Mon, 25 September 2006 14:20
----------------------------------------------------
> Hi,
>
> I know that the triggering of patcherargs is deferlowed, so it is
> correct that it will execute after all loadbangs have gone of. I suspect
> that pattr is the same.

It seems to me that triggering of patcherargs and pattr is not only 'deferlowed', it is also not managed the way triggering of loadbangs is. loadbangs are always triggered inside out, regardless of the position of the subpatcher in the patch structure.

When you try this...

-----------
The same holds when you cut and paste the 'child' patcher in the patcherargsTest object. The prints then look like this:

loadbang: child
loadbang: parent
pattr: parent
pattr: child
patcherargs: child
patcherargs: parent
----------

...for the content of the loadbangTest patcher (so not with the child patcher but the rest), the order will not change. It will still be

loadbang: child
loadbang: parent

even though the definition of the child patcher is now below the rest of the loadbangsTest content if you view the patch as text.

Mattijs

Mattijs's icon

Quote: Trond Lossius wrote on Mon, 25 September 2006 14:20
----------------------------------------------------
> If you need to be 100% sure about sequence of triggering between many
> objects, I would use one central loadbang and trigger. An alternative
> solution would be to use a text file, xml or similar, read it in, and
> then dump it one line at a time.
>
> Best,
> Trond
>

Quote: vade wrote on Mon, 25 September 2006 15:33
----------------------------------------------------
> I just use something like loadbang -> bang first part of patch to
> initialize, sends a bang when its done initing, which triggers a bang
> to the next module, which notifies the next once its done loading,
> etc. This way I can be certain of ordering within a module, and what
> order the modules load in.

I agree, both techniques work if you assume that all the content of the patch is loaded -at once-, but not if other pieces are loaded 1) during 'runtime' or 2) during the editing of the patch (in which case you won't want to restart your entire project patch every time you insert an abstraction)

Mattijs's icon

As promised, this is what I am working on. I have only 15 minutes to post this reply, otherwise I wouldn't have kept my promise ;)

I have no time to explain it (maybe I will do so tomorrow) but anyone that has experience with OSC will recognize what I'm after.

it's a bit too much to paste here and you need jasch's strcmp2 external so I put it all in a zip:

oh, now I realize I didn't include the mac version of strcmp2. I don't have a prog to read dmg files here... got only 5 minutes left... hmm I'm afraid you will have to download it yourself at http://www.jasch.ch/dl/

One more comment, please ignore
• error: pattr: failed to bind to target
I mis-used pattr on purpose. Probably my next post (tomorrow) will be about that error message ;)

Cheers,
Mattijs

Stefan Tiedje's icon

Mattijs Kneppers wrote:
> I believe this illustrates the way the initialization is currently
> ordered, although I assume something will be changed to this system
> in future releases. For now I will have to depend on this though so I
> can only hope the new system will match the way I use the current one
> as closely as possible ;)

I would not hope that this will remain, if you depend on this, be
certain that your patches WILL break in the future. It might be a pain,
but you need to pass an order differently than relying on the bang
order. You will find a way to do it. Some suggestions you could build on:

Use buddy, to force an order of several events within one patch, use the
done message of patcherargs instead of loadbangs. To store information
temporarily use [zl reg]...
Pass the information of certain initialisation states to other places
with send/receive.
The big advantage of such a construction is, you can reinitialise your
patch also later...

You can rely on those methods, that will make your patches more solid.

Stefan

--
Stefan Tiedje------------x-------
--_____-----------|--------------
--(_|_ ----|-----|-----()-------
-- _|_)----|-----()--------------
----------()--------www.ccmix.com

lists@lowfrequency.or's icon

I use a system like vade's - think of loading order like a data
structure, you could use a "linked list" approach.

Or better yet, do it through javascript (or coll) so you have a list
of all events that need to load, in one textual list, somewhere.

-ev

On Sep 26, 2006, at 6:06 AM, Stefan Tiedje wrote:

> Mattijs Kneppers wrote:
>> I believe this illustrates the way the initialization is currently
>> ordered, although I assume something will be changed to this system
>> in future releases. For now I will have to depend on this though so I
>> can only hope the new system will match the way I use the current one
>> as closely as possible ;)
>
> I would not hope that this will remain, if you depend on this, be
> certain that your patches WILL break in the future. It might be a
> pain, but you need to pass an order differently than relying on the
> bang order. You will find a way to do it. Some suggestions you
> could build on:
>
> Use buddy, to force an order of several events within one patch,
> use the done message of patcherargs instead of loadbangs. To store
> information temporarily use [zl reg]...
> Pass the information of certain initialisation states to other
> places with send/receive.
> The big advantage of such a construction is, you can reinitialise
> your patch also later...
>
> You can rely on those methods, that will make your patches more solid.
>
> Stefan
>
> --
> Stefan Tiedje------------x-------
> --_____-----------|--------------
> --(_|_ ----|-----|-----()-------
> -- _|_)----|-----()--------------
> ----------()--------www.ccmix.com
>

jln's icon
Mattijs's icon

Thanks for all your reactions!

FWIW, this is not the usual 'how do I order my loadbangs' issue.

The point is, as I might be able to explain a little better today, that I want to add abstractions while I'm editing.
1) These abstractions have to initialize -themselves-. This has to happen without the necessity of retriggering the onload procedure of the whole patch.
2) The abstractions depend on information from previously inserted abstractions during their initialization.
3) When the whole patch is reloaded, all abstractions must still fit together.

With the OscTree objects I provide an example where this behaviour is necessary. I hope you agree that these particular abstractions can be pretty useful..

Cheers,
Mattijs

Mattijs's icon

Hi again,

I updated the example patches to clear stuff up:
http://www.oli.tudelft.nl/avdl1064/OscTreeV2.zip

again I only included the windows version of the strcmp2 external, if you work on mac you can download it from http://www.jasch.ch/dl/

To understand the power of this concept, open OscTree.pat and try this:

1) tweak the cutoff parameter. You'll see that its OSC path automatically leads all the way to the OscNode object
2) create an object [TS.OscBranch Subtractive] in subpatch deep3
3) change /MonsterSynth/Voice1/FilterBank1/Cutoff to /MonsterSynth/Voice1/Subtractive/FilterBank1/Cutoff
4) tweak the cutoff parameter: it is still connected

I hope this explains a little better..

Regards,
Mattijs

vade's icon

There is no reason that the two techniques need to be mutually
exclusive. :)

v a d e //

www.vade.info
abstrakt.vade.info

On Sep 26, 2006, at 5:28 PM, Mattijs Kneppers wrote:

>
> Thanks for all your reactions!
>
> FWIW, this is not the usual 'how do I order my loadbangs' issue.
>
> The point is, as I might be able to explain a little better today,
> that I want to add abstractions while I'm editing.
> 1) These abstractions have to initialize -themselves-. This has to
> happen without the necessity of retriggering the onload procedure
> of the whole patch.
> 2) The abstractions depend on information from previously inserted
> abstractions during their initialization.
> 3) When the whole patch is reloaded, all abstractions must still
> fit together.
>
> With the OscTree objects I provide an example where this behaviour
> is necessary. I hope you agree that these particular abstractions
> can be pretty useful..
>
> Cheers,
> Mattijs
> --
> http://www.samplemadness.nl/smadsteck
> SmadSteck - Interactive audiovisual sampling soft- and hardware

Mattijs's icon

Quote: vade wrote on Tue, 26 September 2006 23:42
----------------------------------------------------
> There is no reason that the two techniques need to be mutually
> exclusive. :)
>
>

Ah, that's right. Of course I enjoy seeing all these loading order techniques. I especially like the linked-list style loading, even more because I think it is good practice to always actively monitor the moment that a part of a patch finished loading (or doing any other intensive task). The technique I discussed is of a different genre though..

hepi's icon

I hope I can revive this discussion,
I haven't read all of it, but I get a feeling that the basic load order is not right.

It seems trivial that patcherargs should behave like constructor arguments of an object. Thus, an object should be able to be used before it finishes it's construction.

The way it works now, If Patcher A has an abstract patcher B nested in it. And patcher B object is passed arguments through patcherargs. And in patcher A we send a message to B during the load bang, we actually activate B before it finished it's construction, leading to unexpected results.

It seems very cumbersome to use patcherargs 'done' message.

I think the simplest solution is to change the behaviour of patcherargs to act as a constructor (and of course there will have to be a backward compatibility flag which is turned on by default).

Anyone from Max team care to comment on this? Explain the reasoning for the current load order?

hepi's icon

Actually,
What I suggested can easily be implemented.
In an Abstract patch if any input would first bang the patcherargs before forwarding any message, then the patcherargs would serve as constructor arguments.

Easy workaround (-:

hepi's icon

BUG BUG !!
The workaround doesn't always work, because of a BUG in patcherargs.

Scenario:
-------------
When an abstract patcher is instantiated via script, or by creating an object and typing the abstract patcher name with args and attributes (or deleting the object and using ctrl+z),
and within that abstract patcher there is a loadbang object connected to patcherargs object,
then when the loadbang bangs the patcherargs object, empty args and attributes are sent tout.
(only later when the patcherargs object it triggered by Max, then the actuall args and attributes are sent)

woodslanding's icon

Am I to understand from this thread that the best way to tell when a max patch has finished loading is by use of the 'done' feature in patcherargs? Or is there a better way?

woodslanding's icon

I have a different idea for startup, and wanted to run it by wiser heads than mine. I'm thinking of controlling startup behaviour more proactively by creating my app piece by piece either using javascript or pcontrol/load. I would just open an initialization maxpat which would create all my patches in a specific order.

I ran into the problem listed above where every time I edited anything, I had to rerun my loading routine to get everything working again. And now testing individual components has become super tricky--everything is dependent on the startup mechanism.

but maybe the patcherargs bug will be an issue for me, as it sounds like that will be the best way to decide when to load the next patch.??

Can anyone comment on the wisdom of this kind of startup? Any thoughts on using js vs. pcontrol? It seems like with pcontrol, I'd end up with discrete patches, and with js, they'd all be created as subpatches in the master patch. Is there a problem with the previous method if I'm creating a standalone? I guess my js would need to delete everything it created on shutdown. Not sure how to shutdown a bunch of discrete patches. Just tell max itself to quit?

Any suggestions/thoughts welcomed!

-eric

woodslanding's icon

Well, fwiw it did not work well for me. Froze up the startup, and took 10 minutes!

Back to % based loading. I just decided I need to create a testbed object that contains a minimum of support for testing a specific object independent of the project, including the initialization methods.