> teletype: grid # code exchange

Hi folks, Subsequence is a new sequencer that is loosely based on MINIM, above, but with many small changes and some large ones such as:

  • Works with i2c (I made a few variants for Just Friends, Disting, and i2c2midi so far).
  • Weirdly enough, I also have a variant and TT-chords Plaits firmware if you hate i2c.
  • Scraps the arpeggiator and replaces it with a CV-driven “harmonizer” which is similar in function but quite a bit more entertaining to work with. There’s also a clever little option to turn duplicate notes (the curse of generative sequencers IMO) into rests/ties.
  • There are now 4 chord patterns and a simple Arranger that can stitch these patterns together for song sections.
26 Likes

LOVE. I have a sketch of a Norns script which was just a wrapper for Omnichord sample play back with the use of a grid. All this to say I too wish I had a Ombichord and I have put some effort into how to utilize a grid to replicate one and I really like your UI design. I think you did a good job localizing the spirt of omnichord onto the grid hardware. It is interesting to me how unique functionality often emerges when people make ports/clones of an instrument to an open platforms, like Monome (I have noticed this in a lot of Norns scrips). I like the way you expand on the omnichord idea of strumming, being able to use cv to strum the “fretboard” is a cool approach to sequencing/quantizing/arpeggiating.

1 Like

Hi all! Here’s an eight-track trigger sequencer for Teletype + Grid, in which I’ve tricked the four CV outputs into thinking they’re another four triggers. I’ve also used the PARAM knob to set sequence length; I have an extra two scripts (5 & 6) that I might use to randomize / sequence the, err, sequence. Racheting or even sequence length could be nice to have varied as the sequence repeats!

I would love to get feedback re: elegance & simplicity, which I always struggle with — I’m particularly curious if there’s a more efficient way to handle triggering the CV outs, rather than having them each in their own script.

1 

CV.SET 1 V 10
DEL 50: CV.SET 1 V 0


2 

CV.SET 2 V 10
DEL 50: CV.SET 2 V 0


3

CV.SET 3 V 10
DEL 50: CV.SET 3 V 0


4

CV.SET 4 V 10
DEL 50: CV.SET 4 V 0


7

TR.P + Y 1
$ - Y 3


8

D + Z * 16 Y
G.BTN.L D 8
IF G.BTN.V D: $ 7


I

G.BTX 0 0 0 1 1 1 1 5 16 8
PARAM.SCALE 1 15


M

Z WRAP + Z 1 0 X
G.GBTN.L 0 4 4
L 0 7: Y I; $ 8
M 200
X PARAM

The four-channel trigger sequencer that this one is built on came from this thread, but I can’t remember whose code it was — if it’s yours please let me know so I can attribute!

Here’s a video of the program in action; I’m using it to trigger seven of the eight channels of an ALM Squid Salmple, as well as moving a melodic sequence along.

7 Likes

This is a neat idea!

I think there is a lot of room for simplification though. After a bit of playing around with your scripts, here is a version that I think is functionally equivalent but leaves you with a lot more room for other ideas (comments are just for explanation and will need to be removed):

# I
# Use 0 here as lower limit so single step loops work
PARAM.SCALE 0 15 
G.BTX 0 0 0 1 1 1 1 5 16 8
# Set tick length as quarter notes at 120 bpm
M / BPM 120 4

# M
# Use auto-incrementing/wrapping `O` variable. 
# Read & save to `T` (commonly used variable for time steps)
O.MAX PARAM; T O
G.GBTN.L 0 4 4
# Use 1-8 to avoid offset for `CV` and `TR`
L 1 8: $ 8

# 8
# The `I` variable is set automatically during `L 1 8` loop
# and is "passed in" to this script each time it is called
# Set `J = 16 * (I-1) + T` to get button index and light it 
J + T * 16 - I 1; G.BTN.L J 8
# If the current button is not active, then break
IF EZ G.BTN.V J: BRK
# If the value of `I` is between 1 and 4, fire the trigger then break
IF LTE I 4: TR.P I; BRK
# Otherwise, set `I` to the `CV` index and fire
I - I 4; CV.SET I V 10
# Wait half a metro tick before resetting
DEL / M 2: CV.SET I V 0 

