2020-05-12
Listen in your podcast player by searching for Future of Coding, or via Apple Podcasts | Overcast | RSS
Miller Puckette created “The Patcher” Max (the precursor to Max/MSP), and later Pure Data, two of the most important tools in the history of visual programming and computer music. Max was designed by Miller in the mid-1980s as an aid to computer-music composers who wanted to build their own dynamic systems without needing write C code. Max had no facility for sound generation at first, but that would come eventually with the addition of MSP. A decade later, after some academic politics nonsense forced him away from Max, Miller went on to create its successor, the open source Pure Data. Both Max/MSP and Pure Data have become wildly popular, with Max/MSP as a more polished-looking commercial product developed by Cycling ‘74 (now owned by music behemoth Ableton), and Pure Data as the thriving independent community project of hackers and techno-punks. Node-and-wire visual programming languages are almost a cliche at this point, as the vast majority of them either borrow heavily or at least reference the visual design of Miller Puckette’s original Max patcher and its MSP/Pd offspring. Though as you’ll hear in the interview, many of them are poorer for not rethinking some of the underling assumptions of their inspiration.
I decided to bring Miller on the show after hearing a fabulous interview of him by Darwin Grosse on the Art + Music + Technology podcast. (Tip: subscribe, it’s good.) Miller gave a great retelling of the history of Max and Pure Data and the forces at play when he created them, and that episode is a tidy complement the more design-focussed interview here on our show. Miller mentioned in passing that one of the three books he has yet to write would be his thoughts on realtime scheduling, so that was the initial hook for my interview. Looking back on the 30+ years of Max/Pd history, what has he learned about the design of tools? What were the alternative ideas that he didn’t pursue? Where is there room for improvement, perhaps by others picking up where he left off?
In this interview, Miller said a handful of things that were, well, painful for me to hear as a dogmatic champion of visual programming. So if you come into this thinking it’ll be a well-earned hour of congratulation and adoration, sit up and get ready to flip the dang table. This interview was a blast; on a personal level, I was thrilled to have the chance to talk to such an influential figure in the history of my field, and I hope you enjoy it as much as I did.
Quote of the Show: “It’s not only powerful, but it’s also inadequate.”
Miller Puckette is the creator of Max and Pure Data.
You can listen to this episode for more about the history of Max and Pd. That’s from the very cool Art + Music + Technology podcast by Darwin Grosse, which you can back on Patreon.
Music 11 and Csound were non-realtime precursors to Max, created by Barry Vercoe.
Max Matthews is considered the “father of computer music”, and is the namesake of Miller’s Max software. He had worked on a project called RTSKED, which stood for realtime scheduler.
When Miller was at MIT, he had access to people working on realtime computing, but their interests weren’t as nicely aligned with Miller’s as one might have hoped. Those folks were more concerned with problems like mitigating ringing in robotics or servo control.
Though it was in the air at the time, Miller was not directly influenced by Smalltalk, and certainly not by any of the things being added to C++ or Self.
Miller originally wrote Max when he was working at IRCAM.
To make a delay effect, you need a uniquely named delay line to avoid conflicts. To make that work well in Max, Miller added name mangling. To Ivan, this seems akin to the debate around hygienic macros.
Max was originally written for a 68000 processor that had no floating-point unit.
Cycling ‘74 is the company that now owns and develops Max/MSP. They were recently acquired by Ableton, though their integration goes back a bit further to the Max for Live plugin for Ableton Live.
Pure Data attempted to solve a problem in Max — the lack of rich visual representations of data — with a feature called data structures.
The first thing Miller did with Pure Data, back before it became a “Max clone”, was write a paper with physicist Judy Brown on phase vocoders.
One of the issues with data structures in Pure Data is traversal, using an object named pointer. When discussing nested objects, extended to the notion of nested data structures, Ivan wondered whether this was related to bpatcher.
Miller is learning Julia, and is finding it powerful but at times less direct than MATLAB.
Transcript sponsored by Repl.it
Corrections to this transcript are much appreciated!
I found the podcast interview you did with Darwin Grosse.
Oh, yeah.
I enjoyed that a lot. There were a couple of things that you said in that interview that I wanted to follow up on. I felt they would be really interesting to the community that I’m doing this podcast for.
What kind of community?
It’s called the Future of Coding. It’s mostly researchers, mostly people either working independently or in academia, who are interested in… not quite HCI, not quite programming language theory… looking at ways to make richer, more dynamic tools. There’s a very common thread of people who are interested in building visual environments. Max and Pure Data are two of the quintessential touchstones for the history of visual environments.
Something that you said on Darwin Grosse’s podcast is that it was 30 years ago that you were first working on this, and that your recollection about why exactly things came about might be a distant memory at this point.
(laughs) Suspect, yeah, right.
Yeah. So, as much as I would love to go down that rabbit hole and say, “Oh why do you have bangs the way they are,” or that sort of thing, I think a good place to start would be getting anything that you do remember, about how you went about designing The Patcher and Max and then eventually Pure Data.
First off, the thing that always interested me about computer music was the possibility of getting it to work in realtime. The environments that existed when I got started in 1979 were almost exclusively non-realtime. There were the beginnings of things that you could use in realtime, but they were not programmable in any very general way. So, you had a choice between special purpose things of various kinds, or a general purpose language — for instance Music 11, which was the precursor to Csound, which was a fully general sound renderer, but which would never run in realtime.
I was in the lab that was being run by Barry Vercoe, who was the inventor of Csound. Barry’s true interest really wasn’t so much in making a software synthesis engine. In fact, those had existed before Csound. I think that was a sort of a thing that he did in order to just be of practical help to the community. He never saw that as his main drift. His main focus was on was on realtime. So, I fell in with him and caught on to the idea that gee, you could try to make a computer music instrument run in realtime, and that would be a wonderful thing to have happen.
So, the main things that I was thinking about were, first off, being able to design sounds in a software kind of a way. Second, just how to solve the problems that come up when you change the model, from feeding punched cards into a computer into either playing on a keyboard or having other kinds of realtime input coming in — for instance, the sound that would come in from a microphone. A thing that you couldn’t do in Csound or it’s predecessors was hook a microphone up to it and play an instrument into the microphone, and have something come out with an echo, or some distortion, or filtering, or something like that. You couldn’t make a guitar pedal, for instance.
In fact, I remember one visitor to the MIT Experimental Music Studio. The first question they asked when I was showing them what I was doing: “Yeah, can I plug my guitar into that?” And the answer was, “No, you can’t do that just yet.” (laughs) “I’m working on that!”
So, really, the whole thing that I was thinking about had nothing to do with graphical programming environments. In fact, I wasn’t even thinking in terms of graphical programming environments when I got started. I was thinking in terms of realtime structures, and ways that systems could react to realtime inputs.
So, it’s another kind of HCI problem. But it’s not the problem of arranging things on a screen, it’s the problem of making your computer into a musical instrument. I actually didn’t even care at the outset what you had to do to specify what the instrument was going to be. I just cared about having the thing be instrumental in nature, and not batch in nature. That’s pretty much where all the terminology came from.
Another very influential researcher, Max Mathews, who’s usually described as the father of computer music, was also concerned about realtime. One of his ways of thinking about it was that you would trigger things. Triggering, I think etymologically… I assume trigger really comes from pulling the trigger on a weapon. When people talked about triggering things in 1970, I mean, come on… the Department of Defense was funding most computer science research at the time. So, there certainly was a militaristic financial background. The Zeitgeist was militarian in the ’60s and ’70s, as far as computing was concerned. If you wanted to be bored, you would work on banking software. If you wanted to do research, then you were being funded by the military. So I didn’t even think twice about the idea of using terms like trigger. Of course, if you’re going to trigger something, the natural sort of thing that gets triggered is a thing that goes bang.
I thought that was kind of funny, because of course the thing that you do not want to have happen when you plug your amplifier into the wall, is have it go bang. (laughs)
Yeah, like a loud pop or something. Yeah — nope!
Yeah, yeah. So there was actually sort of a built-in warding off of bad luck by giving something the worst outcome as a name.
(laughs) As opposed to like, click, or something like that, yeah.
Yeah, click would be a minor problem, but an explosion would be a major problem! That would be enough perhaps to get the audience to leave the concert hall. (laughs)
So, I started naming things bang, just as a just as a way of saying, “Yeah, this isn’t going to work, but let’s write it anyway.” (laughs)
It really should’ve been a single dot.
Like a period character?
Yeah. Like a single period. You can’t parse it as a number. I actually proposed to the Pd mailing list, “Why don’t I change bang to just period, because it’s completely neutral, it doesn’t say anything about what is going to happen.”
Right.
It’s a nice reference to the Hitchhiker’s Guide to the Galaxy, because the message that gets carried across the galaxy by some automaton, turns out to be a single dot. It means, “Greetings.” (laughs)
Anyway, you wouldn’t want to use exclamation point, because that’s usually pronounced bang. So, why don’t you just use a period? The answer I got back was, “Oh, we love bang, let’s just use bang.” (laughs) Let’s just stick with bang.
It’s totally part of the identity of Max and Pd and the derivative languages that have come since then, for sure.
It’s true. I didn’t really quite invent it, because of course the notion of it being a trigger predates that. But the idea of calling the trigger bang, I think that originated pretty much with me.
So, going back to that early period before you developed the Patcher interface, when you were working on the realtime scheduling problem.
I’ll just, as a brief aside, say: I am a colossal fan of visual programming, and of using graphical metaphors to represent things that are happening inside the execution of a program. I think there’s a lot of really interesting ideas there, that have yet to have their moment.
But what I mainly wanted to talk to you about today was that whole scheduling matter. Specifically because, in the podcast interview with Darwin Grosse, you said that one of the three books that you still have in you is a book on scheduling, that you may someday write that book.
So, that makes me think that whatever thoughts you had about it at the time, you’re still having more and more thoughts about it to this day. I’m curious: how did you approach the problem back then, and how has your perspective on the problem changed in the time since?
Well, first off, being at MIT, I had access to people who thought about realtime programming. I didn’t find that their research actually was answering the questions that I was asking. So the way people thought, or at least the way the people I talked to thought about realtime programming and scheduling back in the day, was: you have a bunch of inputs, and you have a bunch of outputs and you and want the outputs to be some function of the inputs, regardless of time. You simply want to do the computations that compute the outputs from the inputs as fast as possible, or perhaps by some hard deadline.
For instance, the thing that you can’t do is make a metronome, because a metronome isn’t a function. It’s a thing that has its own state.
I didn’t get anything out of the realtime community, at least the bit of it that I talked to. There also were people in other places who were writing realtime operating systems. That was all about interrupt handling and getting things into tight deadlines, usually under a millisecond.
Like what you’d use for landing the Apollo Lander, or doing some sort of fly-by-wire system for a fighter jet. Something where you need a result no matter what, where the quality of the result can be sacrificed, but the result has to arrive in time.
(laughs) I’m not sure how people would talk about quality versus timeliness trade-offs. A better problem space to think about was robotics. You would have an arm, and if you reached too far with the arm you wanted to pull the gain back so the arm would come back in. But if you did that too late, then the arm would come back in a little too far. Then you’d push it back out and it’d go out a little too far, and so on. Pretty soon, you’d punch yourself in the face.
Yeah, or you’d get that hunting behavior, where it oscillates back and forth.
Right, exactly. So most of the people who were doing sub-millisecond scheduling really were worried about robotics applications, or other kinds of servo control.
That wasn’t what I was trying to do. It’s hard to explain what I was trying to do. (laughs) But one of my examples, was, gee, someone walks up to the thing and plays a C major chord and you just want to hear the thing come out the speaker. Well, how would you do that?
Besides those two kinds of examples — the sort of flow-based realtime model and the interrupt-based realtime model — was Max Mathews’ work. He had a thing called RTSKED, which stood for “realtime scheduler.” His programming model was a bunch of parallel processes, each of which was waiting for a specific kind of trigger to set it off. So, for instance — I’ll get this approximately right, but not exactly — you would model a piano as 91 processes. Each of one of which has a dedicated key that’s going to go down — one of the 88 keys, or three pedals. Then there’s going to be some kind of action that will take place when it when gets set off. Then, after whatever the process is takes care of the action that is associated with its trigger, it specifies what the next trigger is that it will wait for.
So, for instance if you want to be conducted, and if you were only playing things on beats, you would wait until the conductor conducted beat one, and would say, “All right, I’ll play note number one, and I’ll wait for the conductor to hit beat two, that’ll be my next wait condition. Then, when beat two comes in, I’ll play the next thing,” and so on, like that.
So, I thought about this and I had two reactions to this. One was that in general there might be several different things — a disjunction of things — that you would want to wait for, and you might want to have different actions based on the various things that might happen. So for instance, this is a bad example, but, the piano — if you hit the soft pedal, the action moves over. If you hit a key, the action goes bang, right? So, you need actually to wait for two things, and whichever of those things happened, you need to make the appropriate response.
You don’t know in advance what order they’re going to happen in. That would be the piano telling you what score you were going to play before you went in and played it.
Just to illustrate that for the listener: the action moving over is something that takes a certain amount of time to happen. Then, pressing the key, if you pressed it right at the same time you’re pressing the soft pedal, the soft pedal won’t necessarily have moved over far enough yet, if you’re doing it incredibly quickly.
Right. Actually, that’s an interesting comment. That’s precisely where the metaphor falls apart. Because in fact, the hammer is flying through the air at the same time as the action is sliding over. You don’t know where the hammer is going to hit the string until the hammer actually hits it and that’s when it matters where the action actually happens to have been shifted over to. (laughs) So really, to model this correctly, you would need to do something continuous in time. Solve some differential equations.
I didn’t take any of that stuff into account. I was thinking, “Well, look, it’s a computer, we don’t have to deal with with physical limitations, we can have things happen instantaneously.” That might make it easier to think about and easier to design the instrument, even though the instrument might not have quite as interesting a character as it would if you really built one.
So that was that was critique number one. I started thinking about, rather than having each so-called process (as Max was calling them) specify what it was waiting for, it would specify simply that it was waiting, and have the thing that triggered it know which processes had to be triggered when it went off.
So, you’re moving some of the knowledge into the message that’s doing the triggering?
Exactly. Or actually, over to the sender. In other words, it’s not the receiver that says where I want to get the message from, it’s the sender that says where I’m going to send the message. That was idea number one.
Idea number two was: rather than have all the data in world be global variables, why don’t you actually have the data be encapsulated in the message that is the trigger? I don’t think people had done that before, at least not in music systems. That’s really what made the Max paradigm what it is — the fact that you send things messages, and the message isn’t just a trigger… (laughs) it’s the trigger, plus all the information that the trigger needs to specify all the things about it that you might care about. Again, determined by the sender, not by the receiver.
Interestingly enough, what that meant was that a thing that received a message didn’t have to go out and read data, it could maintain data encapsulated in itself and it could receive data as part of these messages. Therefore, you would have a very high degree of data encapsulation by using this model.
That’s a that’s a plus and a minus. It’s a plus because it means that your programs will grow more robustly. As you start adding stuff in, you don’t have these interdependencies between things that get out of control.
Yeah, you don’t have to worry about global state changing some local behavior in a way you didn’t expect.
Exactly. But the downside is that, of course, some things really want to be global. Like, the sample rate. So, you don’t want to have to send the sample rate along with every message. So what ended up happening was a sort of a compromise between globality and locality where most everything that is happening that is interesting, in realtime, is local. But certain things that you need, that you really just want to have around — such as stored sounds which are large arrays, or a global such as sample rate — those are indeed global. Things in Max, entities (which are called objects) can go find them, and do things with them.
When you’re doing this work, are you aware of things happening with Smalltalk? Is this ‘85-ish, we’re thinking?
Well I started doing this in about ‘82. I became aware of Smalltalk… I can’t remember exactly when, but somewhere along in there. Somewhere between 1980 and ‘85, two influential object-oriented systems arrived… more than two, but one of them was Smalltalk. Smalltalk-80, as it was called. One was so-called Class C, by one Bjarne Stroustrup, which later became C++. So at MIT, even in ‘82, we had a precursor of C++ that essentially was C with message passing.
It didn’t have all the polymorphism and other kinds of things like that. But what it did have was the notion of a data structure that you would hide from the outside world. You would pass messages which were selectors, that at that time had to be resolved at compile time.
Yeah, static messages rather than…
Right, exactly. But of course you could see immediately how to generalize that. We also knew that Smalltalk was completely dynamic in that respect. So the static versus dynamic thing was a choice to be made.
I think it was very much in the air in programmer’s circles between ‘80 and ‘85, that this was going to be a good way to do things, because it because basically of the data-hiding aspect of it. Max and Pd borrowed that very, very directly. Max and Pd did not borrow notions like inheritance polymorphism, all the other stuff that goes into object-oriented stuff these days. Lazy evaluation, forget it! (laughs)
All the things they added to Smalltalk, on the way to Self and future derivatives, to try to make it scale up to larger programs and give more different ways of forming abstractions.
Right, exactly. As far as I was concerned in the design of Max and Pd, I wasn’t concerned about that, because I was only concerned about things that were as large as a piece of music. However large that would be. I found out that…
They can get pretty big.
(laughs) The size of a piece of music can get up to about a thousand subwindows. But of course, probably not a thousand different subwindows. Probably that would include copies of things. So, probably you would talk about hundreds of unique subwindows in a patch.
Though then, of course, there are people like myself who, upon discovering an environment like Max or Pure Data, say, “Okay, can I metaprogram this and generate programmatically a thousand different subwindows?”
Oh, yes. Oh, yes. I’ve done that! (laughs)
But at that point, you’re not caring about what those thousand subwindows are. You’re caring about the program that generates them.
That’s exactly right. In fact, one person at IRCAM, where I was working, did exactly that — wrote a Lisp program that generated these million-line queue lists that would essentially sequence the passing of audio data from one static location to another in a Max patch… and actually got pieces of music to stage based on this system. I laughed at it, but it actually turned out to work.
Oh wow. I was curious to hear whether they were doing it legitimately, or if they were doing to just see if they could bring down your environment.
(laughs) Mo, it was in an IRCAM studio with a concert date. So, it was legit. It was like, let’s make this work.
What year was that at about, do you think?
I’m guessing that was ‘92 or ‘93.
Oh, okay, so by then the environment has had a lot of use. I’m sure the robustness was a lot higher than it might’ve been when you first started working on it.
Right. I think that was pushing it. But I think at that point things were pretty much settled in.
So, backing up a little bit to the very, very early days of The Patcher and the scheduler behind it. You mentioned three different kinds of scheduling, and there was one that I didn’t quite understand in relation to the others. There’s Max Matthews’ scheduler, which is independent processes that communicate with messages. There’s that hard-realtime kind of scheduling where you care about hitting specific millisecond targets. Then, you also said flow-based scheduling — I want to know what that is.
I’ve forgotten the name, but there was actually a PhD thesis out of MIT under Michael Dertouzos, who is the prof that I was aware of at the time. It was a realtime scheduler that looked like an acyclic graph. You could make graphical representations of it, if you wanted to. The idea was that you had inputs and outputs that were, essentially, voltages. You wanted the output voltage A to be the logarithm of input voltage B, say, and you wanted that to settle by a fixed deadline. In other words, if the input changes, which it would do at discrete moments in time, you had a certain amount of time to get the outputs to be a function of the inputs, which was described in an acyclic graph.
I don’t know what the name of that kind of scheduling paradigm is. It’s a somewhat different thing from from the interrupt-driven kind of thing. You don’t talk in terms of tasks, you only talk in terms of having the outputs reflect the inputs functionally within a deadline.
So, the execution model would be something like: each one of the nodes in this acyclic graph would get a certain number of opportunities to recompute its result, or something like that?
That’s correct. What you would do is, on a computer, you would actually pre-schedule the whole thing. So, you would simply run the nodes in the graph, in a fixed loop of any length that you wanted to. The loop would have to be designed in such a way that you could guarantee that when an input changed, that would trickle down to all of the outputs that it affected by each of their individual deadlines.
I don’t know. That might be kind of a minority approach to realtime programming. But it was something that I was aware of at the time.
That sounds vaguely similar to how some game engines work, in my experience. But I might be misunderstanding it.
It could be. I mean, there’s certain sorts of things that you would want to code that way. I’m trying to think of a good example right now, and kind of failing.
Any other thoughts on scheduling, before we get to the next phase of the evolution of The Patcher?
One thing that turned out to be very important was to have messages actually have ASCII equivalents, so that you could type them, and see them / print them out, and they would print out their entirety when you printed them. So that precluded the idea of having any kind of data structure…
Yeah, any live data.
…because that would require formatting. I suppose you could have messages with parentheses in them, or something like that. But I quickly decided that, since I wanted the message to be human-readable, the best way of doing that (that I could see) was to simply have there be only atoms that were things that you could type — which were symbols and numbers — then, to have the message simply consist of a collection / array of those atoms of various types.
So, did that prevent you from doing things like having a higher-order message, where a message contained a function, or something like that?
Right. You couldn’t send a function around, although you could send its name around. Yeah, that was quite a strict limitation, in what the code would do. I did that partly because I wanted things to run very quickly. I wanted to be clear to the user how long it was going to take a thing to happen. A good measure of that was going to be simply how many messages got passed. Whereas, if the message itself could be some polymorphic thing, then it could be arbitrarily large and complicated. Then, just the fact of passing a message from one thing to another could take a certain amount of CPU time that you would want to care about.
Yeah, you lose the uniformity of how long it takes to process each message, and your utility of using that as a measurement goes out the window.
Right. The other thing is all names are global. That confused a lot of people, because of course that works directly against being able to make scalable programs. Again, that was for the reason that, when I saw composers trying to use computers they would write something like a
, that they had defined somewhere, and not get it. So, actually scoping was a mental hurdle to get over for people, as opposed to a source of power, which it would be in the hands of a programmer.
To the best of my memory, it’s still that case today in Max and Pure Data, is it not? There’s no namespacing or anything like that?
As far as I know. I mean, I haven’t used Max in a while, but as far as I know Max doesn’t have it and I’m pretty sure Pd doesn’t. What you can do in Pd is name-mangle. You can make names that are generated in such a way that they look local. But you can still see what they are, and you can still get them from anywhere else in the program if you really want them.
Which, at the very least, gives you an escape hatch if you need it — if you’re doing something very complex, something where you’re generating code, or generating structures of your flow graph in Pd.
Actually, you need it right away, because as soon as you want to make a delay, you need to have a delay line that you will name. That name should be local to the abstraction that defines the delay.
Right, or else, if you use two of them, they’ll share a-
They’ll fight. So you need it right away. And yet, I make people actually name-munge in order to get that to happen, as opposed to having a local variable kind of facility.
That reminds me a little bit of the debate around hygienic macros. Does that feel similar to you? Or is that sort of a different thing?
Gosh…
Like, in the Lisp community where you have a macro preprocessor, and if you have hygienic macros, you can use names without fear that the macro expansion will cause naming conflicts.
I see. Right. In other words, making making sure the name stays within the macro. Right. I suppose, yeah, if you can’t scope a thing within a macro, then, again, you’re going to have to name-munge to get the thing to work. So, that probably is about the same thing. Or in the early days of C++ when you wanted to make generic functions, like an array add that didn’t know the type of arrays it was adding. Then you would have to write this horrible macro that didn’t know what type it was operating on, and then invoke the macro on all the types that you were going to want to ever define the thing for, right?
Yeah. We’re still, to this day, trying to find better and better ways of dealing with generics. Yeah.
Yeah, right. Exactly.
So, on that topic, when you were working on the early versions of Max, and then later Pure Data, what sort of thoughts about types were you having?
(laughs) Well, I wanted the type system to be as stupid as possible, where “stupid” is intended as a compliment. In the days of Max, there was one consideration that was just practical, which was that I was writing for a 68000 processor. There was no floating-point unit. So floating-point operations were roughly 300 times as expensive as fixed-point ones. So you needed an integer type, as well as a float type. Then, of course you needed a thing for naming, which I called a symbol. Those were the three types. That was it.
So were messages not a type, then? Or would the message be the type of the contents of the message?
Yeah, messages were not a type. That’s right, messages were just messages. (laughs)
I don’t know how to say that, but the type system really had three types.
Yeah. So, those three types are a kind of data that the system is aware of and operating in terms of. Does that then mean messages are not considered part of the data model? Are they part of the execution model? Or something else?
Oh, let’s see… um, I don’t know how to answer that. (laughs)
It might be a very bad question. It’s been about a decade since I did a deep look at the internals of how Max and Pd execute, so…
Yeah, but… I’m actually even thinking just externally. So, internally, in the implementation, a message is simply an array of typed atoms. An atom is just a type, and then a thing of that type. So there are types like that in the .h
file that everyone reads if they want to write a Pd object. But the user never sees those types — “the user” meaning the Pd programmer.
Let’s forget this types question, because that’s a rabbit hole.
When you’re building this environment, how are you distinguishing between you — the programmer, working on the underlying system, and the scheduler, and eventually the interface — versus the end user who’s going to be writing compositions within this environment? Is there a third category, which is people who might be making plugins or extensions? How are you dividing up the different roles of people who are going to be touching this software that you’re building?
Right. I think the answer is that it’s a direct map of the culture at IRCAM in the 1980s. (laughs)
Specifically, there were composers who wrote music, and who would never be much more than a Max user. In other words, they would learn how to make things out of Max, but they wouldn’t actually learn how to make Max, or make additions to Max. Then, there were people called researchers. I was one of them. We researchers would actually write software that, hopefully, the composers would be able to use. Then, there was a layer of people in between, who are now called realizers, but who at the time were called musical assistants. These people were not only power users of Max at the time, but were also people who knew enough about the internals that they could write their own Max objects, which were essentially plugins. I was thinking in terms of those three populations as I was writing along.
Lots of people were able to write small application programs in C, that would go up to 100 lines, and would do a specific thing like interpolate between two rhythms. There were people like that around, and I was interested in having them be able to use their work inside an environment. But then there were people like me around who could make the environment work. Then, there were people who simply would use the rhythm interpolator in a piece of music. They would just want to be able to call it and feed it the two rhythms, you know, make a patch that fed it the two rhythms and enjoy the interpolations afterward. Those would be the composers.
At this point, none of the composers were doing something that I see more of nowadays, where, specifically with Max, now that Cycling ‘74 is owned by Ableton if I remember correctly…
Yeah, I think that’s right. (laughs)
…where, with their tool Max for Live, you can build a Max patch that has a certain user interface skin for it, and then use that within Ableton Live. So, you have this new category of people who are end users of Max, at the same level as the composers at IRCAM, but they’re actually making yet another piece of software, that is used by another less programmatical / more musical person down the road.
(laughs) That’s an interesting comment. That that indeed has happened. I’m working with an Ableton musician right now, who uses plugins that are written in Max sometimes, but he would never actually dare try to use Max himself, he doesn’t have time to learn it. (laughs)
So that is a thing that’s happened. That’s kinda funny because Max itself can have C plugins. So, you have at least two layers of pluginedness going on there.
Yeah. Did you ever feel, back in the early days of working on these projects, that sort of multiplication of the number of different layers of people interacting with the system? In my own work on a visual programming language, which is used by people to make software, which is used by people to make software, it gets really hard to conceptualize, for me. I’m wondering if that’s something you also had to struggle with.
Gosh, I don’t know the answer to that question, because if I did struggle, it was a struggle that was spread out thinly over 30 years of messing around. (laughs)
So, I don’t think I was ever actually aware of that as a thing. What I would be aware of is: people were trying to do things in Pure Data or in Max, and they were coming up with gothic, weird solutions because of design flaws in Pd and Max, because I hadn’t anticipated certain usage patterns. I would see those, and then I would try to abstract a solution to it that I would then add to Max or to Pd. But I was unable to…
I never actually thought about someone who was doing something that I wouldn’t be doing myself.
I’m sure that eventually came up — somebody would come to you and say, “Here’s something I want to do,” and you’d go, “Oh, I’d never thought about doing it that way. Let me go back to the white board and see what I need to change about the core design.”
Yeah, that would happen. The core design is pretty much frozen these days, because you know, there’s 30 years of backwards compatibility to worry about. But that was definitely true in the early days. People would try to do stuff, and it would be hard, and then I would just have to react by making something.
For instance the whole idea of — in Max, there’s a thing called the table, which is a thing where you get to just draw a graph of a sampled function. Then, it can just apply that function to anything. Like, it can use it as a table of probabilities, or it can use it as a transfer function to get from some control change to some level change that might be nonlinear.
It’s just mapping input numbers to output numbers according to this curve that you’ve drawn.
That you draw, right. So, it’s nothing but a response curve. Well that came up because a composer I was working with wanted to be able to do that. The thing that I was calling Max at the time didn’t have that facility, and so I just added it. You know? It was like, okay, that seems like a very general thing that other people are going to want to be able to do. Let’s just add a thing called table that does that.
I’m still angry that it seems every new visual programming environment that comes out these days doesn’t have that. To me, that is such a powerful thing, it’s such an essential thing, when you’re working in a visual paradigm.
It is. It’s not only powerful, but it’s also inadequate. (laughs)
In fact, one of the things that I’ve been struggling with for… not all 30 years, but 20 of them… is a more flexible way of being able to visualize data. This is something I’ve written about but, to say it in 50 words or less: what Max and Pd are very good at is describing realtime processes, and what they’re very bad at is describing heaps of data that you might actually want to just refer to in your process. A good example being a musical score. It’s a heap of data. It’s not functionality at all.
There’s a problem in Max and in Pure Data, which is that you’re writing these things in terms of how they act. You’re making an instrument. But someone wants to store a score in the thing, and then do things that refer to objects in the score. So far, there’s no good design — or at least I haven’t seen a good design — that actually marries these two ideas in a single environment that works.
So, what have you seen, and what have you thought about, for attacking that problem? You’re absolutely right, that’s a huge issue.
There’s an attempt in Pure Data, which is a part of Pure Data that most people don’t look at. (laughs)
It’s called data structures, which is in fact what Pure Data was named for. Right when I started Pure Data, in about ‘96, was when I was thinking most seriously about this question. My idea was to have a draw program, where you could draw shapes, like triangles and whatnot. The colors and the locations of the vertices would be data that you would then integrate into the realtime programming environment. For instance, the shape of a triangle could be turned into the into the timbre controls for a node of music.
Then you would make a score that would be a bunch of triangles on the screen (just make a stupid example). You could tell the thing to play, and you could see the triangles and imagine what they would sound like. Then you could actually get the numbers out and make those sounds, and vice versa — you oughta be able to analyze a sound and turn it into a whole bunch of triangles that together would reproduce that sound in some way. When you think about what that actually would entail it gets very, very difficult and complicated, very, very fast.
I know in my personal experience of playing with that feature of Pure Data, I did find it to be unexpected. Like, as a newcomer to it, I wasn’t sure what to make of it. Knowing now that it’s designed to solve that data visibility problem gives me an interesting perspective on it. I’m assuming this was your idea, you’re — I don’t want to say responsible for it, but — you have authority over it. Are you able to say how you think it worked? Where it fell down? What you might do differently?
So, first off, just to just for fun, I should say: Pd didn’t even start out as a Max clone. I threw all the Max-like stuff in it a year after I started Pd, because there was a music production and I needed to be able to make some sound. (laughs)
Right, and so it’s sort of let’s just go with what we know.
Let’s make a simple, stupid, stripped-down Max, so that we can at least get something happening out the speakers. But in fact, the first thing I ever did with Pure Data was make a graph for a paper that I was writing with Judy Brown, a physicist, on phase vocoders. I wanted to make a graph, and the thing I was graphing went up to about 5.1, and I did not want the graph to go all the way up to 6.0, as any graphing program would do. So I wanted to make a graph where the line just went outside of the rectangle of the graph. (laughs) So I did it, and that was my founding example of what I wanted Pure Data to be able to do.
So to go back to the question of is it working, or why is it not working, what doesn’t work is very easy to find. It’s that, if you want to actually make a patch that goes through the data structure, it is misery. There is an object in Pure Data called pointer, and you have to get a pointer latched onto one of the objects on the screen. There’s no graphical way to do that, you have to do that programmatically, which means you have to make a patch that looks at the objects in the screen and figures out which one the pointer should be pointing at.
The only way to do that right now, is to actually go linearly through all the objects in that screen until you find one that obeys whatever criteria you’re looking for. That’s just horrible.
You can have objects that have objects that have other objects inside them. So, there is actually an encapsulatable data structure thing going on here.
Would that be like a bpatcher? Is that one them?
No, no, it’s like if you wanted to have your triangle have a curve stuck on it, what would you do? You would say, well, the curve is actually going to be an array, and that array is going to be of objects. Those objects could just be numbers, but they could also be any other Pure Data type — a datatype, a data structure. So, you could make the curve actually consist of little triangles.
But then to get the data out of those triangles, at the patch level, is misery, because you have to make a patch that scoots forward until it finds the thing that owns the curve. Then, you have to make another thing that scoots along the curve until it finds the object that you’re looking at. Then the items in that have names that you have to utter in order to get the stupid data back out.
So, it feels very imperative to me.
Yes, it is very imperative, and yet, it’s sort of turned inside out in a weird way, because well… because you’re making a patch that’s doing this. Anything imperative in a patch is going to be kind of sideways or inside-out or something, right?
You’ve got these two conflicting notions of when something’s going to happen.
Right. You have execution time, and you have time time, and those coexist rather difficultly in Pure Data.
That comes to the fore when you’re doing something like, let’s write a Pure Data program to search for prime numbers, just using this stupid algorithm. I’ve done it, just for hilarity’s sake. You come up with something, it’s just purely unreadable. You have two nested until
loops, and you have to use triggers to get the inner loop to actually completely execute before the outer loop ticks forward. By the time you’re done, something that would’ve been three lines of C is, I don’t know, 20 objects or so.
Furthermore, you cannot read it. You… (laughs) You can look at it and laugh. But you would never actually put yourself through programming that for any actual task. So, yeah, that’s another thing. Pd really needs a text language of some kind.
(aghast) You feel that? You feel like it’s worth dropping down to text to do this kind of thing, rather than trying to find a different visual representation that might work visually but still fit the problem you’re trying to solve?
I think so. I think that, text languages are so good at describing going through a collection of things and picking out the one that matches a criterion.
Well, that’s imperative programming, as you call it. That’s to say, that’s the thing where you just sort of say what it is that you want to have happen, as opposed to, you know, finding some sort of functional way of saying, where’s the object that obeys this function? You know? Let’s map this function to everything, and just give me the set of all things that return true, and check that it has one element… and so on, like that.
Like a query, or something like that.
Right. First off, it’s hard to make things like that work in hard realtime.
Second… I’m learning Julia right now, which is a language that has very powerful mapping capabilities. In fact, they seem to get more powerful every time Julia gets a minor upgrade. It’s a wonderful feeling of power, but at the same time, it took me an hour to figure out how to sum the rows of a matrix. (laughs)
I mean, I found it eventually. But you know, in MATLAB you just say it, and in Julia you have to…
The descriptions of how you do it, that I found on the webpages that I first ran into, basically meant that you had to had to do some kind of mapreduce on add. It was like, “Oh, man, am I going to use mapreduce just to do a row sum of an array? All I want to do is have the rows have mean zero.” I just wanted to add them up, divide by n, subtract those. I can write that in two lines of MATLAB. In fact I can write it in one line of Julia now that I’ve figured it out. But it turns out there is a function that does it.
But if you wanted to build that function…
Yeah, if you wanted to build that function — which of course is the ethos of Julia — then you have to do mapreduce, I think. Gosh, mapreduce? Really? Okay. Fine. By the way, it might matter whether you sum it from left-to-right or right-to-left, because of numerical precision issues. (laughs)
So, actually, mapreduce would have to have a little bit of description about how you would like it to mapreduce, in order to be able to specify that. By the time you’ve done all that, I think you might’ve been happier just writing the damn loop. (laughs)
It’s that problem where… you’re pushing programming so far in the direction of mathematics that you start running into the limits of what computers (as we build them) are capable of doing before the abstraction starts leaking, before the machinery of it starts to infect the pure mathematics that you want to preserve.
Oh, I like that metaphor of a leaky abstraction. (laughs) I’m going to use that. But yes, exactly. Also, simply the mental load of understanding what the thing is doing might actually outweigh the increase in elegance. (laughs) Well it’s a trade-off of power versus understandability, I guess.
I know there’ll be some people screaming at their car stereo right now. If somebody was born into an alternate world where imperative programming wasn’t the norm, and this sort of functional or declarative style was more normal, the familiarity would help them, and so it might not be as foreign feeling. But we have our culture. We have C as the underpinning of most modern languages that people learn first.
Yeah, or JavaScript now. (laughs)
Yeah, exactly. So even if it’s just a matter of familiarity, rather than something purer, that’s still a factor that needs to be considered.
Yeah. For me I go back to: I’m writing this for musicians they’re not going to want to understand map, car, mapreduce, right? So I’m living within the world that I’m in, but I have to admit that I feel a lot more comfortable thinking of the computer as a thing that executes things sequentially. (laughs) I don’t mind the idea of just writing down that sequence.
So, when you look at Max or Pure Data, back in your history of working on them and working with them, do you feel like they’re capturing computation as process and as machinery, more than computation as the evaluation of a mathematical structure? Or is it somewhere in between? How do you feel about that?
Well, it does abstract the machine away completely. So, what I’m saying about how I like to think, it might be different from how a composer would like to think, which is more in terms of a reactive… well, more in terms of a musical instrument design.
Yeah, like a guitar pedal or something.
Yeah, it’s not a modeling language, but it acts somewhat like a modeling language, in that you sort of say, “Well, I want a thing, that when you push it here, it does this.” You know? That’s different from a sequentially written program. For me, that’s the right way to design a musical instrument. But if you are going to do something that will traverse a score, which is a heap of data, then from my standpoint the most natural way I would think about that would be procedurally or sequentially.
Yeah. Where you care about something like this imaginary notion of the instruction pointer, where it is at any given moment, that sort of thing.
Exactly. Yes. My comfort zone would be having the things that traverse these data structures basically be some kind of text language. But a procedural one. An instruction based one. An imperative one — is the correct word, right?
Yeah. Well, it’s one of the options.
The transcript for this episode is brought to you by Repl.it.
Folks, the world is in the grip of an unprecedented use of the word unprecedented. Everyone is at home, which means the close collaboration we normally enjoy with our peers, mentors, and students has been shaken up. Before, I could just run downstairs and pull up a chair next to one of my coworkers so we could quickly pair-program our way through a problem. Now, they’ve been reduced to throwing folders of source code at me over the proverbial wall. Not good.
Repl.it, of course, have a great solution to this: collaborative editing, which they delightfully call “Multiplayer”. Send out invites by username, email, or with a unique link, and boom, you and your coworkers, students, friends, and family (if you have a cool family) can seamlessly work together on the same project, live and in realtime.
You see their cursor, they see yours. You each type where you want to type, and it all syncs up like magic. If you’ve used Google Docs or other collaborative tools, you know the idea — but wait ‘til you try it with code. I can even see myself using this when pair programming in person; it’s so nice to be able to zero-in on a specific character, to fix a typo without derailing my partner, to add comments while they add code.
Here are some of my favourite little details Repl.it includes:
For your next pair session, spin up the world’s coolest online REPL, invite your besties, and build something together with Multiplayer.
Thanks to Repl.it for sponsoring our transcript and helping to bring us the future of coding.
I think I’d be remiss if I didn’t ask a little bit about how the original patcher came about. Especially, how you decided on what things to expose to composers, and what things to hide from them. What can you recall about that time and how you approached that problem?
The whole process was of carrying things over from you have to code this in C into you can do this yourself, without having to code in C. In fact, the way I thought about it originally was reusability. So the idea that if you had a sequencer, you could reuse it from one application to another — which would be from one piece to another.
So, what I was thinking about originally was ways of writing little pieces of code in C, so that you could assemble a bunch of them together, perhaps with some new stuff, and make a piece of music out of it. But then the next piece, you would be able to pull, say, half of it out, and reuse.
So, I was still thinking in terms of: the piece would be a C program, but the modules of the C program would be would be largely reusable. At some point, I was showing what I was doing to the scientific director of IRCAM at the time, Jean-Francois Allouis, and I was showing him: so here’s a little bit of C code, and put that together, and it makes this nice oscillator with an amplitude control. He looked at the piece of C code, which is pretty elegantly put together, and he said, “You think a composer’s going to want to do that?” And the answer was kind of, “Eh, maybe not.” (laughs) That was what made me think: maybe I’m just going to make a graph editor to allow you to put these modules together. The way the code modules were fitting together were beginning to look like things that you could connect graphically, even though the functionality itself was pretty much fatally in C. Like, I couldn’t imagine writing a sequencer graphically, but I could imagine, adding two oscillators graphically.
Yeah, like a modular synthesizer with patch cords. Yeah.
Exactly that. In fact, I knew all about modular synthesizers, so I had that sort of model to go on. I knew that that was a very good way to talk about signal flow. But most of what was going on, we were using a 68000 processor, so we weren’t actually directly coding signals at that point. So really, the question was: processes that were about control. Actually I was doing both — I was trying to write oscillators anyway, but I knew I wasn’t going to be able to really use them. But I was also writing things like sequencers, which are control objects, which you could run on a 1 MHz processor. It got to be more and more like: you’re going to have this repository of code, each of which makes some kind of module (which eventually got called an object). What I want to do is make a way for you to be able to put these things together. The way that you put them together should also reflect the message passing / scheduling ideas that I was working on. The obvious thing to do was have the message passing be sent along paths that you’d describe graphically. Also, to have the things that you connect not be pictures of oscillators, but actually command lines that instantiate things.
Explain that a little more. I didn’t quite catch that.
If you’re programming Unix programs for instance, you write a C program. The way you invoke it is you type something to a shell, a bunch of arguments that the shell takes apart and feeds to the C program. I was thinking, the thing that you type in a box is not going to be… well, you’re not going to make an icon of an oscillator, you’re going to make an empty box and type a command to create an object. To me, the best way of doing that was going to be to allow you to just type a command line.
It’s your object name in the first position, and then a couple of arguments to that command invocation?
Right. The object would have its own code that would parse those arguments and decide what to do with them.
At this point, you’ve already got one or more input ports on the top and output ports on the bottom? Or did that come later?
Yeah, you had to have the input and output ports to be able to pass messages back and forth between these objects.
Yeah, so that things get executed at all.
Right. So, I had already thought about the idea of having these objects that were instantiated with command lines, and then defining interconnections between them. The thing that finally occurred to me was that you could actually make the interconnectedness be graphical.
So, before the interconnections were graphical, did you have another solution you were playing with? Or were you just not sure quite how to do that yet?
I actually had a solution, which was you made a text file that gave everything a name. Everything could only have one output at that time. Then you would simply give it, as part of its arguments — usually the last arguments — all the objects that you would connect it to, named.
You specify your signal graph that way.
Right. So everything only had one inlet and one outlet. The connections were all by name. Then, well first off, it became useful to have the idea of different inlet ports that would have different functions, so that the messages themselves didn’t have to say what they were. You could just make the message do what it did by connecting it to the appropriate input.
The other thing that went along with that, was being able to have more than one different output. So that, for instance, something could give out numbers, but then could have another output that would say, no, I don’t have an answer for you, better do something different, or something like that.
I know you say that there is no notion of polymorphism in Max and Pure Data, but that’s sort of hinting in that direction. Where you can have, like, a sum type in a language like Haskell, where you say it’s going to be a number or it’s going to be an empty value. So, your one output is: numbers are going to come out of this output. But if there’s no response, rather than putting it over that same output, we’ll put a different output port. That’s where the empty result is going to come out.
That’s interesting, I hadn’t thought of it that way, at all. But that’s an interesting way to think about it. (laughs)
(laughs) That’s my whole approach, and, I think, a popular approach in this Future of Coding community: learn a little bit about everything, and then try to see connections between things where they don’t exist.
(laughs) Try to make a language that can allow you to describe them.
Yeah. This one’s going to be deeply dissatisfying to the community, and maybe you as well, but I’m just going to ask for my own personal curiosity. You made the original patcher, and then Max grew up out of it and then eventually that got spun out. Then you made Pure Data. At some point Cycling ‘74 came into existence, and Pure Data kept growing as an open source project, and Max kept growing as a commercial project. Max’s user interface was seemingly refined and refined and refined and refined by the folks at Cycling ‘74. Pure Data’s user interface — also refined and refined over the years — looks and feels a lot nicer now than it did back when I first played with it, maybe 20 years ago.
(laughs) Ooh. Yeah.
How much of the direction of the user interface improvements in those projects came from you, and how much of it came from other people? Do you sort of feel like the interface to Max now, and to Pure Data now, fits how you imagined it would progress? Or did it fall short? Or did it exceed what you expected? How did the history of the interface development fit with how you felt it should’ve gone?
Huh. Well, I would say in the case of Pure Data, maybe about half of the evolution was my work and half of it was the work of frustrated users who just wanted to be able to select two objects and hit ⌘K to connect them, as opposed to having to drag that stupid line. I was patient enough to just drag the stupid line. But on the other hand, I noticed that after an hour or two or three of using Pure Data, my shoulders would ache because of the tedium of actually getting the mouse to be within five pixels of some stupid place on the screen. So I’m actually glad that there are people who think a little bit more broadly about the user experience than I am able to.
The at the same time, a lot of the improvements actually were me just getting tired of having to do a thing and finding a faster way to be able to do it. For instance, duplicate. (laughs) That’s an important thing. There are other things like that, that I came up with over time to try to just sort of make life less miserable for people who had to use the program. So a little bit of both.
But Pd also is… there are two things going on. One is just the ease of manipulating objects, and the other is the visual thing that you get on the screen. One thing that I’d been very… not luddite, but very… reactionary about is keeping that as nearly monochrome and as pixel-light as possible. Partly as a matter of aesthetics, because I think it’s… I don’t know if I should not subject other people to things that I find irritating. But I find decorations of all sorts, irritating.
I like straight lines, and I like them better if they’re horizontal and vertical. (laughs) I like simple type. I do not do dingbat type and that kind of stuff. Other people sort of get off on decorating their programs or their windows, in general. You can find things in Pd that will allow you to decorate stuff. But I simply don’t, and avoid having Pd actually present itself that way. Because I — and this is an aesthetic thing — I don’t think it’s healthy to be creating music by making pretty pictures on a screen. (laughs)
It seems like… it’s a distraction. When I see people just making eye candy for themselves — as laptop performers, say — it doesn’t quite infuriate me, but it does disappoint me, because I think they should be focusing all that energy on the sound and not on simply what they see on their screens. (laughs)
You see a strong distinction between something that might have an ergonomic benefit versus something that is there just for… giving somebody the warm fuzzies, or something like that.
That’s right. Ergonomy, I really care about. But having the having beveled boxes…
Drop shadows…
I do not care about. I can’t stand that kind of stuff.
Do you feel like it’s in keeping with the aesthetic of electrical schematics, or something like that, for Pure Data? Or is there some other sort of thing you can point to and say, this is the root of the aesthetic that I’d like to stick with?
Actually it’s my mathematics training. You don’t put in details that aren’t essential to the argument. (laughs) It tries to cut everything down. So it’s deliberately an attempt to cut everything down to the bare essentials, and to leave all distraction out.
Neat. Just the second half of that question was sort of, in how it’s evolved, do you think it fits what you imagined it would’ve been when you started? Or is it different?
It’s actually surprisingly close, I think. Well, Pd hasn’t really evolved a whole lot in any fundamental ways. The evolution that I’ve seen is a growth in the kinds of objects that people can use, and also a growth in the sorts of media that you can apply it to. That was something that I actually was thinking about from the outset, that it should be, in so far as reasonable, medium-agnostic. It’s not quite, because the scheduler… you know… time moves because sound moves in and out. (laughs) But, except for that little detail, it’s media-agnostic.
Yeah. Neat. Well, Miller Puckette, thank you very much for coming on our program and for sharing this bit of history of visual programming with us.
Right. Well, thanks for inviting me. This was a fascinating conversation for me, because this gives me a point of view on Pure Data myself that I don’t often get a chance to explore.