Teletype concepts and thoughts

there is an interesting paradox about developing firmware for something like teletype - i spend most of my time developing, not using new features. this is not always the case, and there are, of course, features that i develop precisely because it’s something i want to use. but even with these i feel like i’m only scratching the surface of what’s possible - which is the very nature of teletype, since there are so many ways to use it. considering these possibilities is an important part of development - use cases inform a feature’s design. and here lies the paradox: i think of many different concepts but realize only a few. this thread is an attempt to document them so that they don’t get lost - and hopefully serve as inspiration and a starting point for discussions. i’ll also share some random thoughts on teletype and some tips & tricks.

45 Likes

concept: teletype as a module expander / controller

if you asked people what they consider the main use for teletype to be, most would probably say sequencing. and indeed, teletype is arguably the ultimate modular tool for creating sequencers and automata. using it as an expander for another module seems like underutilizing it - but i think it’s one of the most exciting aspects of teletype - it allows you to create your own custom expander / controller for a module.

macro controls

let’s use the param knob to control multiple things. typically, to process continuous changes (like the CV input) we want to use a fast metro script:

#I
M 25

#M
L 1 4: CV I PARAM

the init script sets the metro rate to 25ms, and the metro script is used to poll the param knob value and pass it to CV outputs. not super exciting, since we could just mult one of the CV outputs. let’s change the metro to this:

#M
CV 1 PARAM
CV 2 SCALE 0 V 10 V 10 0 PARAM
CV 3 SCALE 0 V 10 0 V 5 PARAM
CV 4 SCALE 0 V 10 V 5 0 PARAM

now both CV 1 and CV 2 will output voltage between 0 and 10V (V 10), but CV 2 reaction to the knob is inverted - it outputs 10V when the knob is all the way down, and 0 when it’s all the way up. additionally, CV 3 and 4 use 0…5V range. you can use any positive range between 0…10V, so you could scale the full knob range to, say, 2V…4V: SCALE 0 V 10 V 2 V 4 PARAM. first 2 parameters for SCALE are the range you’re scaling from (for PARAM knob it’s 0V 10), parameters 3 and 4 are the target range and the last parameter is the value you’re scaling.

with this simple script you can now control 4 parameters at once with one knob. say, you could use it with mimeophon to increase halo and repeats while simultaneously decreasing color.

gestures / actions

this is one of those things that is difficult to do in modular but incredibly easy to do with teletype. let’s use mimeophon again as an example. it has inputs for flip and hold which means we can automate them. let’s say we want to clock mimeophon from teletype and we want flip and hold to get engaged on beat 2 and 4 respectively:

       1234
clock: ----
flip:  -#--
hold:  ---#

mimeophon uses triggers for flip and hold, so what we need to do is: send a trigger to flip on clock pulse 2 and 3 and send a trigger to hold on clock pulse 4 and 1. here is the script:

#M
TR.P 1
D + D 1
IF > D 4: D 1
IF OR EQ D 2 EQ D 3: TR.P 2
IF OR EQ D 1 EQ D 4: TR.P 3

D is the beat counter, trigger output 1 is the clock, trigger output 2 should be connected to flip input, trigger output 3 to hold.
ideas to try: adding some probability and random: IF TOSS: TR.P 2 etc

this is an example of how we can build a synchronized action - now let’s try and create a complex gesture. something like this:

  • turn flip on for 1 second
  • increase halo gradually during that second
  • in the 2nd half of that second also turn hold on

here is the script (and a good example of how easy it is to just do things literally with teletype):

#1
TR.P 2
DEL 500: TR.P 3
DEL 1000: TR.P 2; TR.P 3
CV.SET 1 V 10
CV.SLEW 1 1000; CV 1 0

CV.SET is a good op to use when employing CV slewing - it ignores the current slew setting and sets the voltage immediately.

we now have a complex gesture mapped to trigger input 1 - which we can trigger either manually from keyboard, or by connecting a trigger source to trigger input 1. and we still have 7 scripts left (8 with metro) to program other gestures. we could trigger these gestures from grid. add these lines to the init script:

