Hexadecimal Beats is a system for using Hexadecimal notation (base 16) for notating rhythmic onsets. It allows for notating a set of four sixteenth notes using a single character. The system matches up well with drum programming and modular sequencer programming practices and is useful for drum and melodic line programming for synchronized music.
NOTE: I had developed and worked with this system for a couple of years before coming across prior work by Bernhard Wagner in [http://bernhardwagner.net/musings/RPABN.html](Rhythmic Patterns As Binary Numbers). The article by Wagner discusses the use for notation and gives examples performed by instrumentalists as well as bit shifting and complementation operations.
Hexadecimal (Base 16), Binary (Base 2), and Base 10
A Hexadecimal digit is written using the numbers 0-9 and letters a-f. Each digit maps to one of the base 10 numbers between 0 and 15. A single hexadecimal digit is equivalent to a four-digit base 2 number (i.e., 4 bits). If the 1's and 0's of base 2 are interpreted as note hits and silences, a single hexadecimal digit can represent one beat of material made up of four sixteenth notes.
Converting from Rhythm to Hex
Notation in Hex can take some pratice, but once mastered can be very quick for notating rhythmic ideas. To interpret a four sixteenth note pattern into hex:
- First visualize the four sixteenth notes, then see the on's and off's as 1's and 0's and convert the rhythm into binary. For example, two eighth notes may look like
- Convert from binary: each digit represents a power of 2 and matches up with
8421. If the digit in the rhythm is a one, look at the the match and use that value. For example, for
1010, we have one 8 and one 2, which sums to 10.
- Convert to hex: from 10 we can lookup in the table to see what is the corresponding hex value, which is
Values of Hex Beat Notation
- With practice, one gets famililar with each of the hex values and how to use them to notate a rhythm.
- The hex values stick out and make it easy to remember common rhythms (e.g.,
9228is a 4/4 Son Clave rhythm).
- Hexadecimal is a compressed data format. It takes less characters to express a rhythm than it would in a binary representation or Time Unit Box System (TUBS) notation.
Drawbacks of Hex Beat Notation
- Hexadecimal beats only works with 16th note divisions for a beat. (Though there are tricks to developing 32nd note patterns, see "Hacking 32nd Notes" below)
hexbeat() and hexplay()
livecode.orc provides two opcodes for interpreting hexadecimal beat strings as onsets. First, hexbeat() takes in one required argument, the hex string, and an optional index value. If an index value is not give, the current clock tick is used. The opcode returns a 1 if the given tick corresponds with a hit and a 0 if it corresponds with a silence. For example, with a hex value of
"8"--which translates to
1000 in binary--the following code would result in the following values:
ival1 = hexbeat("8", 0) ;; ival1 equals 1 ival2 = hexbeat("8", 1) ;; ival2 equals 0 ival3 = hexbeat("8", 2) ;; ival3 equals 0 ival4 = hexbeat("8", 3) ;; ival4 equals 0
The output value of
hexbeat() being a 1 or 0 allows it to be used to control onsets either by conditional test or through multiplication for amplitude. For example:
if (hexbeat("80") == 1) then schedule("Sub1", 0, ticks(1), in_scale(0,0), ampdbfs(-12)) endif
would check the current clock tick against the hex beat string and, if the tick matches a beat onset, will return a 1 and allow the if-block to run.
Another way to use the
hexbeat() output is to pair it with
cause() and multiply the amplitude by the result of
hexbeat(). For example, the following will achieve the same result as the previous example:
cause("Sub1", 0, ticks(1), in_scale(0,0), ampdbfs(-12) * hexbeat("80"))
cause() is designed to only fire when it's fifth argument (amplitude) is greater than 0, notes for
Sub1 will only fire according to the hex beat notation.
Learning Hexadecimal Beats
The suggested learning path for Hexadecimal Beat notation is to start off simple and gradually get more complex.
First try working just with strings of
0's. This will be equivalent to notate with just quarter notes and quarter rests. Try using a
hexplay()call with a
BDinstrument and pattern
8. Try modifyin the hex string to
8000, and hear how that affects the rhythm. Next, try adding an additional
hexplay()call with an
SDinstrument pattern of
08. Next try modifyin the
0800and hear how that affects the rhythm.
After notating quarter note rhythms, try working with 8th note rhythms. These would be
a. Again start with just a
BDpattern, then again work with a second
SDpattern with a complementary rhythm.
After working 8th notes, try working with the various single-note 16th note rhythms. These would be
1. Try out these each on their own, then combine with 8th and quarter note rhythms.
Next, try the two-note 16th note rhythms. These would be
Finally, experiment with the three-note 16th note rhythms (
e) and the all 16th-note rhythm (
Additionally, I would highly recommend practicing by:
Notating rhythms you hear in music.
Reproducing 808 patterns found at the 808 Drum Patterns website. There are many patterns to choose from and in many different styles.
Hacking 32nd Notes
While Hex Beats works at 16th note resolution, a hack is available to develop 32nd note rhythms by using a start time offset. In the example below, there are two patterns setup for triggering the CHH (Closed High Hat) instrument. The first uses a standard hexplay() call to generate the usual 16th notes. The second uses a cause() call together with a
p3 / 2 start time (p3 is equal to the current tick length, or the duration of one 16th note). The two together will give the generated rhythm a 32nd note fill on the fourth beat of every other measure.
set_tempo(85) instr P1 hexplay("a", "Sub2", p3, in_scale(-1, 2), fade_in(11, 128) * ampdbfs(xlin(phsm(8), -18, -30))) hexplay("f00c", "Sub5", p3, in_scale(-2, ((p4 % 16) == 13) ? 7 : 0), fade_in(10, 128) * ampdbfs(-12)) hexplay("00000aaa", "Clap", p3, in_scale(-1, 0), fade_in(9, 128) * ampdbfs(xlin(phsm(4), -20, -12))) hexplay("aaff", "CHH", p3, in_scale(-1, 0), ampdbfs(-12)) cause("CHH", p3/2, p3, 0, ampdbfs(-12) * hexbeat("0000000f")) hexplay("080c", "SD", p3, in_scale(-1, 0), fade_in(8, 128) * ampdbfs(-12)) hexplay("91569154", "BD", p3, in_scale(-1, 0), fade_in(7, 128) * ampdbfs(-9)) endin
Hacking Pitch Curves
In the previous example, numeric computations were used to determine if a particular tick was found and, if so, to generate one scale degree:
hexplay("f00c", "Sub5", p3, in_scale(-2, ((p4 % 16) == 13) ? 7 : 0), fade_in(10, 128) * ampdbfs(-12))
The computation checks if the
p4 (the current tick or 16th note) is equal to 13 (which corresponds to the second hit from the
c hex pattern) and, if so, to generate a 7, otherwise a 0. This means that we want all notes to be 0 except for a 7 when were are on tick 13.
Another way to express the same computation would be to use
hexbeat() to generate a 1 or 0 and then to multiply by 7, as follows:
hexplay("f00c", "Sub5", p3, in_scale(-2, hexbeat("0004") * 7), fade_in(10, 128) * ampdbfs(-12))
hexbeat() in this way can be a quick way to generate pitch patterns that alternate between two values.
hexbeat() could be further employed for affecting duration, octave, accent, etc.