Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
464a51f
MVP code and class definitions for mp4
JosephLee19 Mar 2, 2016
81c6ac5
Finished first pass of base code
bwerth Mar 6, 2016
9680811
Base code is working
bwerth Mar 6, 2016
9346375
Still working on some weird errors after adding inversions
bwerth Mar 7, 2016
2d05a8b
Finished adding inversions!
bwerth Mar 7, 2016
30d0764
Added doctests and a header
bwerth Mar 7, 2016
3314f8f
Music21 Implementation of MVP
JosephLee19 Mar 7, 2016
32b605b
Merge branch 'master' of https://github.com/bwerth/InteractiveProgram…
JosephLee19 Mar 7, 2016
ac48a46
Adapted the code for music21
bwerth Mar 7, 2016
d4f7f29
Added MIDI file output to the Music21 Implementation of the MVP
JosephLee19 Mar 7, 2016
9e5aaaf
Finished the create melody method
bwerth Mar 8, 2016
3bcb11e
Finished
bwerth Mar 8, 2016
6aa83d4
MVP Ready for command line interface
JosephLee19 Mar 8, 2016
857081a
Most recent MP4 code ready for user interface
JosephLee19 Mar 9, 2016
3239799
README file for mp4_music_generation.py
JosephLee19 Mar 10, 2016
93178c8
Interactive Algorithmic Music Generation Code 3-10-2016
JosephLee19 Mar 10, 2016
179c1f6
Softdes MP4 Writeup
JosephLee19 Mar 10, 2016
b9f645d
Preparation and Framing Document for Technical Review 1.
JosephLee19 Mar 30, 2016
9326c0f
Added GUI code
bwerth Apr 14, 2016
a1f0c55
Create GUI.py
bwerth Apr 14, 2016
718ff08
Updated README
JosephLee19 Apr 14, 2016
a1e59e9
Current Script for Markov Chain Probability Map Generation
JosephLee19 Apr 14, 2016
c3aecd1
Merge branch 'master' of https://github.com/bwerth/InteractiveProgram…
JosephLee19 Apr 14, 2016
34f4ea8
script for generating a canon out of bach chorale
JosephLee19 Apr 14, 2016
d91e35e
GUI
bwerth Apr 14, 2016
6ab1ffb
markov chain code, used during development
JosephLee19 Apr 20, 2016
6a5b5dd
Current code for generating a melody using markov chains
JosephLee19 Apr 20, 2016
db5e177
current canon generation code using music21
JosephLee19 Apr 20, 2016
f483454
Preparation and Framing Document for Technical Review 2
JosephLee19 Apr 20, 2016
8c08d9a
Added GUI stuff
bwerth May 3, 2016
ec91b6b
finished
bwerth May 3, 2016
3aaaea8
finished
bwerth May 3, 2016
99121f9
default training set folder
JosephLee19 May 4, 2016
2e27886
Current Code for Markov Music Generation
JosephLee19 May 4, 2016
d1178b5
Merge branch 'master' of https://github.com/bwerth/InteractiveProgram…
JosephLee19 May 4, 2016
7d29054
Modified code to accept GUI output as its input
JosephLee19 May 4, 2016
c0175bf
Minor Changes
bwerth May 4, 2016
895eec5
Finished
bwerth May 4, 2016
42484c2
most recent work on the back end
JosephLee19 May 5, 2016
f7bec63
Merge branch 'master' of https://github.com/bwerth/InteractiveProgram…
JosephLee19 May 5, 2016
2c4c248
Finished
bwerth May 5, 2016
741edf5
Merge branch 'master' of https://github.com/bwerth/InteractiveProgram…
JosephLee19 May 5, 2016
379542e
Current main.py program for algorithmic music composition
JosephLee19 May 5, 2016
e841dc4
Added GUI Folder
bwerth May 5, 2016
c10c90f
edited GUI.py
JosephLee19 May 5, 2016
df00ce3
FINISHED!
bwerth May 5, 2016
57de4ad
Finished
bwerth May 5, 2016
d3f483b
Add files via upload
JosephLee19 May 19, 2016
6bf9dc3
Create Technical Review 2 Reflection
JosephLee19 May 20, 2016
ff1d3d7
Create Technical Review 1 Reflection
JosephLee19 May 21, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
314 changes: 314 additions & 0 deletions GUI /GUI.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import NumericProperty, StringProperty, ObjectProperty
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.base import runTouchApp
from kivy.uix.label import Label
from kivy.clock import Clock
from music21 import *
import os
import random
import copy
from kivy.uix.image import Image

