(Teletype) Pre-2.1 Operators and Features


#1

Status as of September 13: 2.1 in beta testing!

Candidate Operators

- MSPB          [ Millis per beat in BPM x     ] (in 2.1 beta as BPM)
- ASM-style conditionals                         (rejected)
- R (AT)        [ Autorepeat                   ] (in development)
- RAMP/LFO      [ Oscillators / envelopes      ] (**no discussion**)
- P/IN.MAP      [ Scale P and IN values        ] (ready for development)
- LAST          [ Millis since script last run ] (in 2.1 beta)
- BREAK         [ Stop executing script        ] (in 2.1 beta)
- MZ            [ True if X % Y == 0           ] (some community support)
- W             [ While loop mod               ] (in 2.1 beta)
- CHAOS         [ Chaotic sequence             ] (in design!)
- FN            [ User-defined functions       ] (in discussion)
- EVERY         [ True every X times called    ] (in discussion)
- @ (Turtle)    [ 2D index to pattern grid     ] (in 2.1 beta)

If you support anything marked rejected, feel free to post about it!


Teletype - basic scripting question
(Teletype) 2.1 Firmware Beta (rc2: EVERY et al.)
#2

Here’s a thought: conditionals that operate on the A (or maybe X) variable.

A [max length command]
JEZ: [some sub]

Where JEZ is stolen from assembly languages, where it means Jump if Equal to Zero. Likewise, you can have JGZ, JLZ and JNZ. (I’m totally amenable to some other three-character keyword. AEZ? IEZ (If Equal to Zero)?)

You could go further and make conditions that operate on A (or X) and B (or Y):

A [long cmd]
B [long cmd]
JGT: [some sub]
JLT: [some sub]
JEQ: [some sub]
JNE: [some sub]

The primary benefit of these type of operators is that they are terse, leaving more much-needed room in the code. It saves one character in the best case IF A (4) vs JNZ (3), but IF GZ A takes 7 characters, while JGZ still takes 3. For the A/B set, the benefit is greater: IF GT A B is 9 chars wide, while JGT is 3.

The other thing on my mind is that there’s no EXIT command or the like to terminate the remainder of the script, as far as I know. That could be done if it’s not against anyone’s idea of the ethos of the language. How about an HCF (Halt and Catch Fire) command to load a blank scene and clear the output hardware?


#3

:stuck_out_tongue:


#4

Right had my morning coffee.


MSPB, that’s super useful. It’s one of those calculations that’s a pain to do in your head. It would also be really useful with DEL and TR.TIME.

It’ll also be a really good OP to start with, as it’s a pure function. I’d add it to ops/maths.c. There are instructions on adding a new OP in the readme, let me know if you run into any problems, and I can use that info to improve the docs. Don’t forget to run the tests as there as some that check to see if all the values have been filled in properly.

If you can also add some docs for MSPB that would also be amazing, but if it’s too much to take in all at once that’s okay too. (Especially if you want to generate the PDFs, as you’ll need Latex/TexLive.)

(What Linux are you on?)


Remember there are symbolic options:

IF ! A: ...
IF > A 0: ...

I’m not so sure about these, I don’t think I would use them. Especially if the variable is hard coded. I’d be more keen on something that took a variable as input. Maybe we should also use a symbol? So:

?0 X:    # if X is zero
?>0 X:   # if X is greater than 0
?== X Y: # if X == Y
etc, etc

(I’m not sure I even like that)

Anyway, I’ll let others chip in, if they think they’ll find them useful.

As a slight aside, I’m in the process of adding a ternary OP (TER, with alias ?), along with some inline array and scale generation OPs:

See here for a description of the ternary OP:


+1 on STOP. I’d consider using a different name though, as STOP maybe be useful in other contexts (e.g. with PLAY). How about BREAK with HCF as an alias for the nerds amongst us (i.e. me).

I would add an extra field to exec_state_t:

typedef struct {
    bool if_else_condition;
    uint8_t exec_depth;
    bool is_exiting;         // or whatever you feel is best
} exec_state_t;

Then you need to figure out the best place to bail out. Possibly you’ll need to do the check in multiple places.

This OP feels like it needs a few tests added too. E.g. how it interacts with MODs and sub commands. And to also make sure that any future additions continue to play nicely with it.


