phil maguire

CV Tools 1 - Implementing a stochastic function generator in Max

Thu 16 December 2021

Background

As a composer I am interested in music that appears static, yet at the same time, never stands still. This has manifested itself mostly in drone music and microsound pieces for modular synthesiser or computer. For example, my recent album IJzer en Staal (2021) or less recent works such as there will be no miracles here. (2016-7).

In recent years I’ve been researching methods of unifying these two instruments into a robust ecology for electronic music making. I’ve often described how I compose and perform as looking for ‘control within a range’; a sphere of possible outcomes that I can influence, but not fully dictate.

Perhaps inevitably, this has led me towards chaos and cybernetic music. I see myself, the synthesiser, and the computer, as three distinct nodes of a networked instrument (which in turn are themselves discrete networked instruments(1)).

I see the next step in the development of my practice as building self-emergent and determining systems within the computer and synthesiser, forming a larger feedback loop both with myself as the composer (2), and the signals producing and controlling the sound.

This will extend to considerations of feedback in terms of the method of listening (via recording, or in a live setting), and audience experience. I think a lot about Simon Katan’s piece God Over Djinn (2011).

As my modular synthesiser has grown, morphed, and finally settled into a relatively simple Doepfer system, I’ve long been interested in implementing control envelopes with some form of randomness. I nearly splashed out on an ADDAC506 Stochastic Function Generator  - an expanded version of the Teia Stochastic Function Generator - on its release a couple of years ago, but a lack of money and perhaps too much common sense stopped me.(3)

Instead, I recently began work on a Max implementation of a similar function generator. I use an Expert Sleepers ES-3 lightpipe module that I use as an interface between the modular and Max. It offers incredibly easy computer control a Eurorack setup: a signal is sent from the computer, to the ADAT outputs on my audio interface, and the signal arrives at the modular with all the relevant voltage scaling taken care of. I’ve also recently expanded the ES-3’s functionality with an Expert Sleepers ES-5, which provides dedicated gate outputs. Tidy!

doepfer_core1.png
Doepfer system in its current form (Dec 2021)

In Max, I tend to avoid too much parameter control, in favour of semi-autonomous behaviours. The ES-3 panel is simply eight jacks for outputting voltage, so keeping the operation of the patch as simple as possible makes sense to me.

With regard to the ADDAC/Teia modules, I implement some features in Max, and omit others:

Implementing

  • Minimum/Maximum controls for rise and fall of the envelope
  • Envelope output
  • Gate output – triggered at the end of the envelope.
  • Fast/medium/slow control
  • Logarithmic/exponential curve control – one for the rise portion of the envelope, and one for the fall portion (4)
  • End of Rise/End of Fall pulse/gate outputs – in addition to the gate output.
  • Stable envelopes – if the minimum time is set higher than the maximum time, then a stable looping envelope is achieved. Useful for locking an interesting envelope shape.

Removing

  • CV inputs – not possible at this stage, but achievable with further expansion of the Expert Sleepers section of my system.
  • Manual gate switch (Teia) – Redundant for my needs.
  • Other features such as slew controls, and random CV/gate outputs - I like simple things, so for now at least, I’m keeping these out.

Finally, I’ve added a control for the voltage range. This allows me to attenuate the signal before the modular if needed. Mostly I will be using it as a Bipolar/Unipolar (-5 to +5V/0 to +5V) switch.

 

Core of the patch

As the voltage generated is nothing more than a rise/fall envelope with randomised attack and decay times, the core of the patch is simple. The [range] subpatcher allows me to select between minimum and maximum value ranges of 0.1, 1, and 10 seconds. The random value is triggered by the [expr] objects from the input integers, whenever a maximum or minimum value is changed. The [minimum] objects compare the randomly generated integer with the maximum value to ensure that, if the minimum value is set higher than the maximum, a fixed looping envelope is generated.

patch_core.png


