Glitch: a noisy fusion of math and music
Meet Glitch — a minimal, modern and easy-to-use synthesizer for Bytebeat music.
Bytebeat (sometimes known as glitch music) is a relatively new experimental genre of electronic music. If you are familiar with retro “chiptune” music you can imagine how it sounds — triangular or square waves making rhythmical scratching noises.
What’s so cool about Bytebeat music if it sounds so harsh? Mathematics. If numbers and formulas is a hard subject to you — most likely you will find Bytebeat music boring. Otherwise, let’s start making sound.
Glitch has no conventional musical notation — there are no notes or chords or even instruments. All you have is a mathematical expression that is evaluated for each time frame to generate the next amplitude value of the sound wave.
Historically, Bytebeat sound is created using the uint8_t data type, which is an unsigned 8-bit integer. It means the lowest possible amplitude level would be zero, and the highest possible would be 255. If you attempt to put values outside of this range — there will be an overflow (256 becomes 1, 257 becomes 2, -1 becomes 255, -2 becomes 254 etc).
Since Glitch was designed to create different kinds of music, it uses a range from -1 to 1 which is typical for the digital sound. In order to convert the historical [0, 255] range to a common [-1, 1] range one can use the built-in “byte()” function, which also controls the overflow if needed.
Glitch provides you with a special variable “t” that gets increased for each evaluation cycle. A simple expression of “byte(t)” produces a sound wave that linearly increases in time and overflows once it reaches the upper limit of 255. That’s how you can play a saw-tooth sound wave.
The frequency of the wave depends on how fast the “t” variable is increased. Most Bytebeat songs are played at 8000 Hz sample rate, so “t” is increased once in every 1/8000 sec = 0.125 ms. The maximum allowed amplitude will be reached in 256 steps, so “t” will reach the overflow point in 256*0.125 ms=0.032 sec. Which means the frequency of the sound wave will be 1/0.032=31.25 Hz. It’s within the audible range, but most likely will sound more like a low-frequency clicking rather than an oscillating sound. You may multiply “t” by some constant value to speed up the increment making the overflows happening more often and increasing the frequency of the sound. For example, “byte(t*8)” results in the saw-tooth wave at 32.25*8=250 Hz.
Saw-tooth wave is probably the most common oscillator function used in Bytebeat music. Now, how can we put a melody into a formula?
Probably Bytebeat music gained its popularity when SIGINT13 gave this talk “Making music with C compiler”. He has shown a really minimal approach of making digital music on a computer without any audio workstations or other traditional audio software. He wrote a short C program, ran it and redirected its output into a command-line audio player (aplay). Here’s the sample program:
And here’s how it sounds:
The formula looks like magic, but it produces rhythmic pattern and even some kind of a polyphonic melody!
There have been some great attempts to create the theory of Bytebeat music but it’s still more about random discovery rather than logical step-by-step composition.
What is known is that the pitch depends on the multiplier of “t”. If the multiplier also depends on “t” somehow — you get a pitch that changes in time. “byte(t*t)” still sounds like instant buzz, but “byte(t*(t/100))” is a loop where pitch is increasing and decreasing. Restricting the pitch multiplier to certain integer values (using bitwise shift instead of the division operator and using a bitwise mask to put it into a valid range) one can get predictable multipliers.
Now, there are some “good” ratios in frequencies. For example, the frequency ratio between octaves is 1:2:4:8 etc, and the ratio between the notes in a major chord is 4:5:6.
Let’s make a major chord arpeggio (a chord broken into a sequence of notes like C, E, F, E). The tempo should be slow enough to hear the individual notes. We will be using “t>>11” as our note index. It will result in a number that increases ~4 times per second. We need to put it into a range of [4, 5, 6]. A simple approach is to make a bitwise AND with 3 then add 4. Bitwise AND will return a sequence of [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3…], while adding 4 to each number gives a sequence of [4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7…]. Seven is a bit out of the chord notes range, but for the sake of simplicity we will keep it, hopefully it won’t break our melody too much. Finally, we will multiply “t” by some constant pitch multiplier and then by our variable note multiplier:
You may learn much more about different concepts of Bytebeat formulas here: http://countercomplex.blogspot.sg/2011/10/some-deep-analysis-of-one-line-music.html
If a melody can be represented as a sequence of algorithmically generated numbers — great, but if not — there should be a more traditional way to encode a sequence of numbers. Some composers used arrays or C strings (that are no different from arrays, really). Glitch has an array function for that — “a(index, a0, a1, a2, a3, …)” — which returns an element at the given index by modulo of the array length. For example a(t>>11, 4, 5, 6) will return a sequence of [4, 5, 6, 4, 5, 6, 4, …].
But to make our formulas look more obfuscated (and more in the spirit of Bytebeat) let’s try to encode note numbers as 4-bit parts of a 32-bit number. For example a major scale would be [0, 2, 4, 5, 7, 9, 11, 12], when written in hexadecimal it becomes 0x024579bc (or 38107580 converted back to a decimal number).
Glitch allows you to use variables and to separate multiple expressions with comma, and commas can be omitted at the end of line, so I will take advantage of this syntax to simplify the expressions. Let’s use “n” variable to denote our “sequence-encoded-as-a-number”.
Now we can take a certain 4-bit nibble at the certain offset (increased as time goes): “p=n>>(((t>>11)&7)<<2)”. Offset is ((t>>11)&7) and we multiply it by 4 because each nibble takes 4 bits.
Remember, this is a note index, not a note frequency. There is a simple way to convert note index into a frequency — (2**(1/12))**note, where “**” is a power operation. The note of 49 is A4 (fourth octave A). And 2**(1/12) is ~1.059. So the frequency of note “p” would be “t*(1.059**(p+51))”.
Easy, huh? Each 32-bit number is an 8-step sequencer where each note is in the range of 16 semi-tones, which is a bit more than one octave. Now we can juggle the sequences and make complex melodies. This is where our array function can be handy, but one can also use a short-circuit operator (&&, ||) to simulate if/then/else. For example “((t>>14)&1)&&verse||chorus” toggles verse and chorus signals every 2 seconds.
Here’s an example of four 8-step sequencers that play some C-major scale tunes:
You may listen to the result here (just click the play button).
So far it’s been mostly saw-tooth waves as they are the easiest ones to implement. For your convenience Glitch also has a sine function “s(t)”. It takes a phase value in the range [0..1] and returns a sine value for the given phase. The sine wave “s(t/256)” has the same frequency as a saw-tooth wave “byte(t)”.
If you take the last formula and replace “t*(1.059**p)” with “s(t/256*(1.059**p))” — you will hear a pretty sine wave playing the same melody. You can mix multiple waves by adding them. For example “w=t*(1.059**p)/256,(s(w)+s(w/2)+s(w*4))/4” is a mix of three sine waves playing in different octaves.
You may also use “r(x)” function to get random numbers in the range [0..x] — this is how you can simulate some drums.
Using only basic arithmetics you can build complex instruments such as FM synthesizer. Here’s an example built with a regular sine wave and some rhythmic but chirpy noise along with the main melody:
Here’s a link to the formula above.
Glitch expression language
Glitch expression language is very simple and supports the following operations:
- Basic math: +, -, *, /, % (modulo) and ** (power)
- Bitwise math: &, |, ^ (XOR or unary negation), <<, >>
- Logical operations: <, >, <=, >=, ==, !=, &&, ||
- Others: comma to separate expressions, assignment to modify the value of the variables, parenthesis to group subexpressions.
There are many build-in function, but only 4 of them are likely to be used in Bytebeat: s(t) — sine wave, r(x) — random values, a(i, …) — get array element at a specific index and l(i) — binary logarithm (can be used to convert frequency back into a note).
Glitch works with floating-point numbers and operates at a higher sample rate (normally 44100Hz) which makes it possible to create sound of higher quality than 8-bit at 8 kHz. However “t” increment speed always matches the 8000Hz sample rate (it often takes rational values depending on your native sample rate). Same about the output values. It can be any floating point number in the range [-1..1] so technically it’s higher sound quality than 8-bit unless you truncate it.
Bytebeat changes the way you think about music. Instead of classical notes, instruments and effects you start thinking about signal functions and try to decode the sound you want to hear into a mathematical expression. You’re a music decomposer now.
Spend some time exploring Glitch library and try to modify existing tunes:
Or try your luck and put random operations with random values (that’s how most great Bytebeat pieces have been composed). Or write repetitive sequences of notes and play them with manually written synthesizers. Then share your creations via Twitter or by simply sending a link.
Future of Glitch
I find it very impressive when simple things turn into a complex beauty when carefully combined. Forth programming language, lambda calculus, UNIX tools and now Bytebeat music.
That’s why I want to keep Glitch clean and minimal. But what are the features you would like to see in the future versions of Glitch? Or perhaps you found a glitch in Glitch — then feel free to report it on Github: https://github.com/naivesound/glitch/issues
If you still think that Glitch might be too limited for you — check out the update.