def testPassThrough_Mono(self): self.midi_hub = midi_hub.MidiHub([self.port], [self.port], midi_hub.TextureType.MONOPHONIC) self.midi_hub.passthrough = False self.send_capture_messages() self.assertTrue(self.port.message_queue.empty()) self.midi_hub.passthrough = True self.send_capture_messages() passed_messages = [] while not self.port.message_queue.empty(): passed_messages.append(self.port.message_queue.get()) passed_messages[-1].time = 0 expected_messages = [ mido.Message(type='note_on', note=0), mido.Message(type='control_change', control=1, value=1), mido.Message(type='note_off', note=0), mido.Message(type='note_on', note=1), mido.Message(type='note_off', note=1), mido.Message(type='note_on', note=2), mido.Message(type='note_off', note=2), mido.Message(type='note_on', note=3), mido.Message(type='control_change', control=1, value=1), mido.Message(type='note_off', note=3) ] self.assertListEqual(passed_messages, expected_messages)
def main(unused_argv): tf.logging.set_verbosity(FLAGS.log) # Initialize MidiHub. hub = midi_hub.MidiHub(None, FLAGS.output_ports.split(','), midi_hub.TextureType.MONOPHONIC) cc = FLAGS.clock_control_number # Assumes 4 beats per bar. metronome_signals = ([midi_hub.MidiSignal(control=cc, value=127)] + [midi_hub.MidiSignal(control=cc, value=0)] * 3) hub.start_metronome(FLAGS.qpm, start_time=0, signals=metronome_signals, channel=FLAGS.channel) try: while True: time.sleep(1) except KeyboardInterrupt: hub.stop_metronome() print('Clock stopped.')
def main(unused_argv): tf.logging.set_verbosity(FLAGS.log) if not _validate_flags(): return # Load generators. generators = [] for bundle_file in FLAGS.bundle_files.split(','): generators.append(_load_generator_from_bundle_file(bundle_file)) if generators[-1] is None: return # Initialize MidiHub. if FLAGS.input_port not in midi_hub.get_available_input_ports(): print "Opening '%s' as a virtual MIDI port for input." % FLAGS.input_port if FLAGS.output_port not in midi_hub.get_available_output_ports(): print "Opening '%s' as a virtual MIDI port for output." % FLAGS.output_port hub = midi_hub.MidiHub(FLAGS.input_port, FLAGS.output_port, midi_hub.TextureType.MONOPHONIC) start_call_signal = ( None if FLAGS.start_call_control_number is None else midi_hub.MidiSignal(control=FLAGS.start_call_control_number, value=0)) end_call_signal = ( None if FLAGS.end_call_control_number is None else midi_hub.MidiSignal(control=FLAGS.end_call_control_number, value=0)) interaction = midi_interaction.CallAndResponseMidiInteraction( hub, generators, FLAGS.qpm, generator_select_control_number=FLAGS.generator_select_control_number, phrase_bars=FLAGS.phrase_bars, start_call_signal=start_call_signal, end_call_signal=end_call_signal, temperature_control_number=FLAGS.temperature_control_number) _print_instructions() interaction.start() try: while True: time.sleep(1) except KeyboardInterrupt: interaction.stop() print 'Interaction stopped.'
def testCaptureSequence_Mono(self): start_time = 1.0 threading.Timer(0.1, self.send_capture_messages).start() self.midi_hub = midi_hub.MidiHub([self.port], [self.port], midi_hub.TextureType.MONOPHONIC) captured_seq = self.midi_hub.capture_sequence( 120, start_time, stop_signal=midi_hub.MidiSignal(type='control_change', control=1)) expected_seq = music_pb2.NoteSequence() expected_seq.tempos.add(qpm=120) expected_seq.total_time = 6 testing_lib.add_track_to_sequence( expected_seq, 0, [Note(1, 64, 2, 3), Note(2, 64, 3, 4), Note(3, 64, 4, 6)]) self.assertProtoEquals(captured_seq, expected_seq)
def setUp(self): self.maxDiff = None self.capture_messages = [ mido.Message(type='note_on', note=0, time=0.01), mido.Message(type='control_change', control=1, value=1, time=0.02), mido.Message(type='note_on', note=1, time=2.0), mido.Message(type='note_off', note=0, time=3.0), mido.Message(type='note_on', note=2, time=3.0), mido.Message(type='note_on', note=3, time=4.0), mido.Message(type='note_off', note=2, time=4.0), mido.Message(type='note_off', note=1, time=5.0), mido.Message(type='control_change', control=1, value=1, time=6.0), mido.Message(type='note_off', note=3, time=100)] self.port = MockMidiPort() self.midi_hub = midi_hub.MidiHub([self.port], [self.port], midi_hub.TextureType.POLYPHONIC) # Burn in Sleeper for calibration. for _ in range(5): concurrency.Sleeper().sleep(0.05)
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
def main(unused_argv): tf.logging.set_verbosity(FLAGS.log) if not _validate_flags(): return # Load generators. generators = [] for bundle_file in FLAGS.bundle_files.split(','): generators.append(_load_generator_from_bundle_file(bundle_file)) if generators[-1] is None: return # Initialize MidiHub. if FLAGS.input_port not in midi_hub.get_available_input_ports(): print "Opening '%s' as a virtual MIDI port for input." % FLAGS.input_port if FLAGS.output_port not in midi_hub.get_available_output_ports(): print "Opening '%s' as a virtual MIDI port for output." % FLAGS.output_port hub = midi_hub.MidiHub(FLAGS.input_port, FLAGS.output_port, midi_hub.TextureType.MONOPHONIC, passthrough=FLAGS.passthrough, playback_channel=FLAGS.playback_channel, playback_offset=FLAGS.playback_offset) if FLAGS.clock_control_number is None: # Set the tick duration to be a single bar, assuming a 4/4 time signature. clock_signal = None tick_duration = 4 * (60. / FLAGS.qpm) else: clock_signal = midi_hub.MidiSignal(control=FLAGS.clock_control_number, value=127) tick_duration = None end_call_signal = (None if FLAGS.end_call_control_number is None else midi_hub.MidiSignal( control=FLAGS.end_call_control_number, value=127)) panic_signal = (None if FLAGS.panic_control_number is None else midi_hub.MidiSignal(control=FLAGS.panic_control_number, value=127)) mutate_signal = (None if FLAGS.mutate_control_number is None else midi_hub.MidiSignal(control=FLAGS.mutate_control_number, value=127)) interaction = midi_interaction.CallAndResponseMidiInteraction( hub, generators, FLAGS.qpm, FLAGS.generator_select_control_number, clock_signal=clock_signal, tick_duration=tick_duration, end_call_signal=end_call_signal, panic_signal=panic_signal, mutate_signal=mutate_signal, allow_overlap=FLAGS.allow_overlap, enable_metronome=FLAGS.enable_metronome, min_listen_ticks_control_number=FLAGS.min_listen_ticks_control_number, max_listen_ticks_control_number=FLAGS.max_listen_ticks_control_number, response_ticks_control_number=FLAGS.response_ticks_control_number, tempo_control_number=FLAGS.tempo_control_number, temperature_control_number=FLAGS.temperature_control_number, loop_control_number=FLAGS.loop_control_number, state_control_number=FLAGS.state_control_number) _print_instructions() interaction.start() try: while True: time.sleep(1) except KeyboardInterrupt: interaction.stop() print 'Interaction stopped.'
def main(unused_argv): tf.logging.set_verbosity(FLAGS.log) if not _validate_flags(): return # Load generators. generators = [] for bundle_file in FLAGS.bundle_files.split(','): generators.append(_load_generator_from_bundle_file(bundle_file)) if generators[-1] is None: return # Initialize MidiHub. hub = midi_hub.MidiHub(FLAGS.input_ports.split(','), FLAGS.output_ports.split(','), midi_hub.TextureType.POLYPHONIC, passthrough=FLAGS.passthrough, playback_channel=FLAGS.playback_channel, playback_offset=FLAGS.playback_offset) control_map = { re.sub('_control_number$', '', f): FLAGS.__getattr__(f) for f in _CONTROL_FLAGS } if FLAGS.learn_controls: CCMapper(control_map, hub).update_map() if control_map['clock'] is None: # Set the tick duration to be a single bar, assuming a 4/4 time signature. clock_signal = None tick_duration = 4 * (60. / FLAGS.qpm) else: clock_signal = midi_hub.MidiSignal(control=control_map['clock'], value=127) tick_duration = None end_call_signal = (None if control_map['end_call'] is None else midi_hub.MidiSignal(control=control_map['end_call'], value=127)) panic_signal = (None if control_map['panic'] is None else midi_hub.MidiSignal(control=control_map['panic'], value=127)) mutate_signal = (None if control_map['mutate'] is None else midi_hub.MidiSignal(control=control_map['mutate'], value=127)) metronome_channel = (FLAGS.metronome_channel if FLAGS.enable_metronome else None) interaction = midi_interaction.CallAndResponseMidiInteraction( hub, generators, FLAGS.qpm, FLAGS.generator_select_control_number, clock_signal=clock_signal, tick_duration=tick_duration, end_call_signal=end_call_signal, panic_signal=panic_signal, mutate_signal=mutate_signal, allow_overlap=FLAGS.allow_overlap, metronome_channel=metronome_channel, min_listen_ticks_control_number=control_map['min_listen_ticks'], max_listen_ticks_control_number=control_map['max_listen_ticks'], response_ticks_control_number=control_map['response_ticks'], tempo_control_number=control_map['tempo'], temperature_control_number=control_map['temperature'], loop_control_number=control_map['loop'], state_control_number=control_map['state']) _print_instructions() interaction.start() try: while True: time.sleep(1) except KeyboardInterrupt: interaction.stop() print 'Interaction stopped.'
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
def main(unused_argv): if FLAGS.list_ports: print "Input ports: '%s'" % ("', '".join( midi_hub.get_available_input_ports())) print "Ouput ports: '%s'" % ("', '".join( midi_hub.get_available_output_ports())) return if FLAGS.bundle_file is None: print '--bundle_file must be specified.' return if (FLAGS.end_call_control_number, FLAGS.phrase_bars).count(None) != 1: print( 'Exactly one of --end_call_control_number or --phrase_bars should be ' 'specified.') return try: bundle = magenta.music.sequence_generator_bundle.read_bundle_file( FLAGS.bundle_file) except magenta.music.sequence_generator_bundle.GeneratorBundleParseException: print 'Failed to parse bundle file: %s' % FLAGS.bundle_file return generator_id = bundle.generator_details.id if generator_id not in _GENERATOR_FACTORY_MAP: print "Unrecognized SequenceGenerator ID '%s' in bundle file: %s" % ( generator_id, FLAGS.bundle_file) return generator = _GENERATOR_FACTORY_MAP[generator_id].create_generator( checkpoint=None, bundle=bundle) generator.initialize() print "Loaded '%s' generator bundle from file '%s'." % ( bundle.generator_details.id, FLAGS.bundle_file) if FLAGS.input_port not in midi_hub.get_available_input_ports(): print "Opening '%s' as a virtual MIDI port for input." % FLAGS.input_port if FLAGS.output_port not in midi_hub.get_available_output_ports(): print "Opening '%s' as a virtual MIDI port for output." % FLAGS.output_port hub = midi_hub.MidiHub(FLAGS.input_port, FLAGS.output_port, midi_hub.TextureType.MONOPHONIC) end_call_signal = (None if FLAGS.end_call_control_number is None else midi_hub.MidiSignal( control=FLAGS.end_call_control_number, value=0)) interaction = midi_interaction.CallAndResponseMidiInteraction( hub, FLAGS.qpm, generator, phrase_bars=FLAGS.phrase_bars, end_call_signal=end_call_signal) print '' print 'Instructions:' print 'Play when you hear the metronome ticking.' if FLAGS.phrase_bars is not None: print('After %d bars (4 beats), Magenta will play its response.' % FLAGS.phrase_bars) print( 'Once the response completes, the metronome will tick and you can ' 'play again.') else: print( 'When you want to end the call phrase, signal control number %d ' 'with value 0' % FLAGS.end_call_control_number) print( 'At the end of the current bar (4 beats), Magenta will play its ' 'response.') print( 'Once the response completes, the metronome will tick and you can ' 'play again.') print '' print 'To end the interaction, press CTRL-C.' interaction.start() try: while True: time.sleep(1) except KeyboardInterrupt: interaction.stop() print 'Interaction stopped.'
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
def app(unused_argv): tf.logging.debug("Starting app") # Start action server action_server = ActionServer() action_server.start() # Init midi ports, keep direct references to output_ports for # direct sending without the hub player if platform.system() == "Windows": input_ports = [ port for port in midi_hub.get_available_input_ports() if MIDI_INPUT_PORT in port ] output_ports = [ port for port in midi_hub.get_available_output_ports() if MIDI_OUTPUT_PORT in port ] if len(input_ports) is not 1 or len(output_ports) is not 1: raise Exception(f"Need exactly 1 midi input ({input_ports}) " f"matching {MIDI_INPUT_PORT}" f"and 1 midi output port ({output_ports}) " f"matching {MIDI_OUTPUT_PORT}," f"you can use LoopMIDI for that") else: input_ports = [MIDI_INPUT_PORT] output_ports = [MIDI_OUTPUT_PORT] hub = midi_hub.MidiHub(input_ports, output_ports, None) output_port = hub._outport.ports[0] # Panic to stop all current messages (note off everywhere) [output_port.send(message) for message in mido.ports.panic_messages()] # Synchronise event for all the loopers, controlled by the metronome bar_start_event = threading.Event() # Common stuff qpm = 80 timing = Timing(qpm) loopers = [] try: # Init and start the loopers, they block on the event drum_looper = SequenceLooper("drums", bar_start_event, action_server, hub, "drum_kit_rnn", "drum_kit", timing, midi_channel=9, bar_per_loop=2) melody_looper = SequenceLooper("melody", bar_start_event, action_server, hub, "attention_rnn", "attention_rnn", timing, midi_channel=0, bar_per_loop=4) loopers.append(drum_looper) loopers.append(melody_looper) [looper.start() for looper in loopers] tf.logging.debug("Loopers started " + str([("drum_looper", drum_looper), ("melody_looper", melody_looper)])) # Start metronome (wait to make sure everything is started) time.sleep(1) metronome = Metronome(bar_start_event, timing) loopers.append(metronome) metronome.start() tf.logging.debug("Metronome started " + str([("metronome", metronome)])) # Wait for the loopers [looper.join() for looper in loopers] except KeyboardInterrupt: print("SIGINT received, stopping action server, loopers and stuff") action_server.stop() [looper.stop() for looper in loopers] return 1 return 0