def testToNoteSequence(self): converter = data.TrioConverter(steps_per_quarter=1, slice_bars=2, max_tensors_per_notesequence=1) mel_oh = data.np_onehot(self.expected_sliced_labels[3][0], 90) bass_oh = data.np_onehot(self.expected_sliced_labels[3][1], 90) drums_oh = data.np_onehot(self.expected_sliced_labels[3][2], 512) output_tensors = np.concatenate([mel_oh, bass_oh, drums_oh], axis=-1) sequences = converter.to_notesequences([output_tensors]) self.assertEqual(1, len(sequences)) self.assertProtoEquals( """ ticks_per_quarter: 220 tempos < qpm: 120 > notes < instrument: 0 pitch: 52 start_time: 2.0 end_time: 4.0 program: 0 velocity: 80 > notes < instrument: 1 pitch: 50 start_time: 1.0 end_time: 2.5 program: 33 velocity: 80 > notes < instrument: 9 pitch: 36 start_time: 0.0 end_time: 0.5 velocity: 80 is_drum: True > notes < instrument: 9 pitch: 38 start_time: 2.0 end_time: 2.5 velocity: 80 is_drum: True > total_time: 4.0 """, sequences[0])
def _hierarchical_pad(input_, output, control): """Pad and flatten hierarchical inputs, outputs, and controls.""" # Pad empty segments with end tokens and flatten hierarchy. input_ = tf.nest.flatten( pad_with_element(input_, max_lengths[:-1], data.np_onehot([end_token], input_depth))) output = tf.nest.flatten( pad_with_element(output, max_lengths[:-1], data.np_onehot([end_token], output_depth))) length = np.squeeze(np.array([len(x) for x in input_], np.int32)) # Pad and concatenate flatten hierarchy. input_ = np.concatenate( [pad_with_value(x, max_lengths[-1], 0) for x in input_]) output = np.concatenate( [pad_with_value(x, max_lengths[-1], 0) for x in output]) if np.size(control): control = tf.nest.flatten( pad_with_element(control, max_lengths[:-1], data.np_onehot([control_pad_token], control_depth))) control = np.concatenate( [pad_with_value(x, max_lengths[-1], 0) for x in control]) return input_, output, control, length
def testToNoteSequence(self): converter = data.TrioConverter( steps_per_quarter=1, slice_bars=2, max_tensors_per_notesequence=1) mel_oh = data.np_onehot(self.expected_sliced_labels[3][0], 90) bass_oh = data.np_onehot(self.expected_sliced_labels[3][1], 90) drums_oh = data.np_onehot(self.expected_sliced_labels[3][2], 512) output_tensors = np.concatenate([mel_oh, bass_oh, drums_oh], axis=-1) sequences = converter.to_notesequences([output_tensors]) self.assertEqual(1, len(sequences)) self.assertProtoEquals( """ ticks_per_quarter: 220 tempos < qpm: 120 > notes < instrument: 0 pitch: 52 start_time: 2.0 end_time: 4.0 program: 0 velocity: 80 > notes < instrument: 1 pitch: 50 start_time: 1.0 end_time: 2.5 program: 33 velocity: 80 > notes < instrument: 9 pitch: 36 start_time: 0.0 end_time: 0.5 velocity: 80 is_drum: True > notes < instrument: 9 pitch: 38 start_time: 2.0 end_time: 2.5 velocity: 80 is_drum: True > total_time: 4.0 """, sequences[0])
def _hierarchical_pad(input_, output, control): """Pad and flatten hierarchical inputs, outputs, and controls.""" # Pad empty segments with end tokens and flatten hierarchy. input_ = nest.flatten(pad_with_element( input_, self._max_lengths[:-1], data.np_onehot([self.end_token], self.input_depth))) output = nest.flatten(pad_with_element( output, self._max_lengths[:-1], data.np_onehot([self.end_token], self.output_depth))) length = np.squeeze(np.array([len(x) for x in input_], np.int32)) # Pad and concatenate flatten hierarchy. input_ = np.concatenate( [pad_with_value(x, self._max_lengths[-1], 0) for x in input_]) output = np.concatenate( [pad_with_value(x, self._max_lengths[-1], 0) for x in output]) if np.size(control): control = nest.flatten(pad_with_element( control, self._max_lengths[:-1], data.np_onehot( [self._control_pad_token], self.control_depth))) control = np.concatenate( [pad_with_value(x, self._max_lengths[-1], 0) for x in control]) return input_, output, control, length
def testToNoteSequenceChordConditioned(self): converter = data.TrioConverter( steps_per_quarter=1, slice_bars=2, max_tensors_per_notesequence=1, chord_encoding=mm.MajorMinorChordOneHotEncoding()) mel_oh = data.np_onehot(self.expected_sliced_labels[3][0], 90) bass_oh = data.np_onehot(self.expected_sliced_labels[3][1], 90) drums_oh = data.np_onehot(self.expected_sliced_labels[3][2], 512) chords_oh = data.np_onehot(self.expected_sliced_chord_labels[3], 25) output_tensors = np.concatenate([mel_oh, bass_oh, drums_oh], axis=-1) sequences = converter.to_notesequences([output_tensors], [chords_oh]) self.assertEqual(1, len(sequences)) self.assertProtoEquals( """ ticks_per_quarter: 220 tempos < qpm: 120 > notes < instrument: 0 pitch: 52 start_time: 2.0 end_time: 4.0 program: 0 velocity: 80 > notes < instrument: 1 pitch: 50 start_time: 1.0 end_time: 2.5 program: 33 velocity: 80 > notes < instrument: 9 pitch: 36 start_time: 0.0 end_time: 0.5 velocity: 80 is_drum: True > notes < instrument: 9 pitch: 38 start_time: 2.0 end_time: 2.5 velocity: 80 is_drum: True > text_annotations < text: 'N.C.' annotation_type: CHORD_SYMBOL > text_annotations < time: 2.0 text: 'C' annotation_type: CHORD_SYMBOL > total_time: 4.0 """, sequences[0])
def _quantized_subsequence_to_tensors(self, quantized_subsequence): # Reject sequences with out-of-range pitches. if any(note.pitch < self._min_pitch or note.pitch > self._max_pitch for note in quantized_subsequence.notes): return [], [] # Extract all instruments. tracks, _ = performance_pipeline.extract_performances( quantized_subsequence, max_steps_truncate=self._max_steps_truncate, num_velocity_bins=self._num_velocity_bins, split_instruments=True) # Reject sequences with too few instruments. if not (self._min_num_instruments <= len(tracks) <= self._max_num_instruments): return [], [] # Sort tracks by program, with drums at the end. tracks = sorted(tracks, key=lambda t: (t.is_drum, t.program)) chunk_size_steps = self._steps_per_bar * self._chunk_size_bars chunks = [[] for _ in range(self._max_num_chunks)] total_length = 0 for track in tracks: # Make sure the track is the proper number of time steps. track.set_length(self._max_steps_truncate) # Split this track into chunks. def new_performance(quantized_sequence, start_step, track=track): steps_per_quarter = ( self._steps_per_quarter if quantized_sequence is None else None) return performance_lib.MetricPerformance( quantized_sequence=quantized_sequence, steps_per_quarter=steps_per_quarter, start_step=start_step, num_velocity_bins=self._num_velocity_bins, program=track.program, is_drum=track.is_drum) track_chunks = split_performance( track, chunk_size_steps, new_performance, clip_tied_notes=True) assert len(track_chunks) == self._max_num_chunks track_chunk_lengths = [len(track_chunk) for track_chunk in track_chunks] # Each track chunk needs room for program token and end token. if not all(l <= self._max_events_per_instrument - 2 for l in track_chunk_lengths): return [], [] if not all( note_seq.MIN_MIDI_PROGRAM <= t.program <= note_seq.MAX_MIDI_PROGRAM for t in track_chunks if not t.is_drum): return [], [] total_length += sum(track_chunk_lengths) # Aggregate by chunk. for i, track_chunk in enumerate(track_chunks): chunks[i].append(track_chunk) # Reject sequences that are too short (in events). if total_length < self._min_total_events: return [], [] num_programs = note_seq.MAX_MIDI_PROGRAM - note_seq.MIN_MIDI_PROGRAM + 1 chunk_tensors = [] chunk_chord_tensors = [] for chunk_tracks in chunks: track_tensors = [] for track in chunk_tracks: # Add a special token for program at the beginning of each track. track_tokens = [self._performance_encoding.num_classes + ( num_programs if track.is_drum else track.program)] # Then encode the performance events. for event in track: track_tokens.append(self._performance_encoding.encode_event(event)) # Then add the end token. track_tokens.append(self.end_token) encoded_track = data.np_onehot( track_tokens, self.output_depth, self.output_dtype) track_tensors.append(encoded_track) if self._chord_encoding: # Extract corresponding chords for each track. The chord sequences may # be different for different tracks even though the underlying chords # are the same, as the performance event times will generally be # different. try: track_chords = chords_lib.event_list_chords( quantized_subsequence, chunk_tracks) except chords_lib.CoincidentChordsError: return [], [] track_chord_tensors = [] try: # Chord encoding for all tracks is inside this try block. If any # track fails we need to skip the whole subsequence. for chords in track_chords: # Start with a pad token corresponding to the track program token. track_chord_tokens = [self._control_pad_token] # Then encode the chords. for chord in chords: track_chord_tokens.append( self._chord_encoding.encode_event(chord)) # Then repeat the final chord for the track end token. track_chord_tokens.append(track_chord_tokens[-1]) encoded_track_chords = data.np_onehot( track_chord_tokens, self.control_depth, self.control_dtype) track_chord_tensors.append(encoded_track_chords) except (note_seq.ChordSymbolError, note_seq.ChordEncodingError): return [], [] chunk_chord_tensors.append(track_chord_tensors) chunk_tensors.append(track_tensors) return chunk_tensors, chunk_chord_tensors
def labels_to_inputs(self, labels, converter): return [data.np_onehot(l, converter.input_depth, converter.input_dtype) for l in labels]
def labels_to_inputs(self, labels, converter): return [ data.np_onehot(l, converter.input_depth, converter.input_dtype) for l in labels ]
def _quantized_subsequence_to_tensors(self, quantized_subsequence): # Reject sequences with out-of-range pitches. if any(note.pitch < self._min_pitch or note.pitch > self._max_pitch for note in quantized_subsequence.notes): return [], [] # Extract all instruments. tracks, _ = mm.extract_performances( quantized_subsequence, max_steps_truncate=self._max_steps_truncate, num_velocity_bins=self._num_velocity_bins, split_instruments=True) # Reject sequences with too few instruments. if not (self._min_num_instruments <= len(tracks) <= self._max_num_instruments): return [], [] # Sort tracks by program, with drums at the end. tracks = sorted(tracks, key=lambda t: (t.is_drum, t.program)) chunk_size_steps = self._steps_per_bar * self._chunk_size_bars chunks = [[] for _ in range(self._max_num_chunks)] total_length = 0 for track in tracks: # Make sure the track is the proper number of time steps. track.set_length(self._max_steps_truncate) # Split this track into chunks. def new_performance(quantized_sequence, start_step, track=track): steps_per_quarter = ( self._steps_per_quarter if quantized_sequence is None else None) return performance_lib.MetricPerformance( quantized_sequence=quantized_sequence, steps_per_quarter=steps_per_quarter, start_step=start_step, num_velocity_bins=self._num_velocity_bins, program=track.program, is_drum=track.is_drum) track_chunks = split_performance( track, chunk_size_steps, new_performance, clip_tied_notes=True) assert len(track_chunks) == self._max_num_chunks track_chunk_lengths = [len(track_chunk) for track_chunk in track_chunks] # Each track chunk needs room for program token and end token. if not all(l <= self._max_events_per_instrument - 2 for l in track_chunk_lengths): return [], [] if not all(mm.MIN_MIDI_PROGRAM <= t.program <= mm.MAX_MIDI_PROGRAM for t in track_chunks if not t.is_drum): return [], [] total_length += sum(track_chunk_lengths) # Aggregate by chunk. for i, track_chunk in enumerate(track_chunks): chunks[i].append(track_chunk) # Reject sequences that are too short (in events). if total_length < self._min_total_events: return [], [] num_programs = mm.MAX_MIDI_PROGRAM - mm.MIN_MIDI_PROGRAM + 1 chunk_tensors = [] chunk_chord_tensors = [] for chunk_tracks in chunks: track_tensors = [] for track in chunk_tracks: # Add a special token for program at the beginning of each track. track_tokens = [self._performance_encoding.num_classes + ( num_programs if track.is_drum else track.program)] # Then encode the performance events. for event in track: track_tokens.append(self._performance_encoding.encode_event(event)) # Then add the end token. track_tokens.append(self.end_token) encoded_track = data.np_onehot( track_tokens, self.output_depth, self.output_dtype) track_tensors.append(encoded_track) if self._chord_encoding: # Extract corresponding chords for each track. The chord sequences may # be different for different tracks even though the underlying chords # are the same, as the performance event times will generally be # different. try: track_chords = chords_lib.event_list_chords( quantized_subsequence, chunk_tracks) except chords_lib.CoincidentChordsError: return [], [] track_chord_tensors = [] try: # Chord encoding for all tracks is inside this try block. If any # track fails we need to skip the whole subsequence. for chords in track_chords: # Start with a pad token corresponding to the track program token. track_chord_tokens = [self._control_pad_token] # Then encode the chords. for chord in chords: track_chord_tokens.append( self._chord_encoding.encode_event(chord)) # Then repeat the final chord for the track end token. track_chord_tokens.append(track_chord_tokens[-1]) encoded_track_chords = data.np_onehot( track_chord_tokens, self.control_depth, self.control_dtype) track_chord_tensors.append(encoded_track_chords) except (mm.ChordSymbolError, mm.ChordEncodingError): return [], [] chunk_chord_tensors.append(track_chord_tensors) chunk_tensors.append(track_tensors) return chunk_tensors, chunk_chord_tensors