Block Options
Just like CALL
commands, nestable blocks can have options as well. The block options table shows the available options.
As you can see, the following options are also available as block options:
quantity
(short version: q
)
multiple
(short version: m
)
shift
(short version: s
)
if
(no short version available)
Moreover there are also some new options, only available for blocks:
tuplet
(short version: t
)
elsif
(no short version available)
else
(no short version available)
Options can be attached to the opening {
or closing }
brace, separated by whitespaces.
Block Options
Long Name |
Short Name |
Type |
Min Value |
Max Value |
quantity |
q |
integer |
1 |
∞ |
multiple |
m |
none |
- |
- |
shift |
s |
integer |
-127 |
127 |
tuplet |
t |
none or string |
- |
- |
if |
- |
condition |
- |
- |
elsif |
- |
condition |
- |
- |
else |
- |
- |
- |
- |
If you want (or must) pass a value to an option, the value must be appended to the option name, separated by a =
symbol or whitespace(s).
If more than one option is used, they have to be separated by a ,
symbol.
Quantity
The quantity
option plays the according block as many times as its value defines.
Eventually we are able to rewrite the function drum-and-bass
correctly and without needing to define the functions drums
and bassline
:
FUNCTION drum-and-bass
{
5: | (d=30%,q=3) e-2:4 -:8. e-2:16
5: | e-2:8 e-2 g-2 e-2:16 a-2 -:2 |
}
{ quantity 4
p: (v=127) hhc,bd1:8 (v=80) hhc
p: (v=127) hhc,bd1,sd1 (v=80) hhc
}
END
FUNCTION drum-and-bass
5: | (d=30%,q=3) e-2:4 -:8. e-2:16
5: | e-2:8 e-2 g-2 e-2:16 a-2 -:2 |
{
p: (v=127) hhc,bd1:8 (v=80) hhc
p: (v=127) hhc,bd1,sd1 (v=80) hhc
} q=4
END
These two examples are equivalent. The first example uses the long form quantity
and adds it to the opening brace.
The second example uses the short form q
for the closing brace.
Another difference is that the second example omits the block around the bass part. This block is optional because without block options it
does not do anything special.
Multiple
The multiple
option (short form m
) can be used to implement different voices playing in the same channel
in the same time.
It plays the block content and then moves the end markers of each involved channel to the position they had before the block has been opened.
The following example is equivalent to the example we used to explain the multiple
option in a function call
(in chapter 3).
But this time we do it completely without functions, only with blocks.
* time 1/8
5: | (d=30%) a-2:16 g-2 |
* time 4/4
{ m
5: | -:1... a-2:16 g-2 |
}
{ q=3
5: | (d=30%,q=3) e-2:4 -:8. e-2:16
5: | e-2:8 e-2 g-2 e-2:16 a-2 -:2 |
{ q=4
p: (v=127) hhc,bd1:8 (v=80) hhc
p: (v=127) hhc,bd1,sd1 (v=80) hhc
}
}
The red part is the anacrusis (upbeat) again. The blue part defines the two notes at the end of the second measure. This is the part with the
multiple option.
Because of this option, the following black part starts at the same time like the blue block.
This black part is repeated three times.
The multiple option is especially useful for music with complex percussion patterns, like in african or latin music.
The following example shows a typical Mambo section with different percussion instruments playing different patterns in the same time.
* tempo 180
{ q=2
// tom tom
{
p: | -:4 t3:8 t3 -:4 t6:8 t6 |
} m, q=2
// bass drum
{
p: | -:4 bd1:2. | - bd1:4 |
} multiple
// bell pattern
{
p: | (q=2) rb:4 (q=4) rb:8
p: | - (q=3) rb rb:4 (q=2) rb:8
} m
// clave
{
p: | -:4 cla cla - | cla:4. cla cla:4 |
}
}
The tom-tom part uses 2 different tom-tom drums.
This pattern is the same in both measures, so the block is repeated by the block option q=2
at the end of the block.
Besides, the option m
(multiple) is used to reset the time, so that the next block begins in the same time.
So you see how both options can be combined.
The bass drum part, marked in blue, only uses the multiple
option, here in its long form. That's needed again because
other parts are following that begin in the same time and in the same channel.
The bell part defines a mambo bell pattern which is very common in afro-cuban music. Here we use the ride bell but it can also be used with
a cow bell or other percussion instruments. This block ends with a multiple option (m
) as well because there is still another
drum part to follow with the same start time.
The last block defines the clave rhythm which is also very typical for latin music like Mambo or Salsa.
This block does not contain a multiple
option because there is nothing more to follow.
All these blocks are nested inside another block with the option q=2
, so that everything is repeated.
Shift
The shift
option (short form s
) works exactly like the shift option for function calls.
It transposes the whole block up or down by an arbitrary number of half tone steps.
Nested blocks can have different shift
options. In this case, the option values for all surrounding blocks are added up
to calculate the resulting shift value.
the following example demonstrates this, first with a lowlevel version and then with a compact version of the same sequence:
{ shift=-24
0 c /4
0 d /4
0 e /4
{ s=12
0 c /4
0 d /4
0 e /4
0 c /4 s=12
}
}
{ shift=-24
0: c d e
{ s=12
0: c d e c+
}
}
The first three notes are played 2 octaves lower because the outer block has a shift
option of -24
.
The next three notes are played only one octave lower because the -24
of the outer block and the +12
of
the inner block are added, and the result is -12
.
In the lowlevel version the last note has its own shift value of +12
which is added as well. The result for this note is 0
, so
the note is not shifted any more.
As the shift option doesn't exist for compact syntax, we use c+
here instead of a shifted c
in order to get the same sequence.
Tuplet
The tuplet
option (short form t
) is used to define that the block content is played as a tuplet.
The option can be used without any value. In this case the tuplet is interpreted as a triplet.
the following example shows the same triplets that we saw already in chapter 2, but this time defined as blocks.
1: (q=8) c-:4
{ tuplet
0: c:8 c c c c:8. c:16 c:8. -:16 c:8 c
{ t
0: c:16 c c
}
0: c:8 |1 c:2 c,e c
}
The blue part is again a nested triplet.
We use a bar line after the nested triplet, marked in red. As we already know, we need to add a tolerance value.
Alternatively a value can be passed to the tuplet
option. The value consists of two numbers, separated by a :
.
A triplet could also be defined as tuplet=3:2
(or t=3:2
).
3:2
means that the length of each note inside the block is multiplied with 2/3.
Or, more generally, X:Y means that each note length inside the block is multiplied with Y/X.
The following example shows the same tuplets we have seen in chapter 2, but this time using block options.
1: (q=8) c-:4
{ tuplet=5:2
0: c:8 c c - c:16 c
}
0: c:4
{ t=3:4
0: c
{ t=3:2
0: c:16 c c
}
}
{ t=7:4
0: |1 c:1 c,g:2 c:4
}
Again we must add a tolerance to the bar line after the nested triplet, marked in red.
If
The if
option can be used to execute a block only under a certain condition.
This transforms the block into something like an if block in other programming languages.
The following example is equivalent to the example we used for if
as a call option.
But this time we don't need any further function for the volta brackets (like
first-ending
or second-ending
):
CALL section(part=1)
CALL section(part=2)
FUNCTION section
0: | c:4 d e f |
{ if=${part}==1
0: | g:2 e |
}
{ if ${part} == 2
0: | e:2 d |
}
END
Another difference is that now we use parameters instead of normal variables. We could not do that while
explaining if
as a CALL option because we didn't learn how to use parameters at that time.
Elsif
The elsif
option can be used for a block after another block with the if
option.
It has its own condition.
The elsif
block is only executed, if:
- The preceeding block is not executed (because its
if
condition if false); and
- The condition of the
elsif
option is true.
Here's a rewrite of the previous example with an elsif
:
CALL section(part=1)
CALL section(part=2)
FUNCTION section
0: | c:4 d e f |
{ if=${part}==1
0: | g:2 e |
}
{ elsif ${part} > 0
0: | e:2 d |
}
END
The if
option in the second block is now replaced by an elsif
.
The condition of the elsif
is now ${part} > 0
. That means, the condition is true, if
the parameter part
is a number higher than 0.
In the first call, the if
block is executed. The elsif
condition is also true, but as
the first block is executed, the second one is skipped anyway.
In the second call, the if
block is skipped. So the elsif
condition is evaluated, and because it's true,
the second block is executed.
You can also add more elsif blocks. Each block is only executed if:
- None of the preceeding
if
or elsif
blocks is executed (because their conditions are all false); and
- The condition of the block's
elsif
option is true.
Here's an example of such an if-elsif chain:
CALL section(part=1)
CALL section(part=2)
CALL section(part=3)
FUNCTION section
0: | c:4 d e f |
{ if=${part} == 1
0: | g:2 e |
}
{ elsif ${part} == 2
0: | e:2 d |
}
{ elsif ${part} == 3
0: | d:2 e |
}
END
Else
After a nestable block with an if
or elsif
option, you can add another
block with the option else
.
This option does not have its own condition.
The else
block is only executed if none of the preceeding if
or elsif
blocks
is executed.
This enables us to rewrite the if
example with only one condition check:
CALL section(part=1)
CALL section(part=2)
FUNCTION section
0: | c:4 d e f |
{ if ${part} == 1
0: | g:2 e |
}
{ else
0: | e:2 d |
}
END
The if
block is executed in the first call, while in the second call the else
block is executed.
Conditions
The if
or elsif
options require a condition, as you learned before.
There are several types of conditions, like the Conditions table shows.
All conditions use an operator, apart from the defined condition.
Most of the operators expect two values, one on the left side and one on the right side of the operator.
Some operators expect only one value.
Conditions
Name |
Operator |
Left value |
Right value |
Type |
equal |
== |
string or number |
string or number |
binary |
not equal |
!= |
string or number |
string or number |
binary |
lower |
< |
integer |
integer |
binary |
greater |
> |
integer |
integer |
binary |
lower or equal |
<= |
integer |
integer |
binary |
greater or equal |
>= |
integer |
integer |
binary |
defined |
none |
none |
parameter |
unary |
not defined |
! |
none |
parameter |
unary |
in |
in |
string or number |
list |
binary |
equal condition (==)
The equal condition uses the operator ==
. It compares the left
value with the the right one. If both values are equal, the condition is true. Otherwise it's false.
not equal condition (!=)
The not equal condition uses the operator !=
. It compares the left
value with the the right one. If both values are equal, the condition is false. Otherwise it's true.
lower condition (<)
The lower condition uses the operator <
. It expects both values to be numbers.
If the left number is lower than the right one, the condition is true. Otherwise, it's false.
greater condition (>)
The greater condition uses the operator >
. It expects both values to be numbers.
If the left number is higher than the right one, the condition is true. Otherwise, it's false.
lower or equal condition (<=)
The lower or equal condition uses the operator <=
. It expects both values to be numbers.
If the left number is lower than or equal to the right one, the condition is true. Otherwise, it's false.
greater or equal condition (>=)
The greater or equal condition uses the operator >=
. It expects both values to be numbers.
If the left number is higher than or equal to the right one, the condition is true. Otherwise, it's false.
defined condition
The defined condition does not use any operator. It expects a call parameter as the only value.
If the parameter has been provided with the CALL
command, the condition is true. Otherwise it's false.
Here's an example:
CALL section(foo=0)
CALL section()
FUNCTION section
0: | c:4 d e f |
{ if ${foo}
0: | g:2 e |
}
{ else
0: | e:2 d |
}
END
The parameter foo
is only provided in the first call.
Then the if
block is executed. In the second call ${foo}
is undefined, and so
the else
block is executed.
not defined condition (!)
The not defined condition uses the operator !
. It expects a call parameter as the only value,
on the right side of the operator.
If the parameter has been provided with the CALL
command, the condition is false. Otherwise it's true.
Summing up, it's the opposite of the defined condition.
Example: if ! ${foo}
This would be executed if the containing function has been called without a parameter foo=...
in condition (in)
The in condition uses the operator in
. It expects a simple value or variable or parameter on the left side.
On the right side it expects a list of values, variables or parameters, separated by ;
. Additional whitespaces are allowed
but not required.
The operator compares the left value with all values of the right side. If the left value is equal to one of the list's elements,
the condition is true. Otherwise it's false.
Here's an example:
CALL section(foo=0)
CALL section(foo=2)
CALL section(foo=4)
FUNCTION section
0: | c:4 d e f |
{ if ${foo} in 0;1;5;10
0: | g:2 e |
}
{ elsif ${foo} in 2 ; 3
0: | e:2 d |
}
{ else
0: | d:2 e |
}
END
The if
block is executed in the first call, because then ${foo}
is 0, which is in the list 0;1;5;10
.
The elsif
block is executed in the second call, when ${foo}
is 2, which is not in the first list.
But 2 is an element of the list 2 ; 3
, so the elsif
condition is true.
In the third call, ${foo}
is 4, which is in neither of the lists. So the else
block is executed.