autoplay
is a simple c++ implementation of a combination of some music composition
algorithms. The target of this project is to create music software that can
automatically generate good melodies in a lovely rhythm with a gentle dynamic.
Random Music Generation technically consists of three parts (with some exceptions when talking about chords, staccatos...), which I've called Random Pitch Generation (RPG), Random Rythm Generation (RRG) and Random Dynamics Generation (RDG).
I've decided to take a look at all three of these types of algorithms separately to get the best result.
The general idea behind RPG is basically an extension on the normal RNGs. After doing
some research, I've come up with the following algorithms for this generation.
For simplicity's sake, we'll suppose there are the following functions (based upon the
corresponding functions in GML
), assuming [...]
is a sequence of numbers (array,
sequential pointers, vector...) and {...}
depicts a map or a dictionary of some sorts
(which maps a key uniquely to a value):
Function Name | Description |
---|---|
choose([...]) |
Pick a random value uniformly from the given list. |
choose({...}) |
Pick a random element from the given map, where an element is a key in the map and the corresponding value the chance (between 0 and 1) that this value is chosen. (e.g. weighted random selection) |
choose([...], dist, a, b, c=false) |
Pick a random value from the given list where the chance that a certain value is picked depends on the dist distribution function. a is the lowest possible value to be mapped and b the highest. The probability of the value at index x is a + (x - min)*(b - a)/(max - min) , with min and max the minimum (index) and maximum (index) of the list. When c is true , we want to center the 0 in our list to the center of our distribution. |
gaussian([...], a=-3, b=3, c=false) |
Shorthand for choose([...], f_g, a, b, c) , where f_g stands for the Gaussian distribution function. |
range(a, b) |
Create a sequential range between a and b . |
This algorithm that is used in the main bulk of the functions described above has the following pseudocode, according to this website.
randomWeight = choose(range(1, sumOfWeights))
for each item in array do
randomWeight = randomWeight - item.weight
if randomWeight <= 0 then
pick this item
fi
done
The algorithms I've come up with (with pn
the new pitch and po
the
old/previous one) are:
This is maybe one of the easiest algorithms that we could use (with the exception of a semitone musical piece). Basically it generates a random note somewhere in the musical spectrum.
pn = choose(range(0, 127))
Most music pieces don't make a lot of jumps. This algorithm, based upon the movement of small particles that are randomly bombarded by molecules of the surrounding medium, basically forces the jumps to be somewhere between three pitches above or below the currently played note. More info here.
pn = choose(range(-3, 3)) + po
As discussed here, 1/f Noise is a very special class of noise and recurs often in nature. Besides the strangely easy algorithm created by Richard F. Voss, there are a few issues: a good selection of the sides of the dice, the mappings and the table to use.
We can say (for instance) that we will use 5-sided "dice", as discussed on the site, but will we only stay in the same octave, only move up, or shift the result over, so we get a similar range to the Brownian Motion?
Maybe we can add some user-definable options?
Invented as a stepping-stone to the Gaussian Voicing implementation, this algorithm came to be. It basically says that the chance for each note chosen is the highest in the middle of our pitch range, playing the piece mostly around the central octave.
It uses the Gauss-curve of a standard normal distribution.
pn = gaussian(range(0, 127))
Voicing generally is a technique most experienced composers and pianists use when writing a piece. It is the idea that the next note that will be played will most likely be close to the one you just played. This is commonly used in the two inversions of a simple chord.
Gaussian Voicing uses the Gauss-curve of a standard normal distribution to focus its center around the justly played note.
pn = gaussian(range(-po, 127-po), -3, 3, true) + po
(Note that in the algorithm two shifts of the pitch are required. The first to centralize
it around po
, the second to bring it back to the valid range.)
pn
will be the following pitch according to a machine-learned markov chain.
This project makes use of the RtMidi library,
current version 3.0.0
.
This library allows for real-time playback of the music. Maybe this dependency will be
removed later on.
To install this dependency, you have to install and update the submodules of this repo. The necessary files will be linked automatically during compilation.
Boost is definitely a powerful library that can handle a lot of different things. In the
scope of this project, Boost
is used for easy JSON
and XML
parsing and generation.
You must have Boost
installed on your system for this to work.
Due to the random nature of the results of autoplay
, trng
was added. This library will
handle all random actions that happen during the music generation.
After painstakingly trying to install trng
similarly to how RtMidi
was installed,
the decision was made to keep it as a submodule, but describe how to install the library
into the opt
folder.
For a detailed description, please read the trng.pdf
in the trng/doc
folder (page 96).
- Install and Update the submodule
- Make sure
autoconf
,automake
andlibtool
are installed. This can be done withsudo apt-get install autotools-dev autoconf libtool-bin
. - Run
autoreconf
on thetrng
folder to make sure everything works as desired. - Configure
trng
in theopt
directory with your preferred compiler (e.g. GNU C++ 7) using the following command:sudo CXX=g++-7 ./configure --prefix=/opt/trng
. - Run
sudo make
andsudo make install
.
TODO: Add scripts for this, so it will work easily on travis and possibly other OS.
Date | Update |
---|---|
07-11-2018 | Added RtMidi library for easy playback. |
13-10-2018 | Started looking at different file formats to export to: - MIDI (might have issues with the non-generality) - MusicXML (standard open format for exchanging digital sheet music) |
13-10-2018 | Added TRNG as a pseudo-random number generator. |
14-10-2018 | Added Boost and started the concept of the RPG . |
14-10-2018 | Did some research on different music generation algorithms |
14-10-2018 | Added Travis CI |
14-10-2018 | Created the Randomizer class to handle all randomization without the need to keep on using the same code over and over again. |