#5

Yeah, that’s where I put it. It was already compiled and working before I made the first post. :wink:


Fun aside: fixed point maths!

    ret = ((((uint32_t)(1 << 31)) / ((a << 20) / 60)) * 1000) >> 11;

Feel free to count the unnecessary brackets.

Yeah, I already did that, too! I’m on Centos7, so I had to compile Python to get up to 3.6, LOL. I waded through finding the dependencies of the doc tools and got it done. Not something I haven’t done a thousand times before on Linux, though I confess that it took a good 45 minute to figure out how to install ttf fonts for XeTeX. (I didn’t figure it out the proper directory / cache tool, but I learned you can dump the ttf files in the compile folder.)

I’m actually thinking of two separate operators:

  1. Do not execute the remainder of the SCRIPT
  2. Clear all outputs and load a blank scene

I don’t have a preference as to the names.


#6

there were several new ops suggested in this thread: Teletype v2 proposals

one thing i’d like to add is a variable reflecting the current script number, this would allow for easy copy/pasting of scripts where the only thing that is different is the script number.

agreed with @sam on JEZ style ops, having a specific variable baked into the op itself seems like too much of a special case… also i think we really ought to add a ternary ? op, this would make for a shorter script in a lot of cases.

+1 for BREAK! not sure about a variation that loads a blank scene though - how do you see it being used? also you can already do it with SCENE op and a dedicated empty scene.


#7

I see it being used by not having to make sure you have a blank scene in the current bank and knowing what number it is :wink: Additionally, it could be more terse.


The main case for them is to reduce code size. I agree that it’s a more limited version of existing functionality, but memory is not an issue and these operators are very cheap to add. It’s not like there are idiomatic uses of X, Y, and Z anyways, and users are not obligated to use these operators.

I always hated Perl’s TIMTOWTDI approach, but I hate the limitations of teletype’s script size more. :stuck_out_tongue:


:+1:


#8

what i meant is, what is the use case where you’d want a script to clear the whole scene without loading a new one? the only use case i can think of is live coding scenario where you use, say, monome walk to go back to clean state.

re: adding specialized ops - it’s definitely easy and fairly cheap to add more specialized ops but that shouldn’t be the only criteria. i think there is danger in diluting the language with too many special cases, which both makes it look more complex for somebody just starting on it, and makes it more difficult for script sharing. any new ops should be carefully considered, imo, and should fit well within the existing structure of the language, following the same general guidelines (although there are several ops already that don’t…).


#9

agree on the second paragraph. on the other side it’s very cool seeing more coders extending the firmware.

I can see the benefit of a blank scene OP, less in script and more in live mode. it would be very handy for having a hard reset and start over.


#10

Great work!
I think Teletype lacks something like a ratcheting generator. One operator or a couple of operators you give an external BPM or train triggers and you can get a ratcheting effect based on incoming trigger multiplication, without modifying teletype’s M.
For doing this I actually use a clock multiplier and AND module, It would be great having all inside Teletype.


#11
  • AT: I’m happy to implement it. Come comment on the issue and once we’re in agreement about syntax and functionality, I’ll bang it out.

  • Comment Operator: I’ll investigate how to do this. It should be easy. Is # free for use? I think so…

  • RAMP/LFO variable / operators: Also doable

A performance ends on bar 64:

IF GT X 64: [finished performance, load blank scene]

I agree that right now you can just

SCENE [some known blank scene]

but it would be nice (IMO) to have a dedicated operator.

Cheap and easy isn’t my driving criteria. It’s code terseness.

I think documentation can solve the new user problem. Introduce a desired idiom in the tutorials, document other idioms independently.

As to script sharing, it won’t pose a problem. Script comprehension, on the other hand would require understanding of the idiom/operators.

:man_shrugging:


#12

how is it performed? not trying to be difficult, just trying to understand the use case. say, i can see this being helpful as a keyboard shortcut, but something that is done by the scripts themselves seems a bit weird. if you were performing in this manner, wouldn’t you want to load your next scene? or you just want the script to stop and then load the next scene manually? that’s what makes it a bit of a special case for me…

as a side note, it’s an exciting topic to consider ops that update the scripts themselves!

in a teletype style language code terseness and readability are both important. special ops usually only help to achieve one of the two.

