Sterling Berg ROMCOM (Informal Version)


Introduction

I hate to disappoint, no I did not make a romantic comedy. ROMCOM stands for Random Original Motivic Composition of Music. ROMCOM is a ~450 line program/ robot that automatically writes and performs music. It can write a lot of songs; 6.36x10^21 to be approximate.

With 12 possible notes, and 4 possible durations, arranged in motifs ranging from 4–12 notes long there are 3.18x10¹⁸ different possible motifs that can be generated by ROMCOM. Those motifs can be played at any of 2000 different tempos, making the number of possible pieces ROMCOM can generate 6,360,000,000,000,000,000,000, is 58 billion times more than the number of people that have ever been born. If one were to listen to each of the approximately, 30 second songs that ROMCOM could generate it would take you 1.9x10²³ years, or about 437 thousand times the estimated age of the universe. That is a lot of music. However, it is still less than the estimated amount of possible melodies that could be written and played by a human, 1.57x10⁵³.

The quality of music generated by ROMCOM varies greatly from piece to piece despite being limited to only 4 scales. Many of the pieces generated by ROMCOM kinda suck — not gonna lie. Nevertheless, more often than one would anticipate, it actuall plays something that’ll make you say “Hey, that pretty good!” The music is seldom happy, sad, exciting, or somber. It is often somewhere in between. This makes sense because the music ROMCOM composes is not targeted, deliberate, or driven like that of a human composer. A human composer will typically know what type of music he or she wants to compose, aim for it, and occasionally miss or fail. ROMCOM does not know anything. It simply composes music at random and occasionally bullseyes the target you would expect a human to aim for.

Background

(Boring stuff)

The majority music is written by humans (duh). Music can be composed in many ways, not always requiring the active participation of a person; music can be created algorithmically. Wolfgang Amadeus Mozart did this with his Musikalisches Würfelspiel, or musical dice game. While playing this game, people could use dice to randomly select pre-composed options and create music. Artificial intelligence like David Cope’s Program EMI (Experiments in Musical Intelligence) can gather data from reading music and compose its own new music.

Random Original Motivic Composition of Music, or ROMCOM, is similar to both examples. It is similar to Moztart’s Musikalisches Würfelspiel, because it relies on randomness to select a key, tempo, and scale. It will then use these constraints, and computations like Cope’s EMI, to generate a motif. Once a random motif is generated, the rest of the piece will be generated using this motif. Immediately after the song is generated it is played on a 5-volt magnetic buzzer.

Design

