Structured Programming

Continuing the discussion from Kinda Frustrated with Apps? Anyone else?:

Here’s a 9 year old post (please alert me if there’s something similar but newer out there):

If I open up mlrv2 and inspect it, I see that it follows some of these guidelines.

That being said, some things about Max are just maddening to an experienced programmer. Like this bit:

Limit your use of Send / Receive

Initially a great way to get rid of extraneous patch cords, these objects can lead to other problems.
In the following patch, a message is sent to the named receive object
“new_result”. The potential problem is at the receiving end. If there
are several receive objects with this name, which one will get the
message first?

https://1cyjknyddcx62agyb002-web-assets.s3.amazonaws.com/AEpatch8.jpg

A typical, if somewhat hazardous, use of send/receive

In this example, the lower receive will get the
message first (since Max works not only right to left, but also bottom
to top in ordering messages). But what if the receive objects are contained within several layers of subpatchers?

This is further complicated if the subpatchers [do_something] and
[do_something_else] operate upon the same data – the order of their
operation may be important.

It can be exceedingly difficult to follow the path of program flow in a complex Max app.

And the notion of using leds to debug a modular Max app? Not exactly what one might call “test-driven development”. :wink:

I’m really interested in exploring this further. I’m going to go through the Supercollider grid studies, and I’m thinking about adapting the Max/Node.js grid studies for the purpose of JS-within-Max. I like the idea of maintaining access to rich DSP resources, so it’d be nice to avoid abandoning Max/Supercollider/something similar altogether.

If anybody wants to point to really excellent examples of structure in complex Max apps (especially with regard to testing/debugging/flow control) or really excellent examples of using the grid from Supercollider or with Javascript-in-Max, I’m all ears!

3 Likes

I’m starting to think in the back of my mind about a ground-up rewrite of mlrv2, as a showcase for structured programming best practices in monome apps. Somebody please stop me now, or offer to help! :wink:

3 Likes

I don’t have the chops to help with anything other than an encouraging word and high-5. Sounds like a wild ride.

2 Likes

@rodrigo has implemented a lot of great techniques into party van, there’s likely much to learn from that app. he’s also mentioned he’s starting v2.

but if you decided to delve in, it’s not insurmountable-- just one step at a time, and likely a complete restart after you get 50% in and realize there’s a cleaner/nicer way of doing things (i’ve rewritten mlr at least 10 times, not all versions went public). the lesson is, when you’re done, you’ll likely have some highly practiced new skills.

i’ve been talking a lot about js but @galapagoose is really into gen~ and it’s worth examining.

1 Like

@rodrigo and I have been talking a bit about TPV2, and I’m looking forward to continuing that discussion (Rodrigo, it looks like I got that job I was hoping to get, so that’s a huge load off my mind!) I’ll definitely dive into TPV and take a look around. Rodrigo, if you felt inclined to point out anything in particular you’ve done to make maintenance and debugging easier, I’d be thrilled.

I might also start a discussion about unit testing over on the cycling74 forums (after I do a search to see what’s already out there).

I admit I haven’t looked closely at mlrv2 but I have looked at a handful of big max patches and one of the things that impressed me was a general lack of procedural abstraction. Folks (sometimes) inline patchers but rarely create sharable abstractions. I wonder if a baby-step towards more robust apps might be to tease out some proper building-block abstractions that can be understood (and tested?) in isolation. Or maybe these instruments/algorithms don’t lend themselves to decomposition?

2 Likes

I agree and would take it further and say that it’d be great if bits of JS where designed to be reused in and of themselves. I’m new enough to Max to not know how shared functions would work (JS instance globals vs. js require) but would love to hear people’s thoughts. (Some relevant conversation over at cycling74.)

1 Like

Indeed I am a big fan of the gen~ ‘codeblock’ as I find dsp loops to make way more sense in linear text fashion. If you do go down the mlr rebuild rabbit hole, i would suggest everything inside the ‘pl.maxpat’ patcher (and parts of ‘output.maxpat’) could be wrapped up into a single powerful gen~ script.

I would however argue that send/receive is an essential tool in any reasonably complicated max patch. Personally I find a mess of patch cords to be far more difficult to understand than some well named send/receive objects. Using segmented patch cords has been indispensable for me to make patches i could revisit and understand, though the wider cords of Max 6&7 aren’t quite as clear as previous versions.

Personally I find the biggest problem with Max to be in customizing the UI. If you want to work in Max, you really have to work with the GUI objects available to you, and not try to totally customize everything like in mlrv2. That level of customization really belongs in a standalone app or plugin. Seriously.

I’d also echo @tehn’s comment about rebuilding everything from scratch and then restarting 50% of the way through. Beware.

2 Likes

Yes, this. I would like to address this.

Reaktor is slightly better on the encapsulation/abstraction front than Max is (I’ve been playing with Blocks and am starting to look at doing a basic grid block)… and gen~, man, whoa. So powerful, but not any better at abstraction or reuse. The best story for encapsulation or testability in Max still looks like it’s to write an external in C, which is a little dismaying.

1 Like