i would say that script comprehension is an important part of script sharing :slight_smile:


#13

I think more useful than a new scene op, would be to enhance the preset loading mode to add an “init” preset either at the beginning or the end of the list.

This would be better done as a key stroke to disable the current line in a script (maybe dim it out). Otherwise you’ll have to jump through some hoops with command_state_t to get the # to work, and there may be other gotchas too (remember the command must also validate, which I’m not sure is 100% possible without adding exceptions to the validation code). And what would you do if you don’t have the spare 2 characters (or spare op) on a command to comment it out?

Thoughts?


I’m afraid I agree with @scanner_darkly on JEZ, etc. Too complex. I’d rather allow longer lines or more scripts (and I don’t really want that either).

We have to be careful, Forth already has a bad reputation as a “write once, read never” language.


I’ll try to get the TER / ? op done soon.


#14

Good points, agreed that it should be a state instead of syntax in light of them. Seems easy enough. I can put a new flag in tele_command_t and implement the functionality easily, but what should the keystroke be?

I can see that point of view. I’m surprised to hear it, however, with the relative verbosity of conditionals as it stands. Am I the only one who constantly bumps the character limit? :confused: (I’ll keep this in my private repo, I guess.)

I already feel that the teletype script language has that character, prefix notation and all. It’s not uncommon for me to read a line three or four times to internalize and validate its function. I also don’t really feel that that the assembly idiom is all that difficult to understand or poisonous to the language as a whole.

I’ll pocket this in a branch for a future discussion about teletype script ethos / idiom.


Here’s another one: a dedicated scaling fetch operator for the range of the PARAM knob value. Consider:

A SCALE 0 16383 [x] [y] PARAM

vs:

A PSCALE [x] [y]

Maybe a better approach would be to add scaling properties to PARAM, as in:

PARAM.RANGE [x] [y]

Where subsequent calls to PARAM are automatically scaled.

edit: Same conversation could be had for IN


#15

An entire composition begins on loading scene 0, uses all available scenes in its function, and has a predetermined termination condition.


#16

As a user without any coding/IT background I get a bit afraid reading all this as it seems to make things more complex to understand.

Evolution is great but I wish you would keep in mind that for someone who is not used to programing computers things like three letter acronyms for nerdy phrases are not always easy to understand or memorize.

And I am afraid it is not done with documentation and the usual “You don’t have to use it” because you have to understand everything and see the whole frame to pick out the things you want to use. I go back to documentation regularly when I write scenes and finding e.g. different versions of IF THEN variations with abreviations using symbols and/or acronyms might fluster the whole syntax style so that it is getting harder to grasp for non professionals.

I would love to keep teletype accessible even for lesser educated people.


#17

Oh boy. Keystrokes is super bike shed territory. (You should have seen the time I nixed the ~…)

Get it working first I suppose… otherwise alt-c or alt-/?

I think semantically the commented status should be part of the scene_script_t rather than tele_command_t, as the commands are used in many contexts where commenting makes no sense.

Also :+1: for doing it!

So, this I’m much more in favour of, and it’s been on my own personal bucket list… I’d go with

PARAM.SCALE x y
PRM.SCL x y        // alias

and the same for IN.

I could try to rationalise this as being because I never use PARAM without the SCALE anyway. (Does anyone?)


#18

interesting use case! i still think there are workaround with existing ops though, depending on how the composition is programmed.

+1 to scale options for IN and PARAM. but extending this idea a bit it’d be nice to consider officially introducing suffixes such as .SCALE as a more general thing, so you could apply it to other variables. so you could do X.SCALE, for instance. and then we could consider adding more suffixes, i would totally use X.+ or X.- as a shortcut to + X 1 and - X 1.


#19

The motivation for SCALE on PARAM and IN stems from the fact that they have constant limits on [a] and [b]. I don’t see the same draw for plain variables, whose [a] and [b] are not defined. As a result, you’d end up having to set the a-b range and x-y range. It would still have the value of prescaling the variable on read, but additionally, how would you handle writing the variable, and when (and how) would you use the “raw” value?


#20

good point. maybe a shortcut for only specifying the upper limit, assuming the lower limit is always 0. but then it’s becoming a bit too specific… definitely makes sense for IN and PARAM though.

for this use i think it would be a readonly op.