'Calls `fn` at every signal message or time period.
The callback function must take exactly one argument, which will be the
current captured NoteSequence.
Exactly one of `signal` or `period` must be specified. Continues until the
captor thread terminates, at which point the callback is called with the
final sequence, or `cancel_callback` is called.
If callback execution is longer than a period, immediately calls upon
completion and logs a warning.
Args:
fn: The callback function to call, passing in the captured sequence.
signal: A MidiSignal to use as a signal to call `fn` on the current
captured sequence, or None.
period: A float period in seconds to specify how often to call `fn`, or
None.
Returns:
The unqiue name of the callback thread to enable cancellation.
Raises:
MidiHubException: If neither `signal` nor `period` or both are specified.'

def register_callback(self, fn, signal=None, period=None):

    class IteratorCallback(threading.Thread, ):
        'A    thread    for    executing    a    callback    on    each    iteration.'
        def __init__(self, iterator, fn):
            self._iterator = iterator
            self._fn = fn
            self._stop_signal = threading.Event()
            super(IteratorCallback, self).__init__()
        def run(self):
            'Calls    the    callback    function    for    each    iterator    value.'
            for captured_sequence in self._iterator:
                if self._stop_signal.is_set():
                    break
                self._fn(captured_sequence)
        def stop(self):
            'Stops    the    thread    on    next    iteration,    without    blocking.'
            self._stop_signal.set()
    t = IteratorCallback(self.iterate(signal, period), fn)
    t.start()
    with self._lock:
        assert (t.name not in self._callbacks)
        self._callbacks[t.name] = t
    return t.name
