def testSleeper_SleepUntil(self):
        # Burn in.
        for _ in range(10):
            concurrency.Sleeper().sleep(.01)

        future_time = time.time() + 0.5
        concurrency.Sleeper().sleep_until(future_time)
        self.assertAlmostEqual(time.time(), future_time, delta=0.005)
예제 #2
0
    def testStartPlayback_Updates(self):
        start_time = time.time() + 0.1
        seq = music_pb2.NoteSequence()
        notes = [
            Note(0, 100, start_time, start_time + 101),
            Note(1, 100, start_time, start_time + 101)
        ]
        testing_lib.add_track_to_sequence(seq, 0, notes)
        player = self.midi_hub.start_playback(seq, allow_updates=True)

        # Sleep past first note start.
        concurrency.Sleeper().sleep_until(start_time + 0.2)

        new_seq = music_pb2.NoteSequence()
        notes = [
            Note(1, 100, 0.0, 0.8),
            Note(2, 100, 0.0, 1.0),
            Note(11, 55, 0.3, 0.5),
            Note(40, 45, 0.4, 0.6)
        ]
        notes = [
            Note(note.pitch, note.velocity, note.start + start_time,
                 note.end + start_time) for note in notes
        ]
        testing_lib.add_track_to_sequence(new_seq, 0, notes)
        player.update_sequence(new_seq)

        # Finish playing sequence.
        concurrency.Sleeper().sleep(0.8)

        # Start and end the unclosed note from the first sequence.
        note_events = [(start_time, 'note_on', 0),
                       (start_time + 0.3, 'note_off', 0)]
        # The second note will not be played since it started before the update
        # and was not in the original sequence.
        del notes[1]
        for note in notes:
            note_events.append((note.start, 'note_on', note.pitch))
            note_events.append((note.end, 'note_off', note.pitch))
        note_events = collections.deque(sorted(note_events))
        while not self.port.message_queue.empty():
            msg = self.port.message_queue.get()
            note_event = note_events.popleft()
            self.assertEqual(msg.type, note_event[1])
            self.assertEqual(msg.note, note_event[2])
            self.assertAlmostEqual(msg.time, note_event[0], delta=0.01)

        self.assertTrue(not note_events)
        player.stop()
예제 #3
0
    def run(self):
        """Sends message on the qpm interval until stop signal received."""
        sleeper = concurrency.Sleeper()
        while True:
            now = time.time()
            tick_number = max(
                0,
                int((now - self._start_time) // self._period) + 1)
            tick_time = tick_number * self._period + self._start_time

            if self._stop_time is not None and self._stop_time < tick_time:
                break

            sleeper.sleep_until(tick_time)

            metric_position = tick_number % len(self._messages)
            tick_message = self._messages[metric_position]

            if tick_message is None:
                continue

            tick_message.channel = self._channel
            self._outport.send(tick_message)

            if tick_message.type == 'note_on':
                sleeper.sleep(self._duration)
                end_tick_message = mido.Message('note_off',
                                                note=tick_message.note,
                                                channel=self._channel)
                self._outport.send(end_tick_message)
예제 #4
0
    def wait_for_event(self, signal=None, timeout=None):
        """Blocks until a matching mido.Message arrives or the timeout occurs.

    Exactly one of `signal` or `timeout` must be specified. Using a timeout
    with a threading.Condition object causes additional delays when notified.

    Args:
      signal: A MidiSignal to use as a signal to stop waiting, or None.
      timeout: A float timeout in seconds, or None.

    Raises:
      MidiHubError: If neither `signal` nor `timeout` or both are specified.
    """
        if (signal, timeout).count(None) != 1:
            raise MidiHubError(
                'Exactly one of `signal` or `timeout` must be provided to '
                '`wait_for_event` call.')

        if signal is None:
            concurrency.Sleeper().sleep(timeout)
            return

        signal_pattern = str(signal)
        cond_var = None
        for regex, cond_var in self._signals:
            if regex.pattern == signal_pattern:
                break
        if cond_var is None:
            cond_var = threading.Condition(self._lock)
            self._signals[re.compile(signal_pattern)] = cond_var

        cond_var.wait()
예제 #5
0
    def run(self):
        """Outputs metronome tone on the qpm interval until stop signal received."""
        period = 60. / self._qpm
        sleeper = concurrency.Sleeper()
        now = time.time()
        next_tick_time = max(
            self._start_time,
            now + period - ((now - self._start_time) % period))
        while self._stop_time is None or self._stop_time > next_tick_time:
            sleeper.sleep_until(next_tick_time)

            self._outport.send(
                mido.Message(type='note_on',
                             note=self._pitch,
                             channel=_METRONOME_CHANNEL,
                             velocity=self._velocity))

            sleeper.sleep(self._duration)

            self._outport.send(
                mido.Message(type='note_off',
                             note=self._pitch,
                             channel=_METRONOME_CHANNEL))

            now = time.time()
            next_tick_time = now + period - ((now - self._start_time) % period)
예제 #6
0
    def run(self):
        """Outputs metronome tone on the qpm interval until stop signal received."""
        sleeper = concurrency.Sleeper()
        while True:
            now = time.time()
            tick_number = max(
                0,
                int((now - self._start_time) // self._period) + 1)
            tick_time = tick_number * self._period + self._start_time

            if self._stop_time is not None and self._stop_time < tick_time:
                break

            sleeper.sleep_until(tick_time)

            metric_position = tick_number % len(self._pitches)
            self._outport.send(
                mido.Message(type='note_on',
                             note=self._pitches[metric_position],
                             channel=_METRONOME_CHANNEL,
                             velocity=self._velocity))

            sleeper.sleep(self._duration)

            self._outport.send(
                mido.Message(type='note_off',
                             note=self._pitches[metric_position],
                             channel=_METRONOME_CHANNEL))
예제 #7
0
  def testSleeper_Sleep(self):
    # Burn in.
    for _ in range(10):
      concurrency.Sleeper().sleep(.01)

    def sleep_test_thread(duration):
      start_time = time.time()
      concurrency.Sleeper().sleep(duration)
      self.assertAlmostEqual(time.time(), start_time + duration, delta=0.005)

    threads = [threading.Thread(target=sleep_test_thread, args=[i * 0.1])
               for i in range(10)]
    for t in threads:
      t.start()
    for t in threads:
      t.join()
예제 #8
0
    def iterate(self, signal=None, period=None):
        if (signal, period).count(None) != 1:
            raise MidiHubException(
                'Exactly one of `signal` or `period` must be provided to `iterate` '
                'call.')

        if signal is None:
            sleeper = concurrency.Sleeper()
            next_yield_time = time.time() + period
        else:
            regex = re.compile(str(signal))
            queue = Queue()
            with self._lock:
                self._iter_signals.append((regex, queue))

        while self.is_alive():
            if signal is None:
                skipped_periods = (time.time() - next_yield_time) // period
                if skipped_periods > 0:
                    tf.logging.warn(
                        'Skipping %d %.3fs period(s) to catch up on iteration.',
                        skipped_periods, period)
                    next_yield_time += skipped_periods * period
                else:
                    sleeper.sleep_until(next_yield_time)
                end_time = next_yield_time
                next_yield_time += period
            else:
                signal_msg = queue.get()
                if signal_msg is MidiCaptor._WAKE_MESSAGE:
                    # This is only recieved when the thread is in the process of
                    # terminating. Wait until it is done before yielding the final
                    # sequence.
                    self.join()
                    break
                end_time = signal_msg.time
            # Acquire lock so that `captured_sequence` will be called before thread
            # terminates, if it has not already done so.
            with self._lock:
                if not self.is_alive():
                    break
                captured_sequence = self.captured_sequence(end_time)
            yield captured_sequence
        yield self.captured_sequence()
예제 #9
0
    def wait_for_event(self, signal=None, timeout=None):
        if (signal, timeout).count(None) != 1:
            raise MidiHubException(
                'Exactly one of `signal` or `timeout` must be provided to '
                '`wait_for_event` call.')

        if signal is None:
            concurrency.Sleeper().sleep(timeout)
            return

        signal_pattern = str(signal)
        cond_var = None
        for regex, cond_var in self._signals:
            if regex.pattern == signal_pattern:
                break
        if cond_var is None:
            cond_var = threading.Condition(self._lock)
            self._signals[re.compile(signal_pattern)] = cond_var

        cond_var.wait()
예제 #10
0
  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)
예제 #11
0
    def iterate(self, signal=None, period=None):
        """Yields the captured sequence at every signal message or time period.

    Exactly one of `signal` or `period` must be specified. Continues until the
    captor terminates, at which point the final captured sequence is yielded
    before returning.

    If consecutive calls to iterate are longer than the period, immediately
    yields and logs a warning.

    Args:
      signal: A MidiSignal to use as a signal to yield, or None.
      period: A float period in seconds, or None.

    Yields:
      The captured NoteSequence at event time.

    Raises:
      MidiHubError: If neither `signal` nor `period` or both are specified.
    """
        if (signal, period).count(None) != 1:
            raise MidiHubError(
                'Exactly one of `signal` or `period` must be provided to `iterate` '
                'call.')

        if signal is None:
            sleeper = concurrency.Sleeper()
            next_yield_time = time.time() + period
        else:
            regex = re.compile(str(signal))
            queue = Queue.Queue()
            with self._lock:
                self._iter_signals.append((regex, queue))

        while self.is_alive():
            if signal is None:
                skipped_periods = (time.time() - next_yield_time) // period
                if skipped_periods > 0:
                    tf.logging.warn(
                        'Skipping %d %.3fs period(s) to catch up on iteration.',
                        skipped_periods, period)
                    next_yield_time += skipped_periods * period
                else:
                    sleeper.sleep_until(next_yield_time)
                end_time = next_yield_time
                next_yield_time += period
            else:
                signal_msg = queue.get()
                if signal_msg is MidiCaptor._WAKE_MESSAGE:
                    # This is only recieved when the thread is in the process of
                    # terminating. Wait until it is done before yielding the final
                    # sequence.
                    self.join()
                    break
                end_time = signal_msg.time
            # Acquire lock so that `captured_sequence` will be called before thread
            # terminates, if it has not already done so.
            with self._lock:
                if not self.is_alive():
                    break
                captured_sequence = self.captured_sequence(end_time)
            yield captured_sequence
        yield self.captured_sequence()
 def sleep_test_thread(duration):
     start_time = time.time()
     concurrency.Sleeper().sleep(duration)
     self.assertAlmostEqual(time.time(),
                            start_time + duration,
                            delta=0.005)
예제 #13
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