study 03 of 10
Decisions and loops
You have already used two words that end with a colon: l 1 16: and if c:. They are
modifiers: they decide whether, how often, or with which chance the rest of the line runs. This study goes
through all of them and builds a drum fill: a snare roll that thickens towards the end of the bar.
A modifier, then a line or a block
A modifier ends with :. What it governs is either the rest of the same line, or, when nothing
follows the colon, the indented lines below it:
def two_forms
menu "LEARN" >> "TWO FORMS"
l 1 4: tr.add i
l 9 12:
tr.add i
pl.set i amp.vol 100A block ends at the first line that is less indented. All the lines of one block must start at the same
column; the width is yours to choose, but only spaces count (a tab is an error). Modifiers also chain on one line,
read from left to right: l 1 16: if er 5 16 i: tr.add i is a loop, then a condition, then the
action.
if, elif, else
if c: runs what it governs when c is true. elif c: (else if) and
else: follow it, on the next lines and at the same indentation; only the first branch whose condition
holds runs.
def kick_snare_hat
menu "LEARN" >> "K S H"
tr.clr
l 1 16:
tr.add i
if eq mod i 8 1: pl.set i amp.vol 127
elif eq mod i 8 5: pl.set i amp.vol 110
else: pl.set i amp.vol 50Output · what the simulator prints for $ otype.py run kick_snare_hat -v
kick_snare_hat 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 50 step 3: amp.vol 50 step 4: amp.vol 50
step 5: amp.vol 110 step 6: amp.vol 50 step 7: amp.vol 50 step 8: amp.vol 50
step 9: amp.vol 127 step 10: amp.vol 50 step 11: amp.vol 50 step 12: amp.vol 50
step 13: amp.vol 110 step 14: amp.vol 50 step 15: amp.vol 50 step 16: amp.vol 50
X trig ! one-shot o trigless trig - trigless lock l locks only . none
part: tempo 120
cost: 332/336 random draws: rand 0 toss 0 prob 0 drunk 0 file 0Loops: l and each
l a b: counts i from a to b, both included, downwards if
a is greater. Its bounds are fixed before the run: numbers, a const, a
param, or an argument of your function, but never a variable. That is what lets OType promise that
every run ends.
Inside a loop in a loop, i is the inner counter and j the outer one:
def diagonal
menu "LEARN" >> "DIAGONAL"
tr.clr
l 1 4: # j: beats 1..4
l 1 4: # i: steps 1..4 of the beat
if eq i j: tr.add add mul sub j 1 4 iOutput · what the simulator prints for $ otype.py run diagonal
diagonal 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: 172/256 random draws: rand 0 toss 0 prob 0 drunk 0 file 0The trig moves one step later in each beat: step 1 of the first beat, step 2 of the second, and so on.
add mul sub j 1 4 i turns the beat and the step in the beat into a step of the pattern:
(j − 1) × 4 + i. Everything after # is a comment.
each: repeats for each step of the current step set, with i as the step. It shines
once you narrow the steps to, say, those that hold a trig; that is the subject of
tracks and steps.
Leaving early: break and stop
break leaves the loop it is in; stop ends the whole function there.
def first_six
menu "LEARN" >> "FIRST SIX"
tr.clr
l 1 16:
if gt i 6: break
tr.add iOutput · what the simulator prints for $ otype.py run first_six
first_six seed 1 (--seed) pattern A01 len 16 (default) track 1
T1 1 5 9 13
XXXXXX..........
X trig ! one-shot o trigless trig - trigless lock l locks only . none
part: tempo 120
cost: 159/208 random draws: rand 0 toss 0 prob 0 drunk 0 file 0Chance and counting: prob, every, skip
prob p: runs what it governs with a chance of p percent. Now the fill: the further
into the bar, the likelier a snare.
def snare_fill
menu "LEARN" >> "FILL"
tr.clr
l 1 16: prob mul i 6: tr.add iOutput · what the simulator prints for $ otype.py run snare_fill --seed 3
snare_fill seed 3 (--seed) pattern A01 len 16 (default) track 1
T1 1 5 9 13
...X.XXX.XXX.XXX
X trig ! one-shot o trigless trig - trigless lock l locks only . none
part: tempo 120
cost: 184/208 random draws: rand 0 toss 0 prob 16 drunk 0 file 0Each run draws new numbers, so each press gives a different fill. The simulator shows one of them (its
--seed fixes which; the randomness study explains seeds).
every n: runs once every n times the line is reached, and skip n: every
time except that one. Their count is kept from one press to the next, so every 4: tr.add 16 adds a
trig on step 16 on every fourth press only.
What you learned
…:- a modifier governs the rest of its line, or the indented block below
if·elif·else- choose between branches
l a b:·each:- count with
i(andjoutside) · visit the steps break·stop- leave the loop · leave the function
prob p:- with p % chance
every n:·skip n:- once every n times · all but that time
Try it
- Rewrite
first_sixwithoutbreak, with the loop bounds alone. - Make the fill thin out instead: a chance of
sub 100 mul i 6. - Add an
every 2:line that clears the track on every other press.