# Declare both screens as separate classes. Currently there is nothing in here, but there will be when we fill out the GUI.
class Logo(Image):
def __init__(self, **kwargs):
super(Logo, self).__init__(**kwargs)
self.size = self.texture_size

class NewClock(Label):
def update(self, *args):
TestApp.screen_manager.current = 'menu'

class CustomDropDown(DropDown):
for i in range(5):
print i

class TitleScreen(Screen):
pass

class MenuScreen(Screen):
translateInput = ObjectProperty(None)
translateButton = ObjectProperty(None)
translateLabel = ObjectProperty(None)
top_layout = ObjectProperty(None)
dd_btn = ObjectProperty(None)
dataset_index = 0

def __init__(self,*args,**kwargs):
super(MenuScreen, self).__init__(*args, **kwargs)
self.drop_down = CustomDropDown()
mainbutton = Button(text='Hello', size_hint=(None, None))
mainbutton.bind(on_release=self.drop_down.open)
self.drop_down.bind(on_select=lambda instance, x: setattr(self.ddID, 'text', x))

def get_datasetindex(self):
if self.ddID == 'btn1':
self.dataset_index = 0
elif self.ddID == 'btn2':
self.dataset_index = 1

def doubles(self,lst):
"""
Generates doubles from a given list - for example [1,2,3,4,5] would become [(1,2),(2,3),(3,4),(4,5)]
"""
res=[]
for lst in lst:
if len(lst) < 2:
pass
for i in range(len(lst) - 1):
res.append((lst[i], lst[i+1]))
return res

def triples(self,lst):
"""
Generates triples from a given list - for example [1,2,3,4,5] would become [(1,2,3),(2,3,4),(3,4,5)]
"""
res=[]
for lst in lst:
if len(lst) < 3:
pass
for i in range(len(lst) - 2):
res.append((lst[i], lst[i+1], lst[i+2]))
return res

def quadrouples(self,lst):
"""
Generates quadrouples from a given list - for example [1,2,3,4,5] would become [(1,2,3,4),(2,3,4,5)]
"""
res=[]
for lst in lst:
if len(lst) < 4:
pass
for i in range(len(lst) - 3):
res.append((lst[i], lst[i+1], lst[i+2], lst[i+3]))
return res


def markov_table_1(self,doubles,database={}):
for double in doubles:
w1, w2 = double
key = w1
if key in database:
database[key].append(w2)
else:
database[key] = [w2]
return database


def markov_table_2(self,triples,database={}):
for triple in triples:
w1, w2, w3 = triple
key = (w1, w2)
if key in database:
database[key].append(w3)
else:
database[key] = [w3]
return database

def markov_table_3(self,quadrouples,database={}):
for quadrouple in quadrouples:
w1, w2, w3, w4 = quadrouple
key = (w1, w2, w3)
if key in database:
database[key].append(w4)
else:
database[key] = [w4]
return database

def generate_string_1(self,note_seed,length,note_database,rhythm_database,rhythm_seed=[2.0]):
"""
Given a note seed in the format [first note], a rhythm seed in the format [quarter length for first note]
the length of the desired output melody, a markov dictionary for the melody, and a markov dictionary for the rhythm, this function returns a tuple of lists
in the format ([notes],[durations])
"""
rhythm_output=[]
note_output=[]
note_output.append(note_seed[0])
rhythm_output.append(rhythm_seed[0])

for i in range(length-1):
i=i+1
key=note_output[i-1]
options=note_database.get(key,["C","D","E","F","G","A","B"])
next_state=random.choice(options)
note_output.append(next_state)
rhythm_key=rhythm_output[i-1]
rhythm_options=rhythm_database.get(rhythm_key)
print rhythm_options
next_rhythm_state=random.choice(rhythm_options,[0.25,0.5,0.5,1.0,1.0,1.0,1.0,2.0,2.0,2.0])
rhythm_output.append(next_rhythm_state)

return (note_output,rhythm_output)

def generate_string_2(self,note_seed,length,note_database,rhythm_database,rhythm_seed=[2.0,2.0]):
"""
Given a note seed in the format [first note, second note], a rhythm seed in the format [quarter length for first note, quarter length for second note]
the length of the desired output melody, a markov dictionary for the melody, and a markov dictionary for the rhythm, this function returns a tuple of lists
in the format ([notes],[durations])
"""
rhythm_output=[]
note_output=[]
note_output.append(note_seed[0])
note_output.append(note_seed[0])
rhythm_output.append(rhythm_seed[0])
rhythm_output.append(rhythm_seed[0])

