Teletype concepts and thoughts

this is great, and please feel free to post here - it’s an open topic / discussion!

your scene in a way is the essence of teletype - it’s a device that orchestrates events based on triggers, but unlike conventional sequencers, instead of just generating a CV/gate you can have more complex logic being executed on each step.

an alternative way to set up this kind of a scene is to just trigger all scripts on each metro but then use something like PROB or EVERY to control individual script execution. the benefit of doing it your way is being able to control all 8 scripts from a single pattern value (a fun thing to do would be generating random pattern values).

why this kind of a scene is great is because you can do many things in each script. you could add ratcheting by doing something like DEL.R 4 / M 4: TR.P 1. or add a simple CV 4 RND V 10 and then use it to modulate a filter or a delay, so you have a sample&hold that will change CV 4 value each time a drum is triggered.

re: allflesh not triggering teletype - you can use gates to trigger scripts, likely it’s just not hitting the threshold.


Thank you, fantastic!
Two main take aways for me:

  1. Should use the param knob more!
  2. Should learn Bitwise OPs!

The way you store the sequence with multiple scripts triggered per step is just genius!!


Same here! Gonna dive into Bitwise ops! Thanks for your post!

1 Like

omg insane system really diggin it ! :heart_eyes:

This was really inspiring and provided several friendly jumping off points for me, thanks.


Concept: Kria Companion

made with an early version of this from a few days ago

I’ve been working extensively with Kria over the past year or so, and have nailed down a pretty good flow with a certain set of external controls, typically through 16n. However, I’ve recently been playing more “hands on knobs” because of certain normalizations within modules (DPO wavefolder), or else because many parameters I’d want to tweak by hand are already receiving modulation from elsewhere and I don’t have 16 free VCA/CV mixing channels lying around. This led me to neglect the 16n, since I’d be constantly riding knobs rather than faders and, in my last bigger patch, I only used three of the sixteen faders (and not particularly elegantly). So, I thought, let’s get rid of the 16n altogether and maybe even teletype while we’re at it.

This is, essentially, a “performance page” for kria tailored to my specific goals that makes heavy use of grid ops for teletype, and that I hope to transfer to satellite soon.

I’d like to say this only took three evenings, coming from lots of tt experience but 0 other coding besides, and the bulk of it was actually done this afternoon after reading about button groups and realizing all of the problems I was facing had already been solved.

I did a little sketch of the button lay out for the parameters I wanted and then set about creating SO MANY groups.

G.GBX 0 1 0 0 1 1 1 0 5 4 8
G.GBX 1 33 4 0 1 1 1 3 6 1 8
G.GBX 2 41 5 0 1 1 1 3 6 1 8
G.GBX 3 49 6 0 1 1 1 3 6 1 8
G.GBX 4 57 7 0 1 1 1 0 6 1 8
$ 8; $ 7

G.GBX 5 65 8 0 1 1 1 0 6 1 8
G.GBX 6 73 9 0 1 1 1 0 6 1 8
G.GBX 7 81 10 0 1 1 1 3 6 1 8
G.GBX 8 89 11 0 1 1 1 3 6 1 8
G.GBX 9 97 12 0 1 1 1 3 6 1 8
TR.TIME 4 11

J 105; K 113; D 121
G.GBX 10 J 13 0 1 1 1 0 6 1 8
G.GBX 11 K 14 0 1 1 1 0 6 1 8
G.GBX 12 D 15 0 1 1 1 0 6 1 8

So that gives us 13 groups of vertically arranged buttons, with a sorta striped pattern to help guide the eye, and with the leftmost group containing four columns of buttons rather than just one column per group. Those GROUP 0 buttons also trigger a different script from the rest of the buttons.

The first four columns I’d like to control harmonic content, with kria scale on the y axis and offset in fifths along the x axis (so that, left to right, you get I, V, II, VI, with highly limited four-note scales interior to Kria, based in part on the rings/plaits chord mode, mapped vertically, most consonant on top, most dissonant on bottom). These buttons all trigger script 5:

A + * 5 G.LED 13 8 * 7 G.BTNX

This first component of A (* 5 G.LED 13 8 ) will be explained later. Otherwise this script just literally “change kria scale to Y (+ 8 cuz that’s where custom kria scales sit for me)” and “create variable A which is equal to X as expressed in fifths (+ some other fuckery)” This A is a component of all of my three “note-triggering” scripts.

