Ejemplo n.º 1
0
  def _generate(self, input_sequence, zero_time, response_start_time,
                response_end_time):
    """Generates a response sequence with the currently-selected generator.

    Args:
      input_sequence: The NoteSequence to use as a generation seed.
      zero_time: The float time in seconds to treat as the start of the input.
      response_start_time: The float time in seconds for the start of
          generation.
      response_end_time: The float time in seconds for the end of generation.

    Returns:
      The generated NoteSequence.
    """
    # Generation is simplified if we always start at 0 time.
    response_start_time -= zero_time
    response_end_time -= zero_time

    generator_options = generator_pb2.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)

    # Get current temperature setting.
    generator_options.args['temperature'].float_value = self._temperature

    # Generate response.
    tf.logging.info(
        "Generating sequence using '%s' generator.",
        self._sequence_generator.details.id)
    tf.logging.debug('Generator Details: %s',
                     self._sequence_generator.details)
    tf.logging.debug('Bundle Details: %s',
                     self._sequence_generator.bundle_details)
    tf.logging.debug('Generator Options: %s', generator_options)
    response_sequence = self._sequence_generator.generate(
        adjust_sequence_times(input_sequence, -zero_time), generator_options)
    response_sequence = note_seq.trim_note_sequence(response_sequence,
                                                    response_start_time,
                                                    response_end_time)
    return adjust_sequence_times(response_sequence, zero_time)
Ejemplo n.º 2
0
def generate(unused_argv):
  """Generates a basic drum sequence of 4 seconds based on a hard coded
  primer"""

  # TODO doc

  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"))

  generator_map = drums_rnn_sequence_generator.get_generator_map()
  generator = generator_map["drum_kit"](checkpoint=None, bundle=bundle)
  generator.initialize()

  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

  # Creates a primer sequence that is fed into the model for the generator,
  # which will generate a sequence based on this one
  # A DrumTrack models a drum sequence by step, so you have step 1 being the
  # midi note 36 (bass drum), followed by 3 steps of silence (those four steps
  # constitutes the first beat or quarter), followed by both notes 36 and 41
  # being struck at the same time (followed by silence by these are optional)
  primer_drums = mm.DrumTrack(
    [frozenset(pitches) for pitches in
     [(38, 51), (), (36,), (),
      (38, 44, 51), (), (36,), (),
      (), (), (38,), (),
      (38, 44), (), (36, 51), (), ]])
  primer_sequence = primer_drums.to_sequence(qpm=qpm)
  primer_start_time = 0
  primer_end_time = primer_start_time + seconds_per_bar

  # Defines the start and end of the generation, which starts at the step
  # after the end of the primer (we'll see in 03.py this calculation makes
  # it harder to fall on proper beats) and ends at total seconds
  # The complete generation will thus contain the primer and the total length
  # needs to be at least the size of the primer
  # TODO doc
  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)

  # We are using the primer sequence here instead of an empty sequence
  sequence = generator.generate(primer_sequence, generator_options)

  # TODO doc
  plot_file = os.path.join("output", "out.html")
  print("Generated plot file: " + str(os.path.abspath(plot_file)))
  pretty_midi = mm.midi_io.note_sequence_to_pretty_midi(sequence)
  plotter = Plotter()
  plotter.show(pretty_midi, plot_file)

  # TODO doc
  input_ports = [name for name in mido.get_output_names()
                 if "VirtualMIDISynth" in name
                 or "FLUID Synth" in name]
  if not input_ports:
    print("Cannot find proper input port in "
          + str(mido.get_output_names()))
  print("Playing generated MIDI in input port names: "
        + str(input_ports))
  midi_hub = mh.MidiHub([], input_ports, None)

  # TODO doc
  empty_sequence = music_pb2.NoteSequence()
  player = midi_hub.start_playback(empty_sequence,
                                   allow_updates=True)
  player._channel = 9

  # TODO doc
  wall_start_time = time.time()
  sequence_adjusted = music_pb2.NoteSequence()
  sequence_adjusted.CopyFrom(sequence)
  sequence_adjusted = adjust_sequence_times(sequence_adjusted,
                                            wall_start_time)
  player.update_sequence(sequence_adjusted,
                         start_time=wall_start_time)

  # TODO doc
  try:
    player.join(generation_end_time)
  except KeyboardInterrupt:
    return 0
  finally:
    return 0