M.ACT 0
G.BTX 1 0 6 2 2 0 4 9 8 1

first, stop the metro script, then create 8 grid buttons and assign them to the metro script. and in the metro script we simply do this to trigger the appropriate script:

#M
IF G.BTNV: SCRIPT G.BTNI

i won’t go into details on grid ops here - check the grid studies if you want to learn more.

what else can we do? we have 128 buttons and are only using 8, since we are limited to 8 scripts / gestures. but we could add some variations by utilizing all 128 buttons like this:

#I
G.BTX 1 0 0 1 1 0 0 9 16 8

#M
IF ! G.BTNV: BREAK
A G.BTNX
SCRIPT + 1 G.BTNY

now any button in row 1 will trigger script 1, any button in row 2 - script 2 etc. but depending on where in the row you press, you’ll get a different value for A (it’ll be set to the X coordinate of the button pressed, so between 0 and 15). let’s modify script 1 as follows:

#1
J SCALE 0 15 100 2000 A
TR.P 2
DEL J: TR.P 3
DEL * J 2: TR.P 2; TR.P 3
CV.SET 1 V 10
CV.SLEW 1 * J 2; CV 1 0

so now even though you have all 16 buttons in row 1 trigger the same gesture (script 1), the response time will depend on where in the row you press - this is done by using the X coordinate to calculate the delay time.

now if we add scripts 2-8 we will have an expander for mimeophon that is capable of executing complex gestures which can be triggered by other modules or manually. to replicate just one gesture we used here would require an envelope generator, a clock divider and some logic modules. teletype replaces all of that - and in a way that allows you to easily modify and recall easily.

to summarize: teletype is a great way to extend functionality of pretty much any module as it allows you to easily program complex actions with precision. not just that, but you can also use it to map external controllers (MIDI or grid) - which is a good topic in itself and one i will cover in a future post.

ideas to try: teletype as an expander doesn’t have to be one way - you can program gestures and trigger some of them from the module you’re using with teletype. for instance, you could create a magneto expander and then use the magneto clock outputs to trigger scripts 1-4 for some synced gestures that would automatically follow the clock.

47 Likes

I think the closest to an “expander” concept I’ve come with Teletype is an FM ratio selector for Hertz Donut mk2. I set it up so I could set the modulation oscillator to follow mode but turn down its frequency fully, and just patch CV1 from Teletype and select the ratio with the Param knob.

I had to determine the values for the pattern experimentally… which was easy enough to do, using a fader from 16n to set the CV and copy it to A, so I could watch it in real time. I could have gotten fancy and saved the value to a pattern with a trigger, but I decided to type it manually :slight_smile:

Another thing I like to do is set a range of pitch values on faders 8 through 16, and use the M script to read fader 7 to select which of those 8 to use for pitch at any given time (quantized or not according to taste).

8 Likes

What an incredibly exciting thread. Following with great interest and want to also thank you so much for the range of tireless work that you’ve already completed on the platform.

7 Likes

concept: preset morpher

inspired by the macro control script above. quick recap: we can use the param knob to control the CV outputs in a more continuous fashion by using the metro script with a high refresh rate, like 25ms: M 25. you can experiment with even higher rates by using the M! op as M caps it at 25 - just expect that teletype might start acting a little weird.

this was the script from the previous post, showing that you can map the knob range to different output ranges by using SCALE:

#M

CV 1 PARAM
CV 2 SCALE 0 V 10 V 10 0 PARAM
CV 3 SCALE 0 V 10 0 V 5 PARAM
CV 4 SCALE 0 V 10 V 5 0 PARAM

it’s a super simple scene but what we have is essentially a 4 CV preset morpher (which makes it sound more exciting). you have one set of voltages when the knob is down all the way, another when it’s all the way up, and turning the knob morphs between them. what would make it really usable though if instead of typing voltage values in we could actually use the knob itself to choose them.

let’s add the ability to record snapshots. it’s simpler than it sounds. first, we need some way to indicate whether the knob is being used for recording or for morphing. let’s use variable A - value of 0 can mean we’re morphing, value 1 - recording CV 1 etc. first, we need to add this line to the metro script:

