The latest version of Max might not look revolutionary, but its familiar appearance conceals some big changes.
Max 6 is the latest version of the graphical audio and media toolkit previously known as MaxMSP. Blog entries and videos presenting new features started appearing online last summer, and Max 6 was given a 'soft launch' at the Cycling 74 Expo conference in Brooklyn last October. It can now be purchased as a download, and in fact there is no longer a boxed version.
It's about four years since Max 5 shipped with its completely re-engineered user interface; Max 6 is a further refinement and, at first sight, looks pretty similar. The real differences start to emerge once you immerse yourself in the process of making or altering Max programs (the creative activity known as 'patching'). If, to use a slightly strained metaphor, the upgrade from Max 4 to Max 5 was akin to moving house, Max 6 has now replaced most of the furniture.
We'll look at the interface changes in some detail, but there are also significant improvements behind the scenes. Max 6's audio processing is now 64-bit throughout. Internal resampling filters improve audio quality when running sub-patchers at different sampling rates. There are some new filter design and visualisation tools, plus — at extra cost — an innovative new environment called Gen for creating DSP processing systems at near native-code efficiency. Finally, an integrated mixing environment allows patchers to be loaded, edited and closed without audio glitches, and the mixer supports multi-core computer hardware.
A further improvement is the pricing model: for almost the same pricethe new lower price of $399, you now get Max, MSP and Jitter, although Gen will cost you an additional £83$100. Academic terms and discounts have also been improved. Owners of Ableton's Max for Live face a slightly more complicated scenario: while Max 6 will work in Max for Live, users currently still only have a licence for Max 5, and are restricted to using Max 6 in its 30-day demo mode (or else paying for a full version of Max 6).
This review isn't going to describe the new features available in Jitter (Max's video package), for reasons of space rather than relevance: many musicians integrate visuals into their practice, and Jitter can be incorporated into audio generation and processing in a variety of ways. Since Jitter is now bundled with Max 6, you are, of course, free to experiment with it.
Max 5 was a massive improvement over Max 4 in terms of usability: as an editing and composing environment, it was much more pleasant to use, and the end results — instruments, effects, musical systems — looked so much better than anything that could be achieved with Max 4's antiquated graphical toolbox. Max 6 improves on Max 5, but in a different direction: Max is now, as Cycling '74's David Zicarelli puts it, more "discoverable”. One element of that discoverability is a wealth of online resources, presented as hyperlinked icons when Max 6 is launched.
Max 5 delivered improvements to the patching experience, but it was still rather lacking in support for novice users who were trying to find their way round. Although every version of Max has included example 'help patchers' for each of the built-in objects, and Max 5 contained an integrated hyperlinked documentation system, it was still rather easy to get lost while trying to discover how to achieve a particular task.
Here's a simple example: suppose you want to play back a sample file, but don't know which Max objects can do this. In Max 5, you might start by creating a new, blank object in a patcher and entering the word 'play'. Max will helpfully suggest a couple of MSP objects with this prefix: 'play~' and 'playbar'. Pick the former, which seems the most likely candidate, and you'd get a pop-up hint describing the kind of messages that the play~ object accepts, and the floating Clue Window would provide a very short description. Unfortunately, play~ cannot play back audio files, and in fact it can't generate audio at all without an associated buffer~ object — but neither fact is clearly indicated here, leaving a novice user somewhat lost.
Let's try the same thing in Max 6. Start typing and a drop-down window appears, again suggesting 'play~' and 'playbar' — the only Max objects beginning with 'play' — but also three objects whose names contain the string 'play', and another 26 whose descriptions contain 'play'. Sure enough, 'sfplay~ — Play audio from disk' would seem to be what we're after.
This scenario shows how Max's object boxes have essentially been transformed into search boxes, to help you find what you want rather than just what you're typing. This spirit of discovery pervades other areas of the user interface, as we'll see.
The integrated documentation is still present, but has been expanded and overhauled: it's now easier to search and navigate. Some new features (such as Gen) are described well and in detail, but others are skimmed over too quickly. I also came across one or two paragraphs labelled 'TEXT HERE', so clearly this is still a work in progress.
At first glance, the visual appearance of Max 6 isn't that different from Max 5. Each Max patcher document contains objects, which are shown either as boxes of text or user-interface components (buttons, sliders, knobs), connected by virtual patch cords which carry messages, digital audio or video matrices. One obvious difference between Max 5 and Max 6 is that the patch cords themselves have been spruced up and now sport some gentle curves: a minor change, but one that greatly improves the patching experience. A tutorial patcher in Max 5 has a cold, angular look compared to the same patcher in Max 6, which is much clearer and easier to 'read'. Given that virtual modular synths and editors have had realistic-looking patch cords for years, this is an overdue and welcome improvement. When a patcher is unlocked for editing, the patch cords now sport a little button on mouse-over giving access to an editing menu. This was available as right- or Ctrl-click in Max 5, but is now more obvious and — that word again — discoverable.
The only other immediate difference between a patcher window in Max 5 and Max 6 is the addition of some new icons along the bottom — and the removal of some old ones. Again, the changes signal the new emphasis on discoverability: the New Object button has been replaced with Show Object Explorer, which brings up a sophisticated, searchable catalogue of objects and patchers. A new Show Key Commands button presents a menu of the one-letter editing commands, so that you don't have to guess them or look them up. Max 5's buttons for bringing objects forwards or backwards have been removed (although the menu items are still present); the Show/Hide Grid button survives, although Snap to Grid is gone as an icon. The debugger has its own enable/disable button, and there's a button for something called the 'mini-mixer' which we'll look at later.
There are two more buttons at the bottom right. Show/Hide Status Bar toggles the display of a one-line text panel which mirrors the contents of the Clue Window (although it doesn't wrap long lines). Open/Close Sidebar toggles something called the Sidebar (see box of that name).
The patching environment has received a lot of attention. The most obvious change is a new circular menu, or 'wheel', which appears when the mouse pointer is positioned at the left-hand edge of an object. (In fact, the most reliable gesture to get the wheel to appear seems to be to move the mouse pointer leftwards away from the object.) The wheel acts as a kind of menu bar, offering menus listing an object's available attributes, inlets, outlets and messages, all documented directly in the menus, the Clue Window and the Status Bar. Select an item from the Messages menu and a message box is created, containing the selected message and attached to the object. Select an inlet or outlet via the Connect menu and a dangling patch cord appears, one end attached to the selected inlet or outlet while the other end sticks to the mouse pointer, ready to be attached to another object.
Select an item from the Attributes menu and something new appears: a connected object called 'attrui' which allows the attribute value to be changed, or a different attribute to be selected for subsequent editing. Attrui is new in Max 6, and is an editing tool which is itself a user-interface object. It's a convenient way to examine how an object behaves as its attributes are changed, and makes it really easy to do things like experiment with different colour schemes by quickly altering colour attributes. Attrui also takes numeric inputs, so it can be used to dynamically alter — and display — attribute changes to an object as a patcher is running.
The wheel also provides a menu of Prototypes — different templates of an object with specific appearance and attributes — and a menu offering fast access to the Inspector, Help Patcher and Reference material for the object.
The circular menu is a clever and sleek piece of design, and does a wonderful job of allowing an object's features to be extensively explored, but experienced Max users will probably find it rather fiddly and choose instead to work with the Inspector, or by typing object names and messages from memory.
Some Max objects, like the filter design objects I'll come to in a moment, take complex sets of parameters, and traditionally Max has not fared well when it comes to managing and manipulating complicated data structures. The 'parameter bloat' problem was first tackled when Jitter was released: instead of lists of numbers, many Jitter objects are configured using named attributes. Max 6 makes another move to improve the processing of data structures with the introduction of dictionaries.
A dictionary is a named area of storage which maps keys to values, so at first glance it looks similar to the old 'coll' (collection) object — and in fact a dictionary can pull its contents from an existing coll object and, in many cases, push them back again. A dictionary can be embedded in its enclosing patcher, or read from (or written to) a text file — or it can be a completely dynamic affair, created as an empty structure whenever the first patcher to use it is opened.
Like colls, multiple dictionary objects with the same name share the same dictionary data, whether in the same or different patchers. Dictionaries, however, have two features that colls do not. Firstly, a dictionary can be hierarchical: entries in a dictionary can themselves be dictionaries (and there's a Max message syntax for traversing these nested structures). Secondly — and this takes a bit of getting used to — entire dictionaries can be passed around Max through patch cords, or by send and receive objects, just like ordinary messages. What actually happens is that the name of the dictionary is transmitted in each message, and any dictionary object that receives this message creates a copy of the named dictionary by cloning the original. (In this respect, dictionaries behave similarly to matrices in Jitter.)
The fact that dictionaries can be passed between objects allows for pipelines of objects which incrementally transform parts of a dictionary as it is passed from each object to the next. A set of built-in objects allow dictionaries to be built and manipulated on the fly: 'dict.group', 'dict.pack' and 'dict.unpack' assemble and deconstruct dictionaries, 'dict.iter' outputs dictionary entries, and 'dict.serialize' and 'dict.deserialize' allow dictionaries to be packaged up in a flattened form, useful for transfer over a network. Finally, 'dict.view' displays a browser-style tree of a dictionary's contents directly in a patcher window.
Here's an example where passing dictionaries between objects could be useful. You may want to build a polyphonic synthesizer using multiple copies of a patcher managed by the poly~ object, and then radically reprogram each voice as it is triggered. Each message triggering a new voice could carry a dictionary of voice parameters — perhaps one of several dictionaries embedded in the parent patcher, or computed dynamically. This is more flexible, and less messy, than passing lots of individual parameters around.
With the launch of Max for Live, Max had the opportunity to take on board some of the principles behind Ableton Live's file and project management tools, and Max 6 comes with its own take on project management. In addition to the traditional Max search path, Max 6 supports a file type called (unsurprisingly) a Project. A Project functions as a localised, private search area for patcher, media, code and data files.
A Project provides a dedicated set of subdirectories, local to the project and in the same directory as the Project file itself. If a patcher is opened from the Project window, it will be able to find any other files in this directory tree. Files can be dragged from the Finder or Windows Explorer to the Project: their names will be added to the appropriate tab in the window, and patchers in the Project will now be able to find them, but the files themselves won't be moved. A Consolidate command copies all the Project files to the appropriate Project-local directories. If you're familiar with Ableton Live, think of this as Collect All and Save.
If, like me, you're a die-hard Max user and insist on organising your patcher and media folders by hand, you can still make use of Projects: each Project has its own local search path — containing an arbitrary list of directories — and this will be used when any patcher in the Project is opened. In my tests, the Project machinery worked well enough, but its behaviour is subtle and under-documented. By the time you read this, there will hopefully be better documentation and examples of its use.
Previous versions of Max processed audio by building what's known as a 'DSP chain': when audio processing was turned on, the network of audio objects and patch cords in all the currently opened patchers would be assembled into a single block of code. This approach has a couple of disadvantages, particularly for live work. Firstly, any change to the arrangement of DSP objects would require the DSP chain to be recompiled, causing a noticeable glitch in the sound — not good if you want to tweak things on stage — and secondly, every patcher you had open was consuming CPU resources, even if it was muted. Opening and closing patcher files as you went along wouldn't help, since that would trigger DSP recompilation and produce glitches.
The DSP compilation machinery has been completely overhauled in Max 6. Every top-level patcher now has its own DSP chain feeding into a global mixer, so an individual patcher can be opened, or closed, without affecting the rest of the audio processing. What's more, a parallel processing option allows top-level patchers to be distributed across multiple processor cores.
A toggle button on a patcher's icon bar opens a mixer control panel for that patcher. On the left, you'll find a volume knob — with integrated VU display — and mute and solo buttons for the patcher. (In fact, multiple output groups can be created by giving output objects distinct names.) The right-hand side of the panel sports a global DSP on/off button, a button for opening the Audio Status window, a CPU measure for the patcher in isolation — useful to track down the culprit if you're running out of processing power — and some latency controls.
Mixer latency is a feature designed to avoid audio glitches when editing a patcher. Audio is generated ahead of time, by a number of milliseconds specified in Max's preferences. If a patcher is altered, the buffered audio is used to effect a smooth crossfade from the old state of the patcher to the new one. A separate ramp time allows patchers to fade in when started or fade out when stopped. Obviously, latency is a trade-off: lower values mean a more responsive application, while higher values result in smoother continuous audio while patching.
There are numerous internal improvements to Max 6's audio processing. For a start, Max 6 now runs digital audio at 64-bit resolution. This doesn't mean that the actual application has been updated to run in a 64-bit address space — it's still 32-bit for now — but audio samples are represented and processed internally as 64-bit floating-point values. This improvement doesn't necessarily translate immediately to higher-quality sound — the sample stream still needs to be converted to and from whatever your soundcard driver supports, and 24-bit integers sound pretty good already — but the higher resolution improves dynamic range for internal processing, and also improves accuracy and precision in situations where an audio signal is being used as a control source (for example, to index into a buffer).
Note that existing third-party objects will continue to operate at 32-bit. Authors will need to modify their objects to take advantage of the 64-bit signal path without loss of resolution.
Another hidden improvement to Max's audio processing is a set of resampling filters, used in situations where the sampling rate is changed internally in part of the signal chain. An obvious example where this takes place is in the 'poly~' object used for running multiple instances of a patcher to create polyphonic voices. The patcher loaded by poly~ can be upsampled or downsampled, and a resampling attribute enables resampling filters to avoid nasty aliasing noise. The 'groove~' object, which performs variable-speed playback of audio buffers, can also resample.
Max 6 also comes with a new collection of filter design tools. The 'filterdesign' object takes a description of an audio filter from values like cutoff frequency, order and pass type down to some quite esoteric parameters ('passband ripple', anyone?) and outputs a set of low-level co-efficients which can be fed into a cascade of biquad filters. The 'filterdetail' object turns these co-efficients into response figures which can be plotted visually using the new 'plot~' object. The plot~ object itself is a sophisticated visualisation tool, capable of drawing linear or logarithmic X-Y graphs, audio waveforms and spectral responses.
Traditionally, Max is an environment where units of functionality — objects — are connected graphically by virtual patch cords which carry numbers, text messages, digital audio or image matrices. Max's huge success is largely due to this graphical, click-and-drag approach to building audio and video processors, but it has a couple of disadvantages. Firstly, some tasks really do work best when built with an old-school programming approach involving variables, expressions and lines of code: there's a level of structure and expressiveness that's only really possible in text. Secondly, the machinery behind Max's patching system can make it difficult to build patchers that can compare in efficiency terms to plug-ins written completely in a lower-level language like C++. Max users requiring that degree of performance have traditionally had to native-code their own objects, a fiddly and thankless task, not least because Windows and Mac OS X require different binaries — and when fundamental changes are made to Max (such as 64-bit audio processing), ongoing maintenance becomes an issue.
Enter an entirely new feature in Max 6, informally referred to as Gen. There is a large selection of objects in the Gen stable, but most of them are concerned with animation and video processing, so we'll concentrate on the audio Gen object called, predictably, 'gen~'.
Gen~ is, at first glance, a new way of making embedded sub-patchers: type the name 'gen~' into a new object box and the resulting object can be double-clicked to open a new patching window. (At least, it can if you have a Gen licence; otherwise, you can use Gen objects but not edit them.) This is no ordinary patcher, however: it's a specialised, optimised patching view dedicated purely to audio processing.
The world of gen~ is rather impoverished compared to 'real' Max: a gen~ patcher's object palette is restricted to particular mathematical and trigonometric operators, waveform generators, filters, accumulators — in fact, the raw components you might work with to construct a dedicated instrument or effect in software (and not that far removed from the components you might use if working with hardware). You won't find any fancy user-interface objects like knobs and faders, but you can create variable parameters inside gen~ and attach them to interface objects in Max proper. A gen~ patcher can also access audio buffers in Max.
Compared to 'real' Max, a gen~ patcher is pretty low-level. The payoff is that gen~ patchers are extremely efficient: their performance is on a par with the equivalent code written in C, and objects in gen~ can process audio at single-sample resolution, opening the door to new oscillator and filter designs. This is possible because the 'objects' in gen~ aren't objects in the Max sense at all: an entire gen~ patcher is compiled, on demand, into a single block of optimised DSP code. The contents of a gen~ patcher are instructions to the DSP compiler, so the entire patcher can be thought of as representing a chunk of textual source code.
This equivalence between patcher and code is reinforced by a new Max 'object' which can only be used inside gen~: 'codebox'. A gen~ codebox is a container for lines of code written in a special-purpose language called GenExpr. The operations and functions in GenExpr are equivalent to those available elsewhere in a gen~ patcher, and the contents of gen~ and codebox are converted to DSP code in the same way, so you are free to mix and match between writing text and patching inside gen~; everything ends up as optimised code.
Building the performance-critical parts of your patcher using Gen is a lot easier than working in C or C++. Changes in the code take effect immediately, and everything is stored in the patcher itself. Equally importantly, working at the level of Gen and codebox is portable: patchers will work in OS X or Windows and with future enhancements to Max (including the new 64-bit processing in Max 6).
Max 5 was such a dramatic improvement over previous releases that the upgrade was really a no-brainer. So what of the similar-looking Max 6?
If you're a Max novice, or anyone having problems remembering the names or behaviour of the hundreds of objects and features Max provides, Max 6 is a clear improvement: even if you don't need or use its new features, you'll get your work done quicker and with less head-scratching. The integrated help is much improved, although there are some holes, and some new features are currently under-documented.
The 64-bit audio processing, resampling filters and filter-design tools advance Max's audio fidelity, but the real breakthrough is Gen, which brings compiled DSP code within everyone's reach, and offers potentially massive performance improvements for low-level audio processing. Alas, you'll have to pay extra to create patchers for it.
All in all, Max 6 is a worthy improvement. Once you've made the jump, you'll really not want to go back.
Max has always been somewhat afflicted by a surfeit of windows, especially since patcher documents are often deeply hierarchical in nature, so sub-windows often need to be open for editing. Many Max objects also have their own special-purpose windows. Max 5 added two debugging windows and the Clue Window, amongst others. These are all in addition to the Max Window, a text console displaying important information and error messages but often buried beneath the clutter associated with patcher editing and performance.
The Sidebar is an attempt to bring this menagerie of windows under control. The most common windows can now appear as if 'docked' as a pane into the Sidebar of any patcher window. The Sidebar is tabbed to select between the panes: Object Explorer, Inspector, Reference documentation and Max Window. The Inspector and Reference panes change their contents to track the currently selected object(s) in the patcher, while the Max pane is global: every Sidebar showing this pane has the same content. Although the original, independent windows are still available, the Sidebar places the most important information and controls somewhere that's quick and easy to get to.
The Object Explorer is new, and replaces the Palette from Max 5. You can still browse user interface objects by their icons, but the Explorer also lists non-interface objects, as well as patcher files located in the search path. The entire list is awfully long, but objects and patchers are sorted into categories, and there's a filter for finding objects by name or by description.