From my brief testing that seems to work the same as your original scripts.

I’ve tried to add explanatory comments to the code but let me know if anything is still unclear and I’ll do my best to clarify.

5 Likes

Hi there!
I decided to release my first script so people can have fun (and perhaps help me get better at coding).

Here’s a demo No. 22 | Gentle Antagonism | Teletype + Grid + JF - YouTube

Gentle Antagonism is a script for teletype meant to be used with grid and two Just Friends (but it can be used without any grid or JFs as you can use the TT’s virtual Grid and CV and trigs are available).

Gentle Antagonism (from now on referred as GA) manifest itself as a grid interface splitted in two -almost- specular halves.
Each half features:

  • 4 oct quantised keyboard
  • looper enable toggle
  • looper length fader

then it features two master controls:

  • scale selector (16 scales available)
  • Antagonist enable toggle (when off looper are disabled as well)

When the Antagonist is enabled it will virtually press four notes on the keyboards (2 notes per half, 1 note in the first 2 oct, 1 note in the second 2 oct).

The concept behind GA is to play the instrument in a canonical way while having some abrupt or pleasant and unexpected variation that might ignite a back to back duet with the Antagonist.

Why is it “Gentle”?
the Antagonist is well educated. it will always stay in tune and on the beat while also leaving the user enough space to play.

GENTLE ANTAGONISM V1

CV & TR 1: L keyboard out
CV & TR 2: R keyboard out
CV & TR 3: L looper out
CV & TR 4: R looper out


#1
A - G.BTNI 72
IF G.BTN.V G.BTNI: $ 2
P.N 0
IF G.BTN.V G.BTNI: P.NEXT A

#2
JF.NOTE N.B A V 4
CV 1 N A; TR.P 1

#3
X + G.FDR.N 1 1
P.N 0; P.L X; P.NEXT; J P.HERE
K N.B J
JF.NOTE K V 2; TR.P 3
CV 3 K

#4
B - G.BTNI 104
IF G.BTN.V G.BTNI: $ 6
P.N 1
IF G.BTN.V G.BTNI: P.NEXT B

#5
Y + G.FDR.N 2 1
P.N 1; P.L Y; P.NEXT; J P.HERE
K N.B J
JF2: JF.NOTE K V 2; TR.P 4
CV 4 K

#6
JF2: JF.NOTE N.B B V 4
CV 2 N B; TR.P 2

#7
G.GBTN.V 1 0; G.GBTN.V 2 0
J RRND 5 250; K RRND 10 250
TR.P 1; G.BTN.PR RRND 64 79 1
TR.P 2; G.BTN.PR RRND 80 95 1
DEL J: G.BTN.PR RRND 96 111 1
DEL K: G.BTN.PR RRND 112 127 1

#8
N.B 0 MUL G.FDR.N 0 -1
G.FDR 1 0 2 8 1 2 3 10
G.FDR 2 8 2 8 1 2 3 10
G.BTN 202 7 1 2 1 1 4 8
G.BTN 201 15 1 1 1 1 4 9
M.ACT G.BTN.V 202

#M
PARAM.SCALE 50 1000; M T
EV 8: T / PRM RRND 1 4
EV 64: $ 7
IF G.BTN.V 200: $ 3
IF G.BTN.V 201: $ 5
L 1 4: TR.TIME I 10

#I
JF0: JF.MODE 1; $ 8
G.GBX 1 64 0 4 1 1 0 2 1 8 4
G.GBX 2 96 8 4 1 1 0 2 4 8 4
G.FDR 0 0 0 16 1 2 3 8
G.BTN 200 0 1 1 1 1 4 10
G.BTN 201 15 1 1 1 1 4 10
15 Likes
PAINTCHIP
A BAD SINGLE-LANE VERSION OF
THE QUANTIZER PART OF
COLORWHEEL (REQUIRES GRID)