#M

IF A: SCRIPT 8; BREAK
CV 1 PARAM
CV 2 SCALE 0 V 10 V 10 0 PARAM
CV 3 SCALE 0 V 10 0 V 5 PARAM
CV 4 SCALE 0 V 10 V 5 0 PARAM

since any positive value is evaluated as “true”, then when we are recording (A is 1…4) it will execute script 8 (which is what we’ll use for recording) and stop.

one more thing: we need to store 8 values - 2 snapshots of 4 CVs. let’s store snapshot 1 in pattern bank 1 and snapshot 2 in pattern bank 2. we also need a variable that determines which snapshot we are recording, let’s use B (we’ll worry about where to set it later). here is script 8:

#8
PN B A PARAM
CV A PARAM

the first line stores the knob value, the second line passes it to the corresponding CV output so we can hear the result.

now, we need a way to trigger recording. let’s use scripts 1-4 to turn recording on, one for each CV, then we can use keyboard to toggle recording. since we need to record 2 snapshots, we could do it this way: executing script 1 enables recording for snapshot 1, executing it again enables recording for snapshot 2, executing it again stops recording and enables morphing again:

#1
IF AND A EQ B 1: B 2; BREAK
IF AND A EQ B 2: A 0; BREAK
A 1
B 1

first line will only get executed when A is not zero (so, we are recording already) and B is 1 (we are recording snapshot 1), so we switch to snapshot 2. second line will only get executed when we are recording snapshot 2, so set A to 0 to stop recording. and if we get past that, we’re not recording, so we enable it.

we can now copy this script to scripts 2-4 (remember, you can select several lines by holding SHIFT and copy them at once). then modify A 1 to A 2 in script 2 etc. here is a neat trick we could use so we wouldn’t even need to edit scripts after duplicating them: A SCRIPT. SCRIPT op returns the current script number, so it’ll do exactly what we need!

switch to pattern view before you record snapshots - this way you can see the values being updated as you turn the knob. it would be also neat to see which value is being recorded at any given time - let’s use the turtle for it! we’ll need to make it visible when we start recording and set its coordinates to the proper pattern cell, and then hide it once recording is done. unfortunately, adding it to the existing script pushes us over the line limit, so we have to modify the script a bit and use another trick - if you have a really long IF condition, store it in a variable and use the variable instead:

J AND A EQ B 1
IF J: B 2; @X B; BREAK
J AND A EQ B 2
IF J: A 0; @SHOW 0; BREAK
A SCRIPT; B 1
@X B; @Y A; @SHOW 1

we can also employ the A SCRIPT trick, so you can just copy this whole script to scripts 2-4 without modifying anything (and we could save ourselves time and make it more readable by moving the whole thing to script 5, changing A SCRIPT to A Z and then scripts 1-4 could simply be Z SCRIPT; SCRIPT 5).

finally, we need to update the metro script to use the new snapshots instead of the fixed values. for each of the 4 CVs we need to scale the current param value from 0…10 V range to the min/max range saved in the pattern banks. this would be something like this:

CV 1 SCALE 0 V 10 PN 1 1 PN 2 1 PARAM

this is definitely too long! let’s use aliases, and also take advantage of using a loop. modify the metro script as follows and add script 7:

#M
IF A: SCRIPT 8; BREAK
L 1 4: SCRIPT 7

#7
J SCL 0 V 10 PN 1 I PN 2 I PRM
CV I J

if you tried it at this point and are wondering why the values are in the middle and start from row 2 - that’s because pattern banks and indexes are 0-based. doesn’t really matter here and simple enough to subtract 1 when needed.

final thing: remember to set the metro rate in the init script, and we need to start with proper values for A and B:

#I
A 0
B 1
M 25

oh, and would be useful to be able to reset all values at once. easy! let’s use script 5:

#4
L 1 4: PN 1 I 0; PN 2 I 0

so here it is, simple enough but pretty useful. and as always, with teletype this can be just a starting point for further exploration. here are some ideas: with something like telexo or er-301 we could control more than 4 values (just have to be careful not to have too many - remember, we are still updating each one of them at 25ms or faster). instead of the knob you could use faderbank to record 16 values at once. and what about storing and morphing between 4 snapshots instead of 2?

