(Teletype) EVERY+SKIP+OTHER+SYNC

SYNC won’t trigger the EVERY commands, just set the count.

I think that maybe SYNC -1 should set all EVERY counts to their MOD minus 1. I can see value in resetting the whole scene to that state.

2 Likes

Here is a build with the changes discussed up to this point.

teletype-2.1.0-rc1-every.zip (489.5 KB) (edit: oops! this one was built with -O2)

teletype-2.1.0-rc1-every.zip (484.8 KB)

The only outstanding question is: what does OTHER at the top of a script do? Currently, it never runs the command.

i feel that each EVERY and SKIP command should set a global flag to true/false depending on their execution. OTHER should read this global flag.

so OTHER at the top of a script is basically just acting on the global flag, which would mean whatever EVERY or SKIP was executed from previous scripts— which i think is interesting musically

1 Like

Yeah, in the light of the full feature set I think that makes a lot of sense. It will only affect the behaviour of the single case that is OTHER-at-the-top.

I’ll make this change and then call the feature complete. Whatever release you want to include it with is fine with me. The branch will sit in my repo until then.

This line is the piece that worries me about EVERY. There’s a precedent for commands that track internal state, DRUNK is one, O is another - but creating an OP (PRE?) where there’s actually multiple internal states introduces a new concept into the language that initially feels out of place.

What if EVERY was just syntactic sugar around % for users that don’t understand modulo?

M:
X + X 1 # increments X each tick, might be an more idiomatic way to do this, but I'm new.

1:
EVERY 2 X: TR.P 1
EVERY 4 X: TR.P 2

It’s more explicit where the counter for EVERY is coming from. Resetting becomes X 0.

The problem that EVERY solves is that there are few general-purpose variables with which to create control flow divisions. Complex polyrhythms become an excercise in seeking out lowest common multiples with which to wrap your counters, and you’re left with fewer variables to do other stuff with.

Just my 2 cents.

1 Like

i mean, it’s done. if the docs match, then we should put it in 2.1. unless there are objections?

this was my initial comment, but EVERY/etc is a useful easy-entry per-line polyrhythm thing. you can still do complex if-else conditionals with manual counting. these new ops represent a special case which is musically interesting enough to make an exception.

3 Likes

Alright, here’s the final build of this feature set:

teletype-2.1.0-rc1-every.zip (484.8 KB)

I’ll drop this as rc2 (a complete violation of the release candidate stage, but whatever) later this week after I’ve soaked the feature some more.

3 Likes

Don’t want to throw off momentum, but I’m not sure why we can’t do complex polyrhythms with modulo or a variation on it, but can do them with a per-line context operator?

1:
EVERY 2: TR.P 1 
EVERY 4: TR.P 2
EVERY 6: TR.P 3

Seems functionally equivalent to:

1:
X + X 1 # moving this from M in my other example so that the count is local to the script.
EVERY 2 X: TR.P 1
...

Just with one extra line (incrementing X). If you wanted to create polyrhythms, you would add a 2 script that was similar, but called on a different rhythm. If the issue is running out of variables (likely) does it make more sense to increase the number of variables rather than introduce a new language paradigm?

What about LOCAL X; X + X 1 that allows a script scoped local variable? That could have utility beyond this example.

I’m not necessarily advocating one over the other, just interested in what I’m missing.

You guys (girls?) continue to hit it out of the park. Well done.

I’m back from a month of travel now, so will try and kick the tyres of rc1 this week, in between bouts of jet lag.

I’d also love to help with the docs (I think in markdown these days), though hours might be hard to come by this week. I’ll put my hand up properly soon if I can wing it.

2 Likes

That would be much appreciated! I’m half-regretful that that I don’t put the time into more full-featured documentation (including the studies), but I realize that it’s not really my strength.

I’m withdrawing my comments above in favor of the proposed. I’m interested in thinking about what EVERY could lead to. It’s essentially a closure PRE? Does that sound right? Anyway - I’m generally in favor of combining general purpose language features into more complex things, but given the space constraints and lack of function creation (although I end up using SCRIPT as a stand in for functions in the couple of hours I’ve spent with TT so far) it makes sense to have some heavy duty constructs like EVERY.

In short, the language enthusiast in me is nervous, but the TT user is intrigued. Regardless, I like the enthusiasm @sliderule, you made my afternoon super interesting. I like thinking about this stuff.

2 Likes

It is one of my strengths, though time management isn’t!

Step 1 for me, read the current docs / threads and try and get a handle on what’s documented and what’s not … while playing with rc1/2.

2 Likes

It occurs to me that there is an outstanding design decision to be made:

What happens when the divisor changes to a number lower than the current count?

Current Behaviour:

  • The count is modulo’d to the new divisor, which may cause the new count to be 0, triggering the calling EVERY statement

Possible Others:

  • The count is reset to 0, and will trigger an EVERY on the call that included the shrunken divisor
  • The count is reset to 0 but will not trigger the EVERY on the call with the shrunken divisor

(These two cases are basically an order of operations thing, but could also be thought of as setting it to divisor - 1 or just 0)

(edit: tagging @tehn in for guidance)

I love the concept of every. To my non-programmer mind it just makes sense. It’s immediate, intuitive, and gives me musical results without having to check the manual, search for an example, and repurpose. Really looking forwars to more tutorials with all the new hotness because I know so much has been added, but between teletype and the er-301 there’s just so much to explore! ( in the best way possible!) you people are amazing.

5 Likes

So I started writing the following out…


Technically not a closure as there is no local stack capture. (The closure refers to closing around local variables.)

I think anonymous function (or lambda function) would be the most correct term. In fact all PRE statements work by passing the POST (a.k.a. the bit after the :) to the MOD as an argument.

So all MOD ops are implemented in a generic way. Except the proposed W, which is why I raised some caution about it.


But thinking about it EVERY may well add some element of closing due to how it tracks internal state. I’m not entirely sure…

1 Like

I also hesitated to post the following…


As a long-time procedural programmer who once tried functional (but didn’t inhale) I had to read the Wikipedia page to answer this question.

…I don’t properly know the answer. I would guess that the hidden count is a bound variable, but I don’t know if the divisor (mod) is, as it gets evaluated and assigned at each evaluation, so it seems like an argument. It’s technically stored inside, but it’s only used during the immediate evaluation, then overwritten the next time.

1 Like

I’d like more variables too…

“What if EVERY was just syntactic sugar around % for users that don’t understand modulo?”

this is the most Cult of Monome-esque line ever. Hilarious. (Granted: I’m on the non-programmer side of this crowd😬)

3 Likes

I came to the Teletype with E/S/O already implemented and have enjoyed them throughly - I would have never figured out the % methods on my own. Seeing the history of this feature was super interesting and I just wanted to chime in and say thanks for the feature!

5 Likes