for i in range(length-2):
i=i+2
key=(note_output[i-2],note_output[i-1])
options=note_database.get(key,["C","D","E","F","G","A","B"])
next_state=random.choice(options)
note_output.append(next_state)
rhythm_key=(rhythm_output[i-2],rhythm_output[i-1])
rhythm_options=rhythm_database.get(rhythm_key,[0.25,0.5,0.5,1.0,1.0,1.0,1.0,2.0,2.0,2.0])
next_rhythm_state=random.choice(rhythm_options)
rhythm_output.append(next_rhythm_state)

return (note_output,rhythm_output)

def generate_string_3(self,note_seed,length,note_database,rhythm_database,rhythm_seed=[2.0,1.0,1.0]):
"""
Given a note seed in the format [first note, second note,third note], a rhythm seed in the format [quarter length for first note, quarter length for second
note, quarter length for third note]
the length of the desired output melody, a markov dictionary for the melody, and a markov dictionary for the rhythm, this function returns a tuple of lists
in the format ([notes],[durations])
"""
rhythm_output=[]
note_output=[]
note_output.append(note_seed[0])
note_output.append(note_seed[0])
note_output.append(note_seed[0])
rhythm_output.append(rhythm_seed[0])
rhythm_output.append(rhythm_seed[0])
rhythm_output.append(rhythm_seed[0])

for i in range(length-3):
i=i+3
key=(note_output[i-3],note_output[i-2],note_output[i-1])
options=note_database.get(key,["C","D","E","F","G","A","B"])
next_state=random.choice(options)
note_output.append(next_state)
rhythm_key=(rhythm_output[i-3],rhythm_output[i-2],rhythm_output[i-1])
rhythm_options=rhythm_database.get(rhythm_key,[0.25,0.5,0.5,1.0,1.0,1.0,1.0,2.0,2.0,2.0])
next_rhythm_state=random.choice(rhythm_options)
rhythm_output.append(next_rhythm_state)

return (note_output,rhythm_output)

def get_dataset(self,dataset_index=0):
path="/home/bwerth/InteractiveProgramming-1/data{}".format(dataset_index)
scores=[]
for filename in os.listdir(path):
scores.append(converter.parse("{}/{}".format(path,filename)))
return scores


def generate_note_lists(self,dataset):
melodyData = []
for score in dataset:
part = score.parts[0].getElementsByClass(stream.Measure) # Returns a list of Measures
melodyData.append([]) # melodyData is a list of phrases, which contains a set of notes with no rests.
for m in part: # For each measure!
for n in m.notesAndRests:
if(type(n) == note.Note):
melodyData[-1].append(n.name)# if it is a note, append the name of the note
elif(type(n) == note.Rest):
melodyData.append([]) # A rest ends a musical phrase so we just start a new sublist here
else: #the other possibility is that it is a chord...in which case, this grabs the top note
melodyData[-1].append(n[-1].name)
return melodyData


def generate_rhythm_lists(self,dataset):
rhythmData = []
for score in dataset:
part = score.parts[0].getElementsByClass(stream.Measure) # Returns a list of Measures
rhythmData.append([]) # melodyData is a list of phrases, which contains a set of notes with no rests.
for m in part: # For each measure
for n in m.notesAndRests:
if(type(n) == note.Note):
rhythmData[-1].append(n.quarterLength)# if it is a note, append the name of the note
elif(type(n) == note.Rest):
rhythmData.append([]) # A rest ends a musical phrase so we just start a new sublist here
else: #the other possibility is that it is a chord...in which case, this grabs the top note
rhythmData[-1].append(n[-1].quarterLength)
return rhythmData


def generate_melody(self,list_of_notes, list_of_rhythms):
octave = 4
streams=stream.Stream()
for indx,c in enumerate(list_of_notes):
pitch=c+str(octave)
note1=note.Note(pitch)
note1.quarterLength=list_of_rhythms[indx]
streams.append(note1)
mf = midi.translate.streamToMidiFile(streams)
mf.open('markov_melody.mid', 'wb')
mf.write()
mf.close()
os.system('/usr/bin/xdg-open ~/InteractiveProgramming-1/markov_melody.mid')# This line opens the MIDI file with the default program

