# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Tests for melodies_lib.""" # internal imports import tensorflow as tf from magenta.common import sequence_example_lib from magenta.music import constants from magenta.music import melodies_lib from magenta.music import sequences_lib from magenta.music import testing_lib NUM_SPECIAL_EVENTS = constants.NUM_SPECIAL_MELODY_EVENTS NOTE_OFF = constants.MELODY_NOTE_OFF NO_EVENT = constants.MELODY_NO_EVENT class MelodiesLibTest(tf.test.TestCase): def setUp(self): self.quantized_sequence = sequences_lib.QuantizedSequence() self.quantized_sequence.qpm = 60.0 self.quantized_sequence.steps_per_quarter = 4 def testGetNoteHistogram(self): events = [NO_EVENT, NOTE_OFF, 12 * 2 + 1, 12 * 3, 12 * 5 + 11, 12 * 6 + 3, 12 * 4 + 11] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) expected = [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2] self.assertEqual(expected, list(melody.get_note_histogram())) events = [0, 1, NO_EVENT, NOTE_OFF, 12 * 2 + 1, 12 * 3, 12 * 6 + 3, 12 * 5 + 11, NO_EVENT, 12 * 4 + 11, 12 * 7 + 1] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) expected = [2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2] self.assertEqual(expected, list(melody.get_note_histogram())) melody = melodies_lib.MonophonicMelody() expected = [0] * 12 self.assertEqual(expected, list(melody.get_note_histogram())) def testGetKeyHistogram(self): # One C. events = [NO_EVENT, 12 * 5, NOTE_OFF] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) expected = [1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0] self.assertListEqual(expected, list(melody.get_major_key_histogram())) # One C and one C#. events = [NO_EVENT, 12 * 5, NOTE_OFF, 12 * 7 + 1, NOTE_OFF] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) expected = [1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1] self.assertListEqual(expected, list(melody.get_major_key_histogram())) # One C, one C#, and one D. events = [NO_EVENT, 12 * 5, NOTE_OFF, 12 * 7 + 1, NO_EVENT, 12 * 9 + 2] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) expected = [2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 1] self.assertListEqual(expected, list(melody.get_major_key_histogram())) def testGetMajorKey(self): # D Major. events = [NO_EVENT, 12 * 2 + 2, 12 * 3 + 4, 12 * 5 + 1, 12 * 6 + 6, 12 * 4 + 11, 12 * 3 + 9, 12 * 5 + 7, NOTE_OFF] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) self.assertEqual(2, melody.get_major_key()) # C# Major with accidentals. events = [NO_EVENT, 12 * 2 + 1, 12 * 4 + 8, 12 * 5 + 5, 12 * 6 + 6, 12 * 3 + 3, 12 * 2 + 11, 12 * 3 + 10, 12 * 5, 12 * 2 + 8, 12 * 4 + 1, 12 * 3 + 5, 12 * 5 + 9, 12 * 4 + 3, NOTE_OFF] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) self.assertEqual(1, melody.get_major_key()) # One note in C Major. events = [NO_EVENT, 12 * 2 + 11, NOTE_OFF] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) self.assertEqual(0, melody.get_major_key()) def testTranspose(self): # MonophonicMelody transposed down 5 half steps. 2 octave range. events = [12 * 5 + 4, NO_EVENT, 12 * 5 + 5, NOTE_OFF, 12 * 6, NO_EVENT] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) melody.transpose(transpose_amount=-5, min_note=12 * 5, max_note=12 * 7) expected = [12 * 5 + 11, NO_EVENT, 12 * 5, NOTE_OFF, 12 * 5 + 7, NO_EVENT] self.assertEqual(expected, list(melody)) # MonophonicMelody transposed up 19 half steps. 2 octave range. events = [12 * 5 + 4, NO_EVENT, 12 * 5 + 5, NOTE_OFF, 12 * 6, NO_EVENT] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) melody.transpose(transpose_amount=19, min_note=12 * 5, max_note=12 * 7) expected = [12 * 6 + 11, NO_EVENT, 12 * 6, NOTE_OFF, 12 * 6 + 7, NO_EVENT] self.assertEqual(expected, list(melody)) # MonophonicMelody transposed zero half steps. 1 octave range. events = [12 * 4 + 11, 12 * 5, 12 * 5 + 11, NOTE_OFF, 12 * 6, NO_EVENT] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) melody.transpose(transpose_amount=0, min_note=12 * 5, max_note=12 * 6) expected = [12 * 5 + 11, 12 * 5, 12 * 5 + 11, NOTE_OFF, 12 * 5, NO_EVENT] self.assertEqual(expected, list(melody)) def testSquash(self): # MonophonicMelody in C, transposed to C, and squashed to 1 octave. events = [12 * 5, NO_EVENT, 12 * 5 + 2, NOTE_OFF, 12 * 6 + 4, NO_EVENT] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) melody.squash(min_note=12 * 5, max_note=12 * 6, transpose_to_key=0) expected = [12 * 5, NO_EVENT, 12 * 5 + 2, NOTE_OFF, 12 * 5 + 4, NO_EVENT] self.assertEqual(expected, list(melody)) # MonophonicMelody in D, transposed to C, and squashed to 1 octave. events = [12 * 5 + 2, 12 * 5 + 4, 12 * 6 + 7, 12 * 6 + 6, 12 * 5 + 1] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) melody.squash(min_note=12 * 5, max_note=12 * 6, transpose_to_key=0) expected = [12 * 5, 12 * 5 + 2, 12 * 5 + 5, 12 * 5 + 4, 12 * 5 + 11] self.assertEqual(expected, list(melody)) # MonophonicMelody in D, transposed to E, and squashed to 1 octave. events = [12 * 5 + 2, 12 * 5 + 4, 12 * 6 + 7, 12 * 6 + 6, 12 * 4 + 11] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) melody.squash(min_note=12 * 5, max_note=12 * 6, transpose_to_key=4) expected = [12 * 5 + 4, 12 * 5 + 6, 12 * 5 + 9, 12 * 5 + 8, 12 * 5 + 1] self.assertEqual(expected, list(melody)) def testSquashCenterOctaves(self): # Move up an octave. events = [12 * 4, NO_EVENT, 12 * 4 + 2, NOTE_OFF, 12 * 4 + 4, NO_EVENT, 12 * 4 + 5, 12 * 5 + 2, 12 * 4 - 1, NOTE_OFF] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) melody.squash(min_note=12 * 4, max_note=12 * 7, transpose_to_key=0) expected = [12 * 5, NO_EVENT, 12 * 5 + 2, NOTE_OFF, 12 * 5 + 4, NO_EVENT, 12 * 5 + 5, 12 * 6 + 2, 12 * 5 - 1, NOTE_OFF] self.assertEqual(expected, list(melody)) # Move down an octave. events = [12 * 6, NO_EVENT, 12 * 6 + 2, NOTE_OFF, 12 * 6 + 4, NO_EVENT, 12 * 6 + 5, 12 * 7 + 2, 12 * 6 - 1, NOTE_OFF] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) melody.squash(min_note=12 * 4, max_note=12 * 7, transpose_to_key=0) expected = [12 * 5, NO_EVENT, 12 * 5 + 2, NOTE_OFF, 12 * 5 + 4, NO_EVENT, 12 * 5 + 5, 12 * 6 + 2, 12 * 5 - 1, NOTE_OFF] self.assertEqual(expected, list(melody)) def testSquashMaxNote(self): events = [12 * 5, 12 * 5 + 2, 12 * 5 + 4, 12 * 5 + 5, 12 * 5 + 11, 12 * 6, 12 * 6 + 1] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) melody.squash(min_note=12 * 5, max_note=12 * 6, transpose_to_key=0) expected = [12 * 5, 12 * 5 + 2, 12 * 5 + 4, 12 * 5 + 5, 12 * 5 + 11, 12 * 5, 12 * 5 + 1] self.assertEqual(expected, list(melody)) def testSquashAllNotesOff(self): events = [NO_EVENT, NOTE_OFF, NO_EVENT, NO_EVENT] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) melody.squash(min_note=12 * 4, max_note=12 * 7, transpose_to_key=0) self.assertEqual(events, list(melody)) def testFromQuantizedSequence(self): testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 0, 40), (11, 55, 1, 2), (40, 45, 10, 14), (55, 120, 16, 17), (52, 99, 19, 20)]) melody = melodies_lib.MonophonicMelody() melody.from_quantized_sequence(self.quantized_sequence, start_step=0, track=0) expected = ([12, 11, NOTE_OFF, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, 40, NO_EVENT, NO_EVENT, NO_EVENT, NOTE_OFF, NO_EVENT, 55, NOTE_OFF, NO_EVENT, 52]) self.assertEqual(expected, list(melody)) self.assertEqual(16, melody.steps_per_bar) def testFromQuantizedSequenceNotCommonTimeSig(self): self.quantized_sequence.time_signature = sequences_lib.TimeSignature(7, 8) testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 0, 40), (11, 55, 1, 2), (40, 45, 10, 14), (55, 120, 16, 17), (52, 99, 19, 20)]) melody = melodies_lib.MonophonicMelody() melody.from_quantized_sequence(self.quantized_sequence, start_step=0, track=0) expected = ([12, 11, NOTE_OFF, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, 40, NO_EVENT, NO_EVENT, NO_EVENT, NOTE_OFF, NO_EVENT, 55, NOTE_OFF, NO_EVENT, 52]) self.assertEqual(expected, list(melody)) self.assertEqual(14, melody.steps_per_bar) def testFromNotesPolyphonic(self): testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 4, 16), (19, 100, 4, 12)]) melody = melodies_lib.MonophonicMelody() with self.assertRaises(melodies_lib.PolyphonicMelodyException): melody.from_quantized_sequence(self.quantized_sequence, start_step=0, track=0, ignore_polyphonic_notes=False) self.assertFalse(list(melody)) def testFromNotesPolyphonicWithIgnorePolyphonicNotes(self): testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 0, 8), (19, 100, 0, 12), (12, 100, 4, 12), (19, 100, 4, 16)]) melody = melodies_lib.MonophonicMelody() melody.from_quantized_sequence(self.quantized_sequence, start_step=0, track=0, ignore_polyphonic_notes=True) expected = ([19] + [NO_EVENT] * 3 + [19] + [NO_EVENT] * 11) self.assertEqual(expected, list(melody)) self.assertEqual(16, melody.steps_per_bar) def testFromNotesChord(self): testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 4, 5), (19, 100, 4, 5), (20, 100, 4, 5), (25, 100, 4, 5)]) melody = melodies_lib.MonophonicMelody() with self.assertRaises(melodies_lib.PolyphonicMelodyException): melody.from_quantized_sequence(self.quantized_sequence, start_step=0, track=0, ignore_polyphonic_notes=False) self.assertFalse(list(melody)) def testFromNotesTrimEmptyMeasures(self): testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 6, 7), (11, 100, 8, 9)]) melody = melodies_lib.MonophonicMelody() melody.from_quantized_sequence(self.quantized_sequence, start_step=0, track=0, ignore_polyphonic_notes=False) expected = [NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, 12, NOTE_OFF, 11] self.assertEqual(expected, list(melody)) self.assertEqual(16, melody.steps_per_bar) def testFromNotesTimeOverlap(self): testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 4, 8), (11, 100, 13, 15), (13, 100, 8, 16)]) melody = melodies_lib.MonophonicMelody() melody.from_quantized_sequence(self.quantized_sequence, start_step=0, track=0, ignore_polyphonic_notes=False) expected = [NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, 12, NO_EVENT, NO_EVENT, NO_EVENT, 13, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, 11, NO_EVENT] self.assertEqual(expected, list(melody)) def testFromNotesStepsPerBar(self): self.quantized_sequence.time_signature = sequences_lib.TimeSignature(7, 8) self.quantized_sequence.steps_per_quarter = 12 self.quantized_sequence.tracks[0] = [] melody = melodies_lib.MonophonicMelody() melody.from_quantized_sequence(self.quantized_sequence, start_step=0, track=0, ignore_polyphonic_notes=False) self.assertEqual(42, melody.steps_per_bar) def testFromNotesStartAndEndStep(self): testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 4, 8), (11, 100, 9, 10), (13, 100, 13, 15), (14, 100, 19, 20), (15, 100, 21, 27)]) melody = melodies_lib.MonophonicMelody() melody.from_quantized_sequence(self.quantized_sequence, start_step=18, track=0, ignore_polyphonic_notes=False) expected = [NO_EVENT, NO_EVENT, NO_EVENT, 14, NOTE_OFF, 15, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT] self.assertEqual(expected, list(melody)) self.assertEqual(16, melody.start_step) self.assertEqual(27, melody.end_step) def testSetLength(self): events = [60] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events, start_step=9) melody.set_length(5) self.assertListEqual([60, NOTE_OFF, NO_EVENT, NO_EVENT, NO_EVENT], list(melody)) self.assertEquals(9, melody.start_step) self.assertEquals(14, melody.end_step) melody = melodies_lib.MonophonicMelody() melody.from_event_list(events, start_step=9) melody.set_length(5, from_left=True) self.assertListEqual([NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, 60], list(melody)) self.assertEquals(5, melody.start_step) self.assertEquals(10, melody.end_step) events = [60, NO_EVENT, NO_EVENT, NOTE_OFF] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) melody.set_length(3) self.assertListEqual([60, NO_EVENT, NO_EVENT], list(melody)) self.assertEquals(0, melody.start_step) self.assertEquals(3, melody.end_step) melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) melody.set_length(3, from_left=True) self.assertListEqual([NO_EVENT, NO_EVENT, NOTE_OFF], list(melody)) self.assertEquals(1, melody.start_step) self.assertEquals(4, melody.end_step) def testToSequenceSimple(self): melody = melodies_lib.MonophonicMelody() melody.from_event_list([NO_EVENT, 1, NO_EVENT, NOTE_OFF, NO_EVENT, 2, 3, NOTE_OFF, NO_EVENT]) sequence = melody.to_sequence( velocity=10, instrument=1, sequence_start_time=2, qpm=60.0) self.assertProtoEquals( 'ticks_per_quarter: 96 ' 'tempos < qpm: 60.0 > ' 'total_time: 3.75 ' 'notes < ' ' pitch: 1 velocity: 10 instrument: 1 start_time: 2.25 end_time: 2.75 ' '> ' 'notes < ' ' pitch: 2 velocity: 10 instrument: 1 start_time: 3.25 end_time: 3.5 ' '> ' 'notes < ' ' pitch: 3 velocity: 10 instrument: 1 start_time: 3.5 end_time: 3.75 ' '> ', sequence) def testToSequenceEndsWithSustainedNote(self): melody = melodies_lib.MonophonicMelody() melody.from_event_list([NO_EVENT, 1, NO_EVENT, NOTE_OFF, NO_EVENT, 2, 3, NO_EVENT, NO_EVENT]) sequence = melody.to_sequence( velocity=100, instrument=0, sequence_start_time=0, qpm=60.0) self.assertProtoEquals( 'ticks_per_quarter: 96 ' 'tempos < qpm: 60.0 > ' 'total_time: 2.25 ' 'notes < pitch: 1 velocity: 100 start_time: 0.25 end_time: 0.75 > ' 'notes < pitch: 2 velocity: 100 start_time: 1.25 end_time: 1.5 > ' 'notes < pitch: 3 velocity: 100 start_time: 1.5 end_time: 2.25 > ', sequence) def testToSequenceEndsWithNonzeroStart(self): melody = melodies_lib.MonophonicMelody() melody.from_event_list([NO_EVENT, 1, NO_EVENT], start_step=4) sequence = melody.to_sequence( velocity=100, instrument=0, sequence_start_time=0.5, qpm=60.0) self.assertProtoEquals( 'ticks_per_quarter: 96 ' 'tempos < qpm: 60.0 > ' 'total_time: 2.25 ' 'notes < pitch: 1 velocity: 100 start_time: 1.75 end_time: 2.25 > ', sequence) def testToSequenceEmpty(self): melody = melodies_lib.MonophonicMelody() sequence = melody.to_sequence( velocity=10, instrument=1, sequence_start_time=2, qpm=60.0) self.assertProtoEquals( 'ticks_per_quarter: 96 ' 'tempos < qpm: 60.0 > ', sequence) def testExtractMelodiesSimple(self): self.quantized_sequence.steps_per_quarter = 1 testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 2, 4), (11, 1, 6, 7)]) testing_lib.add_quantized_track( self.quantized_sequence, 1, [(12, 127, 2, 4), (14, 50, 6, 9)]) expected = [[NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 11], [NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14, NO_EVENT, NO_EVENT]] melodies, _ = melodies_lib.extract_melodies( self.quantized_sequence, min_bars=1, gap_bars=1, min_unique_pitches=2, ignore_polyphonic_notes=True) self.assertEqual(2, len(melodies)) self.assertTrue(isinstance(melodies[0], melodies_lib.MonophonicMelody)) self.assertTrue(isinstance(melodies[1], melodies_lib.MonophonicMelody)) melodies = sorted([list(melody) for melody in melodies]) self.assertEqual(expected, melodies) def testExtractMultipleMelodiesFromSameTrack(self): self.quantized_sequence.steps_per_quarter = 1 testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 2, 4), (11, 1, 6, 11)]) testing_lib.add_quantized_track( self.quantized_sequence, 1, [(12, 127, 2, 4), (14, 50, 6, 8), (50, 100, 33, 37), (52, 100, 34, 37)]) expected = [[NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 11, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT], [NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14, NO_EVENT], [NO_EVENT, 50, 52, NO_EVENT, NO_EVENT]] melodies, _ = melodies_lib.extract_melodies( self.quantized_sequence, min_bars=1, gap_bars=2, min_unique_pitches=2, ignore_polyphonic_notes=True) melodies = sorted([list(melody) for melody in melodies]) self.assertEqual(expected, melodies) def testExtractMelodiesMelodyTooShort(self): self.quantized_sequence.steps_per_quarter = 1 testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 127, 2, 4), (14, 50, 6, 7)]) testing_lib.add_quantized_track( self.quantized_sequence, 1, [(12, 127, 2, 4), (14, 50, 6, 9)]) expected = [[NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14, NO_EVENT, NO_EVENT]] melodies, _ = melodies_lib.extract_melodies( self.quantized_sequence, min_bars=2, gap_bars=1, min_unique_pitches=2, ignore_polyphonic_notes=True) melodies = [list(melody) for melody in melodies] self.assertEqual(expected, melodies) def testExtractMelodiesPadEnd(self): self.quantized_sequence.steps_per_quarter = 1 testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 127, 2, 4), (14, 50, 6, 7)]) testing_lib.add_quantized_track( self.quantized_sequence, 1, [(12, 127, 2, 4), (14, 50, 6, 8)]) testing_lib.add_quantized_track( self.quantized_sequence, 2, [(12, 127, 2, 4), (14, 50, 6, 9)]) expected = [[NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14, NOTE_OFF], [NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14, NO_EVENT], [NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14, NO_EVENT, NO_EVENT, NOTE_OFF, NO_EVENT, NO_EVENT]] melodies, _ = melodies_lib.extract_melodies( self.quantized_sequence, min_bars=1, gap_bars=1, min_unique_pitches=2, ignore_polyphonic_notes=True, pad_end=True) melodies = [list(melody) for melody in melodies] self.assertEqual(expected, melodies) def testExtractMelodiesMelodyTooLong(self): self.quantized_sequence.steps_per_quarter = 1 testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 127, 2, 4), (14, 50, 6, 15)]) testing_lib.add_quantized_track( self.quantized_sequence, 1, [(12, 127, 2, 4), (14, 50, 6, 18)]) expected = [[NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14] + [NO_EVENT] * 7, [NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14] + [NO_EVENT] * 7] melodies, _ = melodies_lib.extract_melodies( self.quantized_sequence, min_bars=1, max_steps_truncate=14, max_steps_discard=18, gap_bars=1, min_unique_pitches=2, ignore_polyphonic_notes=True) melodies = [list(melody) for melody in melodies] self.assertEqual(expected, melodies) def testExtractMelodiesMelodyTooLongWithPad(self): self.quantized_sequence.steps_per_quarter = 1 testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 127, 2, 4), (14, 50, 6, 15)]) testing_lib.add_quantized_track( self.quantized_sequence, 1, [(12, 127, 2, 4), (14, 50, 6, 18)]) expected = [[NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT, NO_EVENT]] melodies, _ = melodies_lib.extract_melodies( self.quantized_sequence, min_bars=1, max_steps_truncate=14, max_steps_discard=18, gap_bars=1, min_unique_pitches=2, ignore_polyphonic_notes=True, pad_end=True) melodies = [list(melody) for melody in melodies] self.assertEqual(expected, melodies) def testExtractMelodiesTooFewPitches(self): # Test that extract_melodies discards melodies with too few pitches where # pitches are equivalent by octave. self.quantized_sequence.steps_per_quarter = 1 testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 0, 1), (13, 100, 1, 2), (18, 100, 2, 3), (24, 100, 3, 4), (25, 100, 4, 5)]) testing_lib.add_quantized_track( self.quantized_sequence, 1, [(12, 100, 0, 1), (13, 100, 1, 2), (18, 100, 2, 3), (25, 100, 3, 4), (26, 100, 4, 5)]) expected = [[12, 13, 18, 25, 26]] melodies, _ = melodies_lib.extract_melodies( self.quantized_sequence, min_bars=1, gap_bars=1, min_unique_pitches=4, ignore_polyphonic_notes=True) melodies = [list(melody) for melody in melodies] self.assertEqual(expected, melodies) def testExtractMelodiesLateStart(self): self.quantized_sequence.steps_per_quarter = 1 testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 102, 103), (13, 100, 104, 106)]) testing_lib.add_quantized_track( self.quantized_sequence, 1, [(12, 100, 100, 101), (13, 100, 102, 105)]) expected = [[NO_EVENT, NO_EVENT, 12, NOTE_OFF, 13, NO_EVENT], [12, NOTE_OFF, 13, NO_EVENT, NO_EVENT]] melodies, _ = melodies_lib.extract_melodies( self.quantized_sequence, min_bars=1, gap_bars=1, min_unique_pitches=2, ignore_polyphonic_notes=True) melodies = sorted([list(melody) for melody in melodies]) self.assertEqual(expected, melodies) def testExtractMelodiesStatistics(self): self.quantized_sequence.steps_per_quarter = 1 testing_lib.add_quantized_track( self.quantized_sequence, 0, [(12, 100, 2, 4), (11, 1, 6, 7), (10, 100, 8, 10), (9, 100, 11, 14), (8, 100, 16, 40), (7, 100, 41, 42)]) testing_lib.add_quantized_track( self.quantized_sequence, 1, [(12, 127, 2, 4), (14, 50, 2, 8)]) testing_lib.add_quantized_track( self.quantized_sequence, 2, [(12, 127, 0, 1)]) testing_lib.add_quantized_track( self.quantized_sequence, 3, [(12, 127, 2, 4), (12, 50, 6, 8)]) _, stats = melodies_lib.extract_melodies( self.quantized_sequence, min_bars=1, gap_bars=1, min_unique_pitches=2, ignore_polyphonic_notes=False) stats_dict = dict([(stat.name, stat) for stat in stats]) self.assertEqual(stats_dict['polyphonic_tracks_discarded'].count, 1) self.assertEqual(stats_dict['melodies_discarded_too_short'].count, 1) self.assertEqual(stats_dict['melodies_discarded_too_few_pitches'].count, 1) self.assertEqual( stats_dict['melody_lengths_in_bars'].counters, {float('-inf'): 0, 0: 1, 1: 0, 2: 1, 10: 1, 20: 0, 30: 0, 40: 0, 50: 0, 100: 0, 200: 0, 500: 0}) class MelodyEncoderDecoderTest(tf.test.TestCase): def setUp(self): self.melody_encoder_decoder = melodies_lib.OneHotEncoderDecoder(60, 72, 0) def testMinNoteMaxNoteAndTransposeToKeyValidValues(self): # Valid parameters melodies_lib.OneHotEncoderDecoder(0, 128, 0) melodies_lib.OneHotEncoderDecoder(60, 72, 11) # Invalid parameters self.assertRaises(ValueError, melodies_lib.OneHotEncoderDecoder, -1, 72, 0) self.assertRaises(ValueError, melodies_lib.OneHotEncoderDecoder, 60, 129, 0) self.assertRaises(ValueError, melodies_lib.OneHotEncoderDecoder, 60, 71, 0) self.assertRaises(ValueError, melodies_lib.OneHotEncoderDecoder, 60, 72, -1) self.assertRaises(ValueError, melodies_lib.OneHotEncoderDecoder, 60, 72, 12) def testInitValues(self): self.assertEqual(self.melody_encoder_decoder.min_note, 60) self.assertEqual(self.melody_encoder_decoder.max_note, 72) self.assertEqual(self.melody_encoder_decoder.transpose_to_key, 0) self.assertEqual(self.melody_encoder_decoder.input_size, 14) self.assertEqual(self.melody_encoder_decoder.num_classes, 14) self.assertEqual(self.melody_encoder_decoder.no_event_label, 0) def testSquashAndEncode(self): events = [100, 100, 107, 111, NO_EVENT, 99, 112, NOTE_OFF, NO_EVENT] melody = melodies_lib.MonophonicMelody() melody.from_event_list(events) sequence_example = self.melody_encoder_decoder.squash_and_encode(melody) expected_inputs = [ [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0], [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]] expected_labels = [2, 9, 13, 0, 13, 2, 1, 0] expected_sequence_example = sequence_example_lib.make_sequence_example( expected_inputs, expected_labels) self.assertEqual(sequence_example, expected_sequence_example) def testGetInputsBatch(self): events1 = [100, 100, 107, 111, NO_EVENT, 99, 112, NOTE_OFF, NO_EVENT] melody1 = melodies_lib.MonophonicMelody() melody1.from_event_list(events1) events2 = [9, 10, 12, 14, 15, 17, 19, 21, 22] melody2 = melodies_lib.MonophonicMelody() melody2.from_event_list(events2) transpose_amount1 = melody1.squash( self.melody_encoder_decoder.min_note, self.melody_encoder_decoder.max_note, self.melody_encoder_decoder.transpose_to_key) transpose_amount2 = melody2.squash( self.melody_encoder_decoder.min_note, self.melody_encoder_decoder.max_note, self.melody_encoder_decoder.transpose_to_key) self.assertEqual(transpose_amount1, -40) self.assertEqual(transpose_amount2, 50) melodies = [melody1, melody2] expected_inputs1 = [ [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0], [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]] expected_inputs2 = [ [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0], [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0], [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]] expected_full_length_inputs_batch = [expected_inputs1, expected_inputs2] expected_last_event_inputs_batch = [expected_inputs1[-1:], expected_inputs2[-1:]] self.assertListEqual( expected_full_length_inputs_batch, self.melody_encoder_decoder.get_inputs_batch(melodies, True)) self.assertListEqual( expected_last_event_inputs_batch, self.melody_encoder_decoder.get_inputs_batch(melodies)) def testExtendMelodies(self): melody1 = melodies_lib.MonophonicMelody() melody1.from_event_list([60]) melody2 = melodies_lib.MonophonicMelody() melody2.from_event_list([60]) melody3 = melodies_lib.MonophonicMelody() melody3.from_event_list([60]) melody4 = melodies_lib.MonophonicMelody() melody4.from_event_list([60]) melodies = [melody1, melody2, melody3, melody4] softmax = [[ [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] ], [ [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0] ], [ [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] ], [ [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] ]] self.melody_encoder_decoder.extend_event_sequences(melodies, softmax) self.assertListEqual(list(melody1), [60, 60]) self.assertListEqual(list(melody2), [60, 71]) self.assertListEqual(list(melody3), [60, NO_EVENT]) self.assertListEqual(list(melody4), [60, NOTE_OFF]) if __name__ == '__main__': tf.test.main()