The next three are per-channel offsets that scale up in fifths and octaves. This is where the key trick of the script comes out: storing values in grid row 8 via brightness (hence, out of reach). In fact, that’s all script 6 does at all. Ninety of our buttons just say “turn off the other buttons in this row and set the brightness of a non-existent square to this integer value so we can MATH it later.”


The next three are per-channel probability faders for controlling note density.

The next three are per-channel clock dividers.

The next one is a “key” designator, which acts as a master offset in fourths (this is that first component of our variable A).

Finally we have a pair of values which are multed together to give the clock base. I like having two. different controls as one can get clean divisions at a glance or deliberately increase / decrease in a fashion that does not contain an obvious division of the prior state (by changing both values simultaneously).

Each of these groups just triggers script 6, but here’s how they get used, ultimately:

J / QT KR.CV 1 N 1 N 1
K / QT KR.CV 1 V 1 V 1
CV.OFF 1 PN 0 G.LED 4 8
PROB - 100 * 14 G.LED 7 8: BRK
CV 1 + V K N WRP + A J 0 11
TR.P 1

Set local variables J + K to nice clean semitone and octave values, respectively. Set the lowest possible note to some number from this list:


corresponding to the position of the fader on column four. If column seven is set very low, probably stop here. But maybe don’t. If not, trigger a note that folds together the proper key and chord offset (on top of the octave / fifth “master offset”) and wraps, maintaining the integrity of any octaving coming from kria.

The next two scripts are duplicates of this, incremented by one in key locations:

J / QT KR.CV 2 N 1 N 1
K / QT KR.CV 2 V 1 V 1
CV.OFF 2 N PN 0 G.LED 5 8
PROB - 100 * 14 G.LED 8 8: BRK
CV 2 + V K N WRP + A J 0 11

J / QT KR.CV 3 N 1 N 1
K / QT KR.CV 3 V 1 V 1
CV.OFF 3 N PN 0 G.LED 6 8
PROB - 100 * 14 G.LED 9 8: BRK
CV 3 + V K N WRP + A J 0 11

And then in the metro script…

EVERY + 1 G.LED 10 8: KR.CLK 1
EVERY + 1 G.LED 11 8: KR.CLK 2
EVERY + 1 G.LED 12 8: KR.CLK 3
J * G.LED 14 8 G.LED 15 8
M * J 30; TR.P 4

I’m posting all this in part to force myself to audit my own work (found two mistakes!!!), and in part to encourage people to take advantage of 1) this awesome thread 2) FUCKING AWESOME GRIDOPS!!! and 3) satellite.

The last part is to ask a little aaaaaaaaaadvice. Are there any overtly dumb things going on here? Something super clunky for no reason? I want to turn this into a satellite script and migrate TT out of my main case (because this is all I’ve been using TT for for a looooooong time), but want to make sure this is smooth sailing first. I know Satellite only has two trigger ins – could I just set it to poll Kria’s trigger outputs in the metro like so: “IF KR.TR 1: $1”, or will this upset the I2C gods? Finally: I’d like to create a per-note keymap for the leftmost quadrant of the grid to highlight “safe” harmonic choices and aid in learning the moves from a set of ~12 possible next moves each rather than 32 – is there a good way to do this in 1 script, possibly storing data in the tracker / unused grid buttons / both? That leap still isn’t happening for me…

Also let me know if there are any questions about this. The thought of a custom Kria page is… Amazing. Then thinking “custom page for ANYTHING” is just… Too much.


This looks really fantastic and gives me another push to revisit grid ops (which so far I’ve found a little on the wrong side of the planned coding / live coding divide for my tastes). I’m very keen on the idea of using Teletype as a metasequencer for kria (and also, perhaps, the other way around)! Can I ask, do you have two grids? Or do you have a reliable way of switching the grid between the two modules. I’ve tried various cables and switches but it’s always ended up being a bit clunky and/or noisy.



This has worked for me but ymmv. I’ve found tt and grid noise to be magically disappearing / reappearing type things, varying due to which wall it’s plugged into, how many LEDs are lit, etc.

I will say that this particular page I use instead of grid control of Kria, not in addition to. My sequences are “prepared” in an extra-especial fashion to work well with this particular set of manipulations.


sorry, finally found the time to reply - this is totally amazing!! the scene itself and the detailed breakdown both.

this is such a great example of how you can essentially add your own features to kria, earthsea and any other i2c controllable apps - all the way to creating your own interface for them! i love the fact that you didn’t just expand kria’s interface but replaced it with your own. and yeah, a good way to use satellite as this is something you likely to build once and then maybe only tweak occasionally (also a reminder for me to fix the bug in satellite).

