A Turing Machine Adaptation
Most of the demos so far are meant to be building blocks of a larger program that could be used to build a composition or architecture for tune generation. This is the first 'big' algorithm, meaning that you could easily fill up most or all of the available I/O with a single device. Let me say that I have a Turing Machine kit, but have not yet had a chance to build it. I have the Grayscale hybrid panel, the main kit, the pulses kit, and the voltages kit. Since the available time that one might classify as 'free' is extremely limited these days, I opted to adapt the Turing Machine theory to the nw2s::b platform to see how it worked out. ### The Basics The Turing Machine with its expanders is a hardware controller that is based entirely around an 8 or 16 bit shift register and a randomization circuit. If you're unfamiliar with it, there's a fair amount of information embedded in the Music Thing Modular videos, but little explicit documentation. Basically the way it works is that the shift register rotates bits from the back to the front, generating a CV signal based on the first 8 bits worth of data. It's cyclical, so effectively creates a very specific type of looped sequence. Variation is introduced through the main control pot. When the potentiometer is completely counter-clockwise, the bits are copied perfectly from the back of the register to the front. When the pot is completely clockwise, the bits are copied completely wrong (i.e. negated every time) from the back of the register to the front. As the pot progresses from the lowest value to the highest value, there is an increasing chance of the copied bit being copied incorrectly. At the midpoint, exactly half of the bits are copied incorrectly, which produces the effect of a completely random stream of bits. ### The Expanders The expanders provide a little more depth to the device by converting the 8 bits and a few select logical operations to a gate signal and a set of 8 sliders to a fairly complex step sequencer. ### The Approach The concept is simple enough, but writing this in code rather than implementing with digital logic chips gives us the opportunity to add a few more degrees of freedom. For example, rather than limiting the shift register to 8 or 16 bits, it can be of arbitrary length. Under the covers, it's implemented as a std::vector
. For the patch developer, here's how you set up the shift register size:
RandomLoopingShiftRegister* shiftregister = RandomLoopingShiftRegister::create(16, DUE_IN_A01, DIV_SIXTEENTH);
This sets up a 16 bit shift register with Analog In 2 as the control pot and responding to 16th note clock divisions.
Also, as with other patches, the clock in any given program is independent of the device itself. In our demo, the clock is a variable clock whose tempo is adjusted on Analog In 1. Other clocks are available including a fixed tempo clock, random tempo clock, and a slave clock that takes its triggers from an external digital input.
Another additional degree of flexibility we have is with the array of inputs and outputs that are available. Since the device is configured in software, we can use as many or as few inputs and outputs as we need. The demo - as it's acting as a preset - obviously uses quite a few different analog and digital outs, but if you're starting from scratch, you'd want to reduce this number to only those that you're actively using.
This code sets up the main CV out on the first analog out. It also sets up a delayed copy of the output on Analog Out 8. The delayed version will be two clock divisions behind the original.
In our demo, the primary CV is operating the A120 cutoff frequency which is filtering the Cloud Generator's saw drone. We aren't using the delayed version.
In addition to being able to easily delay signals, we can also quantize them right inside the box, creating a copy of the CV signal that is pitched to a particular key.
This code sets the key and scale globally for this shift register and then sets up a quantized output as well as a quantized output that is delayed by one clock division.
Our demo has the quantized output driving the main melodic sequence from the Z3000 and the delayed signal is driving the cutoff frequency of the SeM20 which is filtering the filtering the same.
With 16 digital outputs, we have a few to play with, so I've assigned the first 8 to display the first 8 bits of the shift register as gates. They could also be set up as triggers if you prefer, but the trigger duration is extremely short so the lights don't show motion the same way.
shiftregister->setGateOut(1, DUE_OUT_D00, 250);
shiftregister->setGateOut(2, DUE_OUT_D08, 250);
shiftregister->setGateOut(3, DUE_OUT_D01, 250);
shiftregister->setGateOut(4, DUE_OUT_D09, 250);
shiftregister->setGateOut(5, DUE_OUT_D02, 250);
shiftregister->setGateOut(6, DUE_OUT_D10, 250);
shiftregister->setGateOut(7, DUE_OUT_D03, 250);
shiftregister->setGateOut(8, DUE_OUT_D11, 250);
I did want some triggers, so used the next four to drive a couple of inputs of the LDB-1e
The second and third bits are driving the kick and hihat respectively.
#### Logical Operators
There are four logical outputs available. One set of triggers and one set of gates, each with either an OR or an AND operation. These are useful when you'd like an even to happen more or less often than a bit is typically flipped. Each of the operators can have two, three, or four operands.
shiftregister->setLogicalOrTrigger(DUE_OUT_D06, 1, 2, 4, 8);
shiftregister->setLogicalAndTrigger(DUE_OUT_D14, 1, 2, 4, 8);
shiftregister->setLogicalOrGate(DUE_OUT_D07, 500, 2, 7);
shiftregister->setLogicalAndGate(DUE_OUT_D15, 500, 5, 8);
Our snare drum is set up on the AND trigger. We also have the noise signal being gated by the AND Gate.
### Sequencer Outputs
Similarly to the way that the Voltages expansion works on the original Turing Machine, you can set up a step sequencer. The sequencer consists of 8 voltage inputs which, at each step, are added together for the ones whose associated bit is 1.
shiftregister->setSequencerInputs(DUE_IN_A02, DUE_IN_A03, DUE_IN_A04, DUE_IN_A05, DUE_IN_A08, DUE_IN_A09, DUE_IN_A10, DUE_IN_A11);
This output can also be quantized. We are using the unquantized output to drive the cutoff frequency of the Z2040 which is filtering the output of the LDB-1e.
[The entire code listing is available on github.](https://github.com/nw2s/b/blob/master/sketches/nw2s/bAlanesqueDemo/bAlanesqueDemo.ino)