repo for pattern impl for scala and sound processes: https://git.iem.at/sciss/Patterns (check test sources)
also check notes: https://git.iem.at/sciss/Patterns/tree/main/notes
The dual of value and event patterns have been incorporated into Mellite v2.29.1.
{kind: repository, author: HHR, keywords: [patterns, SoundProcesses, porting, translation]}
{author: HHR, date: 12-Jan-2018}
I’m approaching the translation from two sides. One side has to do with the fact that I’m trying to understand my reservations against the model of patterns, where that comes from and how it changes when I see how you work with that. For me it’s interesting to understand why I picked a specific way of working with the pattern system, and not others. One of the things I’m trying to do in the project is to take existing works and see how they could be reformulated in my current system, and what are the implications in this. I want to see what it opens up in terms of possibilities.
{origin: conversation transcript}
This discussion is related to the idea of translating SuperCollider's pattern system into SoundProcesses/Mellite to better understand its structure and its points of friction, or resistance, to this process of porting.
{function: comment, function: contextual, keywords: [SuperCollider, pattern, Mellite, porting, translation]}
{author: HHR, date: 05-sep-2017}
by the way -- thanks for the .scd file; I looked through it yesterday; it's interesting, because I think it's a very different starting point for defining the piece than how we could do this in soundprocesses; it will be interesting to understand in what way it can be translated; obviously, the easiest would be if there was something like a pattern layer in my system (which doesn't exist right now). The involved synthdefs are straight forward to translate. I will look into the pattern objects required -- Pspawner, and Pbind -- to understand how they operate in the e-wind piece. I tried to run it, but not sure I set it up correctly. It seems to refer at some point to an inexistent synthdef named 'gated sine'. Also, do I need to feed a test signal to the microphone, or does it operate without live input? MIDI is another big story, but I understood the piece would also run without the nano control?
{origin: email, keywords: [patterns, soundprocesses, supercollider, translation, porting, experiment]}
{author: HHR, date: 12-Jan-2018}
Yeah, exactly. If I can just drop in there, for me the point is: why is the pattern interesting for me and what could I do with it? In trying out things, the pattern model is an abstraction you use a lot. I could see that from the little sketches you sent me, where I could understand your way of working and formalizing your work. It’s interesting for us to observe how you work with that, because it becomes something that’s not just the pattern system in SuperCollider but I think, as far as I conceive it now, it is also a particular use model, that is how you approach the thing. And it’s also not something that was given, in a way, but it has also a lot to do with your input at some stage in the development of that system.
{origin: conversation transcript}
{author: RK, date: 05-sep-2017}
It is really quite simple. Pspawner is really just syntactic sugar to provide a sequential means of controlling the more functionally flavored patterns. In that context patterns are akin to snippets of musical notation that are spliced together by the function in the Pspawner.
{origin: email, keywords: [patterns, supercollider]}
{author: RK, date: 12-Jan-2018}
In SuperCollider the patterns library represents in many ways a full functional model. A pattern is an abstraction that a little algorithmic score. And it can be freely reused. A pattern is such an object that you say: “Ok, be a stream!”. And it creates a stream for you. So a pattern is a little bit like a class that creates instances. But there’s this very specific doubling, or duality, which is: as a stream it might act one way, but when contributing to the definition of a stream it can act differently. In particular: a number as a stream just returns itself infinitely. But embedded in the definition of another stream it returns itself once. And so this is the fundamental trick that makes you have an easy framework where I can replace a single value with a subsequence of values. That's the interesting thing. What I found out is that it ends up much easier if you can also go into an imperative mode when creating sequences of patterns over long time. And in a way there’s a deep connection, you can think of it as the difference between writing a score and conducting it, or interpreting it. So, writing a score is totally non-causal you know, you can do all these things. But when it comes to actually perform it in time, it’s one thing after another, and the rule of time enters in. So, the functional style is fantastic, because it’s very very expressive. But when it comes to the gig, you want to say: “Now!”. And that’s much harder to do. So that’s kind of a deep issue. What’s really interesting about Scala is that’s designed to work in this cross-relations, and Hanns and I have been talking about that, and how the patterns library, or a version of it, could be added to Mellite. In the context of SuperCollider I had a strong bias, which is like: “Ah. I want processes!”. Because there are lots of things that are easy to write that way. And then the thing is that, in Scala, processes are really an issue, but it has a much more robust kind of functional library.
{origin: conversation transcript, keywords: [_, stream, framework, worfklow, functional, imperative]}
{author: RK, date: 12-Jan-2018}
Fundamentally patterns give a really compact way of describing a fairly complex set of relationships. There are number of different kind of limitations, but it’s much more concise in doing that with routines, let’s say. And for installations in particular. When I want it to be free changed, but I want to have a pretty clear handle on global characteristics, then it’s really nice to generate a pattern definition and then play it. It's like an extremely nice way to deal with issues. What pattern do is not necessarily note generation, which is what all examples do.
{origin: conversation transcript}
e-wind sketch: https://gist.github.com/Sciss/23345991b088365ac812a79b17aca90f
{kind: repository, function: sketch, author: HHR, keywords: [porting, experiment]}
{author: RK, date: 12-Jan-2018}
About the implementation of the pattern system in SuperCollider, there was kind of a design debate on two levels. One fundamental limitation of the original pattern library is that it was purely sequential. And I wanted to be able to have a time-based abstraction. Think at a chord progression: there was no way to express that in the original patterns library, because the original patterns library is purely sequential in form. So it was really great for generating materials, but not great for being descriptive of familiar structures. And it turned out that the issue was that the pattern needs an awareness of time. And furthermore it has to be able to concatenate with other completely separated patterns it might be in sequence with. To do that in SuperCollider, the routine context becomes the place where you can stash the information you need, to glue these things together. And that was absolutely my design intervention in the evolution of patterns, which I was able to sell to James because it turned out to be much more efficient in terms of memory allocation, since you’re not creating and deleting process context blocks all over the place, which kind of stresses the garbage collection.
Now, what that means in the context of Scala I totally don’t know. And I think you’re still trying to figure that out, in a way.
{origin: conversation transcript, keywords: [_, workflow, design, abstraction, library]}
Pattern thinking
{author: RK, event: SC meeting, date: 20-Jan-2018}
So, about my work with the pattern library. The basic idea is to say: I want to take every distinct subgrouping of pitches from a specific musical phrase. Let’s take three notes. I’ll take every distinct different one. And then I’ll find how to play every one of those notes in combination with that group. So these are in essence just some little extracted sub melodies from the larger sequence.
It just turns out that, in order to do this in SuperCollider, you need a bunch of coding. Because, even though array manipulations are certainly great, they’re not necessarily set up to do exactly this. This kind of idea is atemporal. You don’t want to do it in a sequential fashion. You want to take an array and generate all this possibilities. This is a kind of question that probably turns out to be much nicer to do within a functional programming language.
SuperCollider Meeting
20th January 2018, IEM, Graz
{keywords: [SuperCollider, pattern, software, implementation, design]}
{author: RK, event: SC meeting, date: 20-Jan-2018, keywords: [_, Scala, routine]}
It’s easier for me to think about a pattern as a routine. And this is again a part of the interesting conversation with Hanns, because in Scala world you really don’t want to use routines. In fact the whole Scala language group has banished routines! So it’s very interesting for me, because this is the way I think about this stuff in SuperCollider, and it would be really cool to discover an entirely different approach within Scala.
The third SuperCollider meeting took place in the CUBE at the Institute for Electronic Music and Acoustic, Graz.
Ron Kuivila, Hanns Holger Rutz and Daniel Mayer presented their sc-related work. In particular, Ron and Hanns Holger discussed the implementation and usage of the pattern library, and reflected on the differences between the functional and imperative paradigms in music composition.
{function: contextual}
{author: HHR, event: SC meeting, date: 20-Jan-2018, keywords: [_, abstraction, functional, time]}
Ron’s piece has a meta-structure to control something, patterns that are more like functional. Functional in the sense of a description that we could look at as if it was a static structure. Of course it would be turned into a stream, into something that performs. But we can reason about it as something that is just there as an object, and then we add the temporal dimension through another abstraction.
On software biasing
{author: HHR, event: SC meeting, date: 20-Jan-2018, keywords: [_, translation, porting, abstraction, Mellite]}
Software systems preconfigure the way we approach an artistic object, because we have this background layer, we know how these systems work. So they interfere with the way we conceive a specific piece. That’s obvious when you think about a structure like the pattern system, it preconfigures a specific way of thinking about how you could formalize your piece or how you could work with it.
So then one interesting experiment could be to take a specific thing that has this history with it, for example a pattern system, and see what happens when you transport that to another system that doesn’t have an equivalent abstraction, or it has other abstractions. How you find other abstractions that compensate for that particular abstraction or how could you add that abstraction to it.
Ron was working with this little sketch of the parallel structure of the melodies and he’s working in particular with this pattern system in sc. I have developed another system which is based on SuperCollider, but is a different system called Mellite. And so, one question could be what happens when you try to describe this approach in the other system. What does that reveal about the underlined tacit knowledge or about the assumptions that to undergo change.
About the translation process
{author: HHR, event: SC meeting, function: method, date: 20-Jan-2018, keywords: [_, Scala, mellite, porting, experiment]}
Two main steps are involved:
1. Understanding how a pattern system could work in Scala [language in which soundProcesses is wrtitten].
2. Understanding how that then could integrate within my computer music framework [Mellite].
I departed from one of the first sketches Ron made in October. I started with very simple things, I tried to understand how actually this all pattern system works. I copied and pasted some small patterns to see how they evaluate, what do they actually do and how does this all behaves. I wanted to undertand how does this wrapper, that takes the functional pattern system into a more imperative, a more bottom-up system, work.
I tried to eliminate the procedures, everything that is somehow in curly braces. Each of the functions now is printing out the inputs and the outputs. I translated these little functions one by one, to see how easy was that. It turned out that, because both are general programming language and this has nothing to do with temporality yet, this is quite straightforward.
Further strategies
{author: HHR, event: SC meeting, function: method, date: 20-Jan-2018, keywords: [_, Scala, mellite, porting, experiment]}
As Ron already mentioned, the routines don’t exist directly in Scala. Therefore a co-routine is really a tricky structure. Basically the concept in Scala is that if you can do it in the library, do it in the library, not in the language. If you want to have a co-routine, that is a sort of function that you can suspend, it returns something and then is able to pickup the work at a later point, that is actually quite difficult to implement as a library. So I decided to skip that part of the patterns system that is based on routines altogether.
I eliminated all the indeterministic behavior by putting the seeds value of the number generators all to the same value. And this proved that there are some implied things: for example, when you have an unordered set of numbers, you could say that conceptually they are the same, even if the numbers have different orderings, because the idea of a set is that there is no order. But then you need to iterate the set, so it would either put 1,2,3,4 or 1,4,2,3, depending on how the set structure is implemented, if it is a hash set, how the hash is calculated, and so forth. So in order to compare the two, you have first of all to make them completely deterministic.
About collections
{author: HHR, event: SC meeting, date: 20-Jan-2018}
The way you work with collections of numbers are not the same. For example in SC something that takes a collection returns another collection by applying a function to each element. This is called .collect. In Scala I used .map, which is more akin to what most functional programming languages use for something that is called a monadic operation: you map over the elements and return the same structure, or with .flatMap you map from one element to a collection and then flatten the result. So in this case is two steps against one. The style of working is kind of different, in the sense that the Scala collections have a more ‘functional touch’. You usually don’t loop and then say add something to a list. You just compose more the structure.
Data types
{author: HHR, event: SC meeting, date: 20-Jan-2018}
One big difference that makes it also difficult, especially for patterns, is that Scala, as opposed to SC, is a statically typed language. That means that every object you have has a type attached to it. That’s also the case for SC, something is a string, or a number or an array of something. But in statically typed language there’s two steps involved in executing a program: one is to compile it and one is to run it. The compilation step is not part of a dynamically typed language, where these two steps coincide. That means that in this language I have to observe the types, before I can actually run the program, otherwise the compiler would complain, because for instance you cannot add a number to a string. That’s something very very simple in SC, because these types don’t get in your way. Patterns are an interesting example because they are abstractions over element of arbitrary type. In general you have two prototypical patterns, you have a value pattern and then you have the event patterns, which are patterns of dictionaries of things that become descriptions of a sound with a pitch, an envelope and so forth. The most difficult part in modeling the pattern is understanding how we could still create this kind of expressiveness of the patterns in SC, which allow you to arbitrary nest things with their types and so forth, without them getting in your way.