in terms of the script itself not much to add, really! it’s very straightforward and shows that you don’t really need a complicated script. glad you took advantage of groups, it would be difficult to achieve same functionality in a limited script space.

you’ll need something to provide power/pullups for i2c - do you have anything on your i2c bus that would have that? if you’re just planning to use ansible/kria + ansible/satellite you’ll need an i2c backpack or something similar (txb would also work).

should be fine!

yeah i would say use patterns to store coordinates or something like that and then set them in a loop. and then use G.LED with brightness level set to -2 - that’s a special value that will “brighten” whatever is underneath, including buttons.

clever trick with storing values in unused LEDs! you’re limited to range 0-15 though. i’d use fine faders instead with G.FDR.V ops. you can store 64 values this way.

have you seen the awesome ANS.G ops @csboling added a while ago? you’re not limited to app specific i2c ops - you could emulate any grid press or a combination of presses.

1 Like

“This is great; recode everything” – the best kind of feedback!

Really though: switching to faders is gonna help save a ton of space (in subtle ways)! Lots of other gold here, too :slight_smile:

I’ve never done anything with loops but will hopefully start tinkering tonight after the rebuild. Expanding harmonic vocabulary was the real catalyst to move to this (vs a single button that changed keys in fourths) and it’s a little difficult just hunting and pecking for transitions lol.

I was thinking to put Crow + JF on the I2C bus. Crow should gimme the pullups needed, right?

1 Like

Yes, as long as you haven’t disabled the pull-ups in your user script (for whatever reason).
JF running 4.0 firmware also provides some weak pull-ups.


concept: simple performance patch

this is a re-recorded version of the patch i did for flash crash (the original performance was shaky due to my nerves, the recording seem to have some timing issues and the screens aren’t very readable). i initially considered doing something unusual, like creating some special ops or hacking the firmware in some other manner, but what i really wanted to demonstrate is that you don’t need to use a lot of ops or complicated techniques to get something going.

there is also nothing particularly special about 2 teletypes - could probably do the same with one but it made it easier to separate voices. the left teletype controls the left disting ex via i2c, which is used as a drum sample player (sd triggers algorithm). it’s further processed by mimeophone. the right teletype controls telexo / just friends / another disting ex (running augustus loop delay).

the crossfader is mainly used to mix drums and just friends output. i initially planned to do something interesting by controlling teletypes with it by patching the crossfader CV to teletype inputs and using that voltage to control various script aspects, similar idea to octatrack, but ended up not using it that much.

here is the breakdown of what’s happening:

i start by initializing the synth mode on JF. i also wanted to show you can get so much variation by simply playing the same 6 notes (you’ll see below i partially failed to do that even in this re-recorded patch).

L 1 6: JF.NOTE N P I V 5

i populate patch bank 0 with 6 notes and send them to JF with the above loop. from now on the only pitch change that will happen will be through transposition.

create a counter using variable T to simply step through the 6 notes:

T % + 1 T 6; J + T 1

first mistake here, J should be used instead of T on the 2nd line. T % + 1 T 6 means: “add 1 to T, then wrap it back to 0…5 range using the modulo operation”. since i’m using pattern values 1-6, i needed to shift this range to 1…6, which is what J was for.

add some JF modulation using telexo LFO:

TO.OSC.CYC 2 15000
TO.CV 2 V 5

this will start an LFO on output 2 with cycle of 15sec and -5…+5V voltage range.

create a super simple trigger sequencer with grid ops:

G.BTX 0 0 0 1 1 1 0 0 16 8

this creates a block of 1x1 grid buttons in a 16x8 block - 8 tracks with 16 steps each. adding this to the metro to highlight the active step:

T % + 1 T 16
G.CLR; G.REC T 0 1 6 -2 -2

tracks 1-6 will be used to trigger drums 1-6 on the left disting:

L 1 6: SCRIPT 7

and this is script 7:

J + T * - I 1 16

G.BTN.V will tell us if a grid button is pressed or not. since the buttons started with id 0 (1st parameter to G.BTX) and they are given ids that increase left to right then top to bottom, we can calculate the button number for the current track (which is stored in variable I when script 7 is called from the metro) and the current step (stored in variable T) by using the formula above.

if the button is pressed, G.BTN.V J will return 1, so the IF statement executes. EX.TV is a disting op that triggers the drum voice passed as the 1st parameter. the 2nd parameter is loudness, and by using PARAM i can use the teletype knob to control drum volume.

