I am not an expert in probability theory, artificial intelligence and machine learning, moreover, the lessons of elementary music school have long been forgotten. But if you give me 10 minutes, you will find that even a small stock of knowledge can give impressive results in their creative application. I want to share with you how to teach PHP to write music.
For example, such:

')
You can see the melody generated by PHP. Yes, of course, this melody is not the most memorable, but it is not ugly. And surprisingly, the code that generates this sequence of notes is rather short.
So what happens? In short, musical data are analyzed by the script in order to “learn” to understand which intervals make up pleasant melodies. Then the script creates a new composition, choosing heights, based on their knowledge. Technically speaking, the script computes a probability map of melodic intervals and applies the
Markov process to generate a new sequence.
Standing on the shoulders of giants
Writing music comes from nothing. Bach was impressed by Buxtehude and Vivaldi. Chopin was influenced by Liszt and Wagner. Mozart and Haydn taught Beethoven. The same melody phrase can be found in different parts of the work.
Orpheus and Eurydice Gluck and the motif of the hymn
Non Dignus contain common musical phrases.

If you ask PHP to write blindly, the results will not be very. As proof, I will cite a melody composed by comparing random values ​​of successful
rand()
function calls with notes.

If you do not own the technique of
dodecaphony , then for inspiration and understanding it is better to start from classical compositions.
To do this, I first rewrote the melody of several parts of musical works with the help of the
scientific system for designating the pitch . I did not bother with the duration of the notes. Instead, I focused on the very height of the sound. “Before” the first octave from the familiar notes was entered as C4 (where C is the name of the note, 4 is an octave), a note half a tone higher than 'C # 4', another half a tone higher than D4, and so on, the result is a melody (here The first 8 ticks of
Tantum Ergo are shown) were recorded as:

A4 C5 G4 A4 G4 A#4 D5 A4 B4 A4 C5 D5 C5 G4 B4 B4 C5
Now I have a sequence of notes that was easily parsed and which I could also easily use for analysis. For example, which note most likely follows A4?
A4 C5
G4
A4 G4
A#4 D5
A4 B4
A4 C5
D5 C5 G4 B4 B4 C5
which ultimately gives:
C5 G4 B4 C5
We see that in 50% of cases the C5 note follows, in 25% of cases it is C4, and in 25% of cases it is B4.
This process makes of warm and lively music something comprehensible only to a computer with its cold and insensible mathematical essence.
Calling on Dr. Markov
We are familiar with deterministic systems - systems where the same input data always returns the same result. Addition is a deterministic function in which 2 and 4 at the input will always give 6. Stochastic systems, on the contrary, behave with a certain level of randomness. The same input data can produce completely different results, for example, with the
array_rand()
function. In composing music there is an element of chance. If this were not so, any composer, having met the F4 note, would continue it in the same way, creating another hit for the insatiable dynasty of pop singers. But the accident still makes its own adjustments, despite the fact that at the subconscious level the composer understands which combinations are pleasant to the ear.
A striking example of a stochastic system that also relates to a script that composes music is the Markov process (named after the mathematician
Andrei Markov, who not only studied it, but also developed a remarkable beard). This is how
Nick Didkovsky explains :
Markov's analysis examines the sequence of events and analyzes the trends of a single event following it. With this analysis, you can create a new sequence of random and related events that look similar to the original. The Markov process is useful in analyzing related random events, i.e. events that are interrelated with past events.
The traditional example used to illustrate the concept is a graph of weather forecasting. Suppose the next day after a sun has a 90% chance of being sunny as well, and one that follows a rainy one has a 50% chance of being rainy. The graph will look like this:

Depending on the mechanism used to find the probability, walking along the graph of 5 iterations, we might find that the first day is sunny, the next is rainy, after it is sunny again, then sunny and sunny again, or go to sunny, sunny, sunny , rainy, rainy when re-passing.
I hope, now it’s clear what I'm getting at - we have the opportunity to limit the random process of “choosing the next note,” using the weighted probabilities determined by the analysis of the melodies, for better sound.

