4.7 KiB
Bytebeat
Bytebeat is a procedural chiptune/8bit style music generated by a short expression in a programming language; it was discovered/highlighted in 2011 by Viznut (author of countercomplex blog) and others, and the technique capable of producing quite impressive music by single-line code has since caught the attention of many programmers, especially in demoscene. There has even been a paper written about bytebeat. Bytebeat can produce music similar (though a lot simpler) to that created e.g. with music trackers but with a lot less complexity and effort.
This is a beautiful hack for LRS/suckless programmers because it takes quite a tiny amount of code, space and effort to produce nice music, e.g. for games (done e.g. by Anarch).
8bit samples corresponding to unsigned char
are typically used with bytebeat. The formulas take advantage of overflows that create rhythmical patterns with potential other operations such as multiplication, division, addition, squaring, bitwise/logical operators and conditions adding more interesting effects.
Bytebeat also looks kind of cool when rendered as an image (outputting pixels instead of audio samples).
How To
Quick experiments with bytebeat can be performed with online tools that are easy to find on the web, these usually use JavaScript.
Nevertheless, traditionally we use C for bytebeat. We simply create a loop with a time variable (i
) and inside the loop body we create our bytebeat expression with the variable to compute a char that we output.
A simple "workflow" for bytebeat "development" can be set up as follows. Firstly write a C program:
#include <stdio.h>
int main(void)
{
for (int i = 0; i < 10000; ++i)
putchar(
i / 3 // < bytebeat formula here
);
return 0;
}
Now compile the program and play its output e.g. like this:
gcc program.c && ./a.out | aplay
Now we can just start experimenting and invent new music by fiddling with the formula indicated by the comment.
General tips/tricks and observations are these:
- Outputting the variable
i
creates a periodical saw-shaped beat, multiplication/division decreases/increases the speed, addition/subtraction shifts the phase backward/forward. - Squaring (and other powers) create a wah-wah effect.
- Crazier patterns can be achieved by using the variable in places of numerical constants, e.g.
i << ((i / 512) % 8)
(shifting by a value that depends on the variable). - Modulo (
%
) increases the frequency and decreases volume (limits the wave peak). - So called Sierpinski harmonies are often used melodic expressions of the form
i*N & i >> M
. - Bitwise and (
&
) can add distortion (create steps in the wave). - A macro structure of the song (silent/louds parts, verse/chorus, ...) can be achieved by combining multiple patterns with some low-frequency pattern, e.g. this alternates a slower and faster beat:
int cond = (i & 0x8000) == 0;
,cond * (i / 16) + !cond * (i / 32)
- Extra variables can add more complexity (e.g. precompute some variable
a
which will subsequently be used multiple times in the final formula).
Copyright
It is not exactly clear whether, how and to what extent copyright can apply to bytebeat: on one hand we have a short formula that's uncopyrightable (just like mathematical formulas), on the other hand we have music, an artistic expression. Many authors of bytebeat "release" their creations under free licenses such as CC-BY-SA, but such licenses are of course not applicable if copyright can't even arise.
We believe copyright doesn't and SHOULDN'T apply to bytebeat. To ensure this, it is good to stick CC0 to any released bytebeat just in case.
Examples
A super-simple example can be just a simple:
i / 16
The following more complex examples come from the LRS game Anarch (these are legally safe even in case copyright can apply to bytebeat as Anarch is released under CC0):
- distortion guitar rhythmical beat:
~((((i >> ((i >> 2) % 32)) | (i >> ((i >> 5) % 32))) & 0x12) << 1) | (i >> 11)
- electronic/techno:
((0x47 >> ((i >> 9) % 32)) & (i >> (i % 32))) | (0x57 >> ((i >> 7) % 32)) | (0x06 >> ((i >> ((((i * 11) >> 14) & 0x0e) % 32)) % 32))
- main theme, uses an extra variable:
(((i) & 65536) ? (a & (((i * 2) >> 16) & 0x09)) : ~a)
, whereuint32_t a = ((i >> 7) | (i >> 9) | (~i << 1) | i)