IN = SIGNAL TO QUANTIZE
PARAM = ATTENUVERT IN
1 = GATE
CV 1 = LOVELY RESULT

FADERS L TO R:
OFFSET, TRANSPOSE, DENSITY

RIGHTMOST 16 BUTTONS:
SELECT PRESET

OTHER BUTTON:
SAVE PRESET



#1
I SCL 0 V 10 0 VV ABS PRM IN
IF < PRM 0: I * -1 I
J + I N B; J + J N C
N.B 1 D; CV 1 QT.B J

#2
J SCL 0 V 10 1 5 G.FDRV
IF GT J 3: B ? EQ J 4 7 12
ELIF EQ J 3: B 0
ELSE: B ? EQ J 1 -12 -7
$ 1; G.LED 5 0 11

#3
I SCL 0 V 10 -2 2 G.FDRV
C % * I 7 12
$ 1; G.LED 5 0 11

#4
J SCL 0 V 10 1 4 G.FDRV
IF EQ J 1: D 129
ELIF EQ J 2: D 133
ELIF EQ J 3: D 645
ELSE: D 661
$ 1; G.LED 5 0 11

#5
G.BTN.SW G.BTNI; X - G.BTNI 1
G.LED 5 0 8
L 0 2: $ 7
$ 1

#6
L 0 2: PN I X G.FDR.V + 17 I
G.LED 5 0 8

#7
J PN I X
K ? EQ I 2 4 5
J SCL 0 V 10 1 K J
G.FDR.PR + 17 I J

#8
G.BTN 20 5 0 1 1 0 0 6
PARAM.SCALE -1000 1000
G.BTN.PR 1 1

#M

#I
G.FDR 17 0 2 2 5 3 3 2
G.FDR 18 2 2 2 5 3 5 3
G.FDR 19 4 2 2 4 3 7 4
G.GBX 2 1 6 0 1 1 1 0 5 2 8
CV.OFF 1 V 2; B 3; C 3; X 0
D 129; G.FDR.V 19 1; $ 8

#P
0	0	0	0
1	1	1	1
0	0	0	0
63	63	63	63

0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0

#G
0010000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000

0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0
0	2	0	2	0	0	0	0	0	0	0	0	0	0	0	0
0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0
0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0

Should work with a 64, or run grid control mode alongside it on a 128 and write presets right into the patterns. Also you have M and a whole lane of the pattern to yourself, so if you want to write a cheeky 6-line sequencer and just trigger $1 directly, or put CHAOS out onto CV 2 and patch that right back into IN, that’s viable. Many shouts out to @yams and @fourhexagons of course.

7 Likes

Is anyone else here struggling with double triggers using the grid?

All my buttons trigger twice — once on pushing it down, and again when I release it. I’m tired of the EVERY 2: workaround, especially as this only works in some applications… aiee! m

Am I missing some very basic teletype / grid knowhow, here?

Edit: just found @ghost ’s post regarding this way up in the thread — thank you, using G.BTNV as a way of sorting out the “button-down” triggers is incredibly clever!

Thank you! Glad you like it. XD
I finally got a real Omnichord recently, just find the chromatic layout of the origin is so convinient. I didn’t realize that when making this script and thought normal halt-tone layout is better. The origin’s chords use different voicing to keep all chords are at about the same range, it sounds super smooth when playing. What a clever design.

1 Like

This is brilliant, thank you so much! It’s a perfect learning experience to see a scene with the same result but making a lot more efficient use of the code. I had no idea that the I variable could be “passed along” between scripts — I thought it was local to each line, let alone each script!

1 Like

Glad to hear you found my version useful. There are so many ways to do things in Teletype, it’s a fun exercise to try to think of different ways of achieving the same or similar results as another script.

1 Like

Hi there. I’m back to TT after a few years. A bit rusty…
I’m trying to populate a pattern with midi notes incoming close together.
If the script was not running during the previous 1000ms, erase the pattern, and add notes from index 0.

Any help ?

