Best practices in Max?

estevancarlos's icon

I'd love to read some articles or documentation on Max/MSP/Jitter best practices. I'm slowly understanding the language but it still feels like a wilderness. I've come across very useful tutorials that readily admit that what they're teaching may not be the most "efficient" way to do something. I study a variety languages (and am a master of none). I enjoy researching best methods in order to get rid of misconceptions or bad habits I might accrue. Is there any equivalent in Max?

Peter McCulloch's icon

There are threads, but not a document that I'm aware of.

It is much needed, though it would definitely be subjective in some areas.

I have my own mental list of objects that may be harmful to newbies but that this is also specific to the subject(DSP). If you're using Max for something else, these might not apply.

Number~ - since it doesn't behave like number or flonum with pass through and encourages people to downsample instead of figuring out how to solve the problem at signal rate.

Gain~ - because it's a pain to figure out what the actual gain is, and a great way to mess things up inside a feedback loop. (Live.gain~ or *~ are better)

To a lesser extent, gate~ because it's better to use interpolation if you're using it as a way if muting, though there are plenty of situations where gate~ is totally fine. (Building an interpolating gate~ is a good way of introducing abstraction)

Again, these really depend on what you're trying to do.

estevancarlos's icon

Well, I think best practices should be subjective but that these scenarios should be communicated. So it sounds cool to me. I hope Max matures as a community where this is discussed more outside of just forums.

Peter McCulloch's icon

There is the wiki. Not sure if this topic has been started yet, but if not...

estevancarlos's icon

I think I'm unrealistically comparing this language to Javascript. Not on a technical level but in terms of a language that can evolve. We have a hazy period of Javascript and now we have a renaissance of abstractions, frameworks, and functional programming. In addition to a mature discussion on best practices and "right way" vs "wrong way". While learning Max, right vs. wrong still seems murky but maybe that will change with time.

Peter McCulloch's icon

