pattrhub shortcomings and a nice crash
I'm somehow underwhelmed by the pattr snakepit of objects. For all its bloat and complexity, it doesn't go to 100%, and can crash.... read on.
In the control patch below, I'm trying to refer, via [pattrhub ::testui], to a remote top-level UI patcher that contains a [pattrmarker testui].
I'd expect pattrhub to also send me changes made to parameters in the remote patch, like pattrstorage can do with @outputmode, but that works only in the remote patch, DUH!
When the remote patch is not open *before*, pattrhub ignores its arg (and you need to resend the "patcher") message, so no loadbang will do, but one needs to devise a send/receive logic where the remote patch says "I'm here now". I'd expect pattrhub to be notified that the pattrmarker is created (by loading the remote patch or creating it), and connect automatically.
Once connected, after closing the remote UI patch, pattrhub crashes when trying to change a remote param:
Thread 0 Crashed:: CrBrowserMain Dispatch queue: com.apple.main-thread
0 com.cycling74.Max 0x00000001018528c6 object_attr_get + 38
1 com.cycling74.Max 0x00000001018993a3 object_attr_getvalueof_imp + 99
2 com.cycling74.Max 0x0000000101853627 object_attr_getobj + 55
3 com.cycling74.pattrhub 0x0000000126dd97c2 pattrhub_resolve_object_impl + 146
4 com.cycling74.pattrhub 0x0000000126dd7ab2 pattrhub_anything + 194
5 com.cycling74.Max 0x000000010187e8e3 typedmess_fun + 371
6 com.cycling74.Max 0x0000000101869bb2 outlet_anything + 1426
7 com.cycling74.Max 0x000000010187e8e3 typedmess_fun + 371
8 com.cycling74.Max 0x0000000101848f9a aeval + 2314
9 com.cycling74.Max 0x000000010184863e atombuf_eval + 142
10 com.cycling74.message 0x0000000107741a17 jmessage_atombuf_eval + 567
11 com.cycling74.message 0x000000010773f68f jmessage_int + 175
12 com.cycling74.Max 0x000000010187c878 outlet_int + 1560
13 com.cycling74.number 0x00000001276dc029 jnumber_mousedragdelta + 409
For the record: I got the additional tip to look at the patcher inspector for the parent and the child's "global patcher name" attribute. the pattrmarker sets the parent's one and then refuses to set the child to the same name when encapsulating.
Thanks, looks like you've found some bugs and oversights, which we'll take a look at. In particular, I think we can improve the automatic registration/unregistration in pattrhub, which probably haven't been significantly updated since the objects were originally added to Max. Obviously, crashes aren't ideal, so keep an eye open for improvements.
As for the global patcher name issue (which tip I gave you on Facebook), I think we can improve how pattrmarker handles name conflicts (looks like it just fails at the moment). I need to think about your expectation that encapsulation of a pattrmarker object moves the global patcher name. We could certainly provide some ways for pattrmarker to inform you when the wish-name doesn't match the real-name, but I don't know if moving the object should automove the name.
Here's why: the pattrmarker object modifies a patcher attribute; if you delete the pattrmarker object entirely, the global patcher name is retained, and in fact, you never even need a pattrmarker object in order to award this name to a patcher, you can just type it in the inspector. This has roots in the evolution of pattrmarker from a 3rd party object/feature to a core object/feature, and that's just how it is. But I don't know if it's appropriate for an encapsulation to change attributes in the parent patcher. On the other hand, the presence of a pattrmarker is a fairly good indication that you're explicitly assigning that attribute using the pattrmarker object mechanism, so it's worth thinking through.
> As for the global patcher name issue (which tip I gave you on Facebook),
thanks indeed, you understood my question and situation better than myself!
> I think we can improve how pattrmarker handles name conflicts (looks like it just fails
> at the moment). I need to think about your expectation that encapsulation of a
> pattrmarker object moves the global patcher name. We could certainly provide
> some ways for pattrmarker to inform you when the wish-name doesn't match the
> real-name, but I don't know if moving the object should automove the name.
Yes, a warning would already be helpful (but could be missed when it is output only when encapsulating... don't know if that name mismatch state could be warned about at each patch load.)
> Here's why: the pattrmarker object modifies a patcher attribute; if you delete
> the pattrmarker object entirely, the global patcher name is retained, and in
> fact, you never even need a pattrmarker object in order to award this name to a
> patcher, you can just type it in the inspector. This has roots in the evolution
> of pattrmarker from a 3rd party object/feature to a core object/feature, and
> that's just how it is. But I don't know if it's appropriate for an encapsulation
> to change attributes in the parent patcher. On the other hand, the presence of a
> pattrmarker is a fairly good indication that you're explicitly assigning that
> attribute using the pattrmarker object mechanism, so it's worth thinking through.
If that's an option, I'd definitely be for making the "global patcher name" attr editable, and make pattrmarker optional. It would make for one less member in that unwieldy zoo of pattr* objects (one less moment of head scratching "what is this good for? do I really need to remember this object?").
While we're rethinking this for simplification options, couldn't the patcher name be defined by the scripting name? That's one thing everyone is already used to, and easy to reach via CMD-'.
Thanks a lot for caring!...
...Diemo
Another crash when setting from OSC, investigating...
Thread 0 Crashed:: CrBrowserMain Dispatch queue: com.apple.main-thread
0 com.cycling74.Max 0x00000001063b48c6 object_attr_get + 38
1 com.cycling74.Max 0x00000001063fb3a3 object_attr_getvalueof_imp + 99
2 com.cycling74.Max 0x00000001063b5627 object_attr_getobj + 55
3 com.cycling74.pattrhub 0x000000011737d7c2 pattrhub_resolve_object_impl + 146
4 com.cycling74.pattrhub 0x000000011737bab2 pattrhub_anything + 194
5 com.cycling74.Max 0x00000001063e08e3 typedmess_fun + 371
6 com.cycling74.Max 0x00000001063cbbb2 outlet_anything + 1426
7 com.cycling74.Max 0x00000001063e08e3 typedmess_fun + 371
8 com.cycling74.Max 0x00000001063e08e3 typedmess_fun + 371
9 com.cycling74.Max 0x00000001063cbbb2 outlet_anything + 1426
10 com.cycling74.Max 0x00000001063e08e3 typedmess_fun + 371
11 com.cycling74.Max 0x00000001063aaf9a aeval + 2314
12 com.cycling74.Max 0x00000001063aa63e atombuf_eval + 142
13 com.cycling74.message 0x000000012b4cba17 jmessage_atombuf_eval + 567
14 com.cycling74.Max 0x00000001063dfb06 outlet_list + 1398
15 com.cycling74.Max 0x00000001063df1b2 outlet_float + 1458
16 com.cycling74.scale 0x000000012bae55f8 scale_float + 856
17 com.cycling74.Max 0x00000001063df3a3 outlet_float + 1955
18 com.cycling74.Max 0x00000001063ddd79 outlet_bang + 1385
19 com.cycling74.Max 0x00000001063ddd79 outlet_bang + 1385
20 com.cycling74.Max 0x00000001063ddd79 outlet_bang + 1385
21 com.cycling74.Max 0x00000001063ddf50 outlet_bang + 1856
22 com.cycling74.Max 0x00000001064db736 trigger_iterate + 86
23 com.cycling74.Max 0x00000001064db5f5 trigger_anything + 37
24 com.cycling74.Max 0x00000001063e08e3 typedmess_fun + 371
25 com.cycling74.Max 0x00000001063cbbb2 outlet_anything + 1426
26 com.cycling74.Max 0x00000001063e08e3 typedmess_fun + 371
27 com.cycling74.Max 0x00000001063cbbb2 outlet_anything + 1426
28 com.cycling74.udpreceive 0x000000012a60229a osc_parse_osc_packet + 1866
29 com.cycling74.udpreceive 0x000000012a601a30 udprecv_clock_tick + 80
Diemo, this is the same crash as above, don't go to any extra effort to isolate it.
If that's an option, I'd definitely be for making the "global patcher name" attr editable, and make pattrmarker optional. It would make for one less member in that unwieldy zoo of pattr* objects (one less moment of head scratching "what is this good for? do I really need to remember this object?").
This is already the case -- the global patcher name attribute is always available to be set, even without a pattrmarker object. The reason it's not synonymous with the patcher's scripting name is that every patcher in a pattr hierarchy has a name for navigation purposes, but you don't generally want those patchers to be available as "pattrmarked" top-level nodes. Also, pattr/scripting names are patcher-local, while pattrmarker names are global.
I'm still thinking about the name-moves-with-pattrmarker-object expectation, but I'm not 100% convinced. In some ways, it's a question of what is easier to document. In any case, the name collision issue needs to be sorted for people using pattrmarker/global patcher name inside of abstractions/poly~/etc.
I've fixed the pattrhub registration issues, though (and thus the crash), and that fix will eventually make it into an updated Max. But I can't say when at this moment...
@Diemo, my mistake, looks like there's a bug in the way the attribute is presented to the inspector so that the field isn't editable if a pattrmarker object is instantiated anywhere. Clearly not ideal.
i guess it' not editable because if you were to change it manually, the next patcher restart would trigger the instantiation of pattrmarker and hence re-change the patcher's scripting name ?
@vichug yeah, that's correct. the next version will still be uneditable, but only if a pattrmarker is in the patcher in question. If there's no pattrmarker providing the name, that field will be editable.
Hi Jeremy, thanks for the clarification of patcher name/scripting name. It makes complete sense.
What do you think about the expectation that pattrhub also output param changes in the remote patch (with an appropriate @outputmode), and thus make it an actual bidirectional hub, not just a control object? That would allow to completely take over (i.e. link to a hw controller) an existing (sub)patch, without having to instrument it by pattrstorage and send objects.
@diemo sounds reasonable to me, but no promises. pattrhub was originally a fairly primitive object which was largely ignored when pattr, pattrstorage and friends became more complicated (since no one seemed to use it very much). I'm definitely open to making it more useful, and most of the infrastructure is available to do so.
Hi again, another occasional pvar crash when closing a patch, don't know if it's related (and thanks for the hopeful response to the pattrhub suggestion, BTW):
Thread 0 Crashed:: CrBrowserMain Dispatch queue: com.apple.main-thread
0 com.cycling74.Max 0x000000010601c115 pvar_free + 213
1 com.cycling74.Max 0x0000000105f803ce freeobject + 190
2 com.cycling74.Max 0x0000000105ef296a jnewobj_free + 26
3 com.cycling74.Max 0x0000000105f803ce freeobject + 190
4 com.cycling74.Max 0x0000000105f7725b object_free + 27
5 com.cycling74.Max 0x00000001060418ef jpatcher_free + 319
6 com.cycling74.Max 0x0000000105f803ce freeobject + 190
7 com.cycling74.Max 0x0000000105f7725b object_free + 27
8 com.cycling74.Max 0x0000000105f736e0 object_method_imp + 352
9 com.cycling74.Max 0x0000000105cc7fcc jwind_close + 1052
10 com.cycling74.Max 0x0000000105f87794 object_method_typed + 148
11 com.cycling74.Max 0x0000000105eec54f jmenuitem_process + 559
12 com.cycling74.Max 0x0000000105eec2fd jmenu_process + 141
13 com.cycling74.Max 0x0000000105e17f4b interface_process + 11
14 com.cycling74.Max 0x000000010636ebec juce::JuceMainMenuHandler::invokeDirectly(int, int) + 60
15 com.cycling74.Max 0x000000010636eb54 juce::MessageManager::AsyncCallInvoker<juce::JuceMainMenuHandler::invoke(juce::PopupMenu::Item const&, int) const::'lambda'()>::messageCallback() + 52
16 com.cycling74.Max 0x000000010624b36d juce::MessageQueue::runLoopSourceCallback(void*) + 269
17 com.apple.CoreFoundation 0x00007fff32adad17 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
18 com.apple.CoreFoundation 0x00007fff32adacbd __CFRunLoopDoSource0 + 108
19 com.apple.CoreFoundation 0x00007fff32abe67b __CFRunLoopDoSources0 + 195
20 com.apple.CoreFoundation 0x00007fff32abdc45 __CFRunLoopRun + 1189
21 com.apple.CoreFoundation 0x00007fff32abd54e CFRunLoopRunSpecific + 455
22 com.apple.HIToolbox 0x00007fff31d1c1ab RunCurrentEventLoopInMode + 292
23 com.apple.HIToolbox 0x00007fff31d1bee5 ReceiveNextEventCommon + 603
24 com.apple.HIToolbox 0x00007fff31d1bc76 _BlockUntilNextEventMatchingListInModeWithFilter + 64
25 com.apple.AppKit 0x00007fff300b377d _DPSNextEvent + 1135
26 com.apple.AppKit 0x00007fff300b246b -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1361
27 com.apple.AppKit 0x00007fff300ac588 -[NSApplication run] + 699
28 org.cef.framework 0x000000010fab43bc base::mac::CxxPersonalityRoutine(int, _Unwind_Action, unsigned long long, _Unwind_Exception*, _Unwind_Context*) + 4764
29 org.cef.framework 0x000000010fab31d3 base::mac::CxxPersonalityRoutine(int, _Unwind_Action, unsigned long long, _Unwind_Exception*, _Unwind_Context*) + 179
30 org.cef.framework 0x000000010fa723bd uhash_compareUnicodeString_69 + 754989
31 org.cef.framework 0x000000010fa3e3fd uhash_compareUnicodeString_69 + 542061
32 org.cef.framework 0x000000010f722d3b __gxx_personality_v0 + 401403
33 com.cycling74.Max 0x0000000105dceb82 MaxCefEventLoopHandler::runMessageLoop() + 18