Algorithmic Composition: A Gentle Introduction to Music Composition Using Common LISP and Common Music
Skip other details (including permanent urls, DOI, citation information) :This work is protected by copyright and may be linked to without seeking permission. Permission must be received for subsequent distribution in print or electronically. Please contact : [email protected] for more information.
For more information, read Michigan Publishing's access and usage policy.
Chapter 7: Printing and Reading
This chapter introduces you to writing output to your computer's monitor and reading data from the computer keyboard. Displaying information to your monitor is very helpful in locating problems in your programs.
7.1 Print
PRINT will print a constant, symbol, string, or the value of a variable or expression.
The examples in Section 7.1 and 7.2 use the Stella command interpreter. These examples could also be evaluated by the Common LISP interpreter.
It seems as if PRINT prints everything twice. One line of output is caused because of PRINT. The second line of output is printed because LISP returns the last expression evaluated, which in this case, is the argument to PRINT.
7.2 Format
The Common LISP function FORMAT allows you greater control of the formatting of your output. The FORMAT template is:
(FORMAT T FORMAT-CONTROL-STRING)
FORMAT is followed by the symbol T to indicate that we want to print to the monitor. A string is used as the format-control-string.
Notice that FORMAT writes the string without the quotes and returns NIL. The format-control-string is always enclosed in double quotes. The format-control-string may include FORMAT directives- special characters in the format-control-string that cause output to appear in certain ways.FORMAT directives always begin with the tilde (~). Table 7.2.1 gives an overview of some very useful FORMAT directives.
Table 7.2.1
format Directive | Result |
~% | Move to a new line |
~& | Move to a new line only if not already at the start of a new line |
~A | Print the value of a variable or expression. The value of the variable or expression is mapped to the format-control-string. The variable or expression is included in the FORMAT form immediately following the format-control-string. |
~n,F | Print the value of a variable or expression as a floating point value. The floating point value is mapped to the format-control-string. n is variable and specifies the number of positions that will be printed. n is optional. |
this is the first line
and this is the second
NIL
In Example 7.2.2, the second ~%FORMAT directive moves printing to a new line. The ~&FORMAT directive is ignored since printing is already at the start of a new line.
Notice that in Example 7.2.3 the value of *standard-tempo* is mapped to the location of the ~A FORMAT directive in the format-control-string. Notice that the variable *standard-tempo* appears after the format-control-string.
In Example 7.2.4, the FORMAT directive ~n,F is used to control formatting of floating point values.
7.3 Using print and format in Common Music
Sometimes, it may be useful to monitor how Common Music assigns slots by printing values to your computer monitor. An example of why you might want to do this is if you're just becoming familiar with some aspect of Common Music. For example, let's say you'd like to learn more about the Common Music function between. You look-up the documentation for between in the Common Music Dictionary and find:
between lb ub &optional exclude state [Function]
Returns number n such that lb<=n<ub and n!=exclude. Use exclude to avoid direct repetition. state is the random state object to use in the calculation, and defaults to *cm-state*.
At first glance, it may not be obvious what between does.between returns a random number between a lower bound (inclusive) and an upper bound (exclusive). If the upper bound or lower bound are floating point values, between returns a floating point value. The &optional indicates an optional argument in Common LISP. In this case, the optional arguments are for exclude and state.exclude allows you to prevent direct repetition of a randomly-selected value.state is the random state object used to calculate the random value and defaults to the Common Music global variable *cm-state*.
We will use PRINT to gain first-hand experience with between. We use between to randomly specify an amplitude value in the range .5 (inclusive) to .9 (exclusive).
When we mix the generator, we see that the value of the amplitude slot is printed six times, once for each midi-note object that was created as specified by the note slot. Notice that the value of the amplitude slot is a random value between .5 and .9.
Example 7.3.2 explores the optional argument exclude. In this case, we exclude the previous value of the amplitude slot to prevent direct repetition.
You may think that it is strange that the generator print and the algorithm print-again contain one PRINT function that is evaluated six times. The reason for multiple evaluations of PRINT is that algorithms and generators have an implicit looping behavior. Algorithms and generators loop until they reach a specified end, length, or prescribed number of note events.
It would be useful to exercise more control over the manner in which items are printed to your monitor. For example, you may wish to see the value of all of the slots on one line of output and format the floating point value of the amplitude slot so that there are only three positions to the right of the decimal point. You may do this using FORMAT.
interp x env &key :scale :offset :return-type [Function]
Returns the interpolated y value of x in env with optional :scale and :offset values applied: f(x)*scale+offset. The type of the value returned normally depends on the type of the arguments specified to the function. Use :return-type to force the return value to be a specific type, either float, integer or ratio. float may also be specified as a list (float digits) in which case the floating point return value will be rounded to digitnumber of places.
interp returns an interpolated value in a range as specified by env. Optionally, we can scale the value that it returned or add an offset to it. We may use the optional keyword return-type so that interp returns a floating point value, integer, or ratio.
Your actual output may vary because of the RANDOM function.
7.4 Reading Data from the Computer Keyboard
The Common LISP function READ accepts input from the computer keyboard. Generally, READ is used to assign a variable or slot. The READ template is:
(READ)
We can allow the user to enter data from the computer keyboard during the evaluation of an algorithm or generator. Because of the looping behavior of algorithms and generators, Common Music evaluates the READ function as many times as the generator or algorithm loops. Consider the following example that assigns the note slot using READ.
The generator read creates 5 midi-notes. The channel, amplitude, duration, and rhythm slots are assigned when the container is initialized. The body of the generator consists of the Common LISP FORMAT function that prints a user prompt to the computer monitor. The READ function accepts input from the keyboard and that input is assigned to the note slot. Mixing the generator yields the following:
Mix objects: (<cr>=Read)
Start time offset:(<cr>=None)