OTYPElearn1.1scripting for the octatrackoctatrack

The studies
  1. Learn OType
  2. 01Quickstart
  3. 02Numbers and expressions
  4. 03Decisions and loops
  5. 04Variables and memory
  6. 05Tracks and steps
  7. 06Functions
  8. 07Asking the player
  9. 08Chance you can repeat
  10. 09Live scripts
  11. 10When something is wrong
  12. 11Appendix: scope at a glance

study 04 of 10

Variables and memory

A variable holds a number. What sets OType's variables apart is how long they keep it: for one run, from one press to the next, or for the life of a live script. This study builds a rhythm that turns a little further on each press, and a function that alternates between two patterns.

Giving a variable a value

A line that starts with a variable gives it a value; anywhere else, the variable is read.

Listing 4-1 · Assign, then read
def count_up
  menu "LEARN" >> "COUNT UP"
  a 5
  a add a 1             # read a, add 1, store the result back in a
  b mul a 2
  msg "A" a "B" b
Output · what the simulator prints for $ otype.py run count_up
count_up  seed 1 (--seed)  pattern A01 len 16 (default)  track 1
(no track holds anything)
      X trig  ! one-shot  o trigless trig  - trigless lock  l locks only  . none
part:  tempo 120
msg:   "A 6 B 12"
end box: "A 6 B 12" (the last msg, instead of DONE)
cost: 6/6   random draws: rand 0  toss 0  prob 0  drunk 0  file 0

There is nothing to declare for the one-letter variables: they are always there, and start at 0.

Four kinds of letters

nameskindkeeps its value
a b c dlocalfor one run of one function. Every call has its own: a function you call cannot change yours. 0 at the start of each run.
x y z tglobalfrom one press to the next, shared by every function in every file. 0 when the machine starts.
i jcountersset by the loops (i the inner loop, j the one around it); read-only

Use a b c d for working values, and keep x y z t for what really has to survive the press, since every function can change them.

One press A, the next press B

not x is 1 when x is 0, and 0 otherwise. Storing it back in x on each press makes x alternate: 1, 0, 1, 0…

Listing 4-2 · Two rhythms, one press each
def ab_rhythm
  menu "LEARN" >> "A/B"
  x not x
  tr.clr
  if x: l 1 16: if er 5 16 i: tr.add i
  else: l 1 16: if er 3 8 i: tr.add i
Output · what the simulator prints for $ otype.py run ab_rhythm
ab_rhythm  seed 1 (--seed)  pattern A01 len 16 (default)  track 1
T1  1   5   9   13
    X...X..X..X..X..
      X trig  ! one-shot  o trigless trig  - trigless lock  l locks only  . none
part:  tempo 120
cost: 181/225   random draws: rand 0  toss 0  prob 0  drunk 0  file 0

Variables with a name: var

When a function needs to remember something of its own, give it a named variable. var name start goes at the top of the function, before the first statement; the variable starts at start when the scripts are loaded and keeps its value from one press to the next. Unlike x y z t, it belongs to its function alone. A function may have up to 16 of them.

Listing 4-3 · A rhythm that turns one step further on each press
def rotate
  menu "LEARN" >> "ROTATE"
  var shift 0
  shift wrap add shift 1 0 15
  tr.clr
  l 1 16: if er.r 5 16 shift i: tr.add i
  msg "SHIFT" shift
Output · what the simulator prints for $ otype.py run rotate
rotate  seed 1 (--seed)  pattern A01 len 16 (default)  track 1
T1  1   5   9   13
    .X...X..X..X..X.
      X trig  ! one-shot  o trigless trig  - trigless lock  l locks only  . none
part:  tempo 120
msg:   "SHIFT 1"
end box: "SHIFT 1" (the last msg, instead of DONE)
cost: 186/230   random draws: rand 0  toss 0  prob 0  drunk 0  file 0

er.r is er with one more value, a rotation. wrap … 0 15 brings 16 back to 0, so the rhythm comes round after sixteen presses.

Names you can read but not change

A param, a const and the arguments of a function are read like variables, but cannot be assigned: gap 3 on a param gap is an error. You will meet const and arguments in functions.

Values that move by themselves

Three words read like variables but change each time they are read. Each function has its own, kept between presses.

readgivesset with
flip0, 1, 0, 1… one more at each readflip 0
oa counter: 0, 1, 2… up to o.max (63), then round againo 0 · o.min · o.max · o.inc · o.wrap
drunka random walk: one step down, none or one step up at each readdrunk 64 · drunk.min · drunk.max · drunk.wrap
Listing 4-4 · A volume that wanders from step to step
def wander
  menu "LEARN" >> "WANDER"
  drunk.max 15
  drunk 12
  tr.clr
  l 1 16:
    tr.add i
    pl.set i amp.vol add 7 mul drunk 8
Output · what the simulator prints for $ otype.py run wander -v --seed 2
wander  seed 2 (--seed)  pattern A01 len 16 (default)  track 1
T1  1   5   9   13
    XXXXXXXXXXXXXXXX
    step 1: amp.vol 103   step 2: amp.vol 111   step 3: amp.vol 111   step 4: amp.vol 111
    step 5: amp.vol 111   step 6: amp.vol 103   step 7: amp.vol 103   step 8: amp.vol 95
    step 9: amp.vol 103   step 10: amp.vol 95   step 11: amp.vol 103   step 12: amp.vol 95
    step 13: amp.vol 95   step 14: amp.vol 103   step 15: amp.vol 95   step 16: amp.vol 95
      X trig  ! one-shot  o trigless trig  - trigless lock  l locks only  . none
part:  tempo 120
cost: 338/338   random draws: rand 0  toss 0  prob 0  drunk 16  file 0

drunk walks between 0 and 15 here; add 7 mul drunk 8 turns each of its steps into a clear change of volume, from 7 to 127.

What you learned

a 5 · a add a 1
a variable first on a line gets a value
a b c d
local to one run of one function
x y z t
global, kept between presses
i j
loop counters, read-only
var name start
a named variable of one function, kept between presses
flip · o · drunk
values that move at each read
er.r k n r s
a Euclidean rhythm, rotated by r

Try it

  • Make ab_rhythm cycle through three rhythms, with x wrap add x 1 0 2.
  • Rewrite rotate with o instead of var.
  • Keep wander loud: raise drunk.min to 8.