Ejemplo n.º 3
0
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()
    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. We don't especially need that right
    # now, because we could play the sequence immediately, but
    # it will be useful for later examples to have a player to
    # update new sequences with.
    empty_sequence = music_pb2.NoteSequence()
    player = midi_hub.start_playback(empty_sequence, allow_updates=True)
    # Remember that GM 1 compatible synthesizer will play the drums
    # sound bank if the MIDI channel is 10 (but the channel is zero
    # indexed in Magenta MIDI hub so you have to use 9).
    player._channel = 9

    # Now we can play our sequence, but we need to adjust it first.
    # The MIDI player will play the sequence according to wall time,
    # but our sequence starts at 0.
    # Create a new empty note sequence, copy the sequence
    # we want to play in the empty sequence, then move the
    # start of the sequence by wall_start_time amount
    wall_start_time = time.time()
    sequence_adjusted = music_pb2.NoteSequence()
    sequence_adjusted.CopyFrom(sequence)
    sequence_adjusted = adjust_sequence_times(sequence_adjusted,
                                              wall_start_time)

    # The update sequence is the equivalent of "play"
    player.update_sequence(sequence_adjusted, start_time=wall_start_time)

    # We "join" on the thread, meaning the call will block
    # until the player has finished. Because the thread
    # never stops, this call will block indefinitely. By
    # adding a timeout of generation_end_time, the call will
    # return after the end of the sequence being played.
    try:
        print(f"Playing for {generation_end_time}")
        player.join(generation_end_time)
    except KeyboardInterrupt:
        # The KeyboardInterrupt is important if you want to press
        # CTRL-C during the playback to stop the player.
        print(f"Stopping")
        return 0
def generate(unused_argv):
    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"))

    generator_map = drums_rnn_sequence_generator.get_generator_map()
    generator = generator_map["drum_kit"](checkpoint=None, bundle=bundle)
    generator.initialize()

    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

    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

    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)

    sequence = generator.generate(primer_sequence, generator_options)

    plot_file = os.path.join("output", "out.html")
    pretty_midi = mm.midi_io.note_sequence_to_pretty_midi(sequence)
    plotter = Plotter()
    plotter.show(pretty_midi, plot_file)
    print(f"Generated plot file: {os.path.abspath(plot_file)}")

    input_ports = [
        name for name in mido.get_output_names()
        if "VirtualMIDISynth" in name or "FLUID Synth" in name
    ]
    if not input_ports:
        raise Exception(f"Cannot find proper input port in: "
                        f"{mido.get_output_names()}")
    print(f"Playing generated MIDI in input port names: {input_ports}")

    midi_hub = mh.MidiHub([], input_ports, None)

    empty_sequence = music_pb2.NoteSequence()
    player = midi_hub.start_playback(empty_sequence, allow_updates=True)
    player._channel = 9

    # We calculate the length of the generated sequence in seconds,
    # which gives up the loop time in seconds
    loop_time = generation_end_time - primer_start_time
    print(f"Loop time is {loop_time}")

    # We get the current wall time before the loop starts
    wall_start_time = time.time()
    while True:
        try:
            # We get the current wall time for this loop start
            tick_wall_start_time = time.time()

            sequence_adjusted = music_pb2.NoteSequence()
            sequence_adjusted.CopyFrom(sequence)
            sequence_adjusted = adjust_sequence_times(sequence_adjusted,
                                                      tick_wall_start_time)
            player.update_sequence(sequence_adjusted,
                                   start_time=tick_wall_start_time)

            # We calculate the elapsed time from the start of the program
            tick_start_time = time.time() - wall_start_time

            # We sleep for the remaining time in the loop. It means that whatever
            # how much time this loop took, we'll be waking up at the proper
            # next bar.
            # For example, if the loop needs to be 8 seconds, and we took 2.4 seconds
            # executing and arriving here, then we'll sleep only 5.6 seconds to wake
            # up with proper timing.
            sleep_time = loop_time - (tick_start_time % loop_time)
            print(f"Sleeping for {sleep_time}")
            time.sleep(sleep_time)
        except KeyboardInterrupt:
            print(f"Stopping")
            return 0