i also want to use tracks 6-8 to send triggers to teletype #2, so i copy script 7 to script 6 and modify it to send triggers: IF G.BTN.V J: TR.P - I 5 (we have to subtract 5 so that tracks 6-8 translate into trigger outputs 1-3).

i patch teletype #1 trigger output 1 to trigger input 1 on teletype #2. i stop the metronome on the 2nd teletype, and instead call the metro script from script 1. i also clock the augustus loop algorithm on the right disting with EX.AL.CLK.

i also connect trigger output 2 to trigger input 2. now script 2 on teletype #2 is also sequenced from the trigger sequencer. i will use it later to transpose the sequence.

instead of stepping through individual notes i change it to a chord stab:

L 1 6: JF.VTR I V 5

JF.VTR has 2 useful aspects - it triggers JF voices using the last pitch received, but you can still change the volume of each voice.

syncing mimeophone to teletype #1 metronome by using trigger output 4

adding further variation by transposing the whole JF chord:

C % + 1 C 4

JF makes this kind of thing very easy!

i spend a couple of minutes here trying to set up a telexo voice as the bass. first, enable envelope and choose a waveform:

TO.OSC.WAVE 1 2400

then trigger the voice and set the volume using the param knob:


there is no sound because the current pitch is 0 - which is very low.

the bass finally drops! always remember to shift by several octaves up for telexo. i use the same notes i used for transposing the chord for the bass.

drums are pretty static - let’s add some variation on each 8th step. in metro:


which is simply a way to call script 5 in a loop (i only want to modify drums 2-5):

L 2 5: SCRIPT 5

and script 5:

J + 1 * I 3
EX.P + 7 I RRND J + J 5

this needs some unpacking. i prepared drum samples specifically for this patch by collecting 6 samples for each of 6 voices and naming them so that kick would be files 0-5, snare - files 6-11 etc etc. J will give me the number of the 1st sample in the group, and RRND J + J 5 will select a random sample from within that group (except that i made another mistake here and I should be multiplied by 6). i then use EX.P op to change assigned sample to the randomly selected one (side note: changing folders is not instantaneous, so i wouldn’t try to change it live, but changing individual samples seems to be fine!).

add random modulation for mimeophone - i typically use CV RND V 10 as a super quick way to generate stepped random voltage. CV.SLEW could also be very useful here.

further JF variation - instead of playing a chord, i change it to play a random note. there is a mistake in the line - instead of JF.VTR RRND 1 6 V 2 V 7 it should be JF.VTR RRND 1 6 RRND V 2 V 7, so that in addition to playing a random note it should also use a random volume for it, but since i didn’t include RRND it just takes V 2 as the volume parameter, resulting in me trying to figure out why JF is so quiet all of a sudden.

add another random stepped modulation for JF

one more random stepped modulation - but for this one i use script 3, which is triggered from the trigger sequencer track #8 - this is a good way to sync modulation changes.

mute bass drum by changing the loop that triggers drums.

change back from individual notes to a chord stab. i’m still missing RRND in front of V 2 V 7 here, which is a bummer because one of the cool things to do with JF is to play the same chord stab but vary volume of individual notes - you get really nice organic changes.

i finally do something with the crossfader - simply modulating the position with a random voltage generated by teletype, which adds more variation to the drum track.

that’s it! the only remaining thing to mention is that just friends is an incredible sound source - which is bad for practicing, because you get lost in all the sweet spots!


Amazing, thank you for taking the time to record and share all this! It’s really incredible that you’re getting this out of such a small system — all those modules are really pulling their weight! Love the look of the video too :slight_smile:

The way you were thinking about using the crossfader octatrack style is really interesting — using the param-knob or cv in to teletype (in the absence of a cool crossfader module :stuck_out_tongue: ) as a way of sort of “preset shifting” or something, the way people use the octatrack crossfader, seems like something with a lot of performance potential that is under-explored (maybe just by me! lol).


yeah, i was trying to think of a simple mechanism to do that… you are essentially using a value (crossfader position or CV or param knob) to scale between 2 sets of values. one thought was to use pattern banks, one bank for left side values and another bank for right side values, and have a script that would do something like PN 2 I SCALE PN 0 I PN 1 0 V 10 PARAM.

another option is to scale any constants you have in the code, assuming zero is appropriate as the minimum value - let’s say you have DEL.X 15: ... and you want to scale that 15 based on the param knob. you could do something like DEL.X / PARAM / V 10 15 but it’s really awkward. maybe we need a dedicated op for this, so you could do something like DEL.X SC 15 PARAM:


ahhhh i’m such a sucker for modulating delay arps like this. thank you for sharing and all the explanations. i’m watching and learning now!


Here’s a wee demo of what im tinkering away with at the moment.
A lot like Just Play from @midouest , This Teletype scene uses grid ops to play Just Friends in poly mode with Grid, with dual pyramid interface and massive boiling sun.

Big thanks to all on the discord that have been helping me to try and add features and share their insight.

Current features
standard 12tet keyboard output or Quantised output
Hidden Sun Keys 1 & 2 activate two additional generative melodies, with param mapped to their amplitude

Once i’ve refined things more I’ll get all the code up for others to play around with it. Any features youd like to see included? basically 12 hidden buttons for mapping to things like JF.RUN, Triggers, CV outputs, metro etc.

Anyhoo, hope you enjoy the vid


This looks great - did you ever upload the code? I would be interested in having a play

ahh Sorry Jason, I’m afraid this is abandonware that got lost between firmware updates!
As a consolation, If you’ve not seen them already, @modularbeat made Minim and @Erekutoronikku made Gentle Antagonism which both look like excellent TT Gridstruments.


no worries, thanks for getting back - will check out those suggestions :slight_smile:


concept: plock sequencer

i wanted to do something to try the latest disting ex firmware update which allows you to have 4 mutable braids under i2c control. i’ve been using my old braids as a percussion voice a lot, so a trigger sequencer seemed like a good idea. but one of the coolest features of braids is the many models available, so why not make an elektron style plock-able trigger sequencer where you can select a different model for each step? and in addition to the model selection we could control other parameters too, like timbre and colour. something like this:


the top 4 rows represent the trigger sequencer steps - we just need 4 since there are 4 braids oscillators. the bottom 3 rows are taken by the faders we will use to edit step parameters. let’s put this in the init script and execute it by pressing F10:

G.BTX 0 0 0 1 1 0 0 1 16 4
G.FDX 0 0 5 16 1 0 3 4 1 3

you can check that it looks correct using the grid visualizer - go to live screen and press alt-g. let’s unpack:

G.BTX 0 0 0 1 1 0 0 1 16 4
      i x y w h t l s c  r

G.BTX creates a group of buttons:

  • i is the index for the first button, we can start with 0
  • x/y are the coordinates for the first button, we start with the top left corner
  • w/h are the width/height for each button, so 1x1
  • t is the button type, 0 is momentary
  • l is the brightness level for not pressed buttons
  • s is the script assigned for button press/release
  • c is the number of columns
  • r is the number of rows - so 4 rows of 16 columns
G.FDX 0 0 5 16 1 0 3 4 1 3
      i x y w  h t l s c r

G.FDX creates a group of faders - most parameters are the same as above, so we are saying: create 3 rows of faders (one in each column) starting with index 0, starting in 5th row and that are 16 LEDs wide.

typically, we would use latching buttons for the trigger sequencer portion, so why momentary buttons here? that’s because i want faders to only be shown while a trigger button is pressed - this means we need to react to both button presses and releases, and only momentary buttons trigger a script on both. this complicates things a little as we can’t use the button states to tell us which steps are on/off, so we will need to store that in a pattern bank. conveniently, there are 4 banks, so we can dedicate a bank to each one of the 4 oscillators.

we assigned script 1 to buttons, let’s add this line to it:


now script 2 will get triggered when a button is pressed, and we can use the rest of script 1 to treat a button release. whenever a button is pressed, we can flip the state for the corresponding step. let’s add this to script 2:

A % G.BTNI 16; B / G.BTNI 16

G.BTNI is the index of the button that triggered the script. since we told it to start with index 0, and indexes are incremented left-right, row by row, dividing the index by 16 gives us the row number and the remainder of that division (mod) gives us the step number (0…15). we can store them in variables A and B in case we need them later (spoiler: we will). then we simply flip the value of the pattern bank corresponding to the current row and current step.

let’s do the cool bit with the faders only shown when a button is pressed. we can use the “enable” op, in script 2:

L 0 2: G.FDR.EN I 1

this will enable (show) all 3 faders. now we should hide them in script 1 (when a button is released), add this:

L 0 2: G.FDR.EN I 0

and we should add this to the init script so that when the scene is loaded, the faders are hidden until a button is pressed.

now, let’s implement the sequencer part. switch to metro script:

M SCL 0 V 10 500 50 PARAM
x % + 1 X 16
G.REC x 0 1 4 -2 -2
L 0 3: Y I; SCRIPT 8
  • the 1st line will use the param knob to control the metro rate
  • the 2nd line increments X on each step and wraps it so that it stays in 0…15 range - this is our current step
  • 3rd and 4th lines show a vertical line indicating the current step
  • 5th line calls script 8 for each of the rows

script 8 is where we will check if a note should be triggered:

EX.VOX + Y 1 V 2 V 5

if the pattern bank Y value for to step X is zero, we exit, otherwise we play a note on the corresponding oscillator. since we use momentary buttons we also need to show steps that are on, this will need another script as we need to loop through each step, so we add L 0 15: SCRIPT 7 to the beginning of script 8, and set script 7 to this:

G.LED I Y 15

basically: go through every step for row Y and set the LED brightness to 15 if the step is on (remember, we clear all LEDs in metro with G.CLR). at this point we should have a working trigger sequencer that even shows faders when a button is pressed - except the faders don’t do anything yet. let’s add that.

faders will be used to set 3 parameters for each of the 16 steps, 48 values total, and coincidentally we have exactly 48 values remaining unused in each pattern bank. faders are assigned to script 4, so this is where we will set the pattern values when a fader is pressed:

J + A + 16 * G.FDRI 16

if you recall, script 2 sets A to the currently pressed button’s column and B to the button’s row (which corresponds to the pattern bank, so PN B). the first line calculates the pattern index: we start with step 16 (since steps 0…15 are used for the step states), and we additionally increment by 16 for each fader:

  • steps 0…15: step states
  • steps 16…31: 1st parameter value controlled by fader #0
  • steps 32…47: 2nd parameter value controlled by fader #1
  • steps 48…63: 3rd parameter value controlled by fader #2

we also need to initialize faders with the current values when a button is pressed. let’s replace L 0 2: G.FDR.EN I 1 line in script 2 with L 0 2: SCRIPT 3 - we will call script 3 to do the work for each fader (set the fader value and enable it):

J + A + 16 * I 16

now the final piece: use these values to control the actual oscillator parameters. this will also require a script, so let’s add SCRIPT 6 to script 8 right before we play a note, and in script 6 we set the parameters:

K * 13 Y; I PN Y + X 16
IF I: EX.P + 7 K I
I PN Y + X 32
IF I: EX.P + 8 K * I 64
I PN Y + X 48
IF I: EX.P + 9 K * I 64

it looks more complicated that it really is: disting ex dedicates parameters 7-19 to oscillator 1, 20-32 to oscillator 2 etc. so K gives us the parameter offset based on which oscillator we want to control (which corresponds to the row stored in Y). I is then set to the pattern value, and if it’s not zero, we set the required oscillator parameter. parameter 7 is the model, 8 is the timbre and 9 is the colour - the last 2 have range of 0…1024, and since we used coarse faders, their range is 0…15, so we multiply by 64 (for model it just uses the actual value so it can only choose the first 16 models - but you could use fine faders to control a bigger range). why compare a value to zero? this way we can treat the value of zero as a special value for “don’t change the current values”.

this is it! except once you play with it you realize: if you press a step to simply change parameters, it will disable the step once the button is released so you have to re-enable it. what if we changed it so that steps are only disabled if the faders weren’t touched? let’s use variable Z to track that. first, remove PN B A ! PN B A line from script 2 and change it to:

IF PN B A: Z 1
ELSE: PN B A 1; Z 0

script 2 gets triggered when a button is pressed, so this means: if the current step state is already “on”, set Z to 1 to indicate we will need to set the state to “off” when the button is released - unless it’s currently off, in which case we set the step to “on” and Z to zero (meaning - don’t turn off this step when the button is released). and let’s add Z 0 to script 4 which gets triggered when a fader is pressed. finally, add this to the end of script 1 (which gets executed upon a button release):

IF Z: PN B A 0

which translates into: if a button was pressed, and the step was already on, and no faders were touched - turn the step off when the button is released.

final touch: it would be nice to have a script to erase the current state and reset the oscillator parameters. script 5 is still empty and can be used for that:

L 0 255: PN / I 64 % I 64 0
L 0 2: EX.P + I 7 0
L 0 2: EX.P + I 20 0
L 0 2: EX.P + I 33 0
L 0 2: EX.P + I 46 0

perhaps not the most practical script - but a good example of what can be done with grid ops, and it could be optimized to add more functionality.

complete script: plock_seq.txt (1.8 KB)