(Really boring stuff (unless your a computer or music nerd. In which case, you may find this interesting (after all, you’ve read it this far and I expected literally only 7 people to read this))

Every time the ROMCOM’s code is ran, a new and unique song is generated. The quality, style, and musical grandeur can of the generated songs varies greatly. The basic algorithm that ROMCOM follows is,

· Select tempo, key, and scale using random function
· Generate melodic and rhythmic motif based on scale
· Generate song by using the motif, modifying the motif, or improvising on scale.
· Convert the musical array values to scale frequencies
· Output the Frequencies as a square wave to the buzzer

The design of ROMCOM can be broken into 4 sections;

Part 1. Early experimentation
Part 2. Motif generation.
Part 3. Section generation.
Part 4. Performing.

Part 1. Early Experimentation.

ROMCOM was originally could not generate motifs and was restricted to one scale and tempo. Early version would simply select a note from a scale and play it for a random duration. The algorithm was very simple. It first selected a random number, then it used an if-else statement to select a frequency to output based on that number, Fig. 2a. The current version uses a select-case statement., Fig 2b.

Figure 2a. If-Else statement from early version. This code selected notes from a C major blues scale.

Figure 2b. Select-case statement used in ROMCOM. This code is specifically for the major scale.

Part 2. Motif generation.

For the sounds ROMCOM was making to sound more musical, repetition was needed. ROMCOM generates random motifs in like the previously mentioned early versions, Fig 2. However, ROMCOM is not limited to one scale and key. It can choose from 4 scales, 11 keys, and 2000 tempos.

Theses parameters are also chosen using the random function. The scales ROMCOM can choose from include major, minor, major pentatonic, and major blues. Once the scale and key are chosen a random motif of length 4- 12 notes long, is generated, Fig. 3. Immediately after that a rhythmic motif, consisting of whole notes, half notes, quarter notes, and eighth notes, is generated in a similar fashion, Fig. 4.

Figure 3. Code for generating the melodic motif array.

Figure 4. Code for generating rhythmic motif array.

Once these motifs are generated they are printed to the to the serial monitor so that what is about to be played can be seen, Fig. 5.

Figure 5. Example melodic and rhythmic motifs printed on the serial monitor.

The values in the arrays are later converted to frequencies on the Equally Tempered Scale using Equation 1.

Where f is the ffrequencyof the note, R is the frequency of the third octave to the base note of the key, and m is the value in the motif array. Table 1 shows the application of Equation 1 for the key of A natural. These frequencies are later sent to a 5V magnetic buzzer as a square wave signal. Using these two arrays, music is generated, Fig. 6.

Table 1. Application of Equation 1 for the key of A natural.

Figure 6. Motifs arrays from Fig. 5 assuming the key of A natural and a tempo of 120 bpm.

Part 3. Section generation.

The program then uses the motif to generate the rest of the piece. The length of each piece is about 30 seconds, for demonstration purposes. To achieve an average length of about 30 seconds Equation 2 was used.

Where Ls is the length (number of notes) of the piece, Lm is the length of the motif, and t is the duration of a whole note at a given tempo and the constant, 333750, was determined using the average note durations and motif lengths.

ROMCOM generates music in chunks that are the length of the motif. For example, if the motif of a song was 8 notes long, ROMCOM has a 33% chance to change its method of composition every 8 notes. There are three methods of composition that ROMCOM uses; these methods are listed and describe in Table 2.

Table 2. Methods of Composition.

For each of the three methods of composition, there is a 33% chance of being used to generate a motif length. There is also a 33% chance that the rhythmic motif will be used to generate a motif length.

As the piece is being generated, each note value along with the method of composition identifier is printed to the serial monitor. For example, a piece generated with a unique motif, Fig. 7, generated a section of music based on that motif, Fig 8, used all three methods of composition; “Please Calm Down,” “Stick to the Motif,” and then “Lil’ Adventurous.”

Figure 7a. Randomly generated motif serial monitor data.

Figure 7b. Motif Generated assuming Key to be A natural

Figure 8a. Music generated by ROMCOM using motif in Fig. 7.

Figure 8b. Music generated assuming key to be A natural, 120 bpm, and 100% rhythmic motif use. A quarter rest was also added after each motif length to simplify notation.

Part 4. Performing.

Immediately after the scale is determined it is indicated by the amber leds in ROMCOM’s right “eye;” the left “eye” contains the 5V magnetic buzzer and green indicator light, Fig. 9.

Figure 9. ROMCOM’s outputs.

After the section array is generated, the play function is executed, Fig. 10. This function converts the section array values into frequencies on the equally tempered scale using Equation 1. It also determines whether to use the rhythmic motif and prints what is being played to the serial monitor, Fig. 11.

Figure 10. The play function.

Figure 11. Example of data printed to serial monitor during the play function.

Conclusion

Wow. Did you actually read this or just scroll over the really boring stuff? Anyway… Pretty cool right? out of those 6360000000000000000000000 musical motifs one of them is smoke on water, Beethoven's V symphony, and a section of THE MOST AMAZING PIECE OF MUSIC EVER!

References (No I did not just make all those fact up)

anything not listed here that I talked about and you’re interested in,just google. I’m too lazy to hyperlink it all

Codebendercc. “Pitches.h.” Pitches.h. Git Hub, July 2013. Web. 02 May 2017. <https://github.com/codebendercc/arduino-library files/blob/master/examples/02.Digital/toneMelody/pitches.h>.

Cope, David. “Experiments in Musical Intelligence.” Main. UCSC, n.d. Web. 02 May 2017. <http://artsites.ucsc.edu/faculty/cope/experiments.htm>.

Enevoldsen, Keith. “Twelve-Tone Musical Scale.” Twelve-Tone Musical Scale. Thinkzone.wlonk.com, 2016. Web. 02 May 2017. <http://thinkzone.wlonk.com/Music/12Tone.htm>.

Ferrouslepidoptera. “How Many Melodies Are There in the Universe?” How Many Melodies Are There in the Universe? — Everything2.com. Everything2, 19 Aug. 2000. Web. 02 May 2017<https://everything2.com/title/How+many+melodies+are+there+in+the+universe% 53F>.

Haub, Carl. “How Many People Have Ever Lived on Earth?” How Many People Have Ever Lived on Earth? Population Reference Bureau, Oct. 2011. Web. 02 May 2017. <http://www.prb.org/Publications/Articles/2002/HowManyPeopleHaveEverLivedonEar th.aspx>.

Hiller, Lejaren, Isaacson, and Leonard. “Media Art Net | Hiller, Lejaren; Isaacson, Leonard: Illiac Suite: Quartet №4 for Strings.” Medien Kunst Netz. Media Art Net, n.d. Web. 02 May 2017. <http://www.medienkunstnetz.de/works/illiac-suite/>.

Rahul, Kumar. “Artificial Intelligence May Be The Future Of Music Creation.” TheClassicalArts. The Classical Arts, 25 Jan. 2017. Web. 02 May 2017. <http://www.theclassicalarts.com/articles/41438/20170125/artificial-intelligence-future music-creation.htm>.

“Random().” Arduino — Random. Adruino, 2017. Web. 02 May 2017. <https://www.arduino.cc/en/reference/random>.

Redd, Nola Taylor. “How Old Is the Universe?” Space.com. SPACE.com, 20 Dec. 2013. Web. 02 May 2017. <http://www.space.com/24054-how-old-is-the-universe.html>.

“Tone().” Arduino — Tone. Arduino, 2017. Web. 02 May 2017. <https://www.arduino.cc/en/reference/tone>.

Some Useful Things I Used

Code

Please feel free to use and modify my code. Open source FTW! Just don’t claim it as 100% you’re own code, copyright it, and make millions. If you do use it to make money, you need to give that to your robotic performer. Robots deserve rights too. Th3y 4ctu4lly r34lly d0nt. 1'm ju5t 54y1ng th4t 50 th4t skyn3t d035n’t r34d th1s 4nd g3t 4ngry 4T m3…

Also, I’m a pretty bad programmer and Medium isn’t very good at keeping formatting. If you’re really interested I’d recommend copying it into Notepad ++ or something. If not, Vomit bags are provided in the pocket in the seat in front of you.

/*Sterling Berg

This program makes music by selecting notes from a random scale.

The key, scale, and tempo are randomly selected.

Last modified: 5/5/2017 8:12 pm

Resources

“Modified Library”

https://github.com/codebendercc/arduino-library- files/blob/master/examples/02.Digital/toneMelody/pitches.h

Frequencies

http://www.szynalski.com/tone-generator/

Wikipedia Tables

https://en.wikipedia.org/wiki/Music_and_mathematics

Other types of Algorithmically Generated Music:

http://www.medienkunstnetz.de/works/illiac-suite/

http://www.theclassicalarts.com/articles/41438/20170125/artificial-intelligence-future-music-creation.htm

*/

//defining note frequencies

#define C3 131

#define CS3 139

#define D3 147

#define DS3 156

#define E3 165

#define F3 175

#define FS3 185

#define G3 196

#define GS3 208

#define A3 220

#define AS3 233

#define B3 247

#define C4 262

#define CS4 277

#define D4 294

#define DS4 311

#define E4 330

#define F4 349

#define FS4 370

#define G4 392

#define GS4 415

#define A4 440

#define AS4 466

#define B4 494

#define C5 523

#define CS5 554

#define D5 587

#define DS5 622

#define E5 659

#define F5 698

#define FS5 740

#define G5 784

#define GS5 831

#define A5 880

#define AS5 932

#define B5 988

#define C6 1047

//defining keys

#define C 0

#define CS 1

#define D 2

#define DS 3

#define E 4

#define ES 5

#define F 6

#define FS 7

#define G 8

#define GS 9

#define A 10

#define AS 11

#define B 12

int speakerOut1 = 12;

int playPin = 2;

int majorPin = 7; //yellow

int minorPin = 6; //red

int pentPin = 5; //green

int bluesPin = 4; //blue

//========================================

// MAIN

//========================================

void setup() {

Serial.begin(9600);

randomSeed (analogRead(0));

//setting pinmodes

pinMode(speakerOut1, OUTPUT);

pinMode(majorPin, OUTPUT);

pinMode(minorPin, OUTPUT);

pinMode(pentPin, OUTPUT);

pinMode(bluesPin, OUTPUT);

pinMode(playPin, OUTPUT);

//declaring musical elements

int key = random (12); //0–12

int scale = random(4); // 0–3

float tempo = random (500, 2500); // whole note length

displayElements(key, scale, tempo); // output to “right eye”

//mucical arrays

float*motif;

motif = (float*)calloc(20,sizeof(float));

float*rhythmicMotif;

rhythmicMotif = (float*)calloc(20,sizeof(float));

float*section0;

section0 = (float*)calloc(100,sizeof(float));

float*section0Rhythm;

section0Rhythm = (float*)calloc(100,sizeof(float));

// creating part and section lengths

int motifLength = random(4,12);

int section0Length = 333750 / (motifLength * tempo); //yeilds total song length of about 30 seconds

Serial.println( “section length “);

Serial.println( section0Length);

Serial.println( “section length “);

// generating the musical arrays

motif = genMotif(motifLength, scale);

rhythmicMotif = genRhythmicMotif(motifLength);

//displaying motif data

Serial.println( “Motif Rhythym is “);

for (int i=0; i< motifLength; i++){

Serial.print (“ “); Serial.println(rhythmicMotif[i]);

}

Serial.println( “Motif is “);

for (int i=0; i< motifLength; i++){

Serial.print (“ Note”); Serial.println(motif[i]);

}

//generating section and playing

section0 = genSection(section0Length, scale, motifLength, motif);

play(key, rhythmicMotif, motifLength, tempo, section0, section0Length);

if (motif==NULL ||rhythmicMotif==NULL || section0==NULL || section0Rhythm==NULL){

Serial.println(“ — — — — — — MEMORY ERROR — — — — — — “);

}

free(motif); free(rhythmicMotif); free(section0); free(section0Rhythm);

}

//========================================

// DISPLAY ELEMENTS

//========================================

void displayElements(int key, int scale, int tempo){

switch (scale) {

case 0 : digitalWrite(majorPin, HIGH); break; //leds in right eye

case 1 : digitalWrite(minorPin, HIGH); break;

case 2 : digitalWrite(pentPin, HIGH); break;

case 3 : digitalWrite(bluesPin, HIGH); break;

default: Serial.print(“~~~ WAT? ~~~”); break;

}

}

//=======================================

// GEN MOTIF

//========================================

float * genMotif(int motifLength, int scale){

randomSeed (analogRead(0));

float*randomMotif;

randomMotif = (float*)malloc(10*sizeof(float));

for(int i=0; i< motifLength; i++){

randomMotif[i] = (genRandScaleNote(scale));

}

return randomMotif;

free(randomMotif);

}

//=========================================

// GEN RHYTMIC MOTIF

//=========================================

float * genRhythmicMotif(int motifLength){

randomSeed (analogRead(0));

float*randomMotif;

randomMotif = (float*)malloc(10*sizeof(float));

for(int i=0; i< motifLength; i++){

randomMotif[i] = pow(2, random(4)); //1,2,4,8

}

return randomMotif;

free(randomMotif);

}

//===========================================================

// GEN SECTION

//===========================================================

float* genSection( int sectionLength, int scale,

float motifLength, float motif[] ){

Serial.println(“======= Section Notes========”);

float randomSection[100];

int i = 0;

while (i < sectionLength){ //loop until end of section length

int flexibility = random(3); // 0, 1, 2.

// Stick to motif, lil’ adventurous, Please Calm Down

switch (flexibility){

case 0: { // Stick to Motif…

for (int j=0; j<motifLength; j++){ //loop til end of motif length

randomSection[i] = motif[j];

Serial.print(randomSection[i]);

Serial.print(“ ~:|~ “);

i++;

}

} break;

case 1:{ // also motif// Lil’ adventurous…

for (int j=0; j<motifLength; j++){

randomSection[i] = genRandScaleNote(scale);

Serial.print(randomSection[i]);

Serial.print(“ ~XD~ “);

i++;

}

} break;

case 2: { // Sir, please calm down…

for (int j=0; j<motifLength; j++){

float harmony = random(3); // generates number 4–8

randomSection[i] = harmony * motif[j];

Serial.print(randomSection[i]);

Serial.print(“ ~8)~ “);

i++;

}

} break;

}

}

Serial.println(“ “);

return randomSection;

}