and here is what a more complex variation of this idea might look like: morphing faders grid scene

16 Likes

Thank you for these. I’ve found a whit whale of a module recently that was what I had got the TT to interface with. These use cases are incredible real world examples that I am SO EXCITED for. I will be revisiting the original studies, then taking these and the grid studies on as a sort of “applied extensive studies.”

Your work on this module has been so inspiring and I can’t wait to begin applying these concepts in my experimentation.

Thanks so much! (Also, I always forget… what is the ! used for again… :sweat_smile:)

1 Like

Negation, in teletype evaluates to true on non-zero, including negative values

EDIT: Exactly 100% wrong. Should have written (hope I don’t mess it up again):

Negation, in teletype this means 0 becomes 1, non-zero becomes 0

1 Like

Okay, so I reread the line; basically, if a button pressed equals 0, then it breaks that line, meaning it doesn’t run the rest of the scene…
Is that correct?

#I
G.BTX 1 0 0 1 1 0 0 9 16 8

#M
IF ! G.BTNV: BREAK
A G.BTNX
SCRIPT + 1 G.BTNY

I’m reading Study 6 (which I would like to start going back through this again this weekend) I see the competitors and understand. Thanks!

Incredibly interesting and helpful, thank you for posting these!

Just curious, what’s the module and how are you using it with TT? :grin:

1 Like

I feel like this is one of the more basic answers, but the module is an ER-301 :smiley:

They’re just so hard to come by I almost felt bad bragging about it. It’s why I had wanted a TT all along. Having the ability to trigger so many things with simple scripts is a big big plus for me. It allows me to do a lot with a selective few modules.

With the TT and ER-301 connection, I’m dying to try getting the arc involved, having Max patches output i2c signals instead of midi through crow.

1 Like

this doesn’t sound correct - it will evaluate to false on non zero values.

! x will return 1 (equivalent to “true”) if x is 0, and 0 (equivalent to “false”) for any other value. used with IF:

IF ! x: ...

it means: only execute this line if x is 0.
this line:

IF ! G.BTNV: BREAK

is typically used with momentary buttons since the script is called both on button press and release. so if only want to take action on button press, you check the last pressed button value (G.BTNV) - if it’s a release, the value will be 0, so ! G.BTNV will evaluate to true and it will break.

for a second i thought you mean the actual whitewhale module :slight_smile:

3 Likes

How stupid can I be???

You’re obviously 100% correct, my brain must have been… I don’t know what.

Let’s do some simple example lines, that will all fire TR 1 (hope I don’t mess it up this time as well):

TR 1
IF 1: TR 1
IF ! 0: TR 1
1 Like

forgot to update the metro script at the end - updated my post!

concept: patch/preset manager

imagine a micro system that is fully repatchable from teletype. change your whole patch by pressing a key. teletype as the heart of a system: this is the concept i want to explore in this post. using teletype as a preset manager might seem like underutilizing what it’s capable of, but i think it’s the exact opposite, and a good example of how teletype can “glue” a whole system together.


let’s look at preset management first.

what kind of presets can we store? the most obvious example is modules that have no presets but have CV inputs for the parameters you want to store. then it’s as simple as using teletype CV outputs to control those (or using trigger outputs to control gate inputs). with teletype alone you can control 4 CVs and 4 gates. if you need more than that, you could use ansible or telexo to gain another 4 CV and 4 trigger outputs.

the downside to this is that you have to use teletype to change these parameters (or use the knobs and then approximate the knob values with your script). you can address this by using the teletype knob and recording snapshots as shown in the preset morpher post above. still not great, since you have to record each value separately, but this could be addressed by using a midi controller and the midi in ops.

this might still seem fiddly but here is what you gain: you can control CVs more precisely, you can switch multiple CVs at once and you can have multiple banks of values. something like pressure points can be used in this manner and gives you 4 sets of 3 CVs - with teletype you can record and recall 64 sets of 4 CVs (using pattern banks) - and that’s just one scene. and you can do other interesting things, like morphing between different snapshots (i will refer to the post above again).