Ejemplo n.º 5
0
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()
    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 (which is the loop
    # length). Using 240 / qpm, we have a period of 1 bar, or
    # 2 seconds at 120 qpm. We multiply that by 4 bars.
    # (using the Decimal class for more accuracy)
    period = Decimal(240) / qpm
    period = period * (num_bars + 1)
    sleeper = concurrency.Sleeper()
    while True:
        try:
            # We get the next tick time by using the period
            # to find the absolute tick number (since epoch),
            # and multiplying by the period length. This is
            # used to sleep until that time.
            # We also find the current tick time for the player
            # to update.
            # (using the Decimal class for more accuracy)
            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

            print(
                f"now {now} tick_time {tick_time} tick_time_next {tick_time_next}"
            )

            # 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))

            # Sleep until the next tick time
            sleeper.sleep_until(float(tick_time_next))
        except KeyboardInterrupt:
            print(f"Stopping")
            return 0
Ejemplo n.º 6
0
  def run(self):
    sequence = music_pb2.NoteSequence()
    player = self._midi_hub.start_playback(sequence, allow_updates=True)
    player._channel = self._midi_channel

    pretty_midi = pm.PrettyMIDI()
    pretty_midi.instruments.append(pm.Instrument(0))

    # Wait for the dreamer and store the time with the delta
    wall_start_time = time.time()
    self._bar_start_event.wait()

    bar_count = 0
    while not self._stop_signal:
      # Number of seconds we should be at the beginning of this loop
      expected_start_time = self._timing.get_expected_start_time(bar_count)
      # Number of actual seconds since we started this thread from wall clock,
      # which is smaller then the expected start time
      # The difference is between: the actual wakeup time and the expected
      # (calculated) start time. By keeping this we can adjust the sequence
      # according to the drift.
      diff_time = self._timing.get_diff_time(wall_start_time, bar_count)

      tf.logging.debug("Playing " + str(self._timing.get_timing_args(
        wall_start_time, bar_count)))

      # Player
      sequence_adjusted = music_pb2.NoteSequence()
      sequence_adjusted.CopyFrom(sequence)
      sequence_adjusted = adjust_sequence_times(sequence_adjusted,
                                                wall_start_time - diff_time)
      player.update_sequence(sequence_adjusted, start_time=expected_start_time)

      # Plotter
      pretty_midi = mm.midi_io.note_sequence_to_pretty_midi(sequence)
      self._plotter.save(pretty_midi, self._output_plot)
      pretty_midi.write(self._output_midi)

      # Sets timing
      seconds_per_bar = self._timing.get_seconds_per_bar()
      seconds_per_loop = self._bar_per_loop * seconds_per_bar
      loop_start_time = expected_start_time
      loop_end_time = loop_start_time + seconds_per_loop
      generation_start_time = loop_end_time
      generation_end_time = generation_start_time + seconds_per_loop

      action = self._action_server.context.get(self.name, None)

      tf.logging.debug(str(action) + " " + str([
        ("expected_start_time", expected_start_time),
        ("loop_start_time", loop_start_time),
        ("loop_end_time", loop_end_time),
        ("generation_start_time", generation_start_time),
        ("generation_end_time", generation_end_time)]))

      if not action:
        pass
      elif action is ActionType.LOOP:
        sequence = sequences.loop(sequence,
                                  loop_start_time,
                                  loop_end_time,
                                  seconds_per_loop)
      elif action is ActionType.GENERATE:
        sequence = sequences.generate(sequence,
                                      self.name,
                                      self._bundle_filename,
                                      self._config_name,
                                      generation_start_time,
                                      generation_end_time)
      elif action is ActionType.GENERATE_ONCE:
        sequence = sequences.generate(sequence,
                                      self.name,
                                      self._bundle_filename,
                                      self._config_name,
                                      generation_start_time,
                                      generation_end_time)
        self._action_server.context[self.name] = ActionType.LOOP
      elif action is ActionType.RESET_ONCE:
        sequence = sequences.reset(sequence,
                                   loop_start_time,
                                   loop_end_time,
                                   seconds_per_loop)
        self._action_server.context[self.name] = ActionType.LOOP
      elif action is ActionType.RESET_GENERATE:
        sequence = sequences.reset(sequence,
                                   loop_start_time,
                                   loop_end_time,
                                   seconds_per_loop)
        self._action_server.context[self.name] = ActionType.GENERATE_ONCE
      else:
        raise Exception(f"Unknown action {action}")

      while True:
        # Unlock at the start of the bar
        self._bar_start_event.wait()
        bar_count += 1
        if bar_count % self._bar_per_loop == 0:
          break
    def run(self):
        magenta.music.DrumTrack([frozenset([36])])
        primer_drums = magenta.music.DrumTrack(
            [frozenset(pitches) for pitches in [(36, ), (), (), (), (46, )]])
        sequence = primer_drums.to_sequence(qpm=120)

        player = self._midi_hub.start_playback(sequence, allow_updates=True)

        wall_start_time = time.time()

        # TODO describe
        qpm = 120

        # TODO describe
        # steps_per_quarter = 4
        seconds_per_step = 60.0 / qpm / self._sequence_generator.steps_per_quarter

        # TODO describe
        num_steps = 32

        # TODO describe
        total_seconds = num_steps * seconds_per_step

        # TODO describe
        primer_end_time = sequence.total_time

        # TODO describe
        start_time = primer_end_time + seconds_per_step
        end_time = total_seconds

        for index in range(0, sys.maxsize):
            tick_wall_start_time = time.time()

            # TODO describe
            start_time2 = start_time + index * total_seconds
            end_time2 = end_time + index * total_seconds

            # TODO describe
            generator_options = generator_pb2.GeneratorOptions()
            generator_options.generate_sections.add(start_time=start_time2,
                                                    end_time=end_time2)

            # TODO describe
            generator_options.args['temperature'].float_value = 0.1
            generator_options.args['beam_size'].int_value = 1
            generator_options.args['branch_factor'].int_value = 1
            generator_options.args['steps_per_iteration'].int_value = 1

            # TODO describe
            print("index: " + str(index))
            print("primer_end_time: " + str(primer_end_time))
            print("start_time: " + str(start_time))
            print("start_time2: " + str(start_time2))
            print("end_time: " + str(end_time))
            print("end_time2: " + str(end_time2))
            print("wall_start_time: " + str(wall_start_time))
            print("tick_wall_start_time: " + str(tick_wall_start_time))
            print("tick_wall_start_time (adjusted): " +
                  str(tick_wall_start_time - wall_start_time))
            sequence = self._sequence_generator.generate(
                sequence, generator_options)

            sequence_adjusted = music_pb2.NoteSequence()
            sequence_adjusted.CopyFrom(sequence)
            sequence_adjusted = adjust_sequence_times(sequence_adjusted,
                                                      wall_start_time)
            player.update_sequence(sequence_adjusted,
                                   start_time=tick_wall_start_time)

            pm = midi_io.note_sequence_to_pretty_midi(sequence)
            output_file(self._output_file)
            plot = plot_midi(pm)
            show(plot)

            time.sleep(total_seconds -
                       ((time.time() - wall_start_time) % total_seconds))
Ejemplo n.º 8
0
def generate(unused_argv):
    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"))

    generator_map = drums_rnn_sequence_generator.get_generator_map()
    generator = generator_map["drum_kit"](checkpoint=None, bundle=bundle)
    generator.initialize()

    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

    # This time we get the primer from disk instead of hard coding it
    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

    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)

    sequence = generator.generate(primer_sequence, generator_options)

    plot_file = os.path.join("output", "out.html")
    pretty_midi = mm.midi_io.note_sequence_to_pretty_midi(sequence)
    plotter = Plotter()
    plotter.show(pretty_midi, plot_file)
    print("Generated plot file: " + str(os.path.abspath(plot_file)))

    # We find the proper input port for the software synth,
    # this should work on all platforms (if you followed the
    # installation instructions)
    input_ports = [
        name for name in mido.get_output_names()
        if "VirtualMIDISynth" in name or "FLUID Synth" in name
    ]
    if not input_ports:
        print("Cannot find proper input port in " +
              str(mido.get_output_names()))
    print("Playing generated MIDI in input port names: " + str(input_ports))

    # Start a new MIDI hub on that port (incoming only)
    midi_hub = mh.MidiHub([], input_ports, None)

    # Start on a empty sequence, allowing the update of the
    # sequence for later. We don't especially need that right
    # now, because we could play the sequence immediately, but
    # it will be useful for later examples to have a player to
    # update new sequences with.
    empty_sequence = music_pb2.NoteSequence()
    player = midi_hub.start_playback(empty_sequence, allow_updates=True)
    # Remember that GM 1 compatible synthesizer will play the drums
    # sound bank if the MIDI channel is 10 (but the channel is zero
    # indexed in Magenta MIDI hub so you have to use 9).
    player._channel = 9

    # Now we can play our sequence, but we need to adjust it first.
    # The MIDI player will play the sequence according to wall time,
    # but our sequence starts at 0.
    # Create a new empty note sequence, copy the sequence
    # we want to play in the empty sequence, then move the
    # start of the sequence by wall_start_time amount
    wall_start_time = time.time()
    sequence_adjusted = music_pb2.NoteSequence()
    sequence_adjusted.CopyFrom(sequence)
    sequence_adjusted = adjust_sequence_times(sequence_adjusted,
                                              wall_start_time)

    # The update sequence is the equivalent of "play"
    player.update_sequence(sequence_adjusted, start_time=wall_start_time)

    # We "join" on the thread, meaning the call will block
    # until the player has finished. Because the thread
    # never stops, this call will block indefinitely. By
    # adding a timeout of generation_end_time, the call will
    # return after the end of the sequence being played.
    try:
        player.join(generation_end_time)
    except KeyboardInterrupt:
        # The KeyboardInterrupt is important if you want to press
        # CTRL-C during the playback to stop the player.
        return 0
    finally:
        return 0
