tips on structuring/laying out patches?
hi,
Im starting to get the hang of writing max patches, but as a (traditional) programmer, Im getting very frustrated at the mess of it all.
Is there a book/article that explains some way to keep these things tidy?
I already use sub-patches/abstractions, segmented wires/route wire,send/receive - but not really seem to help much.
(and I seem to spend as much time moving stuff around to make it tidy as writing code)
I think I must be missing something pretty fundamental, as I only need about 5 objects in place before the mess starts… so you can imagine the mess my bigger projects are in ;)
Difficult to say really as it sounds like you are doing the the right thing. I admit to embracing the mess to some degree, and enjoying the process of moving stuff around. But then I didn't come from a text programming background. It sounds like you are doing the right things though...
I don't use segmented patch cords at all because I find it to hard to see what's happening if multiple cords overlay each other.
I do use the Alt-Y command a lot to align objects either vertically or horizontally to help keep things neat.
Other than that, definitely abstractions (and nested abstractions) to keep top level stuff small.
I also color related objects to find them quickly and (less often) color the patch cords
I am develop both traditional text based languages and Max. And I agree that the benefits of the patching approach (speed and ease) easily goes to the cost of readability. I also don't have the perfect solution, but over the years I developed some conventions for myself that help me. Non of these are revolutionary, but well here they are:
- Since Max 6 I only works in projects not on single patcher anymore.
- Every project has only one top-lever patcher that I always name main (borrowed from Java programming);
- The top-level patcher shall contain as few objects as possible. Usually they only contain a few abstractions that allow me to see the main data/signal flow. All The rest is done in abstractions.
- I try to think about encapsulation in the way I would handle classes in text-based languages. So I encapsulate by means of logical function.
- Even if I use a subpatch only in one project I usually use an abstraction, not a simple subpatcher. Like this I have a list of all functional elements in the project window.
- The names of abstraction that are only written for the current project are preceded by a project prefix (prefix.abstractionName) - kind of pseudo names spacing - to be able to recognize their scope easily.
- In the top level patcher I keep a copy of every global variable [v] that are used in the project in a certain section. (Just to keep overview and it also helps in debugging). The same for pv in abstractions.
- same for all dicts in the project.
- writing convention for object names like send/receive: I always use camelCase and prefix them with the same prefix as the abstractions (to make sure that two projects do not interfere unintendedly)
- And than of course I separate the UI from the logic. All ui-objects reside in on area of the top level patch or inside a bpatcher if the UI becomes more complex. (pvar, pattr [I started to love the pattr-system] etc are my friends).
- And I use some conventions in color-coding important abstractions by the means of they function (I.e. an abstraction that contains my "audio-engine" will have a certain color).
As I said nothing groundbreaking....
yeah, thats an issue I've with segmented wires too, also the fact it you move the objects around, you then need to mess re-route the wires again.
I also don't like the segment option as i prefer to use click n drag connecting for wires.
a bit more playing and looks like getting in the habit of aligning might help just found the align connections option which works nicely, and routing lots of wires in one go off selection is not bad either.
few things, I haven't figured..
- pushing wires behind objects.. is this possible?
- sometimes when I multiple select objects, i get route patch chords and remove all segments options (to do all)… other times I don't.
(actually i think this is a bug (6.1.6) , as if i move things, sometimes the options return)
also window management, when I start using abstraction/subpatchers, i end up with lots of windows open (sub patches) to move between. is there an easier way to do this?
I notice you can say for a sub patcher to display as a tab on parent, but you have to do this every time, and it only works one level deep. ( i guess the later i can live with) - any way to get around these limitations?
I guess I might get a bit more comfortable when I learn the keyboard shortcuts, to minimize all the mouse work I'm doing at the moment :)
some none layout questions..
are there any performance disadvantages with using send/receive.
(I'm using s #0_x, r #0_x most of the time) - I know i have to be careful with indeterminate receive order (correct?)
when communicating with sub patches, do you put send/receives inside activated directly? or always send via inlets? (i do the later)
coll/tables, i guess these are in a global namespace (unless you use #0?)
i wondering how to updates these 'nicely', if I do inside a sub patch (likely to keep things tidy), then the usage all becomes a bit 'hidden', but i cannot pass them in? or can i? (symbol name?)
sorry loads of questions, i guess I'm trying to find a style that works for me, so I don't end up with a pile of unreadable/maintainable patches.
I am also curious to hear how you guys are organizing you patches!!! ;)
thanks jan, our posts overlapped… but some interesting ideas there…
I like the idea of the naming conventions…
I use projects, so this looks like it could be an interesting way to go, I guess I had worried about having too many abstractions/subpatches, as I was wondering if performance would be hit (additional calling overhead), but sounds like that should be ok.
Do you (or others) have any examples I could look at?
would be interesting to see how it all fits together.
I guess I'm getting used to whats possible in Max, but not see enough to know what the 'conventions' are.
Thanks again to all for the pointers.
Hi technobear,
Personally I don't have any bad experiences with using abstractions, regarding the performance. Same for send/receive pattr etc. For me it is a cost/benefit calculation. It seems to be true that some options show different performance when setting up test scenarios. Compared to signal processing, matrix/openGL calcs the performance gain possible in the scheduler is often really negligible. So optimizing image and sound processing is what I usually focus on. (And a readable project will definitely increase the performance of the developer :) )
Worth also mentioning BPatcher. I find it very useful as I often work on projects I want to be modular, but with UI elements accessible.
Other useful patching shortcuts:
- Holding shift when making connections allows you to connect to multiple inlets from one outlet.
- Holding alt while selecting an area of the patch also selects patchcords
- Holding cmd and making an area selection allows you to re-size multiple objects.
Hello all!
What a nice thread :)
Jan, I was surprised how similar our approaches to organize patches are. I’m also use naming conventions, prefixes, and a list of sends and values on the top patches (I think of it like of API docs). So bellow I’ll describe some differences in detail.
– I use packages instead of projects. I tried to use projects few times, but every time I encountered strange problems and I gave up. So now for every new project I create new package directory structure with simple bash script.
– I name all global variables with UPPER case, like in text-based languages.
– Usually I have two or three top-level patches separated by functionality. I name this patches starting with “+” sign, so they always on the top of the file list in the finder/explorer. For example: +control.maxpat, +sound.maxpat, +video.maxpat, etc.
– I always color send/receive and value objects. They represents “holes” in message flow and shared state respectively, and it is easy for me to keep them in mind analyzing patch when they are colored.
– I’m using period or underscore naming conventions instead of camelCase, because it is really easy to select and edit one part of the name when they separated with “_” or “.” by simple double-clicking on that part.
– Some guys mention here that segmented patch cords poorly affects on understanding how patch works. I solved this problem by coloring patch cords. I think patches looks a lot cleaner with segmented cords.
– And of course abstractions. I don’t like subpatches mostly because they make managing project with VCS harder (especially when merging branches).
For separating UI from logic I use Jamoma framework. It is a brilliant piece of software that really helps me to structure my patches with MVC approach. Except a bunch of helpful utility externals/abstractions it allows to easily control the patch from CUE-scripts (video). Another killer-feature of Jamoma – [jcom.pack≈] external that allows to pack up to 32 MSP signals to single patchcord. Very handy when dealing with multichannel setups. If someone interested I can recommend to read original paper on Jamoma basics.
Also a month ago I’ve discovered another MVC framework based on pattr system — tLb. I didn’t tried it yet, but it seems the guy who developed it made a good work. He describes implementation details on the site.
By the way, guys, are you using a VCS for your projects? I found it a little tricky and interested in what tricks are you using when managing Max projects with VCS?
---
@technobear, I can suggest you to not worry about performance before you actually encounter problems with it. From my experience abstractions/subpatches do not cause noticeable performance degradations.
thanks again some great ideas and those shortcuts are very handy.
ok, so seems some agreements on using abstraction (rather than sub patches)
so how do you make working with this easier?
... is there a way of creating an abstraction from a collection of objects?
(like you can make a sub patch) or do you just use encapsulate, then save the patch?
... how can you rename abstractions easily (I'm thinking code refactoring here)
as far as i can tell, id have to rename everywhere its used, and also to perform the rename i have to use finder... or am i missing something?
seems a bit of a pain, but still ok.
currently i am very tied up, but maybe it would be an idea to start a wiki article on this topic, introducing some approaches of organizing larger projects?
yeah, a wiki article would be cool...
(as would be a 'dummy' project, which showed these kind of 'coding standards' in use)
seems there are a lot of tools we can use to tidy things up (I'm looking at pvar, pattr pv which look interesting)
one thing that Im struggling with, is sharing non-basic data types e.g. coll, table,dict.
Id like to be able to create an abstraction, that does something to an existing (e.g. coll)
(a bit like passing in a reference in C++/java)
eg. lets say I have in my main patch two colls called MajorScale and MinorScale I want to able to have 2 instances of a (single) abstraction called Transpose, in one instance I want it to use MajorScale in the other MinorScale seems I cannot, as Transpose would have to know the name of the coll, and I cannot pass it in.... (or can i using some magic max?)
e.g. Id like to do something like Transpose @scale MajorScale, Transpose @scale MinorScale
currently, I'm trying to approach the problem a different way, but its a bit of a pain.
This thread needs screenshots ;)
@bear I think this might be what your looking for.
In your abstraction [Transpose] create a coll like so [coll #1], save it.
In a new patcher create [Transpose MajorScale] and [Transpose MinorScale]
Open each and one coll will be [coll MajorScale] and the other [coll MinorScale]
@bear You can also use the "refer" message to change the associated coll file on the fly.
@Rick, Thanks,thats exactly what I was looking for :) ... id come across #0, but not #1 etc.
@Holland, thats cool too, useful for table and coll.
Only thing is, its a shame refer does not exist dictionary.
Im a bit confused about the dictionary help text, it reads that if you attach dictionaries, and use the dictionary message you get a reference, but when I tested this, I always get a clone
e.g. below Id like the 'unnamed' dictionary in the centre, to be made to refer to dA or dB.
such that if I change it (using set method) that it will also change the reference dict.
(like refer does for table/coll)
+1 for wiki page. I've created one: https://cycling74.com/wiki/index.php?title=Structuring_Max_patches
Will fill it with examples when I got some free time.
maybe you expect too much. dont forget that five max objects can do what needs 2 pages of text in machine language or in C++. you create a buffer~ in max and start using it - without the need to define variables for the namespace or care about the memory management yourself.
many of us have a love-hate-relationship with max connections, but that what max is all about. :)
-110