This is a fun little program to generate ‘computer music’, specifically ‘bytebeats’ which sound like the chip music featured in the early computer games. As is well-known, sound can be digitised and stored in computers. Conversely, numbers can be converted to sound. But those numbers don’t have to come from a file, they can be generated on the fly, for example by the following program:
[python] #!/usr/bin/python3# bytebeats0.py
t = 0
while True:
print(chr(int(
t
) % 256 ), end=”)
t += 1
[/python]
Pipe this into aplay like so: bytebeats0.py | aplay or into sox: bytebeats0.py | sox -r 8000 -b 8 -c 1 -t raw -e unsigned-integer – -d
(I’m not a sox expert, there’s probably a better way…).
Although the value of t in the loop will grow quite large, we feed t % 256 into the chr() function to keep it in range (of 8-bits). Some people have been experimenting with variations on the simple t formula, by performing bit operations on t – shifting, masking, etc. So for example, instead of t, try other formulae such as
- (t*((15&t>>11)%12)&55-(t>>5|t>>12)|t*(t>>10)*32)-1
- t*3&(t>>10)|t*12&(t>>10)|t*10&((t>>8)*55)&128
- t*4&(t>>10)|t*4&(t*6>>8)&t|64
- t*(t+(t>>9|t>>13))%40&120
This next program uses PyAudio to convert the numbers to an audio stream.
[python] #!/usr/bin/python3import pyaudio
# Initialise PyAudio
PyAudio = pyaudio.PyAudio # error msgs are usually safe to ignore
pa = PyAudio()
audio = pa.open(format=pa.get_format_from_width(1),channels=1,rate=8000,output=True)
t = 0
while True:
audio.write(chr(t%256)) # convert to 8-bit
t += 1
[/python]
You might get some warnings from PyAudio, like:
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side ALSA lib pcm_route.c:947:(find_matching_chmap) Found no matching channel map Cannot connect to server socket err = No such file or directory Cannot connect to server request channel jack server is not running or cannot be started
With any luck, you can safely ignore them.
Finally, let’s add some graphing, and a primitive capability to manage a list of bytebeat functions. It plots a graph of the beginning of the audio sequence. Here are some brief notes about it:
- Import math functions only if you want to try the sine wave
- Instead of plugging the sound function directly into the output statement, I store it in a list of strings, so that I can use them to label the graph
- The stop & start parameters are to make it easier to select functions to play, e.g. a range such as all (start=0, stop = len(funcs)) or the last one
- You need a lot of audio samples for the piece to last long enough; plotting them all would make a very crowded graph
- Sound values are computed in 2 sections 1: graph & audio values, 2: audio values only
- We get values from the function using eval(f)%256, the modulo to keep values in 8-bit range
- Use Pyplot to set up the graph, and plot it. You might need to remove the block parameter…
- Compute the rest of the values
- Write them (as chr()) to the audio stream
- The final input() ensures the final graph doesn’t disappear when the program ends; you might be able to dispense with it.
# ByteBeats.py
import matplotlib.pyplot as pl
import pyaudio
from math import sin, pi
# Initialise PyAudio
PyAudio = pyaudio.PyAudio # error msgs are usually safe to ignore
pa = PyAudio()
audio = pa.open(format=pa.get_format_from_width(1),channels=1,rate=8000,output=True)
funcs = [
‘t*2’,
‘t*5&t>>7|t*3&t>>10|t>>4’,
‘127.5*sin(pi*t/50)+127.5’,
‘t*(t+(t>>9|t>>13))%40&120’,
‘(t&t%255)-(t*3&t>>13&t>>6)’,
‘t*((t>>3|t>>13)&t>>6|t>>8)’,
‘t*4&(t>>10)|t*4&(t*6>>8)&t|64’,
‘(t>>6|t|t>>(16))*10+((t>>11)&7)’,
‘t*(((t>>12)|(t>>8))&(63&(t>>4)))’,
‘t*(4|t*t&4<<t)*(t&(t>>9|t>>13)+1)’,
‘t*3&(t>>10)|t*12&(t>>10)|t*10&((t>>8)*55)&128’,
‘(((t*5&t>>6)^(t>>4|t>>2&t%255|t*3&t>>8)-10)/4)’,
‘(t*((15&t>>11)%12)&55-(t>>5|t>>12)|t*(t>>10)*32)-1’
]
stop = len(funcs) # number of functions
start = stop – 1 # only playing the last one
start = 0 # playing all
pls = 10000 # number of samples to plot
aus = 100000 # number of audio samples
# Note that in this loop, we calculate the samples in 2 parts –
# first those we want to plot, then the rest – so the plot is shown sooner
for i in range(start,stop): # for a range of functions:
f = funcs[i] # select a function
x = [x for x in range(aus)] # compute x range
y = [int(eval(f)%256) for t in x[:pls]] # only what’s needed for plot
pl.figure(figsize=(15,10)) # set the plot size
pl.title(f)
pl.plot(x[:pls],y)
pl.show(block=False)
y[pls:] = [int(eval(f)%256) for t in x[pls:]] # now the rest…
for v in y: # for all y
# replace with print(…,end=”) if no pyaudio
audio.write(chr(v)) # convert to 8-bit
input("Press Enter")[/python]
Installation Notes
You’ll need to install matplotlib, pyaudio, and aplay (or sox). If you’re on Linux it should be fairly easy, just be sure to get the python3- versions. Synaptic is good for installing when you don’t know the exact name, e.g. for matplotlib you should see ‘python3-matplotlib’, for pyaudio it’s python3-pyaudio, and aplay is in the alsa-utils. Or you can use apt-get:
sudo apt-get install python3-matplotlib python3-pyaudio alsa-utils
Mac or Windows I don’t know. Synaptic is a GUI front-end to apt-get, so not I think available on OS-X. I tend to use synaptic first, if possible, or apt-get (command line) or pip (the PyPA recommended tool for installing Python packages) if the instructions say so. I don’t know if there’s a compelling reason to prefer any one of them.
You might want to check out these matplotlib installation notes.
PyAudio is available for Mac. Aplay is Linux only; here’s a thread about aplay equivalents on Mac which happens also to be about bytebeat music one-liners!
If you’re only interested in hearing the music and don’t care about the graphs you can of course cut out the pyplot bits. And you really only need one of aplay or equivalent/pyaudio for that.
If you’re into fractals check out my FractalArt.Gallery. There’s a musical Mandelbrot that works with pyaudio.
More information about bytebeats:
Discover bytebeat. A new genre of algorithmic music has been developed by demoscene coder viznut, a.k.a. PwP. Sharing genes with chiptunes and facilitated by bitwise operators, bytebeats are decidedly non-traditional music created by short, programmatic formulas. Read an explanation of how the formulas work. A few more pieces. (from Today’s formulaic music)
- Bytebeat — Kragen – nopaste
- Bytebeats in C and Python (generative symphonies from extremely small programs)
- Algorithmic symphonies from one line of code — how and why?
- Music from very short programs – the 3rd iteration (YouTube)
- Some deep analysis of one-line music programs
- Experimental music from very short C programs (YouTube)
- /r/bytebeat
- wurstcaptures gen tool
1 comment for “Make ‘Computer Music’ with a very small program!”