EDIT : I managed to register and append incoming notes. But fast incoming notes (like hitting a chord) are not registered. Is there a timing limit for incoming notes to be recognized ?
The code above lets me monitor the notes being added to the pattern :

I : MI.$ 1 1

1: 
IF GT LAST 1 1000: O 0
P O MI.LN

It’s been a while since I’ve written a MIDI scene, but IIRC Teletype does not iterate through MIDI events for you. MI.$ will be called once no matter how many notes have been played since the last iteration of Teletype’s event loop. You have to iterate through the notes themselves from within MI.$ with L 1 MI.LN: .... In practice, this means that you usually have to throw away two scripts just to iterate separately through the note-on and note-off events.

This feature is the most frustrating part of MIDI handling on Teletype, and I don’t really understand why it behaves this way. I’m sure the devs tried an implementation that calls MI.$ once per note, and discarded that idea. Perhaps it resulted in missed notes?

1 Like

teletype checks MIDI events every 25ms. even with frequency this high (which is actually higher than teletype checking for new keyboard events or reading AD converters) in my testing some events would get dropped, especially if you try to play chords or move several knobs at once. storing MIDI events in a buffer and providing ops to iterate over that buffer was the only way to avoid having dropped events.

so in your script 1 you need to do L 1 MI.NL: P O MI.N

there is a reason the iterated op versions use shorter names so that in a lot of cases you can just use a simple loop.

you can assign both events to the same script and check the latest event type with MI.LE.

[this thread is a better place for MIDI op related questions: Teletype MIDI IN ops]

2 Likes

Are you guaranteed that the script will be called at least once for each event type?

the way it works:

  • it checks for new MIDI events in the main event loop
  • when any MIDI events arrive, they are placed into a buffer that can hold up to 10 events. there are separate buffers for note on, note off and cc
  • every 25 ms a timer handler will check if there are any events in the buffer and will call a script assigned to the event type. each script is called only once even if it’s assigned to multiple event types

if you have other questions related to MIDI ops let’s continue in the dedicated thread linked above.

2 Likes

Love this a lot! But I dont’t have 2 JFs, changed the code a tiny bit for using with JF and W/synth
GENTLE ANTAGONISM W:JF.txt (1.1 KB)

7 Likes

Hello everyone!
I’ve had teletype for a few weeks and have had tons of fun building a group of physics based scenes, with visualization via the grid. The first one I made is a bouncing ball simulator, designed for pairing with Just Friends. There isn’t too much user input to it but this was made less of a interactive tool and more of a random rhythm and melody generator.

The concept is relatively simple: there are 6 travelers that spawn with random position and velocity vectors in 2 dimensional space. When a traveler collides with a wall, it generates a note (via JF.VOX) with a random pitch from a user entered scale and random velocity. Parameter knob can be adjusted to “activate” up to 6 travelers (one for each channel of JF in synth mode). Pressing a key on the grid will change the bounding box of the travelers, adjusting the bottom right corner of the rectangle (0,0 always being the top left). I also included some smooth random CV outputs for modulation of other modules in your rack.

Some notes about the scene:

  1. I know the “bouncing ball” concept has been done a few times, I wanted to explore the implementation of the concept in the teletype ecosystem. I also have not seen anyone implement it using oblique angles, only 45 degree increments.

  2. Because I am quantizing the traveler positions to display on the grid, sometimes the path will look like it’s meandering. I knew implementing some kind of anti-aliasing algorithm would completely side track the project so I left it as is.

  3. I ran out of room multiple times and had to refactor some of the scripts multiple times to get it to fit. I sacrificed scripts 7 and 8 to implement a nested loop to create a trailing effect on travelers. I think it was worth it because it looks cool ¯\ _ (ツ) _ /¯.

  4. A keen eye will see that the buttons are declared every time M runs. I couldn’t figure out how to squeeze it into init so thats where it lives. I didn’t see a big performance hit so I left it as is.

  5. If you don’t have a Just Friends the script can easily adapted to use the CV/TR outputs on Teletype. I’ll leave that as an exercise to the reader :slight_smile:

  6. I would put some future refinement ideas down, however I don’t think there’s room for anything else in the scene without sacrificing any of the existing features.

