study 02 of 10
Numbers and expressions
In the quickstart, one line did all the work: if eq mod i 4 1: tr.add i. This study teaches you
to read and write that kind of line: arithmetic, comparisons and logic. On the way, you build off-beat hats and
accents from nothing but numbers.
Prefix notation
OType writes the operation first, then its values. There are no parentheses and no precedence to remember: each operation knows how many values it takes, and takes the ones that follow it.
add 1 mul 2 3
add needs two values:
1 the first
mul 2 3 the second, itself an operation: 2 × 3 = 6
= 1 + 6 = 7
To see it for yourself, store the result in a variable and show it with msg, which writes a short
text in the box at the end of the run (the simulator prints it too):
def math
menu "LEARN" >> "MATH"
a add 1 mul 2 3
msg "A IS" aOutput · what the simulator prints for $ otype.py run math
math 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 IS 7"
end box: "A IS 7" (the last msg, instead of DONE)
cost: 6/6 random draws: rand 0 toss 0 prob 0 drunk 0 file 0a add 1 mul 2 3 is an assignment: a variable name, then a value. Variables have
their own study; for now, a is a box that holds a number.
Read a long expression the same way: find the first operation, give it its values one by one, and when a value
is itself an operation, complete that one first. eq mod i 4 1 is eq of two values:
mod i 4 and 1. So it asks “is the remainder of i by 4 equal to 1?”.
Numbers
Every value is a whole number from −32768 to 32767. There are no fractions: a division drops them, so
div 7 2 is 3 and div -7 2 is −3. A result beyond the range stops at its edge
(mul 300 300 is 32767) instead of wrapping around, and the arithmetic never fails: dividing by zero
gives 0.
| write | or | means |
|---|---|---|
add x y | + x y | x + y |
sub x y | - x y | x − y |
mul x y | * x y | x × y |
div x y | / x y | x ÷ y, without the fraction (0 if y is 0) |
mod x y | % x y | the remainder, never negative: mod -1 4 is 3 |
min x y · max x y | the smaller · the larger | |
abs x · neg x | without its sign · with the opposite sign | |
lim x lo hi | x, kept between lo and hi | |
wrap x lo hi | x, wrapped around into lo … hi |
The symbols are only another spelling: + 1 * 2 3 is the same line as add 1 mul 2 3.
A minus sign glued to a number, -3, is a negative number; spaced, - 3 1, it is a
subtraction.
True and false
OType has no separate true and false: 0 is false, any other number is true. A comparison gives 1 when it holds and 0 when it does not.
| write | or | is 1 when |
|---|---|---|
eq x y | == x y | x equals y |
ne x y | != x y | x differs from y |
lt x y · gt x y | < · > | x is less · greater than y |
le x y · ge x y | <= · >= | x is at most · at least y |
ez x · nz x | x is zero · x is not zero |
Comparisons combine with logic: and x y, or x y, xor x y (one of the two,
not both) and not x. Both sides of and and or are always computed.
Off-beat hats are the odd steps that are not on a beat: an odd step, and not a beat.
def offbeats
menu "LEARN" >> "OFFBEATS"
tr.clr
l 1 16: if and eq mod i 2 1 ne mod i 4 1: tr.add iOutput · what the simulator prints for $ otype.py run offbeats
offbeats seed 1 (--seed) pattern A01 len 16 (default) track 1
T1 1 5 9 13
..X...X...X...X.
X trig ! one-shot o trigless trig - trigless lock l locks only . none
part: tempo 120
cost: 224/272 random draws: rand 0 toss 0 prob 0 drunk 0 file 0Read the condition from the left: and takes two values, eq mod i 2 1 (i is odd) and
ne mod i 4 1 (i is not 1, 5, 9 or 13). Steps 3, 7, 11 and 15 remain.
Choosing a value
? c a b is worth a when c is true, otherwise b. Only the
chosen side is computed. Here it gives each step a volume: loud on the beats, soft in between.
def accents
menu "LEARN" >> "ACCENTS"
tr.clr
l 1 16:
tr.add i
pl.set i amp.vol ? eq mod i 4 1 127 60Output · what the simulator prints for $ otype.py run accents -v
accents seed 1 (--seed) pattern A01 len 16 (default) track 1
T1 1 5 9 13
XXXXXXXXXXXXXXXX
step 1: amp.vol 127 step 2: amp.vol 60 step 3: amp.vol 60 step 4: amp.vol 60
step 5: amp.vol 127 step 6: amp.vol 60 step 7: amp.vol 60 step 8: amp.vol 60
step 9: amp.vol 127 step 10: amp.vol 60 step 11: amp.vol 60 step 12: amp.vol 60
step 13: amp.vol 127 step 14: amp.vol 60 step 15: amp.vol 60 step 16: amp.vol 60
X trig ! one-shot o trigless trig - trigless lock l locks only . none
part: tempo 120
cost: 320/320 random draws: rand 0 toss 0 prob 0 drunk 0 file 0Two new things here. The line l 1 16: ends with its :, so the loop repeats the
indented lines below it, a block, instead of the rest of the line. And pl.set s param value
writes a parameter lock on a step: amp.vol is the volume of the AMP page.
Rhythms in one word
Some operations are whole rhythms. er k n s is 1 when step s plays in a Euclidean
rhythm of k hits spread over n steps:
def five_of_16
menu "LEARN" >> "EUCLID"
tr.clr
l 1 16: if er 5 16 i: tr.add iOutput · what the simulator prints for $ otype.py run five_of_16
five_of_16 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: 180/224 random draws: rand 0 toss 0 prob 0 drunk 0 file 0dr.v c s gives a velocity from one of eight ready-made curves, step by step; you will see it in
the tracks and steps study.
What you learned
- prefix notation
- the operation first, then exactly as many values as it takes
add sub mul div mod- arithmetic on whole numbers, also
+ - * / % min max abs neg lim wrap- bounds and signs
eq ne lt gt le ge ez nz- comparisons: 1 or 0
and or xor not- logic; 0 is false, anything else true
? c a b- a if c, else b
er k n s- a Euclidean rhythm, step by step
pl.set s p v- a parameter lock on step s
msg …- a text at the end of the run
Try it
- Compute
sub 10 mul 2 add 1 2in your head, then check it withmsg. - Write the snare of a backbeat: a trig on steps 5 and 13 only, in one
if. - Make the accents grow through the bar: a volume of
add 40 mul i 5.