From here, the syntax of the message required to generate the envelope signal is calculated. [pack] and [zl.join] take care of this, combining the log/exp curve values for each portion of the envelope, and then generating a list of everything: rise value with this curve, fall value with that curve.

The [curve~] object generates the signal, and sends a bang once it has completed the function, triggering a new random value for the rise and fall (if set to ‘loop’).

 

Range control

The signal being sent to [scale~] is the output of [curve~], scaled to a range set by the slider object. This allows for pre-modular attenuation, and I’ve added a switch that selects between unipolar (0-1 in Max, 0-5V in the modular) and bipolar (-1/+1 & -5/+5V) outputs.

range.png

 

Gate outputs (in progress)

This section deals with the gate outputs offered by the ES-5. The [eor_eoc] subpatcher tracks the stochastic function and sends bangs at the end of the rise, and end of the fall. They generate an impulse signal via [click~]. This works as a pulse for the ES-3, but gives no visual feedback as the LEDs can’t react in time. The [slide~] objects filters, or ‘slows down’ the impulse enough for the LEDs on the ES-3 to react.

This section is still in development, so the random number generation on the left is for testing. There’s nothing special in the [binary] subpatcher, just the relevant numbers being triggered to activate the gate outputs on the ES-5.

gate_outs1.png

 

gate_outs_2.png

 

Patch output (in progress)

As it stands, the stocastic function is sent to output 1 of the ES-3, the [click~] impulses to outputs 5 and 6, the binary signal for the ES-5 to output 7 of the ES-3(5), and a global gate output to output 8.

patch_output.png

 

Next steps

Whilst the gate generation is still in the early stages, it’s already apparent that pulses for end of rise/fall, 8 dedicated gate outputs, and a global gate output, is overkill. No doubt I will eventually remove all but the most used gate or pulse outputs from the final patch.

You also probably noticed in the core of the patch that there is an [expr] object calculating the difference between the minimum and maximum rise values. My rough plan here is to use the difference between these (and the values for the fall time) to influence some sort of probability-controlled gate output for the ES-5. I’m quite open here to how this could operate, and I’m sure I’ll experiment as much with chaotic maths (e.g. logistic maps or other distributions) as intuitive number crunching. (6)

Of course, I currently have no means of influencing the function generator from the modular; we’re operating in one direction, and not in a network. Eventually I’ll expand the modular’s capabilities with an Expert Sleepers ES-6 module. Essentially the reverse of the ES-3(7), this will give me immediate control over the Max patch from the modular.

As is my wont, I’ll be keeping any additions simple. CV control most likely won’t influence anything particularly oblique; most likely core aspects such as log/exp control, and CV control over rise/fall time ranges.

On the Max side of things, I plan to implement the patch as an abstraction, to more easily incorporate into larger projects as a single object. And since all of the ADAT modules involved have eight channels, there is plenty of scope for a multi-channel stochastic function generator.

This projectis the first step in my developing a more formalized practice. I am going to be producing a suite of tools that allow for complex interactions in the computer/synthesiser/composer network, developing an ecology of practice in which the whole is greater than the sum of its parts.

(1) A modular synthesiser is a user-defined assemblage of modules for creating and controlling sound, and Max is in many ways a software equivalent. As for humans, where do we begin?

(2) Or operator?

(3) Envelopes like these can be achieved by patching more ‘vanilla’ modules together, for example by using a standard envelope generator’s gate outputs to trigger a random value from a sample & hold module, back to the envelope generator’s duration input

(4) the ADDAC506 actually implements a Logarithmic rise/exponential fall control controlled with a single dial

(5) The ES-5 requires the ES-3 to operate, and is linked to channels 7 & 8

(6) I should make clear that I am not ‘mathematically minded’. I work intuitively and emotionally, so any incorporated maths will likely be chosen for aesthetic (i.e. musical) reasons, rather than any mathematical consistency

(7) ES-3: ADAT to CV. ES-6: CV to ADAT