def _generate(self, gen_index, input_sequence, zero_time, response_start_time, response_end_time): # pylint: disable-msg=no-member response_start_time -= zero_time response_end_time -= zero_time generator_options = GeneratorOptions() generator_options.input_sections.add(start_time=0, end_time=response_start_time) generator_options.generate_sections.add(start_time=response_start_time, end_time=response_end_time) # Set current temperature setting. generator_options.args["temperature"].float_value = self._temperature # Generate response. generator = self._sequence_generators[gen_index] logging.warn("Generating sequence using '{}' generator.".format( generator.details.id)) # logging.warn("\tGenerator Details:\t{}".format(generator.details)) # logging.warn("\tBundle Details:\t{}".format(generator.bundle_details)) # logging.warn("\tGenerator Options:\t{}".format(generator_options)) response_sequence = generator.generate( adjust_sequence_times(input_sequence, -zero_time), generator_options) response_sequence = trim_note_sequence(response_sequence, response_start_time, response_end_time) return adjust_sequence_times(response_sequence, zero_time)
def generateNewSequence(input_sequence, temperature, write_to_file): input_sequence = mm.quantize_note_sequence(input_sequence, 8) bundle = sequence_generator_bundle.read_bundle_file( '/Library/Application Support/Quin Scacheri/Magenta Beats/drum_kit_rnn.mag' ) generator_map = drums_rnn_sequence_generator.get_generator_map() drum_rnn = generator_map['drum_kit'](checkpoint=None, bundle=bundle) drum_rnn.initialize() qpm = input_sequence.tempos[0].qpm last_end_time = (max( n.end_time for n in input_sequence.notes) if input_sequence.notes else 0) # total_seconds = num_steps * input_sequence.quantization_info.steps_per_quarter; generator_options = generator_pb2.GeneratorOptions() generator_options.args['temperature'].float_value = temperature generate_section = generator_options.generate_sections.add( start_time=last_end_time, end_time=8.0) new_sequence = drum_rnn.generate(input_sequence, generator_options) new_sequence = mm.trim_note_sequence(new_sequence, 2.0, 4.0) new_sequence = mm.quantize_note_sequence(new_sequence, 4) # # new_sequence.quantization_info.steps_per_quarter = 8 if (True): mm.sequence_proto_to_midi_file(input_sequence, 'primer.mid') mm.sequence_proto_to_midi_file(new_sequence, 'new_sequence.mid') return new_sequence
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.SequenceGeneratorException('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 mm.SequenceGeneratorException('This model supports only 1 generate_sections message, but got %s' %len(generator_options.generate_sections)) qpm = (input_sequence.tempos[0].qpm if input_sequence and input_sequence.tempos else mm.DEFAULT_QUARTERS_PER_MINUTE) steps_per_second = mm.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 = mm.trim_note_sequence(input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.quantize_to_step(input_section.start_time, steps_per_second, quantize_cutoff=0) else: primer_sequence = input_sequence input_start_step = 0 last_end_time = (max(n.end_time for n in primer_sequence.notes) if primer_sequence.notes else 0) if last_end_time > generate_section.start_time: raise mm.SequenceGeneratorException('start time: %s, Final note end time: %s' % (generate_section.start_time, last_end_time)) quantized_sequence = mm.quantize_note_sequence(primer_sequence, self.steps_per_quarter) extracted_melodies, _ = mm.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 = mm.quantize_to_step( generate_section.start_time, steps_per_second, quantize_cutoff=0) end_step = mm.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: steps_per_bar = int(mm.steps_per_bar_in_quantized_sequence(quantized_sequence)) melody = mm.Melody([],start_step=max(0, start_step - 1),steps_per_bar=steps_per_bar,steps_per_quarter=self.steps_per_quarter) melody.set_length(start_step - melody.start_step) 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
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.SequenceGeneratorException( '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 mm.SequenceGeneratorException( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) qpm = (input_sequence.tempos[0].qpm if input_sequence and input_sequence.tempos else mm.DEFAULT_QUARTERS_PER_MINUTE) steps_per_second = mm.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 = mm.trim_note_sequence( input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.quantize_to_step( input_section.start_time, steps_per_second, quantize_cutoff=0) else: primer_sequence = input_sequence input_start_step = 0 last_end_time = (max(n.end_time for n in primer_sequence.notes) if primer_sequence.notes else 0) if last_end_time > generate_section.start_time: raise mm.SequenceGeneratorException( '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 = mm.quantize_note_sequence( primer_sequence, self.steps_per_quarter) # Setting gap_bars to infinite ensures that the entire input will be used. extracted_melodies, _ = mm.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 = mm.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 = mm.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( mm.steps_per_bar_in_quantized_sequence(quantized_sequence)) melody = mm.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
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 = mm.DEFAULT_QUARTERS_PER_MINUTE steps_per_second = mm.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 = mm.trim_note_sequence(input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.quantize_to_step(input_section.start_time, steps_per_second, quantize_cutoff=0.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 = mm.quantize_note_sequence(primer_sequence, self.steps_per_quarter) # Setting gap_bars to infinite ensures that the entire input will be used. extracted_drum_tracks, _ = drum_pipelines.extract_drum_tracks( quantized_sequence, search_start_step=input_start_step, min_bars=0, gap_bars=float('inf'), ignore_is_drum=True) assert len(extracted_drum_tracks) <= 1 start_step = mm.quantize_to_step(generate_section.start_time, steps_per_second, quantize_cutoff=0.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 = mm.quantize_to_step(generate_section.end_time, steps_per_second, quantize_cutoff=1.0) if extracted_drum_tracks and extracted_drum_tracks[0]: drums = extracted_drum_tracks[0] else: # If no drum track could be extracted, create an empty drum track that # starts 1 step before the request start_step. This will result in 1 step # of silence when the drum track is extended below. steps_per_bar = int( mm.steps_per_bar_in_quantized_sequence(quantized_sequence)) drums = mm.DrumTrack([], start_step=max(0, start_step - 1), steps_per_bar=steps_per_bar, steps_per_quarter=self.steps_per_quarter) # Ensure that the drum track extends up to the step we want to start # generating. drums.set_length(start_step - drums.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_drums = self._model.generate_drum_track( end_step - drums.start_step, drums, **args) generated_sequence = generated_drums.to_sequence(qpm=qpm) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.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 mm.SequenceGeneratorError( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) # This sequence will be quantized later, so it is guaranteed to have only 1 # tempo. qpm = mm.DEFAULT_QUARTERS_PER_MINUTE if input_sequence.tempos: qpm = input_sequence.tempos[0].qpm steps_per_second = mm.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 = mm.trim_note_sequence( input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.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 mm.SequenceGeneratorError( 'Got GenerateSection request for section that is before or equal to ' '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_primer_sequence = mm.quantize_note_sequence( primer_sequence, self.steps_per_quarter) extracted_seqs, _ = mm.extract_pianoroll_sequences( quantized_primer_sequence, start_step=input_start_step) assert len(extracted_seqs) <= 1 generate_start_step = mm.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. generate_end_step = mm.quantize_to_step( generate_section.end_time, steps_per_second, quantize_cutoff=1.0) if extracted_seqs and extracted_seqs[0]: pianoroll_seq = extracted_seqs[0] else: raise ValueError('No priming pianoroll could be extracted.') # Ensure that the track extends up to the step we want to start generating. pianoroll_seq.set_length(generate_start_step - pianoroll_seq.start_step) # Extract generation arguments from generator options. arg_types = { 'beam_size': lambda arg: arg.int_value, 'branch_factor': 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) total_steps = pianoroll_seq.num_steps + ( generate_end_step - generate_start_step) pianoroll_seq = self._model.generate_pianoroll_sequence( total_steps, pianoroll_seq, **args) pianoroll_seq.set_length(total_steps) generated_sequence = pianoroll_seq.to_sequence(qpm=qpm) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
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)) # This sequence will be quantized later, so it is guaranteed to have only 1 # tempo. qpm = mm.DEFAULT_QUARTERS_PER_MINUTE if input_sequence.tempos: qpm = input_sequence.tempos[0].qpm steps_per_second = mm.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 = mm.trim_note_sequence(input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.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 or equal to ' '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_primer_sequence = mm.quantize_note_sequence( primer_sequence, self.steps_per_quarter) extracted_seqs, _ = polyphony_lib.extract_polyphonic_sequences( quantized_primer_sequence, start_step=input_start_step) assert len(extracted_seqs) <= 1 generate_start_step = mm.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. generate_end_step = mm.quantize_to_step(generate_section.end_time, steps_per_second, quantize_cutoff=1.0) if extracted_seqs and extracted_seqs[0]: poly_seq = extracted_seqs[0] else: # If no track could be extracted, create an empty track that starts at the # requested generate_start_step. This will result in a sequence that # contains only the START token. poly_seq = polyphony_lib.PolyphonicSequence( steps_per_quarter=(quantized_primer_sequence.quantization_info. steps_per_quarter), start_step=generate_start_step) # Ensure that the track extends up to the step we want to start generating. poly_seq.set_length(generate_start_step - poly_seq.start_step) # Trim any trailing end events to prepare the sequence for more events to be # appended during generation. poly_seq.trim_trailing_end_events() # 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) # Inject the priming sequence as melody in the output of the generator, if # requested. # This option starts with no_ so that if it is unspecified (as will be the # case when used with the midi interface), the default will be to inject the # primer. if not (generator_options.args['no_inject_primer_during_generation']. bool_value): melody_to_inject = copy.deepcopy(poly_seq) if generator_options.args['condition_on_primer'].bool_value: inject_start_step = poly_seq.num_steps else: # 0 steps because we'll overwrite poly_seq with a blank sequence below. inject_start_step = 0 args['modify_events_callback'] = functools.partial( _inject_melody, melody_to_inject, inject_start_step) # If we don't want to condition on the priming sequence, then overwrite # poly_seq with a blank sequence to feed into the generator. if not generator_options.args['condition_on_primer'].bool_value: poly_seq = polyphony_lib.PolyphonicSequence( steps_per_quarter=(quantized_primer_sequence.quantization_info. steps_per_quarter), start_step=generate_start_step) poly_seq.trim_trailing_end_events() total_steps = poly_seq.num_steps + (generate_end_step - generate_start_step) while poly_seq.num_steps < total_steps: # Assume it takes ~5 rnn steps to generate one quantized step. # Can't know for sure until generation is finished because the number of # notes per quantized step is variable. steps_to_gen = total_steps - poly_seq.num_steps rnn_steps_to_gen = 5 * steps_to_gen tf.logging.info( 'Need to generate %d more steps for this sequence, will try asking ' 'for %d RNN steps' % (steps_to_gen, rnn_steps_to_gen)) poly_seq = self._model.generate_polyphonic_sequence( len(poly_seq) + rnn_steps_to_gen, poly_seq, **args) poly_seq.set_length(total_steps) if generator_options.args['condition_on_primer'].bool_value: generated_sequence = poly_seq.to_sequence(qpm=qpm) else: # Specify a base_note_sequence because the priming sequence was not # included in poly_seq. generated_sequence = poly_seq.to_sequence( qpm=qpm, base_note_sequence=copy.deepcopy(primer_sequence)) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.SequenceGeneratorException( '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 mm.SequenceGeneratorException( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) qpm = (input_sequence.tempos[0].qpm if input_sequence and input_sequence.tempos else mm.DEFAULT_QUARTERS_PER_MINUTE) generate_section = generator_options.generate_sections[0] if generator_options.input_sections: input_section = generator_options.input_sections[0] primer_sequence = mm.trim_note_sequence( input_sequence, input_section.start_time, input_section.end_time) input_start_step = self.seconds_to_steps(input_section.start_time, qpm) else: primer_sequence = input_sequence input_start_step = 0 last_end_time = (max(n.end_time for n in primer_sequence.notes) if primer_sequence.notes else 0) if last_end_time > generate_section.start_time: raise mm.SequenceGeneratorException( '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 = mm.quantize_note_sequence( primer_sequence, self.steps_per_quarter) # Setting gap_bars to infinite ensures that the entire input will be used. extracted_drum_tracks, _ = mm.extract_drum_tracks( quantized_sequence, search_start_step=input_start_step, min_bars=0, gap_bars=float('inf')) assert len(extracted_drum_tracks) <= 1 start_step = self.seconds_to_steps( generate_section.start_time, qpm) end_step = self.seconds_to_steps(generate_section.end_time, qpm) if extracted_drum_tracks and extracted_drum_tracks[0]: drums = extracted_drum_tracks[0] else: # If no drum track could be extracted, create an empty drum track that # starts 1 step before the request start_step. This will result in 1 step # of silence when the drum track is extended below. drums = mm.DrumTrack([], start_step=max(0, start_step - 1)) # Ensure that the drum track extends up to the step we want to start # generating. drums.set_length(start_step - drums.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_drums = self._model.generate_drum_track( end_step - drums.start_step, drums, **args) generated_sequence = generated_drums.to_sequence(qpm=qpm) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.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 mm.SequenceGeneratorError( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) generate_section = generator_options.generate_sections[0] if generator_options.input_sections: input_section = generator_options.input_sections[0] primer_sequence = mm.trim_note_sequence( input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.quantize_to_step( input_section.start_time, self.steps_per_second, quantize_cutoff=0.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 mm.SequenceGeneratorError( 'Got GenerateSection request for section that is before or equal to ' '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_primer_sequence = mm.quantize_note_sequence_absolute( primer_sequence, self.steps_per_second) extracted_perfs, _ = mm.extract_performances( quantized_primer_sequence, start_step=input_start_step, num_velocity_bins=self.num_velocity_bins, note_performance=self._note_performance) assert len(extracted_perfs) <= 1 generate_start_step = mm.quantize_to_step( generate_section.start_time, self.steps_per_second, quantize_cutoff=0.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. generate_end_step = mm.quantize_to_step( generate_section.end_time, self.steps_per_second, quantize_cutoff=1.0) if extracted_perfs and extracted_perfs[0]: performance = extracted_perfs[0] else: # If no track could be extracted, create an empty track that starts at the # requested generate_start_step. performance = mm.Performance( steps_per_second=( quantized_primer_sequence.quantization_info.steps_per_second), start_step=generate_start_step, num_velocity_bins=self.num_velocity_bins) # Ensure that the track extends up to the step we want to start generating. performance.set_length(generate_start_step - performance.start_step) # Extract generation arguments from generator options. arg_types = { 'disable_conditioning': lambda arg: ast.literal_eval(arg.string_value), '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 } if self.control_signals: for control in self.control_signals: arg_types[control.name] = lambda arg: ast.literal_eval(arg.string_value) args = dict((name, value_fn(generator_options.args[name])) for name, value_fn in arg_types.items() if name in generator_options.args) # Make sure control signals are present and convert to lists if necessary. if self.control_signals: for control in self.control_signals: if control.name not in args: tf.logging.warning( 'Control value not specified, using default: %s = %s', control.name, control.default_value) args[control.name] = [control.default_value] elif control.validate(args[control.name]): args[control.name] = [args[control.name]] else: if not isinstance(args[control.name], list) or not all( control.validate(value) for value in args[control.name]): tf.logging.fatal( 'Invalid control value: %s = %s', control.name, args[control.name]) # Make sure disable conditioning flag is present when conditioning is # optional and convert to list if necessary. if self.optional_conditioning: if 'disable_conditioning' not in args: args['disable_conditioning'] = [False] elif isinstance(args['disable_conditioning'], bool): args['disable_conditioning'] = [args['disable_conditioning']] else: if not isinstance(args['disable_conditioning'], list) or not all( isinstance(value, bool) for value in args['disable_conditioning']): tf.logging.fatal( 'Invalid disable_conditioning value: %s', args['disable_conditioning']) total_steps = performance.num_steps + ( generate_end_step - generate_start_step) if 'notes_per_second' in args: mean_note_density = ( sum(args['notes_per_second']) / len(args['notes_per_second'])) else: mean_note_density = DEFAULT_NOTE_DENSITY # Set up functions that map generation step to control signal values and # disable conditioning flag. if self.control_signals: control_signal_fns = [] for control in self.control_signals: control_signal_fns.append(functools.partial( _step_to_value, num_steps=total_steps, values=args[control.name])) del args[control.name] args['control_signal_fns'] = control_signal_fns if self.optional_conditioning: args['disable_conditioning_fn'] = functools.partial( _step_to_value, num_steps=total_steps, values=args['disable_conditioning']) del args['disable_conditioning'] if not performance: # Primer is empty; let's just start with silence. performance.set_length(min(performance.max_shift_steps, total_steps)) while performance.num_steps < total_steps: # Assume the average specified (or default) note density and 4 RNN steps # per note. Can't know for sure until generation is finished because the # number of notes per quantized step is variable. note_density = max(1.0, mean_note_density) steps_to_gen = total_steps - performance.num_steps rnn_steps_to_gen = int(math.ceil( 4.0 * note_density * steps_to_gen / self.steps_per_second)) tf.logging.info( 'Need to generate %d more steps for this sequence, will try asking ' 'for %d RNN steps' % (steps_to_gen, rnn_steps_to_gen)) performance = self._model.generate_performance( len(performance) + rnn_steps_to_gen, performance, **args) if not self.fill_generate_section: # In the interest of speed just go through this loop once, which may not # entirely fill the generate section. break performance.set_length(total_steps) generated_sequence = performance.to_sequence( max_note_duration=self.max_note_duration) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.SequenceGeneratorException( '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 mm.SequenceGeneratorException( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) # This sequence will be quantized later, so it is guaranteed to have only 1 # tempo. qpm = mm.DEFAULT_QUARTERS_PER_MINUTE if input_sequence.tempos: qpm = input_sequence.tempos[0].qpm steps_per_second = mm.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 = mm.trim_note_sequence( input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.quantize_to_step( input_section.start_time, steps_per_second, quantize_cutoff=0) else: primer_sequence = input_sequence input_start_step = 0 last_end_time = (max(n.end_time for n in primer_sequence.notes) if primer_sequence.notes else 0) if last_end_time > generate_section.start_time: raise mm.SequenceGeneratorException( 'Got GenerateSection request for section that is before or equal to ' '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_primer_sequence = mm.quantize_note_sequence( primer_sequence, self.steps_per_quarter) extracted_seqs, _ = polyphony_lib.extract_polyphonic_sequences( quantized_primer_sequence, start_step=input_start_step) assert len(extracted_seqs) <= 1 generate_start_step = mm.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. generate_end_step = mm.quantize_to_step( generate_section.end_time, steps_per_second, quantize_cutoff=1.0) if extracted_seqs and extracted_seqs[0]: poly_seq = extracted_seqs[0] else: # If no track could be extracted, create an empty track that starts at the # requested generate_start_step. This will result in a sequence that # contains only the START token. poly_seq = polyphony_lib.PolyphonicSequence( steps_per_quarter=( quantized_primer_sequence.quantization_info.steps_per_quarter), start_step=generate_start_step) # Ensure that the track extends up to the step we want to start generating. poly_seq.set_length(generate_start_step - poly_seq.start_step) # Trim any trailing end events to prepare the sequence for more events to be # appended during generation. poly_seq.trim_trailing_end_events() # 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) # Inject the priming sequence as melody in the output of the generator, if # requested. # This option starts with no_ so that if it is unspecified (as will be the # case when used with the midi interface), the default will be to inject the # primer. if not (generator_options.args[ 'no_inject_primer_during_generation'].bool_value): melody_to_inject = copy.deepcopy(poly_seq) if generator_options.args['condition_on_primer'].bool_value: inject_start_step = poly_seq.num_steps else: # 0 steps because we'll overwrite poly_seq with a blank sequence below. inject_start_step = 0 args['modify_events_callback'] = partial( _inject_melody, melody_to_inject, inject_start_step) # If we don't want to condition on the priming sequence, then overwrite # poly_seq with a blank sequence to feed into the generator. if not generator_options.args['condition_on_primer'].bool_value: poly_seq = polyphony_lib.PolyphonicSequence( steps_per_quarter=( quantized_primer_sequence.quantization_info.steps_per_quarter), start_step=generate_start_step) poly_seq.trim_trailing_end_events() total_steps = poly_seq.num_steps + ( generate_end_step - generate_start_step) while poly_seq.num_steps < total_steps: # Assume it takes ~5 rnn steps to generate one quantized step. # Can't know for sure until generation is finished because the number of # notes per quantized step is variable. steps_to_gen = total_steps - poly_seq.num_steps rnn_steps_to_gen = 5 * steps_to_gen tf.logging.info( 'Need to generate %d more steps for this sequence, will try asking ' 'for %d RNN steps' % (steps_to_gen, rnn_steps_to_gen)) poly_seq = self._model.generate_polyphonic_sequence( len(poly_seq) + rnn_steps_to_gen, poly_seq, **args) poly_seq.set_length(total_steps) if generator_options.args['condition_on_primer'].bool_value: generated_sequence = poly_seq.to_sequence(qpm=qpm) else: # Specify a base_note_sequence because the priming sequence was not # included in poly_seq. generated_sequence = poly_seq.to_sequence( qpm=qpm, base_note_sequence=copy.deepcopy(primer_sequence)) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.SequenceGeneratorException( '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 mm.SequenceGeneratorException( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) generate_section = generator_options.generate_sections[0] if generator_options.input_sections: input_section = generator_options.input_sections[0] primer_sequence = mm.trim_note_sequence(input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.quantize_to_step(input_section.start_time, self.steps_per_second, quantize_cutoff=0.0) else: primer_sequence = input_sequence input_start_step = 0 last_end_time = (max( n.end_time for n in primer_sequence.notes) if primer_sequence.notes else 0) if last_end_time > generate_section.start_time: raise mm.SequenceGeneratorException( 'Got GenerateSection request for section that is before or equal to ' '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_primer_sequence = mm.quantize_note_sequence_absolute( primer_sequence, self.steps_per_second) extracted_perfs, _ = performance_lib.extract_performances( quantized_primer_sequence, start_step=input_start_step, num_velocity_bins=self.num_velocity_bins) assert len(extracted_perfs) <= 1 generate_start_step = mm.quantize_to_step(generate_section.start_time, self.steps_per_second, quantize_cutoff=0.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. generate_end_step = mm.quantize_to_step(generate_section.end_time, self.steps_per_second, quantize_cutoff=1.0) if extracted_perfs and extracted_perfs[0]: performance = extracted_perfs[0] else: # If no track could be extracted, create an empty track that starts at the # requested generate_start_step. performance = performance_lib.Performance( steps_per_second=(quantized_primer_sequence.quantization_info. steps_per_second), start_step=generate_start_step, num_velocity_bins=self.num_velocity_bins) # Ensure that the track extends up to the step we want to start generating. performance.set_length(generate_start_step - performance.start_step) # Extract generation arguments from generator options. arg_types = { 'note_density': lambda arg: ast.literal_eval(arg.string_value), 'pitch_histogram': lambda arg: ast.literal_eval(arg.string_value), 'disable_conditioning': lambda arg: ast.literal_eval(arg.string_value), '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) # Make sure note density is present when conditioning on it and not present # otherwise. if not self.note_density_conditioning and 'note_density' in args: tf.logging.warning( 'Not conditioning on note density, ignoring requested density.' ) del args['note_density'] if self.note_density_conditioning and 'note_density' not in args: tf.logging.warning( 'Conditioning on note density but none requested, using default.' ) args['note_density'] = [DEFAULT_NOTE_DENSITY] # Make sure pitch class histogram is present when conditioning on it and not # present otherwise. if not self.pitch_histogram_conditioning and 'pitch_histogram' in args: tf.logging.warning( 'Not conditioning on pitch histogram, ignoring requested histogram.' ) del args['pitch_histogram'] if self.pitch_histogram_conditioning and 'pitch_histogram' not in args: tf.logging.warning( 'Conditioning on pitch histogram but none requested, using default.' ) args['pitch_histogram'] = [DEFAULT_PITCH_HISTOGRAM] # Make sure disable conditioning flag is present when conditioning is # optional and not present otherwise. if not self.optional_conditioning and 'disable_conditioning' in args: tf.logging.warning( 'No optional conditioning, ignoring disable conditioning flag.' ) del args['disable_conditioning'] if self.optional_conditioning and 'disable_conditioning' not in args: args['disable_conditioning'] = [False] # If a single note density, pitch class histogram, or disable flag is # present, convert to list to simplify further processing. if (self.note_density_conditioning and not isinstance(args['note_density'], list)): args['note_density'] = [args['note_density']] if (self.pitch_histogram_conditioning and not isinstance(args['pitch_histogram'][0], list)): args['pitch_histogram'] = [args['pitch_histogram']] if (self.optional_conditioning and not isinstance(args['disable_conditioning'], list)): args['disable_conditioning'] = [args['disable_conditioning']] # Make sure each pitch class histogram sums to one. if self.pitch_histogram_conditioning: for i in range(len(args['pitch_histogram'])): total = sum(args['pitch_histogram'][i]) if total > 0: args['pitch_histogram'][i] = [ float(count) / total for count in args['pitch_histogram'][i] ] else: tf.logging.warning( 'Pitch histogram is empty, using default.') args['pitch_histogram'][i] = DEFAULT_PITCH_HISTOGRAM total_steps = performance.num_steps + (generate_end_step - generate_start_step) # Set up functions that map generation step to note density, pitch # histogram, and disable conditioning flag. mean_note_density = DEFAULT_NOTE_DENSITY if self.note_density_conditioning: args['note_density_fn'] = partial( _step_to_note_density, num_steps=total_steps, note_densities=args['note_density']) mean_note_density = sum(args['note_density']) / len( args['note_density']) del args['note_density'] if self.pitch_histogram_conditioning: args['pitch_histogram_fn'] = partial( _step_to_pitch_histogram, num_steps=total_steps, pitch_histograms=args['pitch_histogram']) del args['pitch_histogram'] if self.optional_conditioning: args['disable_conditioning_fn'] = partial( _step_to_disable_conditioning, num_steps=total_steps, disable_conditioning_flags=args['disable_conditioning']) del args['disable_conditioning'] if not performance: # Primer is empty; let's just start with silence. performance.set_length( min(performance_lib.MAX_SHIFT_STEPS, total_steps)) while performance.num_steps < total_steps: # Assume the average specified (or default) note density and 4 RNN steps # per note. Can't know for sure until generation is finished because the # number of notes per quantized step is variable. note_density = max(1.0, mean_note_density) steps_to_gen = total_steps - performance.num_steps rnn_steps_to_gen = int( math.ceil(4.0 * note_density * steps_to_gen / self.steps_per_second)) tf.logging.info( 'Need to generate %d more steps for this sequence, will try asking ' 'for %d RNN steps' % (steps_to_gen, rnn_steps_to_gen)) performance = self._model.generate_performance( len(performance) + rnn_steps_to_gen, performance, **args) if not self.fill_generate_section: # In the interest of speed just go through this loop once, which may not # entirely fill the generate section. break performance.set_length(total_steps) generated_sequence = performance.to_sequence( max_note_duration=self.max_note_duration) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
def _primer_melody_to_event_sequence(self, input_sequence, generator_options, config): qpm = (input_sequence.tempos[0].qpm if input_sequence and input_sequence.tempos else mm.DEFAULT_QUARTERS_PER_MINUTE) steps_per_second = mm.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 = mm.trim_note_sequence(input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.quantize_to_step(input_section.start_time, steps_per_second, quantize_cutoff=0) else: primer_sequence = input_sequence input_start_step = 0 last_end_time = (max( n.end_time for n in primer_sequence.notes) if primer_sequence.notes else 0) if last_end_time > generate_section.start_time: raise mm.SequenceGeneratorException( '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 = mm.quantize_note_sequence(primer_sequence, self.steps_per_quarter) # Setting gap_bars to infinite ensures that the entire input will be used. extracted_melodies, _ = mm.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 = mm.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 = mm.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( mm.steps_per_bar_in_quantized_sequence(quantized_sequence)) melody = mm.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 - 2) now_encoding = config.encoder_decoder._one_hot_encoding # Extract generation arguments from generator options. primer_events = self._model.primer_melody_to_events( end_step - melody.start_step, melody) for i, event in enumerate(primer_events): primer_events[i] = now_encoding.encode_event(event) return primer_events
def generate(unused_argv): # Downloads the bundle from the magenta website mm.notebook_utils.download_bundle("drum_kit_rnn.mag", "bundles") bundle = mm.sequence_generator_bundle.read_bundle_file( os.path.join("bundles", "drum_kit_rnn.mag")) # Initialize the generator "drum_kit" generator_map = drums_rnn_sequence_generator.get_generator_map() generator = generator_map["drum_kit"](checkpoint=None, bundle=bundle) generator.initialize() # Define constants qpm = 120 num_bars = 3 seconds_per_step = 60.0 / qpm / generator.steps_per_quarter num_steps_per_bar = constants.DEFAULT_STEPS_PER_BAR seconds_per_bar = num_steps_per_bar * seconds_per_step # Use a priming sequence primer_sequence = mm.midi_io.midi_file_to_note_sequence( os.path.join("primers", "Jazz_Drum_Basic_1_bar.mid")) primer_start_time = 0 primer_end_time = primer_start_time + seconds_per_bar # Calculates the generation start and end time generation_start_time = primer_end_time generation_end_time = generation_start_time + (seconds_per_bar * num_bars) generator_options = generator_pb2.GeneratorOptions() generator_options.args['temperature'].float_value = 1.1 generator_options.generate_sections.add(start_time=generation_start_time, end_time=generation_end_time) # Generates on primer sequence sequence = generator.generate(primer_sequence, generator_options) # Outputs the plot os.makedirs("output", exist_ok=True) plot_file = os.path.join("output", "out.html") pretty_midi = mm.midi_io.note_sequence_to_pretty_midi(sequence) plotter = Plotter(live_reload=True) plotter.show(pretty_midi, plot_file) print(f"Generated plot file: {os.path.abspath(plot_file)}") # We find the proper input port for the software synth # (which is the output port for Magenta) output_ports = [ name for name in mido.get_output_names() if args.midi_port in name ] if not output_ports: raise Exception(f"Cannot find proper output ports in: " f"{mido.get_output_names()}") print(f"Playing generated MIDI in output port names: {output_ports}") # Start a new MIDI hub on that port (output only) midi_hub = MidiHub(input_midi_ports=[], output_midi_ports=output_ports, texture_type=None) # Start on a empty sequence, allowing the update of the # sequence for later. empty_sequence = music_pb2.NoteSequence() player = midi_hub.start_playback(empty_sequence, allow_updates=True) player._channel = 9 # We want a period in seconds of 4 bars period = Decimal(240) / qpm period = period * (num_bars + 1) sleeper = concurrency.Sleeper() index = 0 while True: try: # We get the next tick time by using the period # to find the absolute tick number. now = Decimal(time.time()) tick_number = int(now // period) tick_number_next = tick_number + 1 tick_time = tick_number * period tick_time_next = tick_number_next * period # Update the player time to the current tick time sequence_adjusted = music_pb2.NoteSequence() sequence_adjusted.CopyFrom(sequence) sequence_adjusted = adjust_sequence_times(sequence_adjusted, float(tick_time)) player.update_sequence(sequence_adjusted, start_time=float(tick_time)) # Generate a new sequence based on the previous sequence index = index + 1 generator_options = generator_pb2.GeneratorOptions() generator_options.args['temperature'].float_value = 1 generation_start_time = index * period generation_end_time = generation_start_time + period generator_options.generate_sections.add( start_time=generation_start_time, end_time=generation_end_time) sequence = generator.generate(sequence, generator_options) sequence = trim_note_sequence(sequence, generation_start_time, generation_end_time) # Sleep until the next tick time sleeper.sleep_until(float(tick_time_next)) except KeyboardInterrupt: print(f"Stopping") return 0
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.SequenceGeneratorException( '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 mm.SequenceGeneratorException( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) generate_section = generator_options.generate_sections[0] if generator_options.input_sections: input_section = generator_options.input_sections[0] primer_sequence = mm.trim_note_sequence( input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.quantize_to_step( input_section.start_time, self.steps_per_second, quantize_cutoff=0.0) else: primer_sequence = input_sequence input_start_step = 0 last_end_time = (max(n.end_time for n in primer_sequence.notes) if primer_sequence.notes else 0) if last_end_time > generate_section.start_time: raise mm.SequenceGeneratorException( 'Got GenerateSection request for section that is before or equal to ' '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_primer_sequence = mm.quantize_note_sequence_absolute( primer_sequence, self.steps_per_second) extracted_perfs, _ = performance_lib.extract_performances( quantized_primer_sequence, start_step=input_start_step, num_velocity_bins=self.num_velocity_bins) assert len(extracted_perfs) <= 1 generate_start_step = mm.quantize_to_step( generate_section.start_time, self.steps_per_second, quantize_cutoff=0.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. generate_end_step = mm.quantize_to_step( generate_section.end_time, self.steps_per_second, quantize_cutoff=1.0) if extracted_perfs and extracted_perfs[0]: performance = extracted_perfs[0] else: # If no track could be extracted, create an empty track that starts at the # requested generate_start_step. performance = performance_lib.Performance( steps_per_second=( quantized_primer_sequence.quantization_info.steps_per_second), start_step=generate_start_step, num_velocity_bins=self.num_velocity_bins) # Ensure that the track extends up to the step we want to start generating. performance.set_length(generate_start_step - performance.start_step) # Extract generation arguments from generator options. arg_types = { 'note_density': lambda arg: ast.literal_eval(arg.string_value), 'pitch_histogram': lambda arg: ast.literal_eval(arg.string_value), 'disable_conditioning': lambda arg: ast.literal_eval(arg.string_value), '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) # Make sure note density is present when conditioning on it and not present # otherwise. if not self.note_density_conditioning and 'note_density' in args: tf.logging.warning( 'Not conditioning on note density, ignoring requested density.') del args['note_density'] if self.note_density_conditioning and 'note_density' not in args: tf.logging.warning( 'Conditioning on note density but none requested, using default.') args['note_density'] = [DEFAULT_NOTE_DENSITY] # Make sure pitch class histogram is present when conditioning on it and not # present otherwise. if not self.pitch_histogram_conditioning and 'pitch_histogram' in args: tf.logging.warning( 'Not conditioning on pitch histogram, ignoring requested histogram.') del args['pitch_histogram'] if self.pitch_histogram_conditioning and 'pitch_histogram' not in args: tf.logging.warning( 'Conditioning on pitch histogram but none requested, using default.') args['pitch_histogram'] = [DEFAULT_PITCH_HISTOGRAM] # Make sure disable conditioning flag is present when conditioning is # optional and not present otherwise. if not self.optional_conditioning and 'disable_conditioning' in args: tf.logging.warning( 'No optional conditioning, ignoring disable conditioning flag.') del args['disable_conditioning'] if self.optional_conditioning and 'disable_conditioning' not in args: args['disable_conditioning'] = [False] # If a single note density, pitch class histogram, or disable flag is # present, convert to list to simplify further processing. if (self.note_density_conditioning and not isinstance(args['note_density'], list)): args['note_density'] = [args['note_density']] if (self.pitch_histogram_conditioning and not isinstance(args['pitch_histogram'][0], list)): args['pitch_histogram'] = [args['pitch_histogram']] if (self.optional_conditioning and not isinstance(args['disable_conditioning'], list)): args['disable_conditioning'] = [args['disable_conditioning']] # Make sure each pitch class histogram sums to one. if self.pitch_histogram_conditioning: for i in range(len(args['pitch_histogram'])): total = sum(args['pitch_histogram'][i]) if total > 0: args['pitch_histogram'][i] = [float(count) / total for count in args['pitch_histogram'][i]] else: tf.logging.warning('Pitch histogram is empty, using default.') args['pitch_histogram'][i] = DEFAULT_PITCH_HISTOGRAM total_steps = performance.num_steps + ( generate_end_step - generate_start_step) # Set up functions that map generation step to note density, pitch # histogram, and disable conditioning flag. mean_note_density = DEFAULT_NOTE_DENSITY if self.note_density_conditioning: args['note_density_fn'] = partial( _step_to_note_density, num_steps=total_steps, note_densities=args['note_density']) mean_note_density = sum(args['note_density']) / len(args['note_density']) del args['note_density'] if self.pitch_histogram_conditioning: args['pitch_histogram_fn'] = partial( _step_to_pitch_histogram, num_steps=total_steps, pitch_histograms=args['pitch_histogram']) del args['pitch_histogram'] if self.optional_conditioning: args['disable_conditioning_fn'] = partial( _step_to_disable_conditioning, num_steps=total_steps, disable_conditioning_flags=args['disable_conditioning']) del args['disable_conditioning'] if not performance: # Primer is empty; let's just start with silence. performance.set_length(min(performance_lib.MAX_SHIFT_STEPS, total_steps)) while performance.num_steps < total_steps: # Assume the average specified (or default) note density and 4 RNN steps # per note. Can't know for sure until generation is finished because the # number of notes per quantized step is variable. note_density = max(1.0, mean_note_density) steps_to_gen = total_steps - performance.num_steps rnn_steps_to_gen = int(math.ceil( 4.0 * note_density * steps_to_gen / self.steps_per_second)) tf.logging.info( 'Need to generate %d more steps for this sequence, will try asking ' 'for %d RNN steps' % (steps_to_gen, rnn_steps_to_gen)) performance = self._model.generate_performance( len(performance) + rnn_steps_to_gen, performance, **args) if not self.fill_generate_section: # In the interest of speed just go through this loop once, which may not # entirely fill the generate section. break performance.set_length(total_steps) generated_sequence = performance.to_sequence( max_note_duration=self.max_note_duration) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.SequenceGeneratorException( '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 mm.SequenceGeneratorException( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) qpm = (input_sequence.tempos[0].qpm if input_sequence and input_sequence.tempos else mm.DEFAULT_QUARTERS_PER_MINUTE) steps_per_second = mm.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 = mm.trim_note_sequence(input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.quantize_to_step(input_section.start_time, steps_per_second) else: primer_sequence = input_sequence input_start_step = 0 last_end_time = (max( n.end_time for n in primer_sequence.notes) if primer_sequence.notes else 0) if last_end_time > generate_section.start_time: raise mm.SequenceGeneratorException( '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 = mm.quantize_note_sequence(primer_sequence, self.steps_per_quarter) # Setting gap_bars to infinite ensures that the entire input will be used. extracted_melodies, _ = mm.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 = mm.quantize_to_step(generate_section.start_time, steps_per_second) end_step = mm.quantize_to_step(generate_section.end_time, steps_per_second) 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( mm.steps_per_bar_in_quantized_sequence(quantized_sequence)) melody = mm.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
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.SequenceGeneratorException( '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 mm.SequenceGeneratorException( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) qpm = (input_sequence.tempos[0].qpm if input_sequence and input_sequence.tempos else mm.DEFAULT_QUARTERS_PER_MINUTE) generate_section = generator_options.generate_sections[0] if generator_options.input_sections: # Use primer melody from input section only. Take backing chords from # beginning of input section through end of generate section. input_section = generator_options.input_sections[0] primer_sequence = mm.trim_note_sequence(input_sequence, input_section.start_time, input_section.end_time) backing_sequence = mm.trim_note_sequence(input_sequence, input_section.start_time, generate_section.end_time) input_start_step = self.seconds_to_steps(input_section.start_time, qpm) else: # No input section. Take primer melody from the beginning of the sequence # up until the start of the generate section. primer_sequence = mm.trim_note_sequence( input_sequence, 0.0, generate_section.start_time) backing_sequence = mm.trim_note_sequence(input_sequence, 0.0, generate_section.end_time) input_start_step = 0 last_end_time = (max( n.end_time for n in primer_sequence.notes) if primer_sequence.notes else 0) if last_end_time >= generate_section.start_time: raise mm.SequenceGeneratorException( 'Got GenerateSection request for section that is before or equal to ' 'the end of the input section. This model can only extend melodies. ' 'Requested start time: %s, Final note end time: %s' % (generate_section.start_time, last_end_time)) # Quantize the priming and backing sequences. quantized_primer_sequence = mm.quantize_note_sequence( primer_sequence, self._steps_per_quarter) quantized_backing_sequence = mm.quantize_note_sequence( backing_sequence, self._steps_per_quarter) # Setting gap_bars to infinite ensures that the entire input will be used. extracted_melodies, _ = mm.extract_melodies( quantized_primer_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 = self.seconds_to_steps(generate_section.start_time, qpm) end_step = self.seconds_to_steps(generate_section.end_time, qpm) 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( mm.steps_per_bar_in_quantized_sequence( quantized_primer_sequence)) melody = mm.Melody([], start_step=max(0, start_step - 1), steps_per_bar=steps_per_bar, steps_per_quarter=self.steps_per_quarter) extracted_chords, _ = mm.extract_chords(quantized_backing_sequence) chords = extracted_chords[0] # Make sure that chords and melody start on the same step. if chords.start_step < melody.start_step: chords.set_length( len(chords) - melody.start_step + chords.start_step) assert chords.end_step == end_step # 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(melody, chords, **args) generated_lead_sheet = mm.LeadSheet(generated_melody, chords) generated_sequence = generated_lead_sheet.to_sequence(qpm=qpm) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.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 mm.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 = mm.DEFAULT_QUARTERS_PER_MINUTE steps_per_second = mm.steps_per_quarter_to_steps_per_second( self.steps_per_quarter, qpm) generate_section = generator_options.generate_sections[0] if generator_options.input_sections: # Use primer melody from input section only. Take backing chords from # beginning of input section through end of generate section. input_section = generator_options.input_sections[0] primer_sequence = mm.trim_note_sequence( input_sequence, input_section.start_time, input_section.end_time) backing_sequence = mm.trim_note_sequence( input_sequence, input_section.start_time, generate_section.end_time) input_start_step = mm.quantize_to_step( input_section.start_time, steps_per_second, quantize_cutoff=0.0) else: # No input section. Take primer melody from the beginning of the sequence # up until the start of the generate section. primer_sequence = mm.trim_note_sequence( input_sequence, 0.0, generate_section.start_time) backing_sequence = mm.trim_note_sequence( input_sequence, 0.0, generate_section.end_time) 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 mm.SequenceGeneratorError( 'Got GenerateSection request for section that is before or equal to ' 'the end of the input section. This model can only extend melodies. ' 'Requested start time: %s, Final note end time: %s' % (generate_section.start_time, last_end_time)) # Quantize the priming and backing sequences. quantized_primer_sequence = mm.quantize_note_sequence( primer_sequence, self.steps_per_quarter) quantized_backing_sequence = mm.quantize_note_sequence( backing_sequence, self.steps_per_quarter) # Setting gap_bars to infinite ensures that the entire input will be used. extracted_melodies, _ = mm.extract_melodies( quantized_primer_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 = mm.quantize_to_step( generate_section.start_time, steps_per_second, quantize_cutoff=0.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 = mm.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( mm.steps_per_bar_in_quantized_sequence(quantized_primer_sequence)) melody = mm.Melody([], start_step=max(0, start_step - 1), steps_per_bar=steps_per_bar, steps_per_quarter=self.steps_per_quarter) extracted_chords, _ = mm.extract_chords(quantized_backing_sequence) chords = extracted_chords[0] # Make sure that chords and melody start on the same step. if chords.start_step < melody.start_step: chords.set_length(len(chords) - melody.start_step + chords.start_step) assert chords.end_step == end_step # 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(melody, chords, **args) generated_lead_sheet = mm.LeadSheet(generated_melody, chords) generated_sequence = generated_lead_sheet.to_sequence(qpm=qpm) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.SequenceGeneratorException( '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 mm.SequenceGeneratorException( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) generate_section = generator_options.generate_sections[0] if generator_options.input_sections: input_section = generator_options.input_sections[0] primer_sequence = mm.trim_note_sequence( input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.quantize_to_step( input_section.start_time, self.steps_per_second, quantize_cutoff=0.0) else: primer_sequence = input_sequence input_start_step = 0 last_end_time = (max(n.end_time for n in primer_sequence.notes) if primer_sequence.notes else 0) if last_end_time > generate_section.start_time: raise mm.SequenceGeneratorException( 'Got GenerateSection request for section that is before or equal to ' '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_primer_sequence = mm.quantize_note_sequence_absolute( primer_sequence, self.steps_per_second) extracted_perfs, _ = performance_lib.extract_performances( quantized_primer_sequence, start_step=input_start_step, num_velocity_bins=self.num_velocity_bins) assert len(extracted_perfs) <= 1 generate_start_step = mm.quantize_to_step( generate_section.start_time, self.steps_per_second, quantize_cutoff=0.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. generate_end_step = mm.quantize_to_step( generate_section.end_time, self.steps_per_second, quantize_cutoff=1.0) if extracted_perfs and extracted_perfs[0]: performance = extracted_perfs[0] else: # If no track could be extracted, create an empty track that starts at the # requested generate_start_step. performance = performance_lib.Performance( steps_per_second=( quantized_primer_sequence.quantization_info.steps_per_second), start_step=generate_start_step, num_velocity_bins=self.num_velocity_bins) # Ensure that the track extends up to the step we want to start generating. performance.set_length(generate_start_step - performance.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) total_steps = performance.num_steps + ( generate_end_step - generate_start_step) if not performance: # Primer is empty; let's just start with silence. performance.set_length(min(performance_lib.MAX_SHIFT_STEPS, total_steps)) while performance.num_steps < total_steps: # Assume there's around 10 notes per second and 4 RNN steps per note. # Can't know for sure until generation is finished because the number of # notes per quantized step is variable. steps_to_gen = total_steps - performance.num_steps rnn_steps_to_gen = 40 * int(math.ceil( float(steps_to_gen) / performance_lib.DEFAULT_STEPS_PER_SECOND)) tf.logging.info( 'Need to generate %d more steps for this sequence, will try asking ' 'for %d RNN steps' % (steps_to_gen, rnn_steps_to_gen)) performance = self._model.generate_performance( len(performance) + rnn_steps_to_gen, performance, **args) if not self.fill_generate_section: # In the interest of speed just go through this loop once, which may not # entirely fill the generate section. break performance.set_length(total_steps) generated_sequence = performance.to_sequence( max_note_duration=self.max_note_duration) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
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)) generate_section = generator_options.generate_sections[0] if generator_options.input_sections: input_section = generator_options.input_sections[0] primer_sequence = mm.trim_note_sequence(input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.quantize_to_step(input_section.start_time, self.steps_per_second, quantize_cutoff=0.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 or equal to ' '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_primer_sequence = mm.quantize_note_sequence_absolute( primer_sequence, self.steps_per_second) extracted_perfs, _ = performance_pipeline.extract_performances( quantized_primer_sequence, start_step=input_start_step, num_velocity_bins=self.num_velocity_bins, note_performance=self._note_performance) assert len(extracted_perfs) <= 1 generate_start_step = mm.quantize_to_step(generate_section.start_time, self.steps_per_second, quantize_cutoff=0.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. generate_end_step = mm.quantize_to_step(generate_section.end_time, self.steps_per_second, quantize_cutoff=1.0) if extracted_perfs and extracted_perfs[0]: performance = extracted_perfs[0] else: # If no track could be extracted, create an empty track that starts at the # requested generate_start_step. performance = mm.Performance( steps_per_second=(quantized_primer_sequence.quantization_info. steps_per_second), start_step=generate_start_step, num_velocity_bins=self.num_velocity_bins) # Ensure that the track extends up to the step we want to start generating. performance.set_length(generate_start_step - performance.start_step) # Extract generation arguments from generator options. arg_types = { 'disable_conditioning': lambda arg: ast.literal_eval(arg.string_value), '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 } if self.control_signals: for control in self.control_signals: arg_types[control.name] = lambda arg: ast.literal_eval( arg.string_value) args = dict((name, value_fn(generator_options.args[name])) for name, value_fn in arg_types.items() if name in generator_options.args) # Make sure control signals are present and convert to lists if necessary. if self.control_signals: for control in self.control_signals: if control.name not in args: tf.logging.warning( 'Control value not specified, using default: %s = %s', control.name, control.default_value) args[control.name] = [control.default_value] elif control.validate(args[control.name]): args[control.name] = [args[control.name]] else: if not isinstance(args[control.name], list) or not all( control.validate(value) for value in args[control.name]): tf.logging.fatal('Invalid control value: %s = %s', control.name, args[control.name]) # Make sure disable conditioning flag is present when conditioning is # optional and convert to list if necessary. if self.optional_conditioning: if 'disable_conditioning' not in args: args['disable_conditioning'] = [False] elif isinstance(args['disable_conditioning'], bool): args['disable_conditioning'] = [args['disable_conditioning']] else: if not isinstance( args['disable_conditioning'], list) or not all( isinstance(value, bool) for value in args['disable_conditioning']): tf.logging.fatal('Invalid disable_conditioning value: %s', args['disable_conditioning']) total_steps = performance.num_steps + (generate_end_step - generate_start_step) if 'notes_per_second' in args: mean_note_density = (sum(args['notes_per_second']) / len(args['notes_per_second'])) else: mean_note_density = DEFAULT_NOTE_DENSITY # Set up functions that map generation step to control signal values and # disable conditioning flag. if self.control_signals: control_signal_fns = [] for control in self.control_signals: control_signal_fns.append( functools.partial(_step_to_value, num_steps=total_steps, values=args[control.name])) del args[control.name] args['control_signal_fns'] = control_signal_fns if self.optional_conditioning: args['disable_conditioning_fn'] = functools.partial( _step_to_value, num_steps=total_steps, values=args['disable_conditioning']) del args['disable_conditioning'] if not performance: # Primer is empty; let's just start with silence. performance.set_length( min(performance.max_shift_steps, total_steps)) while performance.num_steps < total_steps: # Assume the average specified (or default) note density and 4 RNN steps # per note. Can't know for sure until generation is finished because the # number of notes per quantized step is variable. note_density = max(1.0, mean_note_density) steps_to_gen = total_steps - performance.num_steps rnn_steps_to_gen = int( math.ceil(4.0 * note_density * steps_to_gen / self.steps_per_second)) tf.logging.info( 'Need to generate %d more steps for this sequence, will try asking ' 'for %d RNN steps' % (steps_to_gen, rnn_steps_to_gen)) performance = self._model.generate_performance( len(performance) + rnn_steps_to_gen, performance, **args) if not self.fill_generate_section: # In the interest of speed just go through this loop once, which may not # entirely fill the generate section. break performance.set_length(total_steps) generated_sequence = performance.to_sequence( max_note_duration=self.max_note_duration) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.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 mm.SequenceGeneratorError( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) # This sequence will be quantized later, so it is guaranteed to have only 1 # tempo. qpm = mm.DEFAULT_QUARTERS_PER_MINUTE if input_sequence.tempos: qpm = input_sequence.tempos[0].qpm steps_per_second = mm.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 = mm.trim_note_sequence(input_sequence, input_section.start_time, input_section.end_time) input_start_step = mm.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 mm.SequenceGeneratorError( 'Got GenerateSection request for section that is before or equal to ' '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_primer_sequence = mm.quantize_note_sequence( primer_sequence, self.steps_per_quarter) extracted_seqs, _ = pianoroll_pipeline.extract_pianoroll_sequences( quantized_primer_sequence, start_step=input_start_step) assert len(extracted_seqs) <= 1 generate_start_step = mm.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. generate_end_step = mm.quantize_to_step(generate_section.end_time, steps_per_second, quantize_cutoff=1.0) if extracted_seqs and extracted_seqs[0]: pianoroll_seq = extracted_seqs[0] else: raise ValueError('No priming pianoroll could be extracted.') # Ensure that the track extends up to the step we want to start generating. pianoroll_seq.set_length(generate_start_step - pianoroll_seq.start_step) # Extract generation arguments from generator options. arg_types = { 'beam_size': lambda arg: arg.int_value, 'branch_factor': 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) total_steps = pianoroll_seq.num_steps + (generate_end_step - generate_start_step) pianoroll_seq = self._model.generate_pianoroll_sequence( total_steps, pianoroll_seq, **args) pianoroll_seq.set_length(total_steps) generated_sequence = pianoroll_seq.to_sequence(qpm=qpm) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence
def _generate(self, input_sequence, generator_options): if len(generator_options.input_sections) > 1: raise mm.SequenceGeneratorException( '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 mm.SequenceGeneratorException( 'This model supports only 1 generate_sections message, but got %s' % len(generator_options.generate_sections)) qpm = (input_sequence.tempos[0].qpm if input_sequence and input_sequence.tempos else mm.DEFAULT_QUARTERS_PER_MINUTE) generate_section = generator_options.generate_sections[0] if generator_options.input_sections: input_section = generator_options.input_sections[0] primer_sequence = mm.trim_note_sequence(input_sequence, input_section.start_time, input_section.end_time) input_start_step = self.seconds_to_steps(input_section.start_time, qpm) else: primer_sequence = input_sequence input_start_step = 0 last_end_time = (max( n.end_time for n in primer_sequence.notes) if primer_sequence.notes else 0) if last_end_time > generate_section.start_time: raise mm.SequenceGeneratorException( '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 = mm.quantize_note_sequence(primer_sequence, self.steps_per_quarter) # Setting gap_bars to infinite ensures that the entire input will be used. extracted_drum_tracks, _ = mm.extract_drum_tracks( quantized_sequence, search_start_step=input_start_step, min_bars=0, gap_bars=float('inf')) assert len(extracted_drum_tracks) <= 1 start_step = self.seconds_to_steps(generate_section.start_time, qpm) end_step = self.seconds_to_steps(generate_section.end_time, qpm) if extracted_drum_tracks and extracted_drum_tracks[0]: drums = extracted_drum_tracks[0] else: # If no drum track could be extracted, create an empty drum track that # starts 1 step before the request start_step. This will result in 1 step # of silence when the drum track is extended below. drums = mm.DrumTrack([], start_step=max(0, start_step - 1)) # Ensure that the drum track extends up to the step we want to start # generating. drums.set_length(start_step - drums.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_drums = self._model.generate_drum_track( end_step - drums.start_step, drums, **args) generated_sequence = generated_drums.to_sequence(qpm=qpm) assert (generated_sequence.total_time - generate_section.end_time) <= 1e-5 return generated_sequence