Rungler for Crow

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
39 Likes

Ha - the “Benjamin” is a brilliant name for an off-brand Benjolin.

8 Likes

autocorrect ftw
thanks, and yeah, you are right

1 Like

Oh interesting implementation via sequins, going to dig in! Do I understand it correctly that you have to feed it with two oscillators yourself? Would love to see if I can take some learnings from you to improve my take on the rungler.

2 Likes

Yours is a lot more self-contained, mine is just the register and dac, so you have to build your own patch around it. I wanted to use it with a few different things in my rack, and keep complexity down, so i focused on just that.
Not sure if sequins is completely intentional, but it looks like there are some extra options compared to using a table.

2 Likes

This is a very cool idea, and I look forward to trying it out.

1 Like

Updated the first post with v2.0, completely rewrote and it’s so much tidier now. Also fixed a bug and corrected the implementation of the xor-ed feedback from step 8 to better match Hordijk’s description (thanks @lijnenspel)

I was a bit worried that the coding aspect of crow would be too much, but this has been surprisingly easy to get into

5 Likes

Hi, nice work!
As I would like to immediately try it, but I still can’t understand what to do with the rungler, could you give me an example of what to feed into the inputs? I have a rather rich modular rack so I hope I have what’s needed…
Maybe you can add some rows to the explanation, it could be good for everyone…
Thanks!!
Simone

1 Like

A barebones patch would be:
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.

7 Likes

Now, with lofi digital noise!

7 Likes

I’ve pretty much had this installed on my crow since I got it. It’s a permanent fixture in my palette which is focussed on patch programming, feedback, and cybernetics - thank you for bringing a digital shift register to Crow.

I’ll preface this by saying I’ve absolutely zero scripting experience, but I think I’ve just about understood your script (thank you for making it so clear and for all the commenting - it helps immeasurably to a newbie). One thing I hoped you could explain to aid my understanding is how the 3-bit DAC works? From what I can understand you’re taking bits 6 7 8 of the register (line 66) multiplying them by s[1] s[2] s[3] respectively and summing them together. I don’t quite understand what s[1] s[2] s[3] are? and then how this results in a non-binary voltage aka the rungler output? This my be lack of maths, lack of scripting experience, or a combination of the two.

2 Likes

This made my day, thanks. I haven’t done much coding either, apart from this and the much messier first version.

The dac multiplies three bits with the values stored in S to convert from a three digit binary number to 0-7 in decimal.

Using a the crow-specific sequins to store the numbers 1, 2 and 4 is not really necessary, but it allows me another future possibility for learning about it. The values in the register are stored in the same kind of way, so they could also potentially have sequences derived from them if I figure out a scenario where that would be useful/fun.

4 Likes

Fantastic, thanks so much for explaining that. I get it now. I like the idea of deriving further sequences from values in the register. This complete openness is kind of blowing my mind. There is so much potential for nested functions and sequences and further feedback loops which is particularly exciting to me.

2 Likes

v3.1

A simpler version with just the Rungler and a 3-stage “analog” shift register.

The digital noise and quantiser are gone, but the script is more conceptually coherent. Both the Rungler and ASR are based on the same data-structure, but read from opposite sides. Outputs 1-3 are the first three values in the continuous register, and Output 4 pools from the last three steps of the discrete one.

The data-input accepts both VCOs and function generators, it defaults to bipolar signals, but after going 256 steps without any negative values it will move the threshold for the binary conversion from 0 to 5 volts to work with unipolar signals. Any negative values resets it to 0 volts.

8 Likes

Need to check this out thanks.

1 Like

Thanks for this :slight_smile: Had fun today installing the script to crow and patching. The clock input is a mix of three function generators from Selam. No filters involved. Modulation from crow with equinox vco and loquelic iteritas vco. Piped into Bespoke synth running Unfiltered Audio’s Byome with ‘none more mono’ preset and some verb at the end.

Edit: Expanded the patch with two filters and Skorn da Bask driving the clock, plus radioactive vco added to output 4 mult.

3 Likes

Love the rungler! I can’t seem to get it working. I have druid connected and v3.1 running (does it have to stay connected to a computer the whole time or will crow in theory remember the script?). I have Instruo Ochd running into crow input 1 and Instruo Cs-L into input 2. I’m running a mult out of output 4 as per the instructions to Cs-L and Ochd v/oct ins, attenuating one of them. Am I doing something wrong?

1 Like

If you use ‘u rungler.lua’ in druid it will upload the script and remain in crow even after power cycling.

Your patching sounds correct. Try an LFO or complex cv to input 1. That could get it going.

You may need to mult the output of one of the sound sources in order to monitor it.

1 Like

If the clock is too fast crow disapproves and temporarily freezes, if you slow down the clock a little it should pick back up again. It can take going into low-ish audio rate.

If you have the computer connected you can uncomment the line that has the “print([codestuff…])” in it to see the status of the register in druid every time the clock ticks. If the mechanism of the script works this should make waves of 1s and 0s with intermittent pauses.

3 Likes

@Glitcher and @imminent_gloom thank you both, I’ll try your suggestions later :slight_smile:

2 Likes