Example #1
0
  def testSplitNoteSequenceDuplicateTimeChanges(self):
    # Tests splitting a NoteSequence on time changes for a NoteSequence that has
    # duplicate time changes.
    sequence = common_testing_lib.parse_test_proto(
        music_pb2.NoteSequence,
        """
        time_signatures: {
          numerator: 4
          denominator: 4}
        time_signatures: {
          time: 2.0
          numerator: 4
          denominator: 4}
        tempos: {
          qpm: 60}""")
    testing_lib.add_track_to_sequence(
        sequence, 0,
        [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50),
         (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)])
    testing_lib.add_chords_to_sequence(
        sequence, [('C', 1.5), ('G7', 3.0), ('F', 4.8)])

    expected_subsequence = music_pb2.NoteSequence()
    expected_subsequence.CopyFrom(sequence)
    expected_subsequence.subsequence_info.start_time_offset = 0.0
    expected_subsequence.subsequence_info.end_time_offset = 0.0

    subsequences = sequences_lib.split_note_sequence_on_time_changes(sequence)
    self.assertEquals(1, len(subsequences))
    self.assertProtoEquals(expected_subsequence, subsequences[0])
Example #2
0
  def testSplitNoteSequenceCoincidentTimeChanges(self):
    sequence = common_testing_lib.parse_test_proto(
        music_pb2.NoteSequence,
        """
        time_signatures: {
          numerator: 4
          denominator: 4}
        time_signatures: {
          time: 2.0
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 60}
        tempos: {
          time: 2.0
          qpm: 80}""")
    testing_lib.add_track_to_sequence(
        sequence, 0,
        [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50),
         (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)])
    testing_lib.add_chords_to_sequence(
        sequence, [('C', 1.5), ('G7', 3.0), ('F', 4.8)])

    expected_subsequence_1 = common_testing_lib.parse_test_proto(
        music_pb2.NoteSequence,
        """
        time_signatures: {
          numerator: 4
          denominator: 4}
        tempos: {
          qpm: 60}""")
    testing_lib.add_track_to_sequence(
        expected_subsequence_1, 0,
        [(12, 100, 0.01, 2.0), (11, 55, 0.22, 0.50)])
    testing_lib.add_chords_to_sequence(
        expected_subsequence_1, [('C', 1.5)])
    expected_subsequence_1.total_time = 2.0
    expected_subsequence_1.subsequence_info.end_time_offset = 8.0

    expected_subsequence_2 = common_testing_lib.parse_test_proto(
        music_pb2.NoteSequence,
        """
        time_signatures: {
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 80}""")
    testing_lib.add_track_to_sequence(
        expected_subsequence_2, 0,
        [(40, 45, 0.50, 1.50), (55, 120, 2.0, 2.01), (52, 99, 2.75, 3.0)])
    testing_lib.add_chords_to_sequence(
        expected_subsequence_2, [('C', 0.0), ('G7', 1.0), ('F', 2.8)])
    expected_subsequence_2.total_time = 3.0
    expected_subsequence_2.subsequence_info.start_time_offset = 2.0
    expected_subsequence_2.subsequence_info.end_time_offset = 5.0

    subsequences = sequences_lib.split_note_sequence_on_time_changes(sequence)
    self.assertEquals(2, len(subsequences))
    self.assertProtoEquals(expected_subsequence_1, subsequences[0])
    self.assertProtoEquals(expected_subsequence_2, subsequences[1])