some modules have their own preset management, and in many cases teletype can be used to control those as well. trilogy and ansible come to mind first - whitewhale, earthsea, meadowphysics, ansible can all store presets, and you can select them with ops:

whitewhale: WW.PRESET x and WW.PATTERN x
earthsea: ES.PRESET x and ES.PATTERN x
meadowphysics: MP.PRESET x

ansible ANS.APP x to select an app
kria app: KR.PRE x and KR.PAT x
mp app: MP.PRE x
es app: no ansible versions, use the earthsea ops above
cycles app: CY.PRE x
levels app: LV.PRE x

with ansible ops you can also get the current preset and pattern (where applicable) if you don’t supply a parameter.


other modules / firmwares that allow you to select presets via i2c:

orca: OR.BANK x and OR.PRESET x
disting ex: EX.PRE x
matrixarchate: MA.PGM x

not all i2c enabled modules support preset selection via i2c (you can’t do it on er-301, for instance). not all need it - for something like telexo and just friends it’s just a matter of using individual ops to get them into the desired state (using something like JF.MODE and TO.ENV.ACT).

you can also control various select bus devices - rene mk2, voltage block etc. you will need to use expert sleepers disting ex module for that, and then use the select bus ops and refer to the select bus specification. and if you add a midi breakout, you can also send MIDI program change messages, so you could even control presets on various MIDI devices!


now, what about patch management?

to control an actual patch we’ll need to employ additional modules - VCAs and switches. you could plug an LFO into several VCAs and send it to multiple destinations, for instance, and use teletype CV outs to control which VCAs are open, thus controlling the patch. voltage controllable switches, similar idea: you could use teletype trigger outs with something like doepfer sequential switch or CV outs with doepfer voltage contrllable switch. there are many similar modules to choose from.

you could also implement a patch matrix. you have several options: use something like 4ms vca matrix and 3 telexo modules (which will give you 12 CV outputs, and you have 4 on teletype, so 16 altogether) to control its nodes. not the most practical option perhaps! you could also use disting ex’s matrix mixer algorithm which gives you a 6x4 matrix which you can control directly via i2c. finally, sssr labs sm010 will give you a 16x8 matrix, also directly controllable via i2c - just be aware that it has several quirks that might make it not suitable for your purpose (see the thread for details). grid interface would work really well for controlling a patch matrix.


ok, this one is for completeness sake - you could also store patch notes in a scene description :slight_smile:


as you can see, you can recall many different things via teletype, which makes it a really powerful preset manager. there are many ways you could go about it too.

you could simply have each scene set up various parameters and load specific presets on other modules, and then just load scenes to switch patches. you could store multiple snapshots (both CVs and preset numbers) in one scene using pattern banks.

you could do something more interesting - like the already mentioned morphing between different snapshots (this won’t work for loading presets on other modules, of course). another idea: meta controller. build a grid interface to control presets on other modules all in one place. or take it further and build a meta sequencer that sequences presets (just take into account that it might take some time to load a preset, depending on the module).

or how about this: imagine a grid scene that is set up like a dj mixer. left side selects presets on, say, ansible and earthsea, right side selects presets on disting ex and voltage block. so 4 chains, each one with its own sequencer and sound source. teletype CVs control VCAs so you can control volume of each chain independently. you could program a crossfader too. then you could build a performance where you select a new preset while it’s playing the other side, switch parts gradually, combine them in different ways, all played from a grid.


i would really love to see more discussion in this thread too - please share your own thoughts and ideas or if you got inspired and implemented your own variation of any of the concepts described here i would love to learn about it!

19 Likes

2 posts were merged into an existing topic: Teletype workflow, basics, and questions

I’ve had this drafted here since this topic started, wasn’t sure if you wanted other people to share or if this was more of a diary/log type thing—been really enjoying your ideas thanks for all your work and for sharing!

teletype as nested sequencers

in my smallish case, teletype is really my only sequencer-like-object. I’m working on creating a basic scene which I can use as a starting point when creating songs or performances, rather than building from scratch every time. I don’t really have anything sending gates or triggers in to Teletype, so I wanted to be able to have complex rhythmic control over internally triggering scripts, that was the starting place…

