Ornithopters
This scripts allows you to set-up “Turing Machine” style feedback shift registers (FSRs).
It implements 5 independent shift registers which can create evolving rhythms, sequences and even velocity-sensitive envelope patterns. They can also be used as looping CV recorders or even quadrature LFOs (if you are interested in that just let me know - I should have it added in by tomorrow though)! Each of the 5 shift registers has its own unique type of data storage and voltage output associated with it.
Set the four outputs to different modes to create 4 patterns which each evolve separately but in sync, set all four outputs to read from different locations within the same register for traditional shift register CV delays, or anything in between!
By default, Output 1 generates a gate pattern, Output 2 generates an analog voltage pattern, Output 3 generates a quantized analog voltage pattern, and Output 4 generates envelopes with a pattern of different amplitudes.
The Inputs
info
| name |
description |
Input 1 |
The clock source. |
Input 2 |
Used as the probability CV control: at 0V, all shift registers are frozen into loops. Moving towards +5V increases the probability that the last value will be replaced with a new value upon looping back around. Moving towards -5V increases the amount that a value will mutate/deviate away from its current value (i.e. it sets a max drunk walk distance). |
The Registers
info
| name |
description |
rhythm |
digital register: stores 0s and 1s |
weightedBitSum |
digital-to-analog register: it stores 0s and 1s, however outputs assigned to this register will generate an analog voltage by taking a weighted sum of several bits from the register. Weights are determined by the weights table. Think the Turing Machine Volts expander! |
quantizedWeightedBitSum |
another digital-to-analog register, but outputs assigned to this register will be quantized to a V/oct scale set by the scales table |
analog |
stores analog values between its min and max values. |
quantizedAnalog |
stores analog values between its min and max, but quantizes them into the scale set by the scales table. |
velocityEnvelope |
stores analog values, but they are treated as amplitudes for an envelope generated at the corresponding output. The attack is instantaneous, but the decay is controlled by the outputs slew time (e.g. output[1].slew = 0.3). |
Each register has a length (minimum of 1, maximum of 256, default 16) which determines how many values are stored in it. The last value is looped back to the beginning if Input 2 is set to 0V, creating a fixed pattern with no mutation occurring. You can change the length of a register (non-destructively) at any time using the length key.
rhythm.length = 8
velocityEnvelope.length = 56
The 3 analog registers also have minimum and maximum values they can generate. These are set by their min and max keys:
analog.min = -5
analog.max = 3.4
velocityEnvelope.max = 7.5
The Outputs
info
Each output can be configured to a different mode of voltage generation using the modes table… Depending on the style chosen, the output will automatically be assigned to one of the five shift registers. The location from within that register is set using the locations table.
For instance, running the following will set crow’s 3rd and 4th outputs to read from different locations within the quantized analog voltage register:
modes[3] = 'quantizedAnalog'
modes[4]='quantizedAnalog'
locations[3] = 1
locations[4] = 2
Setting an output’s mode to 'none' will result in the output being freed to be used in another manner:
modes[1] = 'none'
| mode |
register |
info |
'trig' |
rhythm |
setting an output to this mode results in a 10ms trigger pulse generated whenever the readlocation of the output in the rhythm register is a 1. the trigger’s level is determined by the output’s level key - e.g. output[1].level = 5 results in 5V trigs if modes[1] = 'trig'
|
'gate' |
rhythm |
setting an output to this mode results in a gate which remains high whenever the read location in the rhythm register is a 1. the gate’s level is determined by the output’s level key - e.g. output[1].level = 5 results in 5V gates if modes[1] = 'gate'
|
'envelope' |
rhythm |
setting an output to this mode results in an envelope being generated out the corresponding output whenever the read location in the rhythm register is a 1. the envelope’s level is determined by the output’s level key - e.g. output[1].level = 5 results in 5V gates if modes[1] = 'envelope'. the output’s slew time determines the decay time on the envelope: output[1].slew = 0.5 would set a 500ms decay time. |
'weightedBitSum' |
weightedBitSum |
setting an output to this mode results in an analog voltage being generated as a weighted bit sum of several bits from the weightedBitSum register. the weights are set in the weights table. the output slew time works as expected. |
'quantizedWeightedBitSum' |
quantizedWeightedBitSum |
setting an output to this mode results in an analog voltage being generated as a weighted bit sum of several bits from the quantizedWeightedBitSum register. the weights are set in the weights table. the output slew time works as expected. the voltages are quantized into the scale set by the scale table. |
'analog' |
analog |
setting an output to this mode results in an analog voltage being generated. the output slew time works as expected. |
'quantizedAnalog' |
quantizedAnalog |
setting an output to this mode results in an analog voltage being generated. the output slew time works as expected. the voltages are quantized into the scale set by the scale table. |
'velocityEnvelope' |
velocityEnvelope |
setting an output to this mode results in an envelope being generated. the value of the read location in the velocityEnvelope register is used to set the amplitude of the envelope 0 corresponds to 0V amplitude, 10 corresponds to 10V. changing the velocityEnvleope.min and velocityEnvleope.max keys will then let you set the range of allowed envelope amplitudes. decay time is controlled by the output’s slew time. |
|
|
|
Advanced
info
You can reconfigure how outputs assigned to each mode generate their voltages by redefining the functions stored in the action table. for instance, to change how outputs set to the 'analog' mode generate voltage, you could redefine actions.analog:
actions.analog = function(outputIndex)
return lfo(output[outputIndex].rate,analog.register[locations[outputIndex]])
end
You can also create new shift register tables at run time using the newRegister(name,length,digitalOrAnalog,minVal,maxVal) helper function to generate a table. Store the table in a variable with a name of your choice. E.g.:
myRegister = newRegister('voidstarReg',16,'digital',0,1)
Whenever you want to “process them”, pass them to processShiftRegisters(register,cv).
You can then read the values stored from <varName>.register[location].
Code
ornithopters.lua (5.2 KB)
NB: it requires the latest version of druid installed and the most recent crow firmware installed.