I am considering audio and MIDI application in Max (or Max for Live, really), but I am totally comfortable in Java, so something like this also seems attractive. Does anybody have any experience with Max? Is it really geared to people who do not code, or is the goofy/friendly looking UI much more efficient than writing straight code in, say, Java? Also, has anyone wrote a VST plugin in Java, and can share any experiences there?
Max is a dataflow language. I am more familiar with PD, which is by the same author.
The advantage of dataflow as a programming style is that most data dependencies are explicit - you can literally follow the connections between subroutines visually, and they are usually displayed as a line on the screen between them. The difficulty is that order of operations is less explicit, because it is two dimensional in layout, rather than one dimensional as textual code would be.
I do most of my audio stuff in supercollider nowadays, but for a quick sketch of an audio idea, and building a working rough model, pd works great.
The main difficulty of programming in a visual dataflow language is comprehending order of operations. It is possible to create multiple connections from one outlet, but it behooves you to create an explicit [trigger] object to control which of those connections runs first (a line coming from an outlet is conceptually the same as a subroutine call). Also there is a difficulty with experienced programmers with getting used to anonymous parameters - the patching lines have no names, they just have the outlet they are coming from and the inlet they are connected to to identify them.
Another tip is to use encapsulation - in a textual language you would have a library or a class file, in Max or PD you can load an external patch file by name - so you create a small patch with some outlets and inlets, and use that from your other patch in multiple places, rather than copying and pasting (just like you would call functions rather than copying and pasting blocks of code).
[send] and [receive] are for globally setting / getting data, and have all the same problems that come with globals - a common workaround when they are needed is to prepend a unique identifier specific to the current subpatch, the $0 token evaluates to the unique ID of the current subpatch in object names / parameters, and is used for this purpose. This simulates a scoped variable.
Debugging in dataflow is excellent, because it is very easy to detach a set of items from their surrounding patch and run them independently, and turning on trace for a part of the flow is as easy as attaching a number box to an outlet.