This is basically what I have so far—it’s quite basic and I’m sure I will build on it and it may become slightly more complex. The benefit of it is that I can pull up a rhythm or sequence quickly. The more complex the basic building block is the less open ended the building becomes, so it probably wont get too much more complex… I am not a super proficient Teletyper, but I hope this can show that even luddites like myself can learn a couple key tricks and get the tool they need. Big shoutout to Teletype Talk.

  1. I wanted a tempo knob and I found myself not using param much so I put it to use :slight_smile:

    #I
    PARAM.SCALE 60 240
    
    #M
    M BPM PARAM
    L 0 7: $ 8
    P.N 0; P.NEXT
    
  2. Working backwards sort of, but if you understand bitwise ops you can see here I’m using script 8 to trigger scripts 1-7 with binary reading of numbers in pattern 0.

    #8
    X BGET P P.I I
    IF X: $ + 1 I
    
  3. For simplicity I will often have scripts 1-4 controlling triggers 1-4, usually with one trigger controlling a bass drum, one a high hat, and two going to two inputs on a sampler. Heres what it might look like (Sometimes I have TR.P 4 controlled by metro as like a base clock to send to just friends or the samplers grain sync. Then script 4-7 control CV sequencing.)

    #1
    TR.P 1
    
    #2
    TR.P 2
    DEL CHAOS: TR.P 2 (just for fun random hihats)
    
    #3
    TR.P 3
    
    #4
    TR.P 4
    
    #P0
    9 (bass drum + sample 2)
    0
    2 (hihat)
    0
    1 (bd)
    4 (sample 1)
    2 (hh)
    4 (sample 1)
    
  4. Lastly I’ll use the CV outs or i2c to control melody. Using P0 I’ll trigger scripts 5-7 which will advance patterns 1-3. I feel like I may be getting too in the weeds now because even the stuff I wrote just above ^^ is beyond my “base scene”. Once muting gets working properly (Alt-F1, for example, so that it muted from internal triggering as well as external—hopefully on the next teletype update, fingers crossed) then I may leave some of this prewritten, we’ll see. I also have toyed with using AllFlesh to manually trigger scenes 4-7 to get the melodies more off the grid, but I have had no success with this—it seems like it will acknowledge triggers from elsewhere over the bridged connection, but I can’t turn a high gate into triggers by tapping, perhaps even my fastest taps are too long of a gate (although with Just Friends sending triggers it seems like my teletype normally acknowledges two triggers—gate high and gate low—so I’m still a bit puzzled).

  5. Further possibilities: I haven’t had JF hooked up to i2c recently, but the possibility of using binary to control Just Friends in Geode mode or even just to control the triggering of envelopes instead of just triggers has certainly crossed my mind and I may be exploring this in the near future. Multiple bitwise/binary patterns maybe? With something like that, trigger outputs would be freed up for other uses… Basically any deeper i2c control I have yet to really incorporate into this scheme, I have some w/s which may get involved here too…

I hope this seems helpful and on topic to someone :stuck_out_tongue: As you can tell I’m still working on this, and it’s developing alongside my experiments with a Ciani inspired permanent patch which I’ve written about already a couple of places. Part of the appeal of a base patch is also that I will always know — CV 1 controls the bassdrum voice on Mangrove 1, CV 2 and 3 are controlling Mangrove 2. X triggers are doing Y, param is tempo. In building an instrument (which is my goal) I want to easily decipher what the brain is doing at any given time in order to be able to perform using only the teletype keyboard and some knob turning.

PS since writing this draft a couple months ago this thread on acid has made me want to do a version of this base script using binary ops to patch up a little acid machine—a four voice drum machine with some mod channels where you can slowly change individual steps over time… it seems like a perfect job for teletype, and I’m sure there’s more complicated and sophisticated ways to do it, but keeping it simple appeals to me… :slight_smile:

18 Likes

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.

5 Likes

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!!

5 Likes

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

1 Like

omg insane system really diggin it ! :heart_eyes: