diff --git a/AugmentedNet/cli.py b/AugmentedNet/cli.py index 692c5ff9..ff9a2523 100644 --- a/AugmentedNet/cli.py +++ b/AugmentedNet/cli.py @@ -39,15 +39,15 @@ class DefaultArguments(object): "outputRepresentations": [ "Alto35", "Bass35", - # "ChordQuality11", - # "ChordRoot35", + "ChordQuality11", + "ChordRoot35", "HarmonicRhythm7", - # "Inversion4", + "Inversion4", "LocalKey38", "PitchClassSet121", - # "PrimaryDegree22", + "PrimaryDegree22", "RomanNumeral31", - # "SecondaryDegree22", + "SecondaryDegree22", "Soprano35", "Tenor35", "TonicizedKey38", diff --git a/AugmentedNet/output_representations.py b/AugmentedNet/output_representations.py index 3ee641ec..c0266db5 100644 --- a/AugmentedNet/output_representations.py +++ b/AugmentedNet/output_representations.py @@ -112,7 +112,7 @@ class Inversion4(OutputRepresentationTI): classList = list(range(4)) dfFeature = "a_inversion" - def run(self): + def run(self, transposition="P1"): array = np.zeros(self.shape, dtype=self.dtype) for frame, inversion in enumerate(self.df[self.dfFeature]): if inversion > 3: diff --git a/AugmentedNet/texturizers.py b/AugmentedNet/texturizers.py index 0ab94a34..dd86cf33 100644 --- a/AugmentedNet/texturizers.py +++ b/AugmentedNet/texturizers.py @@ -1,13 +1,15 @@ """Templates for texturizing annotation files and turn them into scores.""" import random +from music21 import note +from music21 import interval class TextureTemplate(object): """The base class for texturization templates.""" supported_durations = [4.0, 3.0, 2.0, 1.5, 1.0] - supported_number_of_notes = [3, 4] + supported_number_of_notes = [1, 3, 4] def __init__(self, duration, notes, intervals): self.numberOfNotes = len(notes) @@ -23,11 +25,30 @@ def __init__(self, duration, notes, intervals): self.header = ( "s_offset,s_duration,s_measure,s_notes,s_intervals,s_isOnset\n" ) + if self.numberOfNotes == 1: + self.template = self.templateNote if self.numberOfNotes == 3: self.template = self.templateTriad elif self.numberOfNotes == 4: self.template = self.templateSeventh + def templateNote(self): + if self.duration == 3.0: + return self.templateNoteDottedHalf() + elif self.duration == 1.5: + return self.templateNoteDottedQuarter() + else: + return self.templateNoteBinary() + + def templateNoteDottedHalf(self): + raise NotImplementedError() + + def templateNoteDottedQuarter(self): + raise NotImplementedError() + + def templateNoteBinary(self): + raise NotImplementedError() + def templateTriad(self): if self.duration == 3.0: return self.templateTriadDottedHalf() @@ -76,6 +97,8 @@ class BassSplit(TextureTemplate): the bass note in isolation during the first half, followed by the remaining upper notes.""" + supported_number_of_notes = [3, 4] + def templateTriadBinary(self): dur = self.duration / 2 return f"""\ @@ -135,6 +158,8 @@ class Alberti(TextureTemplate): A 4-note melodic pattern with the contour lowest, highest, middle, highest.""" + supported_number_of_notes = [3, 4] + def templateTriadBinary(self): dur = self.duration / 4 return f"""\ @@ -200,6 +225,7 @@ class Syncopation(TextureTemplate): played in syncopation.""" supported_durations = [4.0, 2.0] + supported_number_of_notes = [3, 4] def templateTriad(self): dur = self.duration / 4 @@ -218,9 +244,142 @@ def templateSeventh(self): """ +class Arpeggio(TextureTemplate): + """A simple arpeggio pattern that climbs and descends the chord. + + The lowest note to the highest note of the chord is played in isolation, + then the highest note to the lowest note is played in isolation.""" + + supported_number_of_notes = [3, 4] + + def templateTriadBinary(self): + dur = self.duration / 4 + return f"""\ +0.0,{dur},,['{self.notes[0]}'],[],[True] +{dur},{dur},,['{self.notes[1]}'],[],[True] +{dur*2},{dur},,['{self.notes[2]}'],[],[True] +{dur*3},{dur},,['{self.notes[1]}'],[],[True] +""" + + def templateTriadDottedHalf(self): + dur = 0.25 + return f"""\ +0.0,{dur},,['{self.notes[0]}'],[],[True] +{dur},{dur},,['{self.notes[1]}'],[],[True] +{dur*2},{dur},,['{self.notes[2]}'],[],[True] +{dur*3},{dur},,['{self.notes[1]}'],[],[True] +{dur*4},{dur},,['{self.notes[0]}'],[],[True] +{dur*5},{dur},,['{self.notes[1]}'],[],[True] +{dur*6},{dur},,['{self.notes[2]}'],[],[True] +{dur*7},{dur},,['{self.notes[1]}'],[],[True] +{dur*8},{dur},,['{self.notes[0]}'],[],[True] +{dur*9},{dur},,['{self.notes[1]}'],[],[True] +{dur*10},{dur},,['{self.notes[2]}'],[],[True] +{dur*11},{dur},,['{self.notes[1]}'],[],[True] +""" + + def templateTriadDottedQuarter(self): + dur = 0.25 + return f"""\ +0.0,{dur},,['{self.notes[0]}'],[],[True] +{dur},{dur},,['{self.notes[1]}'],[],[True] +{dur*2},{dur},,['{self.notes[2]}'],[],[True] +{dur*3},{dur},,['{self.notes[1]}'],[],[True] +{dur*4},{dur},,['{self.notes[0]}'],[],[True] +{dur*5},{dur},,['{self.notes[1]}'],[],[True] +""" + + def templateSeventhBinary(self): + dur = self.duration / 4 + return f"""\ +0.0,{dur},,['{self.notes[0]}'],[],[True] +{dur},{dur},,['{self.notes[1]}'],[],[True] +{dur*2},{dur},,['{self.notes[3]}'],[],[True] +{dur*3},{dur},,['{self.notes[1]}'],[],[True] +""" + + def templateSeventhDottedHalf(self): + dur = 0.25 + return f"""\ +0.0,{dur},,['{self.notes[0]}'],[],[True] +{dur},{dur},,['{self.notes[1]}'],[],[True] +{dur*2},{dur},,['{self.notes[3]}'],[],[True] +{dur*3},{dur},,['{self.notes[1]}'],[],[True] +{dur*4},{dur},,['{self.notes[0]}'],[],[True] +{dur*5},{dur},,['{self.notes[1]}'],[],[True] +{dur*6},{dur},,['{self.notes[3]}'],[],[True] +{dur*7},{dur},,['{self.notes[1]}'],[],[True] +{dur*8},{dur},,['{self.notes[0]}'],[],[True] +{dur*9},{dur},,['{self.notes[1]}'],[],[True] +{dur*10},{dur},,['{self.notes[3]}'],[],[True] +{dur*11},{dur},,['{self.notes[1]}'],[],[True] +""" + + def templateSeventhDottedQuarter(self): + dur = 0.25 + return f"""\ +0.0,{dur},,['{self.notes[0]}'],[],[True] +{dur},{dur},,['{self.notes[1]}'],[],[True] +{dur*2},{dur},,['{self.notes[3]}'],[],[True] +{dur*3},{dur},,['{self.notes[1]}'],[],[True] +{dur*4},{dur},,['{self.notes[0]}'],[],[True] +{dur*5},{dur},,['{self.notes[1]}'],[],[True] +""" + + + def templateSeventh(self): + dur = self.duration / 6 + return f"""\ +0.0,{dur},,['{self.notes[0]}'],[],[True] +{dur},{dur},,['{self.notes[1]}'],[],[True] +{dur*2},{dur},,['{self.notes[2]}'],[],[True] +{dur*3},{dur},,['{self.notes[3]}'],[],[True] +{dur*4},{dur},,['{self.notes[2]}'],[],[True] +{dur*5},{dur},,['{self.notes[1]}'],[],[True] +""" + + +class AuxiliaryNotes(TextureTemplate): + """A pitch pattern that creates a minor second interval in the middle of the chord. + """ + + supported_durations = [4.0, 2.0, 1.5, 1.0] + supported_number_of_notes = [1] + + + def templateNoteBinary(self): + transposed_note_up = note.Note(self.notes[0]).transpose(1) + transposed_name_up = transposed_note_up.nameWithOctave + transposed_note_down = note.Note(self.notes[0]).transpose(-1) + transposed_name_down = transposed_note_down.nameWithOctave + dur = self.duration / 4 + return f"""\ +0.0,{dur},,['{transposed_name_up}'],[],[True] +{dur},{dur},,['{self.notes[0]}'],[],[True] +{dur*2},{dur},,['{transposed_name_down}'],[],[True] +{dur*3},{dur},,['{self.notes[0]}'],[],[True] +""" + + def templateNoteDottedQuarter(self): + transposed_note_up = note.Note(self.notes[0]).transpose(1) + transposed_name_up = transposed_note_up.nameWithOctave + transposed_note_down = note.Note(self.notes[0]).transpose(-1) + transposed_name_down = transposed_note_down.nameWithOctave + dur = 0.25 + return f"""\ +0.0,{dur},,['{self.notes[0]}'],[],[True] +{dur},{dur},,['{transposed_name_up}'],[],[True] +{dur*2},{dur},,['{self.notes[0]}'],[],[True] +{dur*3},{dur},,['{transposed_name_down}'],[],[True] +{dur*5},{dur*2},,['{self.notes[0]}'],[],[True] +""" + + class BlockChord(TextureTemplate): """A block-chord texture. The default texture in music21-generated scores.""" + supported_number_of_notes = [3, 4] + def templateTriad(self): dur = self.duration return f"""\ @@ -239,6 +398,8 @@ def templateSeventh(self): "Alberti": Alberti, "Syncopation": Syncopation, "BlockChord": BlockChord, + "Arpeggio": Arpeggio, + "AuxiliaryNotes": AuxiliaryNotes, } available_durations = list( diff --git a/AugmentedNet/train.py b/AugmentedNet/train.py index 34e5ff3d..a57d0887 100644 --- a/AugmentedNet/train.py +++ b/AugmentedNet/train.py @@ -113,11 +113,11 @@ class ModdedModelCheckpoint(keras.callbacks.ModelCheckpoint): def on_epoch_end(self, epoch, logs={}): monitored = list(availableOutputs.keys()) nonMonitored = [ - "ChordQuality11", - "ChordRoot35", - "Inversion4", - "PrimaryDegree22", - "SecondaryDegree22", + # "ChordQuality11", + # "ChordRoot35", + # "Inversion4", + # "PrimaryDegree22", + # "SecondaryDegree22", ] monitored = [a for a in monitored if a not in nonMonitored] print(f"monitored_outputs: {monitored}")