def generate_song(self,length,dataset_index,note_seed,markov_order):
scores=self.get_dataset(dataset_index)
melody=self.generate_note_lists(scores)
rhythm=self.generate_rhythm_lists(scores)

if markov_order==1:
note_doubles=self.doubles(melody)
rhythm_doubles=self.doubles(rhythm)
note_database=self.markov_table_1(note_doubles)
rhythm_database=self.markov_table_1(rhythm_doubles)
newsong=self.generate_string_1(note_seed,length,note_database,rhythm_database)
list_of_notes=newsong[0]
list_of_rhythms=newsong[1]
self.generate_melody(list_of_notes, list_of_rhythms)

elif markov_order==2:
note_triples=self.triples(melody)
rhythm_triples=self.triples(rhythm)
note_database=self.markov_table_2(note_triples)
rhythm_database=self.markov_table_2(rhythm_triples)
newsong=self.generate_string_2(note_seed,length,note_database,rhythm_database)
list_of_notes=newsong[0]
list_of_rhythms=newsong[1]
self.generate_melody(list_of_notes, list_of_rhythms)

elif markov_order==3:
note_quadrouples=self.quadrouples(melody)
rhythm_quadrouples=self.quadrouples(rhythm)
note_database=self.markov_table_3(note_quadrouples)
rhythm_database=self.markov_table_3(rhythm_quadrouples)
newsong=self.generate_string_3(note_seed,length,note_database,rhythm_database)
list_of_notes=newsong[0]
list_of_rhythms=newsong[1]
self.generate_melody(list_of_notes, list_of_rhythms)
else:
print "Sorry, that markov order is not an option"

class SettingsScreen(Screen):
pass



# Create the screen manager and add the two previously defined screens to it.

class TestApp(App):

screen_manager = ScreenManager()

def build(self):
#self.screen_manager = ScreenManager()
self.screen_manager.add_widget(TitleScreen(name='title'))
self.screen_manager.add_widget(MenuScreen(name='menu'))
self.screen_manager.add_widget(SettingsScreen(name='settings'))
clock = NewClock()
Clock.schedule_once(clock.update, 4)
return self.screen_manager

if __name__ == '__main__':
TestApp().run()
75 changes: 75 additions & 0 deletions GUI /TestApp.kv
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#: kivy 1.7.2
<ScreenManager>:
id: screen_manager
MenuScreen:
id: menu_screen
name: 'MenuScreen'
manager: screen_manager
SettingsScreen:
name: 'SettingsScreen'
manager: screen_manager

<CustomDropDown>:
Button:
id: btn1
text: 'Value 1'
size_hint_y: None
height: 44
on_release: root.select('btn1')
Button:
id: btn2
text: 'Value 2'
size_hint_y: None
height: 44
on_release: root.select('btn2')

<MenuScreen>:
FloatLayout:
Label:
text: "In order to create a melody based on a music genre, you need to decide whether the current note is based on the 1, 2, 3, 4, or 5 last notes. Please enter one of these numbers."
size_hint: (.5,.125)
pos_hint: {'x':.25,'y':.7}
text_size: self.size
TextInput:
id: menu_screen
text: "Enter the desired number of chords"
size_hint: (.5,.125)
pos_hint: {'x':.25,'y':.5}
multiline: False
Button:
text: 'Generate Melody'
on_press:
#transfer the user input from the menu screen to the settings screen for later use
root.manager.get_screen('SettingsScreen').label_text.text = str(menu_screen.text)
#change to the settings screen after the user input has been accounted for
root.manager.current = 'SettingsScreen'
size_hint: (.25,.125)
pos_hint: {'x':.375,'y':.3}

BoxLayout:
id: topLayoutID
#cols: 2
size_hint: 1, .05
pos_hint: {'x': 0, 'y': .95}
Button:
#id: notesDropDownID
id: btn_ddID
text: 'Usage Notes'
on_release: root.drop_down.open(self)
Button:
text: 'About'

<SettingsScreen>:
label_text: label_text
FloatLayout:
Label:
id: label_text
#The text here does not matter because the label_text text parameter is changed manually when the user clicks the button on the
text: '1'
size_hint: (.125,.0625)
pos_hint: {'x':0,'y':.9375}
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
size_hint: (.125,.0625)
pos_hint: {'x':.125,'y':.9375}
Loading