Example #3
0
def magent_melody_extractor(midi_path, max_bars=100):
    data_converter = music_vae_data.OneHotMelodyConverter(
        valid_programs=music_vae_data.MEL_PROGRAMS,
        skip_polyphony=False,
        max_bars=max_bars,  # Truncate long melodies before slicing.
        slice_bars=16,
        steps_per_quarter=4)

    ns = convert_midi("", '', midi_path)
    all_melodies = []
    try:
        note_sequences = sequences_lib.split_note_sequence_on_time_changes(ns)
        for ns in note_sequences:
            # filter notes --------------------------------------------------------
            def filter(note):
                if (data_converter._valid_programs is not None and note.program
                        not in data_converter._valid_programs):
                    return False
                return data_converter._min_pitch <= note.pitch <= data_converter._max_pitch

            notes = list(ns.notes)
            del ns.notes[:]
            ns.notes.extend([n for n in notes if filter(n)])

            # quantize sequence ---------------------------------------------------
            quantized_sequence = mm.quantize_note_sequence(
                ns, data_converter._steps_per_quarter)

            # extract melodies ----------------------------------------------------
            melodies, _ = data_converter._event_extractor_fn(
                quantized_sequence)
            all_melodies.extend(melodies)
    except:
        pass
    return all_melodies
Example #4
0
    def testSplitNoteSequenceDuplicateTimeChanges(self):
        # Tests splitting a NoteSequence on time changes for a NoteSequence that has
        # duplicate time changes.
        sequence = common_testing_lib.parse_test_proto(
            music_pb2.NoteSequence, """
        time_signatures: {
          numerator: 4
          denominator: 4}
        time_signatures: {
          time: 2.0
          numerator: 4
          denominator: 4}
        tempos: {
          qpm: 60}""")
        testing_lib.add_track_to_sequence(sequence, 0, [(12, 100, 0.01, 10.0),
                                                        (11, 55, 0.22, 0.50),
                                                        (40, 45, 2.50, 3.50),
                                                        (55, 120, 4.0, 4.01),
                                                        (52, 99, 4.75, 5.0)])
        testing_lib.add_chords_to_sequence(sequence, [('C', 1.5), ('G7', 3.0),
                                                      ('F', 4.8)])

        expected_subsequence = music_pb2.NoteSequence()
        expected_subsequence.CopyFrom(sequence)
        expected_subsequence.subsequence_info.start_time_offset = 0.0
        expected_subsequence.subsequence_info.end_time_offset = 0.0

        subsequences = sequences_lib.split_note_sequence_on_time_changes(
            sequence)
        self.assertEquals(1, len(subsequences))
        self.assertProtoEquals(expected_subsequence, subsequences[0])
Example #5
0
    def testSplitNoteSequenceCoincidentTimeChanges(self):
        sequence = common_testing_lib.parse_test_proto(
            music_pb2.NoteSequence, """
        time_signatures: {
          numerator: 4
          denominator: 4}
        time_signatures: {
          time: 2.0
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 60}
        tempos: {
          time: 2.0
          qpm: 80}""")
        testing_lib.add_track_to_sequence(sequence, 0, [(12, 100, 0.01, 10.0),
                                                        (11, 55, 0.22, 0.50),
                                                        (40, 45, 2.50, 3.50),
                                                        (55, 120, 4.0, 4.01),
                                                        (52, 99, 4.75, 5.0)])
        testing_lib.add_chords_to_sequence(sequence, [('C', 1.5), ('G7', 3.0),
                                                      ('F', 4.8)])

        expected_subsequence_1 = common_testing_lib.parse_test_proto(
            music_pb2.NoteSequence, """
        time_signatures: {
          numerator: 4
          denominator: 4}
        tempos: {
          qpm: 60}""")
        testing_lib.add_track_to_sequence(expected_subsequence_1, 0,
                                          [(12, 100, 0.01, 2.0),
                                           (11, 55, 0.22, 0.50)])
        testing_lib.add_chords_to_sequence(expected_subsequence_1,
                                           [('C', 1.5)])
        expected_subsequence_1.total_time = 2.0
        expected_subsequence_1.subsequence_info.end_time_offset = 8.0

        expected_subsequence_2 = common_testing_lib.parse_test_proto(
            music_pb2.NoteSequence, """
        time_signatures: {
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 80}""")
        testing_lib.add_track_to_sequence(expected_subsequence_2, 0,
                                          [(40, 45, 0.50, 1.50),
                                           (55, 120, 2.0, 2.01),
                                           (52, 99, 2.75, 3.0)])
        testing_lib.add_chords_to_sequence(expected_subsequence_2,
                                           [('C', 0.0), ('G7', 1.0),
                                            ('F', 2.8)])
        expected_subsequence_2.total_time = 8.0
        expected_subsequence_2.subsequence_info.start_time_offset = 2.0

        subsequences = sequences_lib.split_note_sequence_on_time_changes(
            sequence)
        self.assertEquals(2, len(subsequences))
        self.assertProtoEquals(expected_subsequence_1, subsequences[0])
        self.assertProtoEquals(expected_subsequence_2, subsequences[1])
Example #6
0
def preprocess_notesequence(note_sequence, presplit_on_time_changes):
    """Preprocesses a single NoteSequence, resulting in multiple sequences."""
    if presplit_on_time_changes:
        note_sequences = sequences_lib.split_note_sequence_on_time_changes(
            note_sequence)
    else:
        note_sequences = [note_sequence]

    return note_sequences
Example #7
0
def preprocess_notesequence(note_sequence, presplit_on_time_changes):
  """Preprocesses a single NoteSequence, resulting in multiple sequences."""
  if presplit_on_time_changes:
    note_sequences = sequences_lib.split_note_sequence_on_time_changes(
        note_sequence)
  else:
    note_sequences = [note_sequence]

  return note_sequences
Example #8
0
 def to_tensors(self, note_sequence):
   """Python method that converts `note_sequence` into list of tensors."""
   if self._presplit_on_time_changes:
     note_sequences = sequences_lib.split_note_sequence_on_time_changes(
         note_sequence)
   else:
     note_sequences = [note_sequence]
   results = []
   for ns in note_sequences:
     r = self._to_tensors(ns)
     if r[0]:
       results.extend(zip(*r))
   sampled_results = self._maybe_sample_outputs(results)
   return list(zip(*sampled_results)) if sampled_results else ([], [])
Example #9
0
 def to_tensors(self, note_sequence):
   """Python method that converts `note_sequence` into list of tensors."""
   if self._presplit_on_time_changes:
     note_sequences = sequences_lib.split_note_sequence_on_time_changes(
         note_sequence)
   else:
     note_sequences = [note_sequence]
   results = []
   for ns in note_sequences:
     r = self._to_tensors(ns)
     if r[0]:
       results.extend(zip(*r))
   sampled_results = self._maybe_sample_outputs(results)
   return list(zip(*sampled_results)) if sampled_results else ([], [])
Example #10
0
 def to_tensors(self, note_sequence):
     """Python method that converts `note_sequence` into list of tensors."""
     if self._presplit_on_time_changes:
         note_sequences = sequences_lib.split_note_sequence_on_time_changes(
             note_sequence)
     else:
         note_sequences = [note_sequence]
     results = []
     for ns in note_sequences:
         inputs, outputs = self._to_tensors(ns)
         if inputs:
             lengths = [len(i) for i in inputs]
             results.extend(zip(inputs, outputs, lengths))
     sampled_results = self._maybe_sample_outputs(results)
     return tuple(zip(*sampled_results)) if sampled_results else ([], [],
                                                                  [])
Example #11
0
def test_split_and_quantize():
    for midi_path in common.midi_big_paths:
        # print(midi_path)
        ns = convert_midi("", '', midi_path)
        note_sequences = sequences_lib.split_note_sequence_on_time_changes(ns)

        pm = pretty_midi.PrettyMIDI(midi_path)
        nc = NoteContainer.from_pretty_midi(pm)

        split_ncs = nc_lib.split_on_time_signature_tempo_change(nc)

        for nc, ns in zip(split_ncs, note_sequences):
            assert_nc_ns(nc, ns)

            qnc = nc_lib.quantize_note_container(nc, 4)
            qns = mm.quantize_note_sequence(ns, 4)
            assert_nc_ns(qnc, qns, quantized=True)
  def testSplitNoteSequenceNoTimeChanges(self):
    sequence = copy.copy(self.note_sequence)
    testing_lib.add_track_to_sequence(
        sequence, 0,
        [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50),
         (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)])
    testing_lib.add_chords_to_sequence(
        sequence, [('C', 1.5), ('G7', 3.0), ('F', 4.8)])

    expected_subsequence = music_pb2.NoteSequence()
    expected_subsequence.CopyFrom(sequence)
    expected_subsequence.subsequence_info.start_time_offset = 0.0
    expected_subsequence.subsequence_info.end_time_offset = 0.0

    subsequences = sequences_lib.split_note_sequence_on_time_changes(sequence)
    self.assertEquals(1, len(subsequences))
    self.assertProtoEquals(expected_subsequence, subsequences[0])
  def testTimeChangeSplitter(self):
    note_sequence = common_testing_lib.parse_test_proto(
        music_pb2.NoteSequence,
        """
        time_signatures: {
          time: 2.0
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 60}""")
    testing_lib.add_track_to_sequence(
        note_sequence, 0,
        [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50),
         (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)])
    expected_sequences = sequences_lib.split_note_sequence_on_time_changes(
        note_sequence)

    unit = note_sequence_pipelines.TimeChangeSplitter()
    self._unit_transform_test(unit, note_sequence, expected_sequences)
  def testTimeChangeSplitter(self):
    note_sequence = common_testing_lib.parse_test_proto(
        music_pb2.NoteSequence,
        """
        time_signatures: {
          time: 2.0
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 60}""")
    testing_lib.add_track_to_sequence(
        note_sequence, 0,
        [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50),
         (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)])
    expected_sequences = sequences_lib.split_note_sequence_on_time_changes(
        note_sequence)

    unit = note_sequence_pipelines.TimeChangeSplitter()
    self._unit_transform_test(unit, note_sequence, expected_sequences)
Example #15
0
    def testSplitNoteSequenceNoTimeChanges(self):
        sequence = copy.copy(self.note_sequence)
        testing_lib.add_track_to_sequence(sequence, 0, [(12, 100, 0.01, 10.0),
                                                        (11, 55, 0.22, 0.50),
                                                        (40, 45, 2.50, 3.50),
                                                        (55, 120, 4.0, 4.01),
                                                        (52, 99, 4.75, 5.0)])
        testing_lib.add_chords_to_sequence(sequence, [('C', 1.5), ('G7', 3.0),
                                                      ('F', 4.8)])

        expected_subsequence = music_pb2.NoteSequence()
        expected_subsequence.CopyFrom(sequence)
        expected_subsequence.subsequence_info.start_time_offset = 0.0
        expected_subsequence.subsequence_info.end_time_offset = 0.0

        subsequences = sequences_lib.split_note_sequence_on_time_changes(
            sequence)
        self.assertEquals(1, len(subsequences))
        self.assertProtoEquals(expected_subsequence, subsequences[0])
