process: sequencer environment design experimentation
I am designing a environment to make sequencer systems, based on the licog composer, but with the intention to allow the user to design any kind musical pattern making system. I have been working on the building blocks of this environment : what is the set of components that would allow the user to make the widest possible gamut of pattern making tools.
There are many decisions to be taken for component within this environment, regarding the communication and functioning protocol, that I realized that was crucial for getting a healthy base for any future developments. If there is anything whimsical on the way that this device is trigger, or about what this device outputs, then in future developments I would need to make compromises either in the functionality of these devices, or in the compatibility that these devices would have with the older ones. A good illustration, as always, is the Lego building block. By good luck or by a good decision, lego has been able to keep innovating and creating new pieces, allowing the user to build a very wide range of things, while still keeping compatibility with their earliest pieces. All this was dependent on that very first design of the mechanical joint that the first Lego block had. I personally find that the not so positive example is little bits. Little bits, I think that was a nice opportunity that got spoiled because of a poor definition of the communication between modules; because each module is orthogonal, and the physical shape of the first little bits was mostly designed for one input- one output pieces, now they face the following two problems: a) there are many components and systems that cannot be done, and b) some implementations of the environment have to break some rules. An example of the point a, is that despite all the enthusiasm around littleBits, in my opinion, there has not been really interesting toys made out of this. In general having a set of littleBits allow a very limited range of things that can be built. Playing with littleBits remain within the spectrum of making 'hello worlds' over and over. The for the case of Korg little bits, the spectrum of possible synths to be built is so narrow, that I can't see how can any synth could be built that doesn't already exist. An example of the point b is that in little bits Korg, the filter module needed an additional input than that single input that the environment seemed to specify, and it ended up having a lateral plug to allow that additional input.
While making a environment , it is impossible to define a correct interface between the system elements because usually it is unknown what the future elements are going to be. A possible approach to solve this, that I have taken, is to explode the current units of my system, into units that could build the units of my environment . Within the current context of actually making the building blocks to make pattern-making systems, this means that I am either defining the sub-components of the component in order to define the components in a way that will ensure that any other future component is compatible, assuming that it will be possible to build these still unknown components from the same sub-components than the components that are currently being designed.
These components, however, could have properties that can change how the object behaves. In this way, the process can be cheated in a way that we end up with a single component that has so many configuration options, that it can cover any functionality. Perhaps for some system designs this could be handy, but as I am targeting the design of physical units, I put a limit to myself where each object should have the simplest parameter tweaking interface possible, and the script that defines it's behaviour should be simple, and as monolithic as possible (avoiding too many switch statements).
After working on this process, I ended up defining a message as being a 3 byte message, that makes it midi friendly but also has an optional header for n-length messages, and four modules to process these messages.
- operator module: it performs operations to the three first bytes of the message (perhaps in the future it should allow operations on longer messages, but so far I haven't found use for the longer messages). The operations can be arithmetic (e.g. adding one to the second byte of the incomming message) or boolean, making it effectively an input filter (e.g. the message passes only if the first byte is 0x80). The operator calculates and propagates the input as soon as received.
- FIFO module: this module stores incoming bytes in an array, if the byte header | 0xF0 equals 0x20, and sends+ deletes the oldest byte of the byte header | 0xF0 equals 0x00. There are many other possible headers that may be implementing such as getting the message without removal, getting all the messages, getting the newest message, getting a specific message by index, etc.
- Output module: converts bangs into output. It depends on the context, the output module may send a MIDI signal, trigger a CV, turn a light on, trigger a solenoid, etc.
messages details (are very prone to redefinition):
- first byte defines the function of the message. Each module has a different set of reactions for each message header. This makes it similar to midi messages, where the header defines the role of the message. This was defined in this way also because the FIFO module needed to have distinct functions of store message and send buffer messages. If the functions were indistinct, it would not be possible to delay messages as it is required to make a counter, and to make a licog molecule. It could also allow for expressions with multiple variables such as a=n*c, in the operator modules.
- there is a specific header for longer messages, and if the message has this header, the component must wait for a closure byte to stop reading the message. This protocol needs some more specification, as obviously certain data string could accidentally contain a closure message that is intended to be part of the data.
The first image on this post shows how a 16 step sequencer can be made out of these components. A licog round-robin can be made on the same principle. Licogs are also easy to implement with these modules, as one can trigger a sound upon bang, store it in fifo until next clock, and send all messages in fifo on every clock to the next Licog. This distribution of parts satisfactorily covers the domain of sequencers and licog composer, but it still needs more testing regarding the domain of note offs and control messages.
I speculate three potential interesting products out of this environment:
- an online playing tool where one can make music collaboratively
- a virtual sequencer, where parameters inside a user custom designed sequencer system are tweaked through a physical interface. I imagine a button matrix with screen and encoders, that has an arduino for hardware, and a raspberry pi for the virtual system. The user would be able to graphically program the pattern making tool, define what parameters are to be controlled from the interface and how they are ordered in it, and then play music with this element as a stand alone sequencer. Each module would need an additional property, that defines a realtion with a user interface. Each component should have an additional parameter, where data is addressable from a ui.
- a set of physical blocks that let the user build pattern making tools in a fashion similar to the one of little bits. Among these blocks, there are also constructs that comprise the function of many blocks together, but allow a more easy manipulation of this set as an abstraction. (for example, a step sequencer that would allow to shift the pattern, which would not be possible in case this pattern was built out from many interconnected blocks)