OSC address parsing (the easy way ;-)
Hi there,
I'm trying to extract the first part of an OSC address using the CNMAT odot package and found a complicated solution and guess I am missing the easy one.
Example : given the OSC message "/foo/note 60", I try to get "foo", as this part of the OSC message can vary.
I thought [o.route] or something similar should have a mechanism to extract the parts of the address by an index e.g., but I don' see it.
Hence I implemented it via [o.expr.codebox] (see the attached patcher), but I think there should be an easier way to do it.
Any ideas?
strip slash and route whatever you want
iirc, [regexp / @substitue " "] caused some nasty memory leaks back in the day, and this forum helped me come up with this, which I still don't grok to this very day, lol
[regexp [\\w\\.\\-]+]
Thanks @SOURCE AUDIO and @WETTERBERG , for your easy solutions - I had forgotten that in Max I also got regular expressions at my disposal.
But my challenge is, that I am already in Odot land (using udpreceive 54000 cnmat), when I am in the need of extracting the first part of the address, which means that the input is not a Max messages, but a FullPacket message, like
FullPacket 48 105553168201408
So what I am really looking for is an easy CNMAT Odot way of doing it - an Odot external which I have not come across so far, or an available attribute or message that I have missed.
On the other hand, the more I use Odot the more it comes to my mind that using `o.expr.codebox` isn't that bad.
In the end my approach substitutes the `regexp` logic with a `o.expr.codebox` one and uses just a different way of string parsing - whereby `regexp` is more elegant, although harder to read & and understand at a first glance, especially when one hasn't worked with regular expressions for a while (hieroglyphics are easier to remember & read ;-).
My concerns were also about performance, as this code will be executed on OSC messages that come from a playing surface (an Open Stage Control "Client"), so I don't want to introduce too much latency. But I guess that `o.expr.codebox` uses a just-in-time compilation (after you leave its editor or save the patch), so it should be efficient.
Or in other words : it's not like calling JavaScript, especially hopping onto (being queued onto) the low priority thread.
Is that it?
You need to route up to the last part of the address to get the actual value as a regular Max message. Otherwise you still get a FullPaquet message.
Hi @TFL,
what I am looking for is the name of the first part of the address and not any values.
Or in other words, the initial OSC Message maybe something like this
/foo/note : 82
but the next OSC message may have a different first part, like this
/yoc/note : 84
So I am in the need to extract the first part of the OSC address, which maybe e.g. "foo" or "yoc" or something completely different.
The point is, that I want to abstract some parts of the OSC address and make them variable (they are not static and not known upfront), and their actual valid values (names) are read from a config file.
I thought that the need of parsing an OSC address is so common, that Odot has several approaches to achieve and handle this in different kind of situations.
The classic [o.route] approach only works, if you know the OSC address of the OSC message upfront - setting the value to route via [set 1 $1] dynamically e.g. does not help either, as this would end up in an iteration over all possible values, which would be a "waste of performance".
Optimal would be a theoretically (not existing as far as I know - but I am by no means an expert of odot) odot object like this
o.parse 0
where the first attribute would be the 0-based index of the OSC address part the object should find and output via its left outlet. Feeding e.g. "/foo/note : 82" into it would result in "foo".
once you expand packet into plain text
Thanks @Source Audio !
[o.atomize] with no attribute is the one (at least one ;-) I have overlooked.
And as so often, the naming of Max objects (or externals) are surprisingly creative and hide their goodness underneath an "opinionated" name (maybe better : an individual perspective of a problem domain and a set of verbs / commands to act inside of it, which isn't obvious for others at first glance ;-).
Your approach is great - this is nice to read & compact as well - thanks again for taking your time!
You are welcome.
And happy holidays !
P.S.
I did not experience any problems with that regexp substitution,
but what WETTERBERG mentioned might be worth using instead ?
I am sure he has reasons to post that, maybe on large amount of
data flow it makes (or made) the difference.
@Source Audio ... oh yes, happy holidays and a happy new year !
Regarding what @WETTERBERG mentioned - "back in the day" can mean a lot, like e.g. a bug that might have been fixed in the meantime.
If it is or was a bug, does it depend on @substitute or is / was it a "general purpose" kind of bug with [regexp]?
As regular expression can create groups, this calls for a nested structure of memory to hold the data that are returned as the result (or result set) - depending on the input data this memory structure can grow or shrink and hence missing cleaning things up on the heap "on shrink" is a perfect pitfall for a memory leak.
Helpful it would be, if someone who has deeper knowledge about [regexp], because of intense usage and hence experience, could give some information about this ... or someone from C74 ;-).
Another approach would be : implement an automated test for this and investigate what happens.
In this case a NodeJS script might come to help, that sends lots of OSC messages with random performance values over a long period of time - this is easy to do.
But I haven't gone into the low-level side of things in Max yet, and don't know if tracing of memory consumption is possible inside of Max (in a reliable fashion ... even its a good idea to let the "thing to observe" report things over its own behavior ;-) - looking at the statistics of the operating system tools would be an alternative, but not that ideal.