Rungler for Crow - v3.1
The Rungler circuit from Hordijks Benjolin
This is a pretty good description of how the rungler works:
https://electro-music.com/forum/topic-38081.html
While I played modular grid before building my current modular I had a benjolin in there for most of the iterations. As it turned out I never got one, but the rungler is still on my mind, when I got a crow it seemed like a good exercise to get started (and then keep tinkering with).
Changelog:
v1.0 First attempt
v1.1 Added multiplied feedback from step 8
v2.0 Rewrite, feedback from step 8 more accurate and quantiser should work
v2.1 Changed output 3 to lofi digital noise and updated documentation
v3.1 Rewrite, simpler concept; Rungler + 3-stage analog shift register. Defaults to bipolar data, but can auto-detect unipolar signals and adjust the threshold for binary conversion accordingly.
Requirements
Crow, moving voltages to clock and sample, a mixer to rungle the voltage-sources
Documentation
-- Input 1: Clock
-- Input 2: Data to be sampled into the shift-registers.
-- Converts to binary at 0v by default or at 5v if
-- the last 256 values sampled are below zero.
-- This allows both VCOs and function generators
-- to provide data without extra modules.
-- Outputs 1-3: Analog shift register with 3 steps
-- Output 4: 3-bit DAC reading the last steps of the digital shift register
-- (the Rungler!)
A patch and an explanation:
Plug VCOs or LFOs into the inputs; mult output 4 to two attenuators or attenuverters; patch each of these to control the frequency of the oscillators; monitor one of the oscillators.
The first oscillator is the clock, on every rising edge it samples the second oscillator and adds its value to a shift register that outputs a stepped modulation-signal.
A usual implementation has the rungler patched so that it feeds back on the sources providing its input resulting in a chaotic pattern that intermittently jumps from one state to the next.
The output is created by running the last 3 steps of the register through a 3-bit DAC, which gives 8 possible values. The register is also feed back on itself by combining the new value with the last step using an xor gate.
There are several different versions of the Benjolin out there that all have slight variations, most have two wide-range VCOs and a filter with loads of cross modulation and feedback as well as multiple outputs from both oscillators, combinations of them and the filter.
Download
v3.1
--- Rungler for Crow v 3.1 //////// Imminent gloom
-- The rungler is designed by Rob Hordijk and is described here:
-- https://electro-music.com/forum/topic-38081.html
-- Input 1: Clock
-- Input 2: Data to be sampled into the shift-registers.
-- Converts to binary at 0v by default or at 5v if
-- the last 256 values sampled are below zero.
-- This allows both VCOs and function generators
-- to provide data without extra modules.
-- Outputs 1-3: Analog shift register with 3 steps
-- Output 4: 3-bit DAC reading the last steps of the digital shift register
-- (the Rungler!)
a = {}
c = {}
d = {}
s = 'none' -- or fill a {} with pretty numbers to quantize
sum = 0
function rotate(t, l)
table.insert(t, 1, t[l])
table.remove(t, l)
end
function check_input()
sum = 0
for n = 1, 256 do sum = sum + c[n] end
return sum
end
function init()
input[1].mode ('change', 1, 0.1, 'rising')
for n = 1, 3 do output[n].scale = s end
for n = 1, 8 do a[n] = 0.0 end
for n = 1, 256 do c[n] = 0 end
for n = 1, 8 do d[n] = 0 end
end
input[1].change = function()
if check_input() == 0 then threshold = 5 else threshold = 0 end -- replace with "threshold = 0" (or 5) to disable auto adjust for bi-/unipolar data
a[1] = input[2].volts
c[1] = input[2].volts < 0 and 1 or 0
d[1] = input[2].volts > threshold and 1 or 0 ~ d[8]
output[1].volts = a[1]
output[2].volts = a[2]
output[3].volts = a[3]
output[4].volts = d[6] * 4 + d[7] * 2 + d[8] * 1
-- print(table.concat(d, " ")) -- ooh, shiney!
rotate(a, 8)
rotate(c, 100)
rotate(d, 8)
end
v2.1
--- rungler for crow v2.1 //////// Imminent gloom
-- the Rungler is Rob Hordijks idea; it's a very good idea.
-- my best guess at one based on https://electro-music.com/forum/topic-38081.html
-- input 1: clock, rising edge
-- input 2: data
-- output 1: s/h (bonus feature #1)
-- output 2: quatized s/h (bonus feature #2)
-- output 3: digital noise (bonus feature #3)
-- output 4: RUNGLER!
-- WTF and basic patch:
-- Plug VCOs or LFOs into the inputs; mult output 4 to two attenuators or
-- attenuverters; patch each of these to control the frequency of the
-- oscillators; monitor one of the oscillators.
-- The first oscillator is the clock, on every rising edge it samples the
-- second oscillator and adds its value to a shift register that outputs
-- a stepped modulation-signal.
-- A usual implementation has the rungler patched so that it feeds back
-- on the sources providing its input resulting in a chaotic pattern that
-- intermittently jumps from one state to the next.
-- The output is created by running the last 3 steps of the register
-- through a 3-bit DAC, which gives 8 possible values. The register is
-- also feed back on itself by combining the new value with the last step
-- using an xor gate.
-- There are several different versions of the Benjolin out there that
-- all have slight variations, most have two wide-range VCOs and a filter
-- with loads of cross modulation and feedback as well as multiple
-- outputs from both oscillators, combinations of them, and the filter.
register = sequins{0,0,0,0,0,0,0,0} -- use sequins as register
r = register
s = {4,2,1} -- set up 3-bit DAC
function init()
input[1].mode('change',1.0,0.1,'rising') -- set up input 1 to take clock
output[2].scale({0,2,3,7,8},12,1) -- set scale for output 2
m:start() -- start metro for noise
end
function to_bin(value,threshold) -- check if value is over threshold and output 1/0
b = value > threshold
return b and 1 or 0
end
function noise() -- output +/-5 volts randomly when called
rnd = math.random(1000, -1000) * 0.005
output[3].volts = rnd
end
m = metro.init{event = noise -- metronome that calls the noise function really fast
, time = 0.0004
, count = -1
}
input[1].change = function()
v = input[2].volts -- get voltage from input 2
r[1] = to_bin(v,0)~r[8] -- convert to 1/0, xor with step 8, save to step 1
output[1].volts = v -- output s/h
output[2].volts = v -- output quantized s/d
output[4].volts = r[6]*s[1]+r[7]*s[2]+r[8]*s[3] -- output step 6-8 via 3-bit DAC
r:settable({r[8],r[1],r[2],r[3],r[4],r[5],r[6],r[7]}) -- Rotate register
end