"[...]faintly you came tapping, tapping at my chamber door"

[…]faintly you came tapping, tapping at my chamber door - v1.1/2.0

A touch-based sequencer for crow and landscape.fm’s allflesh (or similar)

A tactile interface for an interfaceless computer. A sequencer that does nothing to protect you from your own terrible ideas, lack of fine motor control?

Use the touch-plates to tap out a sequence, erase part of it, play some more, adjust the speed, derive rhythmic counterpoints.

I’m daydreaming about NOON and made something that is sort-of-similar to a part of the pulsar 23, although that wasn’t really the main point. It has a free-running loop that you can fill with gates using the touch-pads and it outputs a ramp in time. You can change the speed or go with what you get on startup.

Changelog

20 08 2022: Improved responsiveness at low speeds by reading to and from the sequence outside the clock-function at a higher rate.

22 08 2022: A two-channel version exists using W/del to set speed, see post #5 for details. I’m keeping v1.1 here since it works with just the crow.

Requirements

Crow, allflesh by landscape.fm or something similar that lets you patch by touch.

Documentation

Setup consists of inserting the allflesh in input 2 (and outputs 1-2 since you are already doing one) while the system is off, and not touching the pads while powering on. This lets crow configure the input to read an approximate 0 volts while idle and I’m guessing this value is not the same for all systems.

Inputs:

  1. Set tempo takes -5 to +5 volts, if unpatched tempo is random each time you power on
  2. Touchplate. High voltages add gates to pattern, low voltages remove them.
    Adjacent gates are continuous.

Outputs:

  1. Touchplate. Constant +5 volts
  2. Touchplate. Constant -5 volts
  3. Sequence of 10v gates
  4. Ramp of stepped voltages from -5 at start to +5 volts at the end of the sequence

Partial touches, depending you how badly you conduct electricity, may produce weird results if they waver across the threshold.

The constant voltages can be touch-patched elsewhere as well, and the stepped ramp probably does interesting things when feed into comparators and logicked against the sequence and some LFOs.

Download

v1.1
--- [...]faintly you came tapping, tapping at my chamber door 1.0 //////// Imminent gloom
-- A touch-based sequencer for crow and landscape.fm's allflesh (and noon)

-- On startup crow looks at the voltage coming in through input 2 to find the
-- current zero. For this to make sense, the input must be connected and not
-- touched when turning the case on.

-- Input 1: Offset, -5 to 5 volts to set BPM, randomly defaults to 100-140 on startup
-- Input 2: Touchpad, voltages here creates the pattern

-- Output 1: Touchpad, +5v, add gates to pattern
-- Output 2: Touchpad, -5v, remove gates
-- Output 3: This is where the sequence of gates emerges
-- Output 4: A ramp corresponding to the sequence length

v_cal = 0.0
threshold = 0.1
s = {}
length = 24*4  -- 4 beats @ 24ppqn
step = 0

function init()
  v_cal = input[2].volts  -- get approximate zero for input 2
  for n = 1,length do s[n] = 0.0 end
  input[1].mode('stream', 0.01)
  input[2].mode('stream', 0.001)
  output[1].volts = 5
  output[2].volts = -5
  clock.tempo = 80 + math.random(0, 60)  -- starts at a different speed each time
  clock.run(clockwork)
end

function clockwork()
  while true do
    clock.sync(1/4/24)
    step = step + 1
    if step > length then step = 0 end
    output[4].volts = (10 / length * step) - 5
  end
end

input[1].stream = function()
  clock.tempo = math.max((input[1].volts + 5) * 20, 1)  -- +/-5v to 1-200 bpm, must never be 0
end

input[2].stream = function()  -- this lets inputs happen anytime and not just as the clock ticks
  if input[2].volts - v_cal > threshold then s[step] = 10.0 end
  if input[2].volts - v_cal < 0 - threshold then s[step] = 0.0 end
  output[3].volts = s[step]
end

47 Likes

This is a beautiful little idea! It’s always really nice to see these smaller scripts that have one really focused concept & the endless possibilities come from how you play it :slight_smile:

9 Likes

i dig this idea and wanna try :smiley:

1 Like

got the all flesh, just need the crow :rofl:

1 Like

There is a version 2.0, but it comes with some tradeoffs:

You get two channels that run at the same rate - but you loose the stepped ramp and the cv over speed.

The sequence rate is controlled by the delay time of a W/del - change the delay time and you simultaneously change the sequencers speed.

If anyone (@Galapagoose?) can tell me why I am getting different values returned from ii.wdel.get ‘rate’ than I put into ii.wdel.rate (), I might be able to figure out a way to have the sequence follow the delaytime but not the division. Which I think would be neat.

Download

v2.0
--- [...]faintly you came tapping, tapping at my chamber door 2.0 //////// Imminent gloom
-- A touch-based sequencer for crow and landscape.fm's allflesh (and noon), and w//

-- Plug touchplates into the inputs, don't touch them and power you case on so
-- crow can get an idea of where zero is and calibrate them correctly.

-- Time is sett using a W/del linked over the ii bus, the sequences follow
-- the delaytime. Rate currently multiplies the sequence time, but I would like
-- to not be the case and for it to only affect the delaytime.

-- Input 1: Touchpad, valtages here creates the first pattern
-- Input 2: Touchpad, voltages here creates the second pattern

-- Output 1: Touchpad, +5v, add gates to pattern
-- Output 2: Touchpad, -5v, remove gates
-- Output 3: This is where the first sequence of gates emerges
-- Output 4: This is where the second sequcence of gates emgerges

v_cal_1 = 0.0
v_cal_2 = 0.0
threshold_1 = 0.1
threshold_2 = 0.1
s1 = {}
s2 = {}
length_1 = 24 * 4  -- 4 beats @ 24ppqn
length_2 = 24 * 4
step_1 = 0
step_2 = 0
del_time = 0.5
del_rate = 0.5

function init()
  v_cal_1 = input[1].volts  -- get approximate zero for the inputs
  v_cal_2 = input[2].volts
  for n = 1,length_1 do s1[n] = 0.0 end
  for n = 1,length_2 do s2[n] = 0.0 end
  input[1].mode('stream', 0.001)
  input[2].mode('stream', 0.001)
  output[1].volts = -5
  output[2].volts = 5
  clock.run(timecheck)
  clock.run(clockwork)
end

ii.wdel.event = function(e, value)  -- lets w.del answer when we ask about time
  if e.name == 'time' and e.device == 1 then del_time = value end
  if e.name == 'rate' and e.device == 1 then del_rate = value end
end

function timecheck()
  while true do
    ii.wdel[1].get 'time'
    ii.wdel[1].get 'rate'
    clock.tempo = 60 / del_time / 4
    clock.sleep(0.01)
  end
end

function clockwork()
  while true do
    clock.sync(1 / 4 / 24)
    step_1 = step_1 + 1
    step_2 = step_2 + 1
    if step_1 > length_1 then step_1 = 0 end
    if step_2 > length_2 then step_2 = 0 end
  end
end

input[1].stream = function()
  if input[1].volts - v_cal_1 > threshold_1 then s1[step_1] = 10.0 end
  if input[1].volts - v_cal_1 < 0 - threshold_1 then s1[step_1] = 0.0 end
  output[3].volts = s1[step_1]
end

input[2].stream = function()
  if input[2].volts - v_cal_2 > threshold_2 then s2[step_2] = 10.0 end
  if input[2].volts - v_cal_2 < 0 - threshold_2 then s2[step_2] = 0.0 end
  output[4].volts = s2[step_2]
end

2 Likes