Ejemplo n.º 9
0
    def run(self):
        # TODO
        sequence = self._primer_sequence
        player = self._midi_hub.start_playback(sequence, allow_updates=True)

        # TODO
        seconds_per_step = 60.0 / self._qpm / self._sequence_generator.steps_per_quarter
        num_steps_per_bar = self._sequence_generator.steps_per_quarter * 2
        seconds_per_bar = num_steps_per_bar * seconds_per_step
        seconds_per_loop = self._bar_per_loop * seconds_per_bar

        # TODO MOVE
        plotter = Plotter(max_bar=16, live_reload=True)
        pretty_midi = pm.PrettyMIDI()
        pretty_midi.instruments.append(pm.Instrument(0))
        pretty_midi.instruments[0].append(pm.Note(100, 36, 0, 1))

        # TODO
        wall_start_time = time.time()

        # TODO
        for bar_count in range(0, sys.maxsize):
            # TODO
            cursor_time = bar_count * seconds_per_loop

            # TODO
            sequence_adjusted = music_pb2.NoteSequence()
            sequence_adjusted.CopyFrom(sequence)
            sequence_adjusted = adjust_sequence_times(sequence_adjusted,
                                                      wall_start_time)
            player.update_sequence(sequence_adjusted, start_time=cursor_time)

            # TODO MOVE TO UTILS
            pretty_sequence = mm.midi_io.note_sequence_to_pretty_midi(sequence)
            for instrument in pretty_sequence.instruments:
                for note in instrument.notes:
                    pretty_midi.instruments[0].notes.append(note)
            plotter.show(pretty_midi, self._output_file)

            # TODO
            loop_start_time = cursor_time
            loop_end_time = loop_start_time + seconds_per_loop
            generation_start_time = loop_end_time
            generation_end_time = generation_start_time + seconds_per_loop
            generator_options = generator_pb2.GeneratorOptions()
            generator_options.args['temperature'].float_value = 1
            generator_options.generate_sections.add(
                start_time=generation_start_time, end_time=generation_end_time)

            # TODO
            if bar_count % self._num_loops == 0:
                print("GENERATING")
                sequence = self._sequence_generator.generate(
                    sequence, generator_options)
                sequence = sequences_lib.trim_note_sequence(
                    sequence, generation_start_time, generation_end_time)
            else:
                print("LOOPING")
                sequence = sequences_lib.trim_note_sequence(
                    sequence, loop_start_time, loop_end_time)
                sequence = sequences_lib.shift_sequence_times(
                    sequence, seconds_per_loop)

            # TODO 1 wake up per bar
            sleep_time = seconds_per_loop - (
                (time.time() - wall_start_time) % seconds_per_loop)
            time.sleep(sleep_time)