Definitely a smaller user base for Max, and lots of users without CS backgrounds. (I'm one of them) Not that that's entirely necessary for coding, but it definitely is hard to talk about architecture from "Hello, World".

The other thing keeping this from happening is that (at least previously) everything is organized ad hoc, so using other people's code only works if conventions are followed; there's no notion of namespaces. (this is great for newbies, but would be useful for power users)

estevancarlos's icon

I would actually like to encourage a discussion on "best practices" in Max. Since I'm still very new, I don't know if there are limitations on this idea. However as I learn more, I reflect on some very messy patches I've seen (although I learn a lot from them) and wonder how we can teach about ways of better organizing a patch.

Perhaps the issue here is that I'm also a designer and I know having the information well-organized can have a positive impact on the programmer and end-user. Obviously though, I understand why not all the free patches online are well-organized but I do think we could discuss how to encourage the discipline.

For example, does anyone have interested methods of color coordinating? Using sends and receives? Organizing objects? Etc.

brendan mccloskey's icon

Besides the wiki and that recent thread, I think we can say "what is the best way to use a hammer" but cannot ask "what is the best way to use a colour palette". Transgressive practice notwithstanding. I may be overthinking my response however.

Incorrect use = creativity, sometimes. And MaxMSP will not forgive blatant errors anyway.

estevancarlos's icon

"Incorrect use = creativity"

Yeah, I would agree and I hope you weren't misunderstanding my argument or reference to color coordination. Although I may be stating the obvious, design isn't about random creativity. It's about communication, user interaction, user experience. Design would be only one part (and sometimes irrelevant) of the larger concern of "best practices".

estevancarlos's icon

For example, we should all agree that a cluster of crisscrossed wires is not a good idea (whether or not it's avoidable) when it comes to the matter of visually communicating the process at hand.

The follow up question is: how can this be avoided and are there good, bad, and better ways to avoid this? That's the question I'm posing.

brendan mccloskey's icon

Oh, absolutely. As a fellow designer, I agree that we cannot "design for transgressions". There is, as you suggest, a clear distinction between poor design and poor use. And yes, my choice of analogy (colour palette) was poor. I meant to differentiate between tool and instrument.

Interesting thread

Brendan

brendan mccloskey's icon

Best practice, on a purely personal level, in MaxMSP entails discriminating between what the user does and does not need to see or know. I think it depends on whether you are coming from a practical or artistic standpoint. And I may have derailed the thread towards the dark woods of the artistic ;-)

Brendan

estevancarlos's icon

Actually, I don't think I clarified. I'm talking mostly about the visual organization of the inside of the patch. In other words, the "User" I speak of is the programmer. Not the final user just playing with the software.

If we take an open source perspective on this, we should promote sharing, communication, and clarity in the program/patch. For example, commenting on your code in a traditional programming language is critical. In the Max it doesn't seem to be a commonplace tradition. I think it should be promoted.

Peter McCulloch's icon

Couple of rules of thumb that I use:

  • If you look at a group of objects and they do one thing, they should be encapsulated. (or an abstraction if it looks reusable) Use descriptive subpatcher names.

  • Long-patch cords are a code smell, and the more you see, the smellier they are.

  • Learn about #0 for abstractions and poly~. It's great for local sends and receives (e.g. send #0_foo) that you can use to share values locally.

  • There are three numbers to worry about in terms of quantities: 0, 1, and many. If you can only accommodate certain specific lengths for a particular process, your data model is probably inadequate. Don't build your own data models if you don't have to, and you almost never have to.

  • Any time a control-rate patch cord goes to multiple places, you should use trigger, bangbang, etc. to indicate ordering. If you don't know the data type, you can use "l" to send lists. Do not use delay/pipe to do what trigger is better suited for. Avoid dependence on right-to-left ordering. Learn about bondo and buddy and which to use when.

  • If you want two pieces of information to arrive at the same time, put them into a list. It's much simpler to send one list of eight parameters to eight places in a predictable order than it is to manage 8 parameters going to 8 places. Zl.nth is your friend.

  • Feedback connections should be distinct. I make mine red.

  • Always provide arguments to objects, especially MSP objects. Cycle~ with a frequency of 0 (aka no argument provided...) outputs full-volume DC offset. Ouch. (there are a couple exceptions to this rule, but it's a really good one)

  • Table, multislider, itable, and coll do way more than you expect. Read the manual pages.

  • If timing accuracy matters, do it at signal rate.

  • Comment the inputs/outputs of subpatchers and abstractions so people don't have to look inside to figure out what they do.

  • Use "selector"-style messages instead of adding inlets to your abstractions where possible.

  • Learn poly~. It takes time, but it solves innumerable problems once you properly know how to use it. (and it's not limited to MSP)

That said, some of these strategies are less suitable for exploration. You can't connect to something if it's buried down in a patch. If I know what I'm building, I'm more likely to block code out.

Roman Thilenius's icon

the more you work modular and create abstractions, the less you need to bother about developing bad habits because abstractions and subpatches are the basis for quickly updating your projects with "better" code when you learn something new later.

Roald Baudoux's icon

- change background color of unlocked patchers in Objet Defaults to see more easily when you're editing ;
- in a similar fashion, replace the pale blue of ezdac~ and ezadc~ with red to notice more easily when audio is on or off ;
- patcherargs takes abstractions and bpatchers one level further ;
- the forward object is an improvement over the send object because you can change the destination dynamically - too bad Max cannot show which receive objects they are connected to upon mouse click ;
- color panels locked to background put behind a group of object can help to group them mentally when you don't want to hide them inside a subpatcher ;
- in complex patchers, a unique loadbang connected to a trigger and many send objects helps to set the order of initialization for different parts of the patcher ;
- sometimes pulling the data from the receiving part using value or coll can be a better solution than pushing them from the sending part with send/forward/receive (especially when you are working heavily on a patcher meant to be loaded into a poly~ object) ;
- when you create a new substructure which solves a specific problem, copy it in an empty patcher and save it into a dedicated folder ;
- universal is a handy tool to retrigger all loadmess or loadbang objects without reloading a patcher ;

By the way if both message and number~ could be used to simultaneously display and transmit data it would help beginners a lot !

Ernest's icon

Rather than have multiple input ports to a subpatch for individual values, it is helpful to send values in a list, with a route object inside the subpatch to send the values to different functions. The example patch in the toolbox for polyvoice illustrates this, as well as using the same method for custom poly voice assignment.

Peter McCulloch's icon

Listfunnel is also incredibly useful for parallel poly~ patches. (I.e. where you're not dynamically switching voices on and off)

estevancarlos's icon

This is all fantastic advice. Thanks to everyone for contributing. This is certainly helping me think through the process of programming.

AudioMatt's icon

Aside from things that apply to most languages, the 'practice' that changed my life the most in max was the realization that I should almost never cross scheduler-rate patch chords. Also, everything, visually, should be left justified.

estevancarlos's icon

Can you explain the scheduler rate issue?

Peter McCulloch's icon

It's about maintaining right-to-left order, I think. Trigger takes care of problems like that, since the order of the outlets is guaranteed.

AudioMatt's icon

[trigger] but also [value]. Learning other programming languages and then coming back caused me to look at max in a much more productive and structured way. I can't believe I basically used max without variables. It seems insane now. I'm still creative but when I want to get something boring done like munging data, being methodical yields amazing results.

samnichols's icon

I'm arriving to this kind of late. This is a great thread, though. It'd be nice to see this topic over at the wiki. (I checked quickly but didn't notice it)

At a CNMAT workshop they taught me to use [OSC-route] to control the flow of information through my patch. It's made my life a lot simpler. Everything can get flagged with a clear label (using slash-delimited addresses). This helps you build a clear patch, and also makes it easier to understand the patch when you get stuck. Also: using [OSC-route] (even without necessarily using Open Sound Control) has an important side benefit, bc. it means that you are building in comments, as you go.

And you can always use the right-most outlet, and bypass the [OSC-route] object, if you like.

estevancarlos's icon

This is great. Thanks for sharing this. It should be on the wiki and Cycling 74 should promote a conversation on the topic. Max has so much more potential if we better understood effective programming practices.

At a CNMAT workshop they taught me to use [OSC-route] to control the flow of information through my patch. It’s made my life a lot simpler. Everything can get flagged with a clear label (using slash-delimited addresses). This helps you build a clear patch, and also makes it easier to understand the patch when you get stuck. Also: using [OSC-route] (even without necessarily using Open Sound Control) has an important side benefit, bc. it means that you are building in comments, as you go.

And you can always use the right-most outlet, and bypass the [OSC-route] object, if you like.