Example #16
0
    def testSplitNoteSequenceMultipleTimeChangesNoSplitNotes(self):
        sequence = common_testing_lib.parse_test_proto(
            music_pb2.NoteSequence,
            """
        time_signatures: {
          numerator: 4
          denominator: 4}
        time_signatures: {
          time: 2.0
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 60}
        tempos: {
          time: 4.25
          qpm: 80}""",
        )
        testing_lib.add_track_to_sequence(
            sequence,
            0,
            [
                (12, 100, 0.01, 3.0),
                (11, 55, 0.22, 0.50),
                (40, 45, 2.50, 3.50),
                (55, 120, 4.0, 4.01),
                (52, 99, 4.75, 5.0),
            ],
        )
        testing_lib.add_chords_to_sequence(sequence, [("C", 1.5), ("G7", 3.0), ("F", 4.8)])

        expected_subsequence_1 = common_testing_lib.parse_test_proto(
            music_pb2.NoteSequence,
            """
        time_signatures: {
          numerator: 4
          denominator: 4}
        time_signatures: {
          time: 2.0
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 60}""",
        )
        testing_lib.add_track_to_sequence(
            expected_subsequence_1,
            0,
            [(12, 100, 0.01, 3.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01)],
        )
        testing_lib.add_chords_to_sequence(expected_subsequence_1, [("C", 1.5), ("G7", 3.0)])
        expected_subsequence_1.total_time = 4.25
        expected_subsequence_1.subsequence_info.end_time_offset = 0.75

        expected_subsequence_2 = common_testing_lib.parse_test_proto(
            music_pb2.NoteSequence,
            """
        time_signatures: {
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 80}""",
        )
        testing_lib.add_track_to_sequence(expected_subsequence_2, 0, [(52, 99, 0.5, 0.75)])
        testing_lib.add_chords_to_sequence(expected_subsequence_2, [("G7", 0.0), ("F", 0.55)])
        expected_subsequence_2.total_time = 0.75
        expected_subsequence_2.subsequence_info.start_time_offset = 4.25

        subsequences = sequences_lib.split_note_sequence_on_time_changes(sequence, split_notes=False)
        self.assertEquals(2, len(subsequences))
        self.assertProtoEquals(expected_subsequence_1, subsequences[0])
        self.assertProtoEquals(expected_subsequence_2, subsequences[1])
 def transform(self, note_sequence):
   return sequences_lib.split_note_sequence_on_time_changes(note_sequence)
 def transform(self, note_sequence):
     return sequences_lib.split_note_sequence_on_time_changes(note_sequence)
Example #19
0
    def testSplitNoteSequenceMultipleTimeChanges(self):
        # Tests splitting a NoteSequence on time changes, truncating notes on splits
        # that occur inside notes.
        sequence = common_testing_lib.parse_test_proto(
            music_pb2.NoteSequence, """
        time_signatures: {
          numerator: 4
          denominator: 4}
        time_signatures: {
          time: 2.0
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 60}
        tempos: {
          time: 4.25
          qpm: 80}""")
        testing_lib.add_track_to_sequence(sequence, 0, [(12, 100, 0.01, 10.0),
                                                        (11, 55, 0.22, 0.50),
                                                        (40, 45, 2.50, 3.50),
                                                        (55, 120, 4.0, 4.01),
                                                        (52, 99, 4.75, 5.0)])
        testing_lib.add_chords_to_sequence(sequence, [('C', 1.5), ('G7', 3.0),
                                                      ('F', 4.8)])

        expected_subsequence_1 = common_testing_lib.parse_test_proto(
            music_pb2.NoteSequence, """
        time_signatures: {
          numerator: 4
          denominator: 4}
        tempos: {
          qpm: 60}""")
        testing_lib.add_track_to_sequence(expected_subsequence_1, 0,
                                          [(12, 100, 0.01, 2.0),
                                           (11, 55, 0.22, 0.50)])
        testing_lib.add_chords_to_sequence(expected_subsequence_1,
                                           [('C', 1.5)])
        expected_subsequence_1.total_time = 2.0
        expected_subsequence_1.subsequence_info.end_time_offset = 8.0

        expected_subsequence_2 = common_testing_lib.parse_test_proto(
            music_pb2.NoteSequence, """
        time_signatures: {
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 60}""")
        testing_lib.add_track_to_sequence(expected_subsequence_2, 0,
                                          [(40, 45, 0.50, 1.50),
                                           (55, 120, 2.0, 2.01)])
        testing_lib.add_chords_to_sequence(expected_subsequence_2,
                                           [('C', 0.0), ('G7', 1.0)])
        expected_subsequence_2.total_time = 2.01
        expected_subsequence_2.subsequence_info.start_time_offset = 2.0
        expected_subsequence_2.subsequence_info.end_time_offset = 5.99

        expected_subsequence_3 = common_testing_lib.parse_test_proto(
            music_pb2.NoteSequence, """
        time_signatures: {
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 80}""")
        testing_lib.add_track_to_sequence(expected_subsequence_3, 0,
                                          [(52, 99, 0.5, 0.75)])
        testing_lib.add_chords_to_sequence(expected_subsequence_3,
                                           [('G7', 0.0), ('F', 0.55)])
        expected_subsequence_3.total_time = 0.75
        expected_subsequence_3.subsequence_info.start_time_offset = 4.25
        expected_subsequence_3.subsequence_info.end_time_offset = 5.0

        subsequences = sequences_lib.split_note_sequence_on_time_changes(
            sequence)
        self.assertEquals(3, len(subsequences))
        self.assertProtoEquals(expected_subsequence_1, subsequences[0])
        self.assertProtoEquals(expected_subsequence_2, subsequences[1])
        self.assertProtoEquals(expected_subsequence_3, subsequences[2])
