Kevin Doyle
There are three main types of structure available in AMPLE:
a) Loops;
b) Conditionals;
c) Conditional loops.
b) Conditionals;
c) Conditional loops.
I will examine each of these in turn over the next few
issues of AMPLINEX and give examples of their use. In this issue I will look at
conditionals.
Conditionals in AMPLE
One of the facilities available to the AMPLE programmer,
which is absent from many non-language based computer music packages, is the
ability to interact with the listener by passing him or her a degree of control
as the music is playing. Another is the ability to introduce random elements into
the music which can generate a different result each time it is played.
To develop either of these techniques fully the use of conditional
structures will become necessary.
Many people will be familiar with the conditional structure
in BASIC of -
IF test THEN action1 ELSE action2
where 'test' is normally an expression (e.g. X=2 or A$="Y")
which is evaluated to be TRUE or FALSE. IF it is TRUE then 'action1' is
performed; if FALSE then 'action2' is performed.
In AMPLE the equivalent form is -
test IF( action1 )ELSE( action2 )IF
so that the result of evaluating the expression 'test' is
either ON (true) or OFF (false). If the result is ON then 'action1' is performed;
if OFF then 'action2' is performed.
So, using the AMPLE expression #= which tests the equivalence
of two numbers, the following trivial example can be constructed:
"equal" [
#= IF( "Yes" )ELSE( "No" )IF $OUT
]
#= IF( "Yes" )ELSE( "No" )IF $OUT
]
which takes two numbers and reports whether they are equal.
Thus, entering '3 4 equal' gives the result 'No' and entering '5 5 equal' gives
the result 'Yes'.
Using more complex conditions it is possible to construct an
interactive music program. Suppose you have written four different melody lines
for a particular player in a piece. Normally you may decide on a suitable sequence
for these and then construct a word to play them in that order. So, if the melody
lines were stored as mdy1, mdy2, mdy3 and mdy4, and were to be assigned to player
1 you might create:
"part1" [ mdy1 mdy3 mdy4
mdy2 mdy1 mdy3 ]
mdy2 mdy1 mdy3 ]
to play the melodies in the sequence you wanted.
To allow the listener (or yourself) to control the order of
the melody lines as the piece is playing, you could construct the following
word:
"part1" [
6 FOR(
"Choose a melody (1-4) " $OUT
#IN
#11 49 #= IF( mdy1 )ELSE(
#11 50 #= IF( mdy2 )ELSE(
#11 51 #= IF( mdy3 )ELSE(
#11 52 #= IF( mdy4 )IF)IF)IF)IF
#2
)FOR
]
6 FOR(
"Choose a melody (1-4) " $OUT
#IN
#11 49 #= IF( mdy1 )ELSE(
#11 50 #= IF( mdy2 )ELSE(
#11 51 #= IF( mdy3 )ELSE(
#11 52 #= IF( mdy4 )IF)IF)IF)IF
#2
)FOR
]
This word uses 'nested' conditional structures to test for four
possibilities. When the message "Choose a melody (1-4)" is displayed the
AMPLE word #IN is used to wait for a keypress and to return its ASCII number. The
AMPLE word #11 is then used to duplicate this number. This is because the
following test (#=) 'uses' the two numbers supplied to produce the ON or OFF flag
and the keypress number may be needed for further tests if the result of the
first test is OFF.
The first test takes the keypress number and compares it to 49
(the ASCII code for "1"). If they are equal this will leave the ON
flag and the action between the IF( and the )ELSE( statements will be performed
- in this case the word 'mdy1'.
If the keypress number is not equal to 49 then the action
after the )ELSE( statement will be performed - in this case this is another IF()ELSE()IF
structure.
Again the keypress number is first duplicated for further
use and then a test is performed to see if it is equal to 50 (the ASCII code
for "2"). If it is then 'mdy2' is performed, otherwise another
IF()ELSE()IF begins.
This happens two more times and at the end each of the four conditional
structures is terminated by its )IF statement. In this case all four occur together.
Finally, there will be a redundant keypress number left over
from one of the conditional structures and this must be discarded using the
AMPLE word #2.
In this example the keypress tests are performed six times to
generate a sequence of six melody lines.
There are, however, two problems with this example as it
stands. Firstly, if another key is pressed other than 1-4 then nothing will
happen. To get round this problem we could change the structure so that a
default melody is chosen, for example:
"part1" [
6 FOR(
"Choose a melody (1-4) " $OUT
#IN
#11 49 #= IF( mdy1 )ELSE(
#11 50 #= IF( mdy2 )ELSE(
#11 51 #= IF( mdy3 )ELSE(
mdy4 )IF)IF)IF
#2
)FOR
]
6 FOR(
"Choose a melody (1-4) " $OUT
#IN
#11 49 #= IF( mdy1 )ELSE(
#11 50 #= IF( mdy2 )ELSE(
#11 51 #= IF( mdy3 )ELSE(
mdy4 )IF)IF)IF
#2
)FOR
]
which would select 'mdy4' if neither 1, 2 nor 3 were
selected.
Alternatively, we could construct a loop which would repeat the
question until an answer within the range 1-4 was returned. I will look at this
type of conditional loop in the next issue.
The second problem with these examples is that of timing.
The word 'part1' waits for a keypress in order to select a melody line - but
this might mean that the melody begins at the wrong point in the piece or that
no melody is played at all.
It might be easier in this case to let the system select the
melody lines as it requires them but still allow for variation in the melody
lines played.
To achieve this we can use the random number generating
facilities of AMPLE.
In the above example we could replace the keypress number with
a random number generated by AMPLE. To do this we can use the AMPLE word RANDL.
This takes the form:
n RANDL
where n is a number in the range -32768 to 32767 and which produces
a number in the range 0 to n inclusive.
The four melody example above might then become:
"part1" [
6 FOR(
3 RANDL
#11 0 #= IF( mdy1 )ELSE(
#11 1 #= IF( mdy2 )ELSE(
#11 2 #= IF( mdy3 )ELSE(
#11 3 #= IF( mdy4 )IF)IF)IF)IF
#2
)FOR
]
6 FOR(
3 RANDL
#11 0 #= IF( mdy1 )ELSE(
#11 1 #= IF( mdy2 )ELSE(
#11 2 #= IF( mdy3 )ELSE(
#11 3 #= IF( mdy4 )IF)IF)IF)IF
#2
)FOR
]
Here the random number range is 0 to 3 giving the four options
required. Using RANDL means there is no need to consider the possibility of a
number outside this range as there was with the first keypress example.
There are two other AMPLE words related to random numbers.
The first, RAND, generates a random number in the range -32768 to 32767. The second,
RAND!, allows a 'seed' number to be set for random number generation so that
the same sequence is produced by the use of RAND or RANDL. So in the example above
we could allow the listener to enter a number and thereby generate a 'random' but
repeatable sequence of melody lines. Thus:
"Enter a number :"$OUT #IN RAND!
could be inserted at the start of the piece, perhaps in the 'RUN'
word before the players begin.
By careful setting of random number limits and use of conditional
structures complex randomly generated pieces can be created. The tests used in these
conditional structures may themselves be complex and there are several logical
operators in AMPLE to enable such tests to be performed.
The operators are shown below with truth tables for their results
and examples of their use.
AND | OFF | ON |
–––––––––––––––––
OFF | OFF | OFF |
–––––––––––––––––
ON | OFF | ON |
–––––––––––––––––
–––––––––––––––––
OFF | OFF | OFF |
–––––––––––––––––
ON | OFF | ON |
–––––––––––––––––
E.g. to test if a number n is in the range 3 to 7:
n #11 2 #> #12 8 #< AND
(#12 swaps two numbers - in this case it swaps the result of
the first test with the second copy of the number n.)
OR | OFF | ON |
–––––––––––––––––
OFF | OFF | ON |
–––––––––––––––––
ON | ON | ON |
–––––––––––––––––
–––––––––––––––––
OFF | OFF | ON |
–––––––––––––––––
ON | ON | ON |
–––––––––––––––––
E.g. to test if a number
n is either greater than 10 or less than 5:
n #11 10 #> #12 5 #< OR
XOR | OFF | ON |
–––––––––––––––––
OFF | OFF | ON |
–––––––––––––––––
ON | ON | OFF |
–––––––––––––––––
–––––––––––––––––
OFF | OFF | ON |
–––––––––––––––––
ON | ON | OFF |
–––––––––––––––––
E.g. to test whether either, but not both, of two numbers n1
and n2 are equal to 3:
n1 n2 3 #= #12 3 #= XOR
NOT | |
–––––––––––
OFF | ON |
–––––––––––
ON | OFF |
–––––––––––
–––––––––––
OFF | ON |
–––––––––––
ON | OFF |
–––––––––––
E.g. to test whether a number n is not equal to 12:
n 12 #= NOT
In the next I will be looking at conditional loops using the
AMPLE expression REP( )UNTIL( )REP.
Published in AMPLINEX 002,
November1987