This simple process allows us to create tolerable melodies, spending much less time than it would take a monkey, accidentally knocking on the keys of the organ to play the complete works of Messiaen.
Robots composers (singularity is near)
Well, I hope, in general, you understand the key principles that I used to create music. Even if not, you at least suffered my humor and deserved to see a bit of code.
<?php namespace Zaemis; class Composer { private $pitchProb; public function __construct() { $this->pitchProb = []; } public function train($noteData) { $numNotes = count($noteData); for ($i = 0; $i < $numNotes - 1; $i++) { $current = $noteData[$i]; $next = $noteData[$i + 1]; $this->pitchProb[$current][] = $next; } } public function compose($note, $numNotes) { $melody = [$note]; while (--$numNotes) { $i = array_rand($this->pitchProb[$note], 1); $note = $this->pitchProb[$note][$i]; $melody[] = $note; } return $melody; } }
<?php require_once '../include/Zaemis/Composer.php'; use Zaemis\Composer; $noteData = trim(file_get_contents('../data.txt')); $noteData = explode(' ', $noteData); $c = new Composer(); $c->train($noteData); $melody = $c->compose($_GET['note'], $_GET['count']); echo '<img src="img/notes/clef.png" alt="Treble Clef">'; foreach ($melody as $note) { echo '<img src="img/notes/' . urlencode($note) . '.png" alt="' . $note . '">'; }
The learning process is described in the
train()
method, which accepts an array of notes for learning (coded tune separated by spaces). The code is simple, fast and looks clumsy; Notes are stored in a two-dimensional array with probability indirectly implied by the number of elements.
In the filled state, the array will look something like this:
array(9) { ["A4"]=> array(13) { [0]=> string(2) "C5" [1]=> string(2) "G4" [2]=> string(3) "A#4" [3]=> string(2) "C5" [4]=> string(2) "B4" [5]=> string(3) "A#4" [6]=> string(2) "G4" [7]=> string(2) "A4" [8]=> string(2) "D5" [9]=> string(2) "G4" [10]=> string(2) "C5" [11]=> string(2) "C5" [12]=> string(2) "G4" } ["C5"]=> array(11) { ...
Looking at the data, we see that a randomly selected note, the next after A4, has about a 31% chance of becoming C5 because 4 of the 13 list items contain this value. (Yes, I know, it is better to operate with probabilities than to keep in memory a list of all possible notes in a composition, but I did it intentionally to better illustrate the idea.)
The
compose()
method encapsulates the logic for generating a melodic sequence. Receiving at the input the desired duration of a sequence of notes following the initial one, the method randomly selects the value of notes from the array until it receives as many as needed.
Naturally, we are people and we want to see the result in our usual musical notation. Therefore, I created a set of images to help the script. Each image reflects a note in the appropriate place among other notes. file names correspond to the names of the notes. Passing through the melody and rendering IMG-elements suits me perfectly.
Faster, higher, stronger!
It is quite impressive how simple the ideas used were when writing a script capable of behaving, almost like a real composer. Of course, there is no limit to perfection, much more can be added and corrected. You can consider this your first experience in mastering musical intelligence. David Cope, who has studied computer music since 1981,
said :
Simply splitting up a piece of music into smaller pieces and randomly combining them in a new order will almost certainly produce nonsense. Effective rebuilding requires extensive musical analysis and very careful rebuilding in order to remain effective even at the most basic level.
In addition to the obvious changes, such as changes in the height of the matrix to maintain probabilities, what improvements would you make? Maybe replace this naive approach with a completely different mechanism for analyzing music? Analyze input data from MIDI files? What is needed to identify harmony? What about chords? Duration of notes? The "handwriting" of composers? Can your script be trained based on the analysis of your own good melodies and use them to supplement your knowledge base? How could you redistribute samples to create new works?
I would be interested to read your comments on the results of experiments in the field of artificial intelligence of the controlled composition of music.
From the translator : I really wanted to listen to the melodies that are obtained as a result.
savostin offered to output to MIDI using
the PHP library , I liked the idea. And the melodies themselves, as it seemed to me, are the easiest to take from the Internet in
RTTTL format. In a hurry I sketched an example from the article, but sharpened for working with RTTTL and connected the output to MIDI. Now everyone will be able to evaluate the work done by the author of the article.
Demo