Ejemplo n.º 10
0
  def run(self):
    """The main loop for a real-time call and response interaction."""
    start_time = time.time()
    self._captor = self._midi_hub.start_capture(self._qpm, start_time)

    if not self._clock_signal and self._metronome_channel is not None:
      self._midi_hub.start_metronome(
          self._qpm, start_time, channel=self._metronome_channel)

    # Set callback for end call signal.
    if self._end_call_signal is not None:
      self._captor.register_callback(self._end_call_callback,
                                     signal=self._end_call_signal)
    if self._panic_signal is not None:
      self._captor.register_callback(self._panic_callback,
                                     signal=self._panic_signal)
    if self._mutate_signal is not None:
      self._captor.register_callback(self._mutate_callback,
                                     signal=self._mutate_signal)

    # Keep track of the end of the previous tick time.
    last_tick_time = time.time()

    # Keep track of the duration of a listen state.
    listen_ticks = 0

    # Start with an empty response sequence.
    response_sequence = music_pb2.NoteSequence()
    response_start_time = 0
    response_duration = 0
    player = self._midi_hub.start_playback(
        response_sequence, allow_updates=True)

    # Enter loop at each clock tick.
    for captured_sequence in self._captor.iterate(signal=self._clock_signal,
                                                  period=self._tick_duration):
      if self._stop_signal.is_set():
        break
      if self._panic.is_set():
        response_sequence = music_pb2.NoteSequence()
        player.update_sequence(response_sequence)
        self._panic.clear()

      tick_time = captured_sequence.total_time

      # Set to current QPM, since it might have changed.
      if not self._clock_signal and self._metronome_channel is not None:
        self._midi_hub.start_metronome(
            self._qpm, tick_time, channel=self._metronome_channel)
      captured_sequence.tempos[0].qpm = self._qpm

      tick_duration = tick_time - last_tick_time
      if captured_sequence.notes:
        last_end_time = max(note.end_time for note in captured_sequence.notes)
      else:
        last_end_time = 0.0

      # True iff there was no input captured during the last tick.
      silent_tick = last_end_time <= last_tick_time

      if not silent_tick:
        listen_ticks += 1

      if not captured_sequence.notes:
        # Reset captured sequence since we are still idling.
        if response_sequence.total_time <= tick_time:
          self._update_state(self.State.IDLE)
        if self._captor.start_time < tick_time:
          self._captor.start_time = tick_time
        self._end_call.clear()
        listen_ticks = 0
      elif (self._end_call.is_set() or
            silent_tick or
            listen_ticks >= self._max_listen_ticks):
        if listen_ticks < self._min_listen_ticks:
          tf.logging.info(
              'Input too short (%d vs %d). Skipping.',
              listen_ticks,
              self._min_listen_ticks)
          self._captor.start_time = tick_time
        else:
          # Create response and start playback.
          self._update_state(self.State.RESPONDING)

          capture_start_time = self._captor.start_time

          if silent_tick:
            # Move the sequence forward one tick in time.
            captured_sequence = adjust_sequence_times(
                captured_sequence, tick_duration)
            captured_sequence.total_time = tick_time
            capture_start_time += tick_duration

          # Compute duration of response.
          num_ticks = self._midi_hub.control_value(
              self._response_ticks_control_number)

          if num_ticks:
            response_duration = num_ticks * tick_duration
          else:
            # Use capture duration.
            response_duration = tick_time - capture_start_time

          response_start_time = tick_time
          response_sequence = self._generate(
              captured_sequence,
              capture_start_time,
              response_start_time,
              response_start_time + response_duration)

          # If it took too long to generate, push response to next tick.
          if (time.time() - response_start_time) >= tick_duration / 4:
            push_ticks = (
                (time.time() - response_start_time) // tick_duration + 1)
            response_start_time += push_ticks * tick_duration
            response_sequence = adjust_sequence_times(
                response_sequence, push_ticks * tick_duration)
            tf.logging.warn(
                'Response too late. Pushing back %d ticks.', push_ticks)

          # Start response playback. Specify the start_time to avoid stripping
          # initial events due to generation lag.
          player.update_sequence(
              response_sequence, start_time=response_start_time)

          # Optionally capture during playback.
          if self._allow_overlap:
            self._captor.start_time = response_start_time
          else:
            self._captor.start_time = response_start_time + response_duration

        # Clear end signal and reset listen_ticks.
        self._end_call.clear()
        listen_ticks = 0
      else:
        # Continue listening.
        self._update_state(self.State.LISTENING)

      # Potentially loop or mutate previous response.
      if self._mutate.is_set() and not response_sequence.notes:
        self._mutate.clear()
        tf.logging.warn('Ignoring mutate request with nothing to mutate.')

      if (response_sequence.total_time <= tick_time and
          (self._should_loop or self._mutate.is_set())):
        if self._mutate.is_set():
          new_start_time = response_start_time + response_duration
          new_end_time = new_start_time + response_duration
          response_sequence = self._generate(
              response_sequence,
              response_start_time,
              new_start_time,
              new_end_time)
          response_start_time = new_start_time
          self._mutate.clear()

        response_sequence = adjust_sequence_times(
            response_sequence, tick_time - response_start_time)
        response_start_time = tick_time
        player.update_sequence(
            response_sequence, start_time=tick_time)

      last_tick_time = tick_time

    player.stop()