Housekeeping/tidying up patches

piearesquared's icon

I have started learning max recently and this is the first patch that I have made that is not related to a tutorial. It's a sampler/sequencer/livelooper and it's huge! I am pretty sure that there's a way for making it more accessible as I feel that even if I want to add more stuff to it, it's too cluttered that it's becoming kind of a pain. So are there any tips with regards to what I might want to change in order to make it at least seem a little bit more elegant/manageable?

The patch (attached) needs a little bit of explanation though as I made it as a sort of soundscape generator:
- There are 7 drag and drop spots for samples, passing through an eight step sequencer then through an adsr~ envelope/delay/degrader~/pan/lores~ and gain (the reason it's 7x8 is that I want to map everything to my apc40)
- Then there are four buffers to record the output of the sequencer and loop them. The first two are synced to global tempo, with the first being 8 bas long and the second 4 bars. The last two are kinda random and I am using them basically to loop certain parts of the output. EVerything out of here has sends for a delay & reverb with everything going through an EQ/Filter
- The four buffers underneath are attached to the ezadc~ and I am using these mainly for guitar inputs (they are all syncd to the tempo, set to start recording only at the first beat and also have their dedicated sends to a reverb, delay and a stutter~ object which I can't seem to get to sync to tempo at all)
AAAAnd all of that is going to a compressor (which is not really smart but given the clutter I am finding that adding a compressor on each channel a bit too much)

any suggestions are very very extremely welcome
Mo

Untitled1.txt
txt
Rodrigo's icon

A couple things right off the bat:

-Compartmentalize/Abstract! - there's a lot of repeated blocks of code. Turn them into abstractions/bpatchers. You can use arguments (#1/#2) to name the sends so you can use the same bit over and over again.
-Look to matrixctrl and live.step for the sequencer bits. Much more manageable than loose toggles.

The first comment along will make your patch infinitely more legible and easy to maintain, and the second point will make it easier to use.

benniy's icon

yes! that is pretty big!
i'm not at all the DSP guy, so i can't give you advices on that – and i must admit, i wont test your patch for its (probably very awesome) functionality for now. how ever some very basic tips i -after some time of cycling- try to follow and that might be helpful in the beginnings with max:in many cases you can a use single multislider as apposed to very many togglesin many cases you can use a single multislider as apposed to very many int (or float) boxes in the long run, you'll probably start designing your patches in a less visual way (...using less and less and less UI object. they tend to !kill! performance) a quite noble style of patching is to avoide message-boxes (such as "setloop $1 $2", "replace $1" etc etc etc ) if you can work with [prepend] (in your case [prepend setloop] etc etc) also "stop", "clear", "1" (and all these guys) in message-boxes can be substituted by triggers such as [t stop], [t clear], [t 1] ... – it's really more CPU friendly

there's probably more, but this might give you a start for some "perfections". generally really pay attention to the visiual / UI stuff. i've spent LOADS of time building pretty and detailed interfaces just to see my patch choke on them and disfunction in the end.

benniy's icon

( +1 @rodrigo )

piearesquared's icon

Thanks guys for your responses,

@rodrigo using $1, $2...etc was my initial intention, the thing I can't wrap my head around though is this: will sending multiple values (for example for cutoff frequencies) to the same filter but each with its own variable (i.e. $1 through $6) tell max to override the values or will they all play simultaneously. I tried actually using multiple patchers but then again they're only saving space but not streamlining anything. I have just looked at bpatcher, that seems like it might actually solve a lot of problems, need to see what it's exactly all about though. (also, I took a look at your karma~ looper and it's actually very close to what I was trying to achieve with this, I'll download it now and see how you managed to keep it all looking so approachable/friendly/nice)

@Benniy these are some very good tips, I have probably never used a multislider (always seemed daunting to me) but I will try to incorporate some of those. As for trigger objects, I only use them sparingly here as I am yet to fully understand their full functionality so I guess I will need to look into that as well. Also, I completely understand what you're saying with regards to trying to make it all look pretty with UI objects and in retrospect they might actually be the reason for all the lag that's occurring, I had no idea that they put a strain on resources.

I guess I have a long day of re-patching ahead of me then haha

benniy's icon

i may misunderstand, how ever if i may help: arguments to patchers / abstractions / bpatchers aren't necessarily there to set variables and values, but rather constants, that in return may help to actually assign values and variables within these patchers / abstractions / bpatchers. a basic example:

you have 2 (identical) abstractions with the arguments 1 and 2, so [patcher 1] and [patcher 2]. these arguments are accessed from "inside" the abstraction via the hash sybmbol (#). to replace something within your abstraction with the value provided as an argument, you'd put in "#1" .. so, for example: [route #1] would be transformed into [route 1] within your first patcher and [route 2] within your second patcher.

you can add more arguments to an abstraction – these are accessed by succeeding numbers . lets say you provide patcher one with the arguments [patcher 1 a hello 5] – you'd use #1 for the argument "1", #2 for the argument "a", #3 for the argument "hello" and #4 for the argument "5".

i usually route data into abstractions using the [route] object (and therefore only one equal send). dunno if this is clever, but it keeps decent order. so, from outside of your abstraction, you'd "tag" data with a number by prepending it (e.g. dial -> [prepend 1] -> [send somewhere]).

patcherabstraction.zip
zip
benniy's icon

oh, and – as for triggers: i can't imagine how you have patched so far without fully understanding them :) they're possibly THE most important object for ordering messages in max (and therefore patching in general). definitely read up on them! :)

Roman Thilenius's icon

it is quite easy to patch without triggers as long as you dont understand what they do. only when you understand it you have to use them all the time. :)

the most simple example which can teach you what they do is:

1. connect a numberbox to both inlets of a [+ ] object and see what it does.

2. connect the numberbox via a [t i i] to the [+ ] - which does the same.

3. now change the order between the [t i i] and the [+ ] so that the connections cross each other and see what happens now.

4. if you still dont get it, do the same 3 three steps but this time watch the whole thing in tracing mode.

-110

Rodrigo's icon

Triggers, arguments (#1), and prepend/route are some of the voodoo/secretsauce of good patching that is hard to pick up just doing things on your own as there's almost no way you'd run into those solutions.

Style wise, I do something similar to what @benniy described in having objects with only one inlet/outlet and things being routed around. Makes for cleaner and MUCH more legible code.

piearesquared's icon

@roman the example you gave of trigger is pretty much the only way I use trigger in my patch haha, I think I understand what it does in general, but I am yet to implement it in any meaningful way (or yet to harness its supersauce powers). At this point I am actually thinking of just restarting the patch from scratch and keeping these ideas of arguments, triggers, bpatcher, routes and less UI objects in mind. Thank you so much guys :)

Bill 2's icon

Mo, if the patch is already working you don't have to start from scratch. Just do one logical section at a time. Encapsulate a section then tidy it up - get some clear and neat inlets and outlets happening and describe them using the inspector. If there's an identical section being used several times save it as a patch (complete with the techniques listed above). As the others have said, it's MUCH easier to understand the whole patch when it's divided into sections like that, then if you want details just double-click on the appropriate sub-patch. Send and receive objects can be really handy, too, to avoid cables being too messy. And it all fits on your computer screen without having to scroll! ;-)

I've got to agree about trigger objects - they're a fantastic way to get one thing (number, message, bang, whatever) to do several tasks, and - importantly - in the correct order.

I often have lots of comment boxes, buttons, message boxes, etc. while I'm working on a patch. Then when it's working and finished, I describe all the details - how it works, etc. - in a separate program (an outliner file that lives in my Max documents folder) and delete all those visual helpers. The patch can also be a bit messy and spread out till I know it's working; I don't go to the trouble of making it super-neat and tidy till it's finished cos I keep changing it.

(Still haven't tried to figure out your patch though!)

Cheers, Bill

piearesquared's icon

That sounds like the more reasonable thing to do. Even though I am kinda scared that the moment I started playing around with it I will mess up its functionality. Maybe I'll just do a save as and then use all these techniques and see if it gets the patch to where I want it to