@jasonw22
If you’re going to look at something, take a look at Cut Glove, as it’s more or less a stripped down and updated TPV (the core looper/fx anyways). I also built most of it last year, so it’s a more mature and consistent programming style. Parts of TPV are terrrrrifying, (jesus, look at wtpa_1.maxpat if you want to have a laugh!). That’s one of the oldest bits of code in there, and it’s like a house of cards, so I’ve kind of worked around it as much as possible, but the solution to that problem was just rebuilding from scratch, which is what Cut Glove is.

I’ve used a bit more js here and there, and want to use more of it, but I think it’s harder to ‘hack’ into. So unless you understand the whole block of js, it’s harder to just pull out the bits you want/need. But it’s obviously much better for loops/logic.

I do try to avoid using sends/receives as much as possible, and never use them for audio (send~/receive~). Style-wise I’ve tried to go with a 2-inlet/2-outlet structure for everything. So audio in/out, and an “control” in/out, which uses prepend and route to make for readable flow. Plus I comment and color code the living shit out of everything.

In a share-y way I really want to get into making Max projects, but with something like TPV, there are sooo many files, and with the project documentation not being great, Ive never sat down and figured out how to make sure all of the files are included in the packaged up version. The Max packages thing is a great step forward for getting people into setting up, updating, and managing externals, but it’s still a bit faffy in general.

And yes, TPV2 is coming along nicely. Been working out some really interesting grid interface stuff, just ironing out some bugs.
I look forward to talking about UI stuff too! Congrats on getting the gig.

2 Likes

@misuba do you think it’d be possible to create a serialosc object for Reaktor, out of curiosity? I’ve played around with Reaktor slightly, and it seems pretty darn interesting, especially with Blocks.

@jasonw22 definitely, but maybe it’s another topic.

1 Like

Amazing readings. Thanks. So helpful.

On the subject of JavaScript and/or gen~ within Max, I suspect the single-threaded nature of JavaScript makes it unusable for audio processing. The folks who are making a large use of JavaScript within Max appear to be primarily concerned with MIDI data.

There are two things attracting me to JavaScript:

  • I know it really well
  • There are robust unit testing frameworks that already exist for it

But I’m concerned that I may want to do some DSP programming at which point does my JavaScript work become useless? But if I go the gen~ route it looks like I’ll be on my own for implementing any unit testing framework?

Starting to wonder if I should just stick to C.

Yeah most of the js I’ve seen has been dealing with list/array/loop stuff.

gen~ is great for dsp as you can then use it inside (and outside) of Max. Though it’s probably best to avoid doing non-dsp things with it, as it calculates every sample, which is quite expensive if not needed.

Tangentially, I really hope that cycling74 do something to bridge the gap between Max/gen~ and “real” code that can be used elsewhere. Especially with things like bela out there.

Interesting-seeming book.
http://www.areditions.com/lyon-designing-audio-objects-for-max-msp-and-pd-das025.html

Designing Audio Objects for Max/MSP and Pd

Max/MSP and Pd are the data flow audio programs electronic musicians prefer for their rapid prototyping capabilities, graphical resemblance to analog synthesizer patching, and a wide variety of available synthesis and processing methods. However, a powerful element of these programs is surprisingly under-utilized: the ability to create (in C) new audio externals to process audio with sample-level precision.

The advantage of writing externals in C is the ability to gain far greater control over the specification of new signal processing algorithms that are otherwise difficult or impossible to achieve with data-flow patching techniques. Additionally, externals coded in C can be considerably more CPU-efficient than the comparable algorithm implemented as a patch.

Learning how to write externals for Max/MSP and Pd in C opens an entirely new world of creative possibilities for electronic musicians. This book guides the reader step-by-step through the process of designing externals, from concept through implementation. Twelve externals are presented, each revealing new sonic, musical, and programming possibilities.

The multi-platform approach of this book supports the compilation of Pd externals on Linux, Mac OS X, and Windows, and the compilation of Max/MSP externals on Mac OS X and Windows. The CD-ROM contains complete code for all projects presented in the book. The Max/MSP externals are designed for use with Max 5; a supplementary chapter on the CD-ROM describes how to update Max 5 code to make use of 64-bit processing with Max 6.

I’m concerned about this. As I begin to talk with @Rodrigo about some UI design for TPV2 (partially inspired by the recent tease of the sexy-looking 2020 app) I need to start getting a lot more aware of what constraints the built-in GUI objects present. I’m not surprised to hear that breaking Max’s built-in GUI abstractions makes for far more brittle apps.

indeed, you can really only do control rate interaction with js in max. and that is fine, given gen~ does dsp.

the “dumber” parts of the monome modules have almost interchangeable syntax when it comes to js to c conversion. hence the code in mp2 in max is nearly identical to that in the module. copy-paste, really. i mean, within specific funtion blocks. ie copy the grid key code, then copy the grid led refresh code.

Although I know JavaScript well, I think I’d rather just stick with C than flip between JS and gen~ depending on whether I’m doing control rate or audio rate. It just seems more coherent to me. Unless there are good reasons not to use C?