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)
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise sequence_generator.SequenceGeneratorError( 'This model supports at most one input_sections message, but got %s' % len(generator_options.input_sections)) if len(generator_options.generate_sections) != 1: raise sequence_generator.SequenceGeneratorError( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) if input_sequence and input_sequence.tempos: qpm = input_sequence.tempos[0].qpm else: qpm = note_seq.DEFAULT_QUARTERS_PER_MINUTE steps_per_second = note_seq.steps_per_quarter_to_steps_per_second( self.steps_per_quarter, qpm) generate_section = generator_options.generate_sections[0] if generator_options.input_sections: input_section = generator_options.input_sections[0] primer_sequence = note_seq.trim_note_sequence(input_sequence, input_section.start_time, input_section.end_time) input_start_step = note_seq.quantize_to_step( input_section.start_time, steps_per_second, quantize_cutoff=0) else: primer_sequence = input_sequence input_start_step = 0 if primer_sequence.notes: last_end_time = max(n.end_time for n in primer_sequence.notes) else: last_end_time = 0 if last_end_time > generate_section.start_time: raise sequence_generator.SequenceGeneratorError( 'Got GenerateSection request for section that is before the end of ' 'the NoteSequence. This model can only extend sequences. Requested ' 'start time: %s, Final note end time: %s' % (generate_section.start_time, last_end_time)) # Quantize the priming sequence. quantized_sequence = note_seq.quantize_note_sequence( primer_sequence, self.steps_per_quarter) # Setting gap_bars to infinite ensures that the entire input will be used. extracted_melodies, _ = melody_pipelines.extract_melodies( quantized_sequence, search_start_step=input_start_step, min_bars=0, min_unique_pitches=1, gap_bars=float('inf'), ignore_polyphonic_notes=True) assert len(extracted_melodies) <= 1 start_step = note_seq.quantize_to_step( generate_section.start_time, steps_per_second, quantize_cutoff=0) # Note that when quantizing end_step, we set quantize_cutoff to 1.0 so it # always rounds down. This avoids generating a sequence that ends at 5.0 # seconds when the requested end time is 4.99. end_step = note_seq.quantize_to_step( generate_section.end_time, steps_per_second, quantize_cutoff=1.0) if extracted_melodies and extracted_melodies[0]: melody = extracted_melodies[0] else: # If no melody could be extracted, create an empty melody that starts 1 # step before the request start_step. This will result in 1 step of # silence when the melody is extended below. steps_per_bar = int( note_seq.steps_per_bar_in_quantized_sequence(quantized_sequence)) melody = note_seq.Melody([], start_step=max(0, start_step - 1), steps_per_bar=steps_per_bar, steps_per_quarter=self.steps_per_quarter) # Ensure that the melody extends up to the step we want to start generating. melody.set_length(start_step - melody.start_step) # Extract generation arguments from generator options. arg_types = { 'temperature': lambda arg: arg.float_value, 'beam_size': lambda arg: arg.int_value, 'branch_factor': lambda arg: arg.int_value, 'steps_per_iteration': lambda arg: arg.int_value } args = dict((name, value_fn(generator_options.args[name])) for name, value_fn in arg_types.items() if name in generator_options.args) generated_melody = self._model.generate_melody( end_step - melody.start_step, melody, **args) generated_sequence = generated_melody.to_sequence(qpm=qpm) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence