| Exercise 8.1 - State and Counters |
1 |
2 |
|
Variables allow us to set and store temporary or changeable information that we can draw upon in code. One particularly useful application is in keeping track of the current state of the music, which can be used to create progressions and iterative processes - varying repeats to add form and structure to a passage of music. In combination with the repeating pattern, they can be used like an SB0/SBx repeat (accessed with .repeat - see Tutorial 4), but which allow us to see, set, and control the current value. Such "counters" are even evident in traditional music to keep track of a musician's place in a piece (i.e. bar or measure number).
Define a variable to use as a bar counter:
- Move the cursor to the top left cell of the pattern and press " (speechmarks). A blank red label appears, ready for you to enter the label text.
- Enter "Bar" as your label text, and press Enter.
- Open the formula editor for the first cell of the pattern (by pressing '='), and press Tab to switch to the code block view (see previous tutorial).
- Underneath the existing code (which mutes all subsequent channels), write the following line:
@Bar = @Bar + 1
- This code reads the current value of @Bar, increments it, and assigns it back to @Bar.
- Press Ctrl-Enter to commit and execute the code, and close the formula editor. The effect parameter of the labelled cell should now read "01".
The pattern shown is based on repetitions of the first bar (16 rows). Every time the cell is played, the number increases, allowing us to use this variable as a counter to track time or progress through the music.
Other formulas in the pattern will read the counter and make decisions on what to do, so as to evolve the music over time, as explored in part 2.
| Exercise 8.2 - Counters and Progressions |
1 |
2 |
|
In this exercise, you will use the @Bar counter to selectively unmute channels in the rest of our pattern, which contain the building blocks for a piece of electronic dance music: drums, bass, lead, pad, etc. The piece is created from a single bar that simply repeats - but, as the counter increases, new layers will be added or removed from the mix to provide a musical progression.
Add rules to unmute the initial channels:
The remaining channels use a combination of handwritten music and formulas to provide new layers that build and vary the piece. Some contain formulas that reference @Bar themselves, or use their own variables (e.g. @Note) or arrays (e.g. @Notes) - some may even mute other channels, based on conditions or variables (overriding your earlier code!).
Define rules to unmute the remaining channels:
- Experiment with different conditions to enable the remaining channels at musically appropriate times, using additional lines of code like those above.
- A common technique is to separate changes by four bars – or multiples of four.
- Study the formulas in the channels, and work out how they function. As you cursor around the code, descriptions of the keywords will appear in the help bar below. You can also press Alt-Shift-= for a listing of all code in the pattern, and use the Code Reference (in the Help menu) for unfamiliar keywords. Click here to reveal some explanations.
- Channel 05 alternates between two different bass lines. It works out which bass line to use, 1 or 2, with its .param formula, then references the array, using the .param to indicate which column to take notes from - the row offset into the array is the same as the currently playing row index (.row).
- Channel 08 and 09 use a second counter with an array to ascend a scale - a counter within a counter, going from 0 to 3 based on the value of @Bar. As @Bar goes 1,2,3,4,5,6,7,8, etc. @Note goes 0,1,2,3, 0,1,2,3, etc. To do this, it uses the mod(x,y) function, which takes the modulo - the remainder of x divided by y (in this case 4).
- Channels 10 to 12 gradually get louder, by using a multiple of @Bar to set the channel volume (using Mxx), but only starting when @Bar is 33h, and never setting more than 30h volume (via the min() function, which returns the lesser of two values).
- Above, we unmuted channels after a certain number of bars by detecting when @Bar is greater than a value, but you can also limit the bars it plays by also using the less than operator (<), combined with the AND operator (&&):
(@Bar > X && @Bar < Y) ? Z
This expression does Z (e.g. unmute a channel) as long as we are after X bars and before Y bars. You can also use the OR operator (e.g. x || y), which evaluates to true if either of the conditions is true. For example, the following code is true outside the range X to Y:
(@Bar < X || @Bar > Y) ? Z
- If you've had a go and run into difficulties, click here to see one possible solution.
@Bar > 0 ? channel(2).mute = 0
@Bar > 4 ? channel(3).mute = 0
@Bar > 8 ? channel(4).mute = 0
@Bar > 12 ? channel(5).mute = 0
@Bar > 20 ? channel(6).mute = 0
@Bar > 28 ? channel(7).mute = 0
@Bar > 32 ? channel(8).mute = 0
@Bar > 40 ? channel(9).mute = 0
@Bar > 52 && @Bar < 69 ? channel(10).mute = 0