The Grid
Compact percussion for eurorack inspired from Grids, by émilie gillet, one of my favorite modules.
an example setup
I’ve spent a lot of time considering percussion for eurorack, and this is essentially where I am. I wanted to post a basic release of this script before it moved too far into the past. I’ve actually evolved this script into a new version with uses a 2hp Route to multiplex additional channels, but the basic script works well and may provide you some inspiration of your own. (I’m going to include a number of ideas for how to adapt this to different uses, including without the TXi, below.)
A key motivator in approaching this script is knowability. Grids offers a staggering amount of possibility in its design, but presents challenges to performance usage. However, many of the underlying ideas are useful to managing complex live systems!
The general idea is that you have patterns mapped to to the bottom knob of the TXi. Unlike Grids, there is no attempt made to blend between patterns and there is only one dimension of navigation. The patterns are created by hand. Please experiment with your own! 
Thoughts on pattern organization:
I primarily make techno-y stuff, so I have square 4/4 style beat variations to the left of noon, and more asymmetrical percussion to the right of noon. Noon is vanilla 4 to the floor. You can have more than the 5 patterns that I have specified, but a lower number will make the knobs more knowable. Obviously feel free to change your notions about how to organize them or disregard them, but I’d encourage you to keep something safe at a fixed position so you can find it easily (at the noon, min, or max positions).
Unnecessary knowledge about Grids:
Part of the reason I wanted to make this, is that even after spending considerable time with Grids, I found it too risky to navigate experimentally in a live context - all of my music is improvised. I considered modifying the firmware, but the code for Grids is complex, and the patterns are derived mathematically from her research on percussion. Each element in the 16 canonical patterns of Grids (which are used for blending) has 256 increments of nuance, which means even very small changes to the channel levels can produce very different patterns. I’ve reduced resolution to 16 increments to make the patterns easier to design and explore.
Requirements
crow, TXi
(thoughts below if you want to try without a TXi)
Documentation
crow
– in1: 24pqn clock input
– in2: reset
– out1: bass drum
– out2: snare drum / clap
– out3: closed high hat
– out4: random event clock triggers
txi
– knob1: kick amount
– knob2: snare amount
– knob3: hats amount
– knob4: pattern
Load the script on to crow. Wiggle some knobs! It should work as written! Adjusting any knob to it’s max position will roll the channel.
What is boost?
You will see a set of variables for boost. Boost creates a variation in the indicated measure by adding the boost value to whichever knobs you indicate in boostMap. For any channel with “boost” enabled in the boost map, for the measure specified by boostMeasure, the boostValue will be added to the channels’ knob values. This is a way to create some interest in your patterns without having to constantly attend to the knobs, by default the 4th measure will add a little extra density to the kick and snare patterns, as that’s a safe and common way to add some interest.
Considerations for case arrangement:
I find it helpful to have the TXi at the left most edge of my case. It’s also a good idea to acquire the wire and clips to make i2c cables so you can manage your lengths as you see fit based on your module choices and arrangements. I find it best to either have the crow below or immediately next to the percussion modules, as in the example image above to minimize cable run lengths.
Script
Note: I haven’t actually run this version of the script in a bit, so I’ve left the debugging comments I had had in place in case I’ve overlooked something. This uses the newer crow 2.0 ii events, but may stop working if those protocols change. I’ll try to keep this little dude up to date.
--- the grid - 0.5.1
-- author: Clayton Grey
-- inspired from Grids, by émilie gillet, one of my favorite modules
-- updated to support crow 2.0.0 ii events
-- crow
-- in1: 24pqn clock input
-- in2: reset
-- out1: bass drum
-- out2: snare drum / clap
-- out3: closed high hat
-- out4: random even clock triggers
-- txi
-- knob1: kick amount
-- knob2: snare amount
-- knob3: hats amount
-- knob4: pattern
-- Notes:
-- Adjust boost to taste (see below).
-- Please write your own patterns! The idea is that things left of noon have kicks on the 4's and things the right of noon can go asymetical. I've just done 7 patterns but you can do more, but keep the total odd.
-- Patterns 1 and noon are intentionally variations on each other, so conside keeping those as "safe" locations to dial to.
-- A stylistic choice was made to have patterns become similar at high values to ease transitions when using the device on it's own.
-- Boost creates a variation in the indicated measure by adding the boost value to whichever knobs you indicate in boostMap
boost = 3 -- value added
boostMeasure = 4 -- measure to add then reset, 2-8 all add interest, 0 disables
boostMap = {true,true,false} -- kick, snare, hats
patterns = {
-- 0 is off, values are included based on knobs positions, max knob value (16) auto rolls
{{1,0,14,0, 7,0,14,0, 4,0,9,0, 7,0,14,0},
{9,0,0,0, 1,0,0,0, 9,0,0,0, 7,0,0,0},
{9,0,7,0, 14,0,1,0, 9,0,7,0, 14,0,1,0}},
{{1,0,14,0, 7,0,14,0, 4,0,9,0, 7,9,14,0},
{0,0,7,0, 0,0,1,9, 0,0,7,0, 0,0,4,14},
{7,0,9,0, 4,0,9,0, 7,0,9,0, 1,0,9,0}},
{{1,0,13,0, 7,0,9,0, 3,0,9,0, 7,0,14,0},
{14,0,7,0, 11,0,1,0, 14,0,7,0, 11,0,4,0},
{9,0,11,0, 3,14,7,14, 9,0,11,0, 1,13,7,14}},
-- noon roller
{{1,0,14,0, 7,0,14,0, 4,0,9,0, 7,0,14,0},
{9,0,0,0, 1,0,0,0, 9,0,0,0, 7,0,0,0},
{14,0,1,0, 9,0,7,0, 14,0,1,0, 9,0,7,0}},
{{1,0,14,9, 0,14,0,7, 14,0,4,0, 14,0,11,11},
{0,0,0,0, 1,0,0,0, 0,9,0,14, 9,0,7,0},
{9,14,9,0, 6,14,6,0, 12,14,12,0, 1,14,2,0}},
{{1,0,14,0, 14,0,9,14, 14,0,14,0, 4,0,7,0},
{0,0,0,0, 0,0,0,0, 1,0,0,9, 0,0,14,14},
{0,0,7,0, 0,0,1,0, 0,0,7,0, 0,0,1,0}},
{{1,0,4,0, 9,7,14,0, 1,0,4,0, 9,7,14,0},
{0,0,0,0, 0,0,1,9, 0,0,0,0, 0,0,7,0},
{9,0,1,0, 9,0,7,0, 9,0,1,0, 9,0,7,0}}
-- {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0} blank for new patterns
}
knobMap = {
[1] = "kickMask",
[2] = "snareMask",
[3] = "hatMask",
[4] = "pattern"
}
knobs = {
kickMask = 7;
snareMask = 2;
hatMask = 4;
pattern = 1
}
clock = 1
measure = 1
-- Trent's TXi snipet
chan = 1
--
function init()
input[1]{ mode = 'change'
, direction = 'rising'
}
input[2]{ mode = 'change'
, direction = 'rising'
}
for n=1,4 do
output[n].slew = 0.0015
end
-- Poll TXi params to set clock divisions
metro[1].event = function(c)
for i=1,4 do ii.txi.get('param', i) end
end
metro[1].time = 0.05
metro[1]:start()
-- Trent's TXi snipet
ii.txi.event = function( event, data )
--print(event.arg)
if event.name == 'param' then
chan = event.arg
if data > 9.98 then data = 9.98 end -- kludge: prevent nil index for peak value
if (chan == 4) then
knobs[knobMap[chan]] = (quantizeToStepsDetent(data,#patterns,1))+1
-- if chan == 4 then print(chan, ":", data, "/", (quantizeToSteps(data,15,1.1))+1) end
else
knobs[knobMap[chan]] = (quantizeToSteps(data,17,1.1))
end
--print(chan)
end
end
--
end
-- clock
input[1].change = function()
--print('Tick : ',clock)
theBoost = 0
for n=1,3 do
-- BOOST!
if ((measure == boostMeasure)
and (boostMap[n])
and (knobs[knobMap[n]] > 0))
then
theBoost = boost
else
theBoost = 0
end
--print(knobs[knobMap[n]])
if (((patterns[knobs.pattern][n][clock] <= (knobs[knobMap[n]] + theBoost))
and (patterns[knobs.pattern][n][clock] > 0))
or (knobs[knobMap[n]] == 16)) --roll baby
then output[n]( pulse() )
end
end
if ((math.random(2) == 1) and ((clock % 2) == 1)) then output[4]( pulse() ) end
-- print(knobs.pattern)
-- print(knobs.kickMask)
-- print(knobs.snareMask)
-- print(knobs.hatMask)
if clock == 16 then
-- print(measure, "/",boostMeasure)
clock = 0
if (boostMeasure > 0) then
if measure == boostMeasure then
measure = 0
end
measure = measure + 1
end
end
clock = clock + 1
end
-- reset
input[2].change = function(s)
--print ('Reset')
clock = 1
measure = 1
end
function quantizeToStepsDetent(value, steps, centerWidth)
local centerBottom = 5 - (centerWidth / 2)
local centerTop = 5 + (centerWidth / 2)
--print ( value, centerBottom, centerTop, centerWidth)
if (value < centerBottom) then
return math.floor(range(0, centerBottom, 0, math.floor(steps / 2), value))
elseif (value > centerTop) then
return math.floor(range(centerTop, 10, math.ceil(steps / 2), steps, value))
else
return math.floor(steps / 2)
end
end
function quantizeToSteps(value,steps)
return math.floor(range(0, 10, 0, steps, value))
end
function range(min, max, newMin, newMax, value)
return newMin + (value - min) * (newMax - newMin) / (max - min)
end
function round(value)
return (value > 0.5) and math.ceil(value) or math.floor(value)
end
Troubleshooting i2c to the TXi:
I was having a hell of a time with my TXi’s and this script, where it would seemingly randomly drop connectivity during use. I spent hours trying to debug this from both the crow and the TXi side with no luck. However! When I made my own i2c cables, the problem disappeared. So try new cables if you’re getting unexplainable behavior.
Suggestions for Expansion and Modification
This idea can go much further; and as noted above, I’ve already moved beyond this. I see this as a useful starting point for people exploring this idea, and if you decide to explore this route, please let me know your ideas! Here are some considerations that I’ve made to spur your imagination:
- In this implementation, I have the last output doing a random voltage. You could also make this a 4th pattern channel and gang it’s density control with one of the other knobs.
- You could make the last channel a Turing machine that changes based on one ore more knob positions. It could generate a new pattern only when you change patterns for example.
- You could add blending back into the patterns and forgo the “notched” input reading that this script currently does to bring it closer to Grids.
- You could gang snare and hat density in order to re-introduce the X/Y navigation of Grids.
- I’ve repurposed the TXi inputs in a further evolution of this script, but you could also use them to improve this script! You could add mutes, add complex controls for a 4th channel Turing Machine, jump to a random pattern each measure if high, boost if high, roll a channel when high. You could even mix these effects based on which set of inputs are high. Implement swing or the mimic the chaos knob from Grids! There are lots of possibilities.
- You could introduce negative numbers to patterns and have the left side of the knob ignore negative values and the right side of the pattern knob use absolute values. This is akin to how the “Grids” mode in Marbles works to weight snare and kick density from it’s root patterns. Which is another way you could approach this concept!
Removing the TXi
Some suggestions for how you might make use of this without a TXi.
If you wanted to use this script WITHOUT a TXi, you could with some big sacrifices: Feed a clock to input one (start a timer when you get a clock, if it expires, reset the global position to 0 - so you can auto reset). You don’t strictly need a reset, I’ve just chosen to because I didn’t need the other input for anything else in my particular usage. If you do this auto-reset trick, you can then read CV on input 2, but you’d only have one global density control. That might work okay for you, depending on how you set your expectations. You would also, accordingly, only have one pattern with how things are setup, but there are ways around that!
You could make going all the way to 0 a kind of pattern advance or randomization and have a “soft 0” above it. You could also try to come up with some kind of gestural control (if CV dips down then up advance the pattern back, if the CV dips up then down, then advance the pattern). But it wouldn’t be smooth, and you’d have to be very thoughtful about how patterns transition.
Alternatively, you could sacrifice density and rely on external muting or manually plugging and unplugging of jack to control what’s on and off. If you did that the CV could act as a pattern morph control. I didn’t elect to to do this in my script. It just depends on your priorities and what you want the script to do.
If you wanted to get super weird with it, you could also control the clock via internal scripting and catch a trigger to perform a manual sync with something like a stack cable as a temporary patched connection. Then you could use both inputs as you saw fit, but you could fall out of sync potentially, so it would depend what your goals were (is this for live or studio use).