| Exercise 7.1 - Functions and Macros |
1 |
2 |
3 |
|
Click here to watch this tutorial on YouTube™
Previously, we created blocks of code capable of more flexible and complex musical processes, which can be reused either by way of the clipboard or the .run() mechanism. In this tutorial, instead of placing the code in the pattern directly, we enter it 'outside' the music, in slots designated for useful code that we envisage using in multiple places or situations.
This represents one of the most powerful concepts in programming: defining functions (or macros) – creating reusable blocks of code to do a specific job. In both programming and music, it is common to repeat elements or processes; functions allow you to write the code once and then use it again and again - but unlike the .run() mechanism, can also adapt to different situations through the use of input arguments.
Explore using code blocks as functions:
- Open the Macro Editor, by pressing Ctrl-Shift-=. You will again be presented with a single text box for your code, but now have 10 numbered effects (0xy to 9xy) that can each contain a different code block (macro) that can be "called" from any part of the pattern.
- In this tutorial, a number of examples have been provided for you (0xy to 4xy). To move between them, press the Tab key. In the first slot (0xy), you will find the code from the previous tutorial. If you play the pattern from the start, you will notice that the code is applied every time there is an (0xy) effect, in the cell hosting it.
- Explore the other macros by moving the cursor to the different sections (labelled 0xy to 3xy/4xy ) and playing the pattern using the Space bar.
- When ready, move to step 2.
| Exercise 7.2 - Arguments and Parameters |
1 |
2 |
3 | | |
Each macro takes one or two input values, known as arguments (x and y, or xx), which can be used to input values to the code and vary its behaviour.
Like pattern effects seen previously (such as @xx for tempo, SDy for note delay, etc.), the two digits following the effect type / macro number (0 to 9) are parameters that can be specified when the macro is used.
There are two ways to use them: you can either use each digit as a separate argument (x and y), each from 0 to F (0 to 15, in hex), or combine both to be a single argument (xy – or, if you prefer, xx), from 00 to FF (0 to 255, in hex). In your macro code, you simply write x, y, and xy (or xx) as values (variables) instead of fixed numbers, and they will assume the value(s) passed from the pattern when the macro is used.
Use arguments to adapt the 0xy effect macro:
- We will extend the code from the Code Blocks tutorial, provided in macro 0xy, by using arguments to vary its behaviour – making it more flexible and useful in a wider range of situations (i.e. even more reusable).
- The following code shows how arguments are used to vary how far ahead the new note is (x rows), and what interval (pitch relationship, y semitones) is added.
[+x].pitch = .pitch + y
- Edit the code for 0xy as shown above, then go back to the pattern (Escape key) and play it from the start, to see how the parameters are used (the pattern is already populated with test values).
- Move to step 3 to explore further functions.
| Exercise 7.3 - Functions in Practice |
1 |
2 |
3 | |
The goal of code is to elegantly represent a process we can use multiple times... in different places, generating different results, based on different inputs. We often want to be able to predict and carefully control what code does, to meet a well-defined purpose, but we can also (especially in music and art) leave variation to chance - e.g. when there are a range of alternatives as good as each other, or when we don't know what we want, and when we're looking for something new.
Abstracting processes (e.g. into macros or functions) reduces the complexity of systems - in both software and music - making it easier to understand, create, and explore the bigger picture. Instead of editing individual pitches, a function might allow you to explore families of different melodies, harmonies, rhythms, etc.
Explore the remaining functions:
- There are ten slots for macro effects. Several further example functions have been provided in effects 1xy to 4xy, and used in different sections of the pattern.
-
Look at the code and listen to the playback behaviour of each effect to see how they work, considering the the musical function they serve.
- After you have had a go at deciphering their code for yourself, click the corresponding entry below to reveal a full description:
1xy - a simple harmoniser
This macro takes the current pitch (that is, where the effect is used) and creates two additional notes in the next two channels to form a chord, transposed by x and y semitones respectively. For example, an xy pair of "37" produces a minor triad, whilst a "47" produces a major triad.
2xy - a volume randomiser
This macro takes one parameter (xy) and varies the volume of the cell by a random value between 0 and xy. Such a function could, for example, be used to define a rough volume sequence (as effect parameters), but introduce a random (perhaps more humanistic) element to the final performance.
3xy/4xy - a murder mystery
These two macros are used in combination to generate a more complex musical pattern. 3xy provides our initial tonal palette: placing copies of the previous pitch used on the current channel (last.pitch) in the next three channels (transposing the last two up an octave).
To see this effect in action on its own, "comment out" the code in 4xy (by inserting ’ at the start of each line of code). This disables its execution without deleting the code, so it is easy to re-enabled it. Comments are often used in this way to temporarily turn bits of code off and on - to help understand, debug, or isolate different elements). Re-enable the code when done.
The 4xy effect is then applied to this tonal palette to sculpt a sequence by harmonising and randomly deleting the pitches 3xy has inserted, based on two parameters. The first (x) decides how likely the pitch is to change, and the second (y) decides how it will be transposed from the original pitch. A second line introduces a 10% chance that a 'note off' will be ended, terminating the current note.
The result is a musical texture on harp and strings, based on a minor tonality that would not be out-of-place on a TV crime drama - or in a video game, where the music can be generated based on the player's actions and pace.
The last macro exploits a unique feature in Manhattan that supports
probalistic conditional statements (or "possibly-or-else").
In computing, zero is typically false and all other values (notably including one) are true. In Manhattan, a condition that results in a value between 0.0 and 1.0 becomes a probability of it being true - from 0 (0% chance, always false) to 1 (100%, always true).
The following examples show how you can easily add stochastic or probalistic processes in your code - i.e. introduce
controlled randomness in your music:
0 ? x : y ' never x, always y
1 ? x : y ' always x, never y
0.5 ? x : y ' equal chance of x or y
0.1 ? x ' 10% chance of x (or do nothing)
1/4 ? x ' one chance in four (= 0.25 / 25%)
1/3 ? x : (1/2 ? y : z) ' equal chance
0.5 ? x : (0.5 ? y : z) ' x:y:z 50:25:25
Before continuing to the next tutorial, spend a little time coming up with a few of your own functions, in the remaining slots (5
xy to 9
xy). Feel free to work with the existing content of the pattern, or venture into new channels (muting or unmuting as appropriate).