//========================================

// GEN SCALE NOTE

//========================================

float genRandScaleNote ( int scale) {

float randomNote;

int randomNum = random(8);

switch (scale) {

case 0 : { //major

switch (randomNum) {

case 0: randomNote = 0; break;

case 1: randomNote = 2; break;

case 2: randomNote = 4; break;

case 3: randomNote = 5; break;

case 4: randomNote = 7; break;

case 5: randomNote = 9; break;

case 6: randomNote = 11; break;

case 7: randomNote = 12; break;

default: Serial.print(“~~~ WAT? ~~~”); break;

}

} break;

case 1 : { //minor

switch (randomNum){

case 0: randomNote = 0; break;

case 1: randomNote = 2; break;

case 2: randomNote = 3; break;

case 3: randomNote = 5; break;

case 4: randomNote = 7; break;

case 5: randomNote = 8; break;

case 6: randomNote = 10; break;

case 7: randomNote = 12; break;

default: Serial.print(“~~~ WAT? ~~~”); break;

} break; }

case 2: { //maj pentatonic with 7

switch (randomNum){

case 0: randomNote = 0; break;

case 1: randomNote = 2; break;

case 2: randomNote = 4; break;

case 3: randomNote = 7; break;

case 4: randomNote = 9; break;

case 5: randomNote = 12; break;

case 6: randomNote = 0; break;

case 7: randomNote = 10; break;

default: Serial.print(“~~~ WAT? ~~~”); break;

} break; }

case 3: { // blues

switch (randomNum){

case 0: randomNote = 0; break;

case 1: randomNote = 3; break;

case 2: randomNote = 5; break;

case 3: randomNote = 6; break;

case 4: randomNote = 7; break;

case 5: randomNote = 10; break;

case 6: randomNote = 12; break;

case 7: randomNote = 0; break;

default: Serial.print(“~~~ WAT? ~~~”); break;

} break ;

}

}

return randomNote;

}