Example #20
0
  def testSplitNoteSequenceMultipleTimeChanges(self):
    # Tests splitting a NoteSequence on time changes, truncating notes on splits
    # that occur inside notes.
    sequence = common_testing_lib.parse_test_proto(
        music_pb2.NoteSequence,
        """
        time_signatures: {
          numerator: 4
          denominator: 4}
        time_signatures: {
          time: 2.0
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 60}
        tempos: {
          time: 4.25
          qpm: 80}""")
    testing_lib.add_track_to_sequence(
        sequence, 0,
        [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50),
         (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)])
    testing_lib.add_chords_to_sequence(
        sequence, [('C', 1.5), ('G7', 3.0), ('F', 4.8)])

    expected_subsequence_1 = common_testing_lib.parse_test_proto(
        music_pb2.NoteSequence,
        """
        time_signatures: {
          numerator: 4
          denominator: 4}
        tempos: {
          qpm: 60}""")
    testing_lib.add_track_to_sequence(
        expected_subsequence_1, 0,
        [(12, 100, 0.01, 2.0), (11, 55, 0.22, 0.50)])
    testing_lib.add_chords_to_sequence(
        expected_subsequence_1, [('C', 1.5)])
    expected_subsequence_1.total_time = 2.0
    expected_subsequence_1.subsequence_info.end_time_offset = 8.0

    expected_subsequence_2 = common_testing_lib.parse_test_proto(
        music_pb2.NoteSequence,
        """
        time_signatures: {
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 60}""")
    testing_lib.add_track_to_sequence(
        expected_subsequence_2, 0,
        [(40, 45, 0.50, 1.50), (55, 120, 2.0, 2.01)])
    testing_lib.add_chords_to_sequence(
        expected_subsequence_2, [('C', 0.0), ('G7', 1.0)])
    expected_subsequence_2.total_time = 2.01
    expected_subsequence_2.subsequence_info.start_time_offset = 2.0
    expected_subsequence_2.subsequence_info.end_time_offset = 5.99

    expected_subsequence_3 = common_testing_lib.parse_test_proto(
        music_pb2.NoteSequence,
        """
        time_signatures: {
          numerator: 3
          denominator: 4}
        tempos: {
          qpm: 80}""")
    testing_lib.add_track_to_sequence(
        expected_subsequence_3, 0,
        [(52, 99, 0.5, 0.75)])
    testing_lib.add_chords_to_sequence(
        expected_subsequence_3, [('G7', 0.0), ('F', 0.55)])
    expected_subsequence_3.total_time = 0.75
    expected_subsequence_3.subsequence_info.start_time_offset = 4.25
    expected_subsequence_3.subsequence_info.end_time_offset = 5.0

    subsequences = sequences_lib.split_note_sequence_on_time_changes(sequence)
    self.assertEquals(3, len(subsequences))
    self.assertProtoEquals(expected_subsequence_1, subsequences[0])
    self.assertProtoEquals(expected_subsequence_2, subsequences[1])
    self.assertProtoEquals(expected_subsequence_3, subsequences[2])