I don’t have a demo video posted anywhere, I can upload something if anyone would like. Please try it out and let me know what you think!

BOUNCE

BOUNCE 6
JF MODE: TRANSIENT/SOUND
HIT GRID KEY TO LIMIT BOUNDS
OF EXPLORATION. INCREASE
PARAM FOR MORE FRIENDS.
CVS OUTPUT SMOOTH RANDOM
VOLTAGE FOR MODULATION

#1
PN 0 A + PN 0 A PN 2 A
PN 1 A + PN 1 A PN 3 A
IF > PN 0 A X: $ 3
IF < PN 0 A 0: $ 4
IF > PN 1 A Y: $ 5
IF < PN 1 A 0: $ 6

#2
G.BTX 1 0 0 1 1 0 0 0 16 8
L 0 15: C I; $ 7
I / PN 0 A 100; J / PN 1 A 100
G.LED I J 15

#3
I - PN 0 A X
PN 0 A - X I
J + A 6; PN 2 J * PN 2 J -1
J PN 0 RRAND 10 17
K V RRAND 1 5; I + A 1
JF.VOX I N J K

#4
PN 0 A * PN 0 A -1
J + A 6; I + A 1
PN 2 J * PN 2 J -1
J PN 0 RRAND 10 17
K V RRAND 1 5; I + A 1
JF.VOX I N J K

#5
I - PN 1 A Y
PN 1 A - Y I
J + A 6; PN 3 J * PN 3 J -1
J PN 0 RRAND 10 17
K V RRAND 1 5; I + A 1
JF.VOX I N J K

#6
PN 1 A * PN 1 A -1
J + A 6; I + A 1
PN 3 J * PN 3 J -1
J PN 0 RRAND 10 17
K V RRAND 1 5; I + A 1
JF.VOX I N J K

#7
L 0 7: D I; $ 8
L 1 4: CV.SLEW I 5000
EVERY 1000: CV 1 RAND V 8
EVERY 500: CV 2 RAND V 8
EVERY 600: CV 3 RAND V 8
EVERY 700: CV 4 RAND V 8

#8
J G.LED C D
IF > J 0: J - J 1; G.LED C D J
X * G.BTNX 100; X + X 99
Y * G.BTNY 100; Y + Y 99

#M
B - PRM 1; JF.SHIFT V -1
L 6 11: J - I 6; PN 2 J PN 2 I
L 0 5: PN 2 I / PN 2 I PRM
L 6 11: J - I 6; PN 3 J PN 3 I
L 0 5: PN 3 I / PN 3 I PRM
L 0 B: A I; $ 1; $ 2

#I
M 100; PARAM.SCALE 1 6
L 0 5: PN 0 I RAND 1599
L 0 5: PN 1 I RAND 799
L 6 11: PN 2 I RRAND -200 200
L 6 11: PN 3 I RRAND -100 100
JF.RMODE 1; JF.MODE 1

#P
0	8	0	0
1	1	1	1
0	0	0	0
63	63	63	63

33	69	30	-1
23	4	14	-15
25	59	11	-7
99	51	32	12
29	44	21	6
51	76	7	12
0	0	181	-6
0	0	88	-92
0	0	68	-44
0	0	192	74
0	0	129	40
2	0	45	73
4	0	0	0
7	0	0	0
9	0	0	0
11	0	0	0
14	0	0	0
16	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0
0	0	0	0

#G
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000

0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0
0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0
0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0
0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0

BOUNCE.txt (2.3 KB)

11 Likes

great work, added it to the codex!

1 Like

plockable trigger sequencer: Teletype concepts and thoughts - #38 by scanner_darkly

8 Likes

so glad you’re enjoying it! I only read this now, great work on changing the script! I actually already prepared it but then didn’t manage to post it so thank you for the help. I’m releasing a slightly different version soon btw (hopefully today)

2 Likes