//========================================

// PLAY

//========================================

void play (int key, float*rhythmicMotif, int motifLength, float tempo, float*partNote, int partLength){

Serial.println(“ ===== Play ===== “);

int j=0;

int useRhythmicMotif = 3;

float octave = 1; //sets the overall pitch

double freqOut = 0;

float noteDuration = 0;

float*partRhythm;

//getting “fundamental” frequency or first note of scale

switch (key){

case 0: key = C3; break;

case 1: key = CS3; break;

case 2: key = D3; break;

case 3: key = DS3; break;

case 4: key = E3; break;

case 5: key = F3; break;

case 6: key = FS3; break;

case 7: key = G3; break;

case 8: key = GS3; break;

case 9: key = A3; break;

case 10: key = AS3; break;

case 11: key = B3; break;

case 12: key = C3; break;

default: Serial.print(“~~~ WAT? ~~~”); break;

}

for(int i=0; i< partLength; i++){

if (j== motifLength){ //repeating use the rhtythic motif

j=0;

j++;

}

freqOut = (octave * key * (pow(2, (partNote[i] / 12.0)))); //calculating frequency

useRhythmicMotif = random(4); //0–3 //gives it a 25% chance of improvising

if (useRhythmicMotif > 0){ //deciding and calculating note duration

noteDuration = tempo / rhythmicMotif[j];

}

else{

noteDuration = tempo / pow(2, random(6));

}

tone(speakerOut1, freqOut); digitalWrite(playPin, HIGH); //playing the soud

delay(noteDuration); noTone(speakerOut1); digitalWrite(playPin, LOW); //duration of sound

delay(15); // 1/2 duration of “breath”

//Displaying what is being played; notes (hz,array value), duration (ms)

Serial.print(“play: “); Serial.print(freqOut); Serial.print(“ “); Serial.println(partNote[i]);

Serial.print(“duration: “); Serial.print(noteDuration); Serial.print(“ “); Serial.println(rhythmicMotif[j]);

delay(15);

j++;

}

}

void loop() {//not used, only plays one song

}

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.