def to_tensors(self, item): """Converts to tensors and adds hierarchical padding, if needed.""" tensors = self._to_tensors(item) sampled_results = data.maybe_sample_items(list(zip(*tensors)), self.max_tensors_per_item, self.is_training) if sampled_results: unpadded_results = data.ConverterTensors(*zip(*sampled_results)) else: unpadded_results = data.ConverterTensors() if not self._max_lengths: return unpadded_results # TODO(iansimon): The way control tensors are set in ConverterTensors is # ugly when using a hierarchical converter. Figure out how to clean this up. 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 padded_results = [] for i, o, c, _ in zip(*unpadded_results): try: padded_results.append(_hierarchical_pad(i, o, c)) except TooLongError: continue if padded_results: return data.ConverterTensors(*zip(*padded_results)) else: return data.ConverterTensors()
def _to_tensors_fn(self, note_sequence): # Performance sequences require sustain to be correctly interpreted. note_sequence = note_seq.apply_sustain_control_changes(note_sequence) if self._chord_encoding and not any( ta.annotation_type == CHORD_SYMBOL for ta in note_sequence.text_annotations): try: # Quantize just for the purpose of chord inference. # TODO(iansimon): Allow chord inference in unquantized sequences. quantized_sequence = note_seq.quantize_note_sequence( note_sequence, self._steps_per_quarter) if (note_seq.steps_per_bar_in_quantized_sequence(quantized_sequence) != self._steps_per_bar): return data.ConverterTensors() # Infer chords in quantized sequence. note_seq.infer_chords_for_sequence(quantized_sequence) except (note_seq.BadTimeSignatureError, note_seq.NonIntegerStepsPerBarError, note_seq.NegativeTimeError, note_seq.ChordInferenceError): return data.ConverterTensors() # Copy inferred chords back to original sequence. for qta in quantized_sequence.text_annotations: if qta.annotation_type == CHORD_SYMBOL: ta = note_sequence.text_annotations.add() ta.annotation_type = CHORD_SYMBOL ta.time = qta.time ta.text = qta.text if note_sequence.tempos: quarters_per_minute = note_sequence.tempos[0].qpm else: quarters_per_minute = note_seq.DEFAULT_QUARTERS_PER_MINUTE quarters_per_bar = self._steps_per_bar / self._steps_per_quarter hop_size_quarters = quarters_per_bar * self._hop_size_bars hop_size_seconds = 60.0 * hop_size_quarters / quarters_per_minute # Split note sequence by bar hop size (in seconds). subsequences = note_seq.split_note_sequence(note_sequence, hop_size_seconds) if self._first_subsequence_only and len(subsequences) > 1: return data.ConverterTensors() sequence_tensors = [] sequence_chord_tensors = [] for subsequence in subsequences: # Quantize this subsequence. try: quantized_subsequence = note_seq.quantize_note_sequence( subsequence, self._steps_per_quarter) if (note_seq.steps_per_bar_in_quantized_sequence(quantized_subsequence) != self._steps_per_bar): return data.ConverterTensors() except (note_seq.BadTimeSignatureError, note_seq.NonIntegerStepsPerBarError, note_seq.NegativeTimeError): return data.ConverterTensors() # Convert the quantized subsequence to tensors. tensors, chord_tensors = self._quantized_subsequence_to_tensors( quantized_subsequence) if tensors: sequence_tensors.append(tensors) if self._chord_encoding: sequence_chord_tensors.append(chord_tensors) tensors = data.ConverterTensors( inputs=sequence_tensors, outputs=sequence_tensors, controls=sequence_chord_tensors) return hierarchical_pad_tensors(tensors, self.max_tensors_per_notesequence, self.is_training, self._max_lengths, self.end_token, self.input_depth, self.output_depth, self.control_depth, self._control_pad_token)