Ejemplo n.º 1
0
    def __init__(self, cue):
        self.notify = Signal()

        self._clock = self._Clock
        self._active = False
        self._cue = cue
        self._cue.changed('duration').connect(self.__init)

        self.__init()
Ejemplo n.º 2
0
class CueTime(metaclass=MetaCueTime):
    """Provide timing for a Cue.

    Once created the notify signal provide timing for the given cue.
    The current time is queried using `Cue.current_time()`.

    .. note::
        The notify signal is emitted only when the cue is running.
    """
    _Clock = Clock_100

    def __init__(self, cue):
        self.notify = Signal()

        self._clock = self._Clock
        self._active = False
        self._cue = cue
        self._cue.changed('duration').connect(self.__init)

        self.__init()

    def __init(self, *args):
        if self._cue.duration > 0 and not self._active:
            # Cue "status" signals
            self._cue.started.connect(self.start, Connection.QtQueued)
            self._cue.paused.connect(self.stop, Connection.QtQueued)
            self._cue.stopped.connect(self.stop, Connection.QtQueued)
            self._cue.end.connect(self.stop, Connection.QtQueued)
            self._cue.error.connect(self.stop, Connection.QtQueued)

            if self._cue.state & CueState.Running:
                self.start()
            self._active = True
        elif self._cue.duration < 0 and self._active:
            self._cue.started.disconnect(self.start)
            self._cue.paused.disconnect(self.stop)
            self._cue.stopped.disconnect(self.stop)
            self._cue.end.disconnect(self.stop)
            self._cue.error.disconnect(self.stop)

            self.stop()
            self._active = False

    def __notify(self):
        """Notify the cue current-time"""
        if self._cue.state & (CueState.Running ^ CueState.Pause):
            self.notify.emit(self._cue.current_time())

    def start(self):
        self._clock.add_callback(self.__notify)

    def stop(self):
        try:
            self._clock.remove_callback(self.__notify)
        except Exception:
            # TODO: catch only the exception when the callback is not registered
            pass
Ejemplo n.º 3
0
    def __init__(self):
        super().__init__()
        self.discovered = Signal()

        # Create UDP socket
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)

        self._running = True
        self._cache = []
Ejemplo n.º 4
0
class Dbmeter(GstMediaElement):
    ElementType = ElementType.Plugin
    MediaType = MediaType.Audio
    Name = "DbMeter"

    interval = GstProperty('level', default=50 * Gst.MSECOND)
    peak_ttl = GstProperty('level', default=Gst.SECOND, gst_name='peak-ttl')
    peak_falloff = GstProperty('level', default=20, gst_name='peak-falloff')

    def __init__(self, pipeline):
        super().__init__()

        self.level_ready = Signal()

        self.pipeline = pipeline
        self.level = Gst.ElementFactory.make('level', None)
        self.level.set_property('post-messages', True)
        self.level.set_property('interval', 50 * Gst.MSECOND)
        self.level.set_property('peak-ttl', Gst.SECOND)
        self.level.set_property('peak-falloff', 20)
        self.audio_convert = Gst.ElementFactory.make('audioconvert', None)

        self.pipeline.add(self.level)
        self.pipeline.add(self.audio_convert)

        self.level.link(self.audio_convert)

        bus = self.pipeline.get_bus()
        bus.add_signal_watch()
        self._handler = bus.connect('message::element', self.__on_message)

    def dispose(self):
        bus = self.pipeline.get_bus()
        bus.remove_signal_watch()
        bus.disconnect(self._handler)

    def sink(self):
        return self.level

    def src(self):
        return self.audio_convert

    def __on_message(self, bus, message):
        if message.src == self.level:
            structure = message.get_structure()
            if structure is not None and structure.has_name('level'):
                self.level_ready.emit(structure.get_value('peak'),
                                      structure.get_value('rms'),
                                      structure.get_value('decay'))
Ejemplo n.º 5
0
class DbMeter(GstMediaElement):
    ElementType = ElementType.Plugin
    MediaType = MediaType.Audio
    Name = QT_TRANSLATE_NOOP('MediaElementName', 'dB Meter')

    interval = GstProperty('level', default=50 * Gst.MSECOND)
    peak_ttl = GstProperty('level', default=Gst.SECOND, gst_name='peak-ttl')
    peak_falloff = GstProperty('level', default=20, gst_name='peak-falloff')

    def __init__(self, pipeline):
        super().__init__()

        self.level_ready = Signal()

        self.pipeline = pipeline
        self.level = Gst.ElementFactory.make('level', None)
        self.level.set_property('post-messages', True)
        self.level.set_property('interval', 50 * Gst.MSECOND)
        self.level.set_property('peak-ttl', Gst.SECOND)
        self.level.set_property('peak-falloff', 20)
        self.audio_convert = Gst.ElementFactory.make('audioconvert', None)

        self.pipeline.add(self.level)
        self.pipeline.add(self.audio_convert)

        self.level.link(self.audio_convert)

        bus = self.pipeline.get_bus()
        bus.add_signal_watch()
        self._handler = bus.connect('message::element', self.__on_message)

    def dispose(self):
        bus = self.pipeline.get_bus()
        bus.remove_signal_watch()
        bus.disconnect(self._handler)

    def sink(self):
        return self.level

    def src(self):
        return self.audio_convert

    def __on_message(self, bus, message):
        if message.src == self.level:
            structure = message.get_structure()
            if structure is not None and structure.has_name('level'):
                self.level_ready.emit(structure.get_value('peak'),
                                      structure.get_value('rms'),
                                      structure.get_value('decay'))
Ejemplo n.º 6
0
    def __init__(self):
        super().__init__()

        self.action_done = Signal()
        self.action_undone = Signal()
        self.action_redone = Signal()

        self._undo = deque()
        self._redo = deque()
        if self.MaxStackSize > 0:
            self._undo.maxlen = self.MaxStackSize
            self._redo.maxlen = self.MaxStackSize

        self._saved = False
        self._saved_action = None
Ejemplo n.º 7
0
    def __init__(self, files, threads, mode, ref_level, norm_level):
        super().__init__()
        self.setDaemon(True)

        self._futures = {}
        self._running = False
        self._action = GainAction()

        # file -> media {'filename1': [media1, media2], 'filename2': [media3]}
        self.files = files
        self.threads = threads
        self.mode = mode
        self.ref_level = ref_level
        self.norm_level = norm_level

        self.on_progress = Signal()
Ejemplo n.º 8
0
class CueWaitTime:
    """Provide timing for Cue pre/post waits.

    Once created the notify signal provide timing for the specified wait for the
    given cue.
    The time since the wait start is calculated internally using the :mod:`time`
    module functions.
    """
    class Mode(IntEnum):
        Pre = 0
        Post = 1

    def __init__(self, cue, mode=Mode.Pre):
        self.notify = Signal()

        self._clock = Clock_100
        self._start_time = 0
        self._last = 0
        self._cue = cue
        self._mode = mode

        if self._mode == CueWaitTime.Mode.Pre:
            self._cue.prewait_ended.connect(self.stop, Connection.QtQueued)
            self._cue.prewait_start.connect(self.start, Connection.QtQueued)
            self._cue.prewait_paused.connect(self.stop, Connection.QtQueued)
            self._cue.prewait_stopped.connect(self.stop, Connection.QtQueued)
        elif self._mode == CueWaitTime.Mode.Post:
            self._cue.postwait_ended.connect(self.stop, Connection.QtQueued)
            self._cue.postwait_start.connect(self.start, Connection.QtQueued)
            self._cue.postwait_paused.connect(self.stop, Connection.QtQueued)
            self._cue.postwait_stopped.connect(self.stop, Connection.QtQueued)

    def __notify(self):
        if self._mode == CueWaitTime.Mode.Pre:
            self.notify.emit(int(self._cue.prewait_time() * 100) * 10)
        else:
            self.notify.emit(int(self._cue.postwait_time() * 100) * 10)

    def start(self):
        self._clock.add_callback(self.__notify)

    def stop(self):
        try:
            self._clock.remove_callback(self.__notify)
        except Exception:
            # TODO: catch only the exception when the callback is not registered
            pass
Ejemplo n.º 9
0
class MIDIInput(MIDICommon):
    def __init__(self, port_name='AppDefault'):
        super().__init__(port_name=port_name)

        self.alternate_mode = False
        self.new_message = Signal()
        self.new_message_alt = Signal()

    def open(self):
        port_name = mido_port_name(self._port_name, 'I')
        self._port = mido_backend().open_input(name=port_name,
                                               callback=self.__new_message)

    def __new_message(self, message):
        if self.alternate_mode:
            self.new_message_alt.emit(message)
        else:
            self.new_message.emit(message)
Ejemplo n.º 10
0
    def __init__(self, cue, mode=Mode.Pre):
        self.notify = Signal()

        self._clock = Clock_100
        self._start_time = 0
        self._last = 0
        self._cue = cue
        self._mode = mode

        if self._mode == CueWaitTime.Mode.Pre:
            self._cue.prewait_ended.connect(self.stop, Connection.QtQueued)
            self._cue.prewait_start.connect(self.start, Connection.QtQueued)
            self._cue.prewait_paused.connect(self.stop, Connection.QtQueued)
            self._cue.prewait_stopped.connect(self.stop, Connection.QtQueued)
        elif self._mode == CueWaitTime.Mode.Post:
            self._cue.postwait_ended.connect(self.stop, Connection.QtQueued)
            self._cue.postwait_start.connect(self.start, Connection.QtQueued)
            self._cue.postwait_paused.connect(self.stop, Connection.QtQueued)
            self._cue.postwait_stopped.connect(self.stop, Connection.QtQueued)
Ejemplo n.º 11
0
class Discoverer(Thread):
    def __init__(self):
        super().__init__()
        self.discovered = Signal()

        # Create UDP socket
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)

        self._running = True
        self._cache = []

    def run(self):
        self._socket.sendto(bytes(MAGIC, 'utf-8'), ('<broadcast>', PORT))

        while self._running:
            data, addr = self._socket.recvfrom(1024)
            if data is not None and addr is not None:
                data = str(data, 'utf-8')
                # Take only the IP, discard the port
                addr = addr[0]
                # Check if valid and new announcement
                if data.startswith(MAGIC) and addr not in self._cache:
                    # Get the host name
                    host = data[len(MAGIC):]
                    # Append the adders to the cache
                    self._cache.append(addr)
                    # Emit
                    self.discovered.emit((addr, host))

    def stop(self):
        self._running = False
        try:
            self._socket.shutdown(socket.SHUT_RDWR)
        except Exception:
            pass
        self._socket.close()
        self.join()

    def get_discovered(self):
        return self._cache.copy()
Ejemplo n.º 12
0
    def __init__(self, pipeline):
        super().__init__()

        self.level_ready = Signal()

        self.pipeline = pipeline
        self.level = Gst.ElementFactory.make('level', None)
        self.level.set_property('post-messages', True)
        self.level.set_property('interval', 50 * Gst.MSECOND)
        self.level.set_property('peak-ttl', Gst.SECOND)
        self.level.set_property('peak-falloff', 20)
        self.audio_convert = Gst.ElementFactory.make('audioconvert', None)

        self.pipeline.add(self.level)
        self.pipeline.add(self.audio_convert)

        self.level.link(self.audio_convert)

        bus = self.pipeline.get_bus()
        bus.add_signal_watch()
        self._handler = bus.connect('message::element', self.__on_message)
Ejemplo n.º 13
0
    def __init__(self):
        self._elapsed = 0
        self._start_time = 0
        self._ended = False

        self._waiting = Event()
        self._waiting.set()
        self._is_waiting = Event()
        self._is_waiting.set()

        self.start = Signal()
        self.ended = Signal()
        self.paused = Signal()
        self.stopped = Signal()
Ejemplo n.º 14
0
class MIDIInputHandler(MIDICommon):

    def __init__(self, port_name='default', backend_name=None):
        super().__init__(port_name=port_name, backend_name=backend_name)

        self.alternate_mode = False
        self.new_message = Signal()
        self.new_message_alt = Signal()

    def __new_message(self, message):
        if self.alternate_mode:
            self.new_message_alt.emit(message)
        else:
            self.new_message.emit(message)

    def _open_port(self):
        # We don't expect to find a port named "default", if so, we assume
        # this port is the default one.
        if self._port_name in self.get_input_names():
            self._port = self._backend.open_input(self._port_name,
                                                  callback=self.__new_message)
        else:
            # If the port isn't available use the default one
            self._port = self._backend.open_input(callback=self.__new_message)
Ejemplo n.º 15
0
    def __init__(self, files, threads, mode, ref_level, norm_level):
        super().__init__()
        self.setDaemon(True)

        self._futures = {}
        self._running = False
        self._action = GainAction()

        # file -> media {"filename1": [media1, media2], "filename2": [media3]}
        self.files = files
        self.threads = threads
        self.mode = mode
        self.ref_level = ref_level
        self.norm_level = norm_level

        self.on_progress = Signal()
Ejemplo n.º 16
0
    def changed(self, property_name):
        """
        :param property_name: The property name
        :return: The property change-signal
        :rtype: Signal
        """
        if property_name not in self.__class__.__properties__:
            raise ValueError('no property "{0}" found'.format(property_name))

        signal = self.changed_signals.get(property_name, None)

        if signal is None:
            signal = Signal()
            self.changed_signals[property_name] = signal

        return signal
Ejemplo n.º 17
0
    def __init__(self):
        super().__init__()

        self.action_done = Signal()
        self.action_undone = Signal()
        self.action_redone = Signal()

        self._undo = deque()
        self._redo = deque()
        if self.MaxStackSize > 0:
            self._undo.maxlen = self.MaxStackSize
            self._redo.maxlen = self.MaxStackSize

        self._saved_action = None
Ejemplo n.º 18
0
    def __init__(self, pipeline):
        super().__init__()

        self.level_ready = Signal()

        self.pipeline = pipeline
        self.level = Gst.ElementFactory.make('level', None)
        self.level.set_property('post-messages', True)
        self.level.set_property('interval', 50 * Gst.MSECOND)
        self.level.set_property('peak-ttl', Gst.SECOND)
        self.level.set_property('peak-falloff', 20)
        self.audio_convert = Gst.ElementFactory.make('audioconvert', None)

        self.pipeline.add(self.level)
        self.pipeline.add(self.audio_convert)

        self.level.link(self.audio_convert)

        bus = self.pipeline.get_bus()
        bus.add_signal_watch()
        self._handler = bus.connect('message::element', self.__on_message)
Ejemplo n.º 19
0
    def __init__(self, id=None):
        super().__init__()
        self._waiting = Event()
        self._waiting.set()

        self.id = str(uuid4()) if id is None else id
        self._type_ = self.__class__.__name__

        self.pre_wait_enter = Signal()
        self.pre_wait_exit = Signal()
        self.post_wait_enter = Signal()
        self.post_wait_exit = Signal()

        self.started = Signal()
        self.stopped = Signal()
        self.paused = Signal()
        self.error = Signal()
        self.next = Signal()
        self.end = Signal()

        self.stopped.connect(self._waiting.set)
        self.changed('next_action').connect(self.__next_action_changed)
Ejemplo n.º 20
0
    def __init__(self, id=None):
        super().__init__()
        self.id = str(uuid4()) if id is None else id
        self._type_ = self.__class__.__name__

        self._st_lock = Lock()
        self._state = CueState.Stop
        self._prewait = RWait()
        self._postwait = RWait()

        # Pre-Wait signals
        self.prewait_start = self._prewait.start
        self.prewait_ended = self._prewait.ended
        self.prewait_paused = self._prewait.paused
        self.prewait_stopped = self._prewait.stopped

        # Post-Wait signals
        self.postwait_start = self._postwait.start
        self.postwait_ended = self._postwait.ended
        self.postwait_paused = self._postwait.paused
        self.postwait_stopped = self._postwait.stopped

        # Fade signals
        self.fadein_start = Signal()
        self.fadein_end = Signal()
        self.fadeout_start = Signal()
        self.fadeout_end = Signal()

        # Status signals
        self.interrupted = Signal()     # self
        self.started = Signal()         # self
        self.stopped = Signal()         # self
        self.paused = Signal()          # self
        self.error = Signal()           # self, error, details
        self.next = Signal()            # self
        self.end = Signal()             # self

        self.changed('next_action').connect(self.__next_action_changed)
Ejemplo n.º 21
0
    def __init__(self):
        super().__init__()

        self.paused = Signal()
        """Emitted when paused (self)"""
        self.played = Signal()
        """Emitted when played (self)"""
        self.stopped = Signal()
        """Emitted when stopped (self)"""
        self.interrupted = Signal()
        """Emitted after interruption (self)"""
        self.eos = Signal()
        """End-of-Stream (self)"""

        self.on_play = Signal()
        """Emitted before play (self)"""
        self.on_stop = Signal()
        """Emitted before stop (self)"""
        self.on_pause = Signal()
        """Emitted before pause (self)"""

        self.sought = Signal()
        """Emitted after a seek (self, position)"""
        self.error = Signal()
        """Emitted when an error occurs (self, error, details)"""

        self.elements_changed = Signal()
        """Emitted when one or more elements are added/removed (self)"""
Ejemplo n.º 22
0
    def __init__(self, port_name='AppDefault'):
        super().__init__(port_name=port_name)

        self.alternate_mode = False
        self.new_message = Signal()
        self.new_message_alt = Signal()
Ejemplo n.º 23
0
    def __init__(self):
        self.property_changed = Signal()
        #: Emitted after property change (self, name, value)

        self.changed_signals = {}
        """Contains signals that are emitted after the associated property is
Ejemplo n.º 24
0
class ActionsHandler:
    """Do/Undo/Redo actions and store the in stacks.

    Provide methods for using actions, an storing them in stacks, allowing
    to undo and redo actions.
    """
    MaxStackSize = int(cfg.config['Actions']['MaxStackSize'])

    def __init__(self):
        super().__init__()

        self.action_done = Signal()
        self.action_undone = Signal()
        self.action_redone = Signal()

        self._undo = deque()
        self._redo = deque()
        if self.MaxStackSize > 0:
            self._undo.maxlen = self.MaxStackSize
            self._redo.maxlen = self.MaxStackSize

        self._saved = False
        self._saved_action = None

    def clear(self):
        self._undo.clear()
        self._redo.clear()
        self._saved_action = None

    def do_action(self, action):
        action.do()

        self._logging(action, 'Last action: ')
        self._undo.append(action)
        # Clean the redo stack for maintain consistency
        self._redo.clear()
        self._saved = False

        self.action_done.emit(action)

    def undo_action(self):
        if self._undo:
            action = self._undo.pop()
            action.undo()

            self._logging(action, 'Undo: ')
            self._redo.append(action)
            self._saved = False

            self.action_undone.emit(action)

    def redo_action(self):
        if self._redo:
            action = self._redo.pop()
            action.redo()

            self._logging(action, 'Redo: ')
            self._undo.append(action)
            self._saved = False

            self.action_redone.emit(action)

    def set_saved(self):
        self._saved = True
        if self._undo:
            self._saved_action = self._undo[-1]

    def is_saved(self):
        if self._undo:
            return self._saved or self._undo[-1] is self._saved_action
        else:
            return True

    def _logging(self, action, pre, ):
        message = action.log()
        if message.strip() == '':
            message = type(action).__name__

        logging.info(pre + message)
Ejemplo n.º 25
0
class RWait:
    """Provide a resumeable-wait mechanism."""
    def __init__(self):
        self._elapsed = 0
        self._start_time = 0
        self._ended = False

        self._waiting = Event()
        self._waiting.set()
        self._is_waiting = Event()
        self._is_waiting.set()

        self.start = Signal()
        self.ended = Signal()
        self.paused = Signal()
        self.stopped = Signal()

    def wait(self, timeout, lock=None):
        """Block until the timeout is elapsed or `pause` or `stop` are called.

        If the wait is paused, the next time this function is called the timeout
        will be `total_timeout - elapsed_time`.

        :param timeout: time to wait
        :param lock: lock to release before and re-acquired after the wait
        :return: True if the wait has not been interrupted by `pause` or `stop`
        :rtype: bool
        """
        if self._is_waiting.is_set():
            # Clear the events
            self._waiting.clear()
            self._is_waiting.clear()
            # Set the start-time
            self._start_time = time.monotonic() - self._elapsed

            self.start.emit()

            if lock is not None:
                lock.release()

            # Wait for the "remaining" time
            self._ended = not self._waiting.wait(timeout - self._elapsed)

            # If the wait is ended by timeout
            if self._ended:
                self._elapsed = 0
                self.ended.emit()

            # Notify that we are not waiting anymore
            self._is_waiting.set()

            if lock is not None:
                lock.acquire()

            return self._ended

        return False

    def stop(self):
        """Stop the wait."""
        if self.current_time() > 0:
            self._waiting.set()
            self._is_waiting.wait()

            # Check self._ended to ensure that the wait is not ended by timeout
            # before `self._waiting.set()` is called in this method.
            if not self._ended:
                self._elapsed = 0
                self.stopped.emit()

    def pause(self):
        """Pause the wait."""
        if not self._is_waiting.is_set():
            # Calculate elapsed time ASAP
            elapsed = time.monotonic() - self._start_time
            self._waiting.set()
            self._is_waiting.wait()

            # Check self._ended to ensure that the wait is not ended by timeout
            # before `self._waiting.set()` is called in this method.
            if not self._ended:
                self._elapsed = elapsed
                self.paused.emit()

    def current_time(self):
        """Return the currently elapsed time."""
        if self._is_waiting.is_set():
            return self._elapsed

        return time.monotonic() - self._start_time

    def is_waiting(self):
        return not self._is_waiting.is_set()

    def is_paused(self):
        return self._is_waiting.is_set() and self.current_time() > 0
Ejemplo n.º 26
0
 def __init__(self):
     self.protocol_event = Signal()
Ejemplo n.º 27
0
class GainMainThread(Thread):
    MAX_GAIN = 20  # dB

    def __init__(self, files, threads, mode, ref_level, norm_level):
        super().__init__()
        self.setDaemon(True)

        self._futures = {}
        self._running = False
        self._action = GainAction()

        # file -> media {"filename1": [media1, media2], "filename2": [media3]}
        self.files = files
        self.threads = threads
        self.mode = mode
        self.ref_level = ref_level
        self.norm_level = norm_level

        self.on_progress = Signal()

    def stop(self):
        self._running = False
        for future in self._futures:
            self._futures[future].stop()
            future.cancel()

    def run(self):
        self._running = True

        with ThreadPoolExecutor(max_workers=self.threads) as executor:
            for file in self.files.keys():
                gain = GstGain(file, self.ref_level)
                self._futures[executor.submit(gain.gain)] = gain

            for future in futures_completed(self._futures):
                if self._running:
                    try:
                        self._post_process(*future.result())
                    except Exception:
                        # Call with the value stored in the GstGain object
                        self._post_process(*self._futures[future].result)
                else:
                    break

        if self._running:
            MainActionsHandler().do_action(self._action)
        else:
            logging.info('REPLY-GAIN:: Stopped by user')

        self.on_progress.emit(-1)
        self.on_progress.disconnect()

    def _post_process(self, gained, gain, peak, uri):
        if gained:
            if gain > self.MAX_GAIN:
                gain = self.MAX_GAIN

            if self.mode == 0:
                volume = min(1 / peak, pow(10, gain / 20))
            else:  # (self.mode == 1)
                volume = 1 / peak * pow(10, self.norm_level / 20)

            for media in self.files[uri]:
                self._action.add_media(media, volume)

            logging.info('REPLY-GAIN:: completed ' + uri)
        else:
            logging.error('REPLY-GAIN:: failed  ' + uri)

        self.on_progress.emit(1)
Ejemplo n.º 28
0
    def __init__(self, cue_model):
        self._cue_model = cue_model

        self.cue_executed = Signal()  # After a cue is executed
        self.focus_changed = Signal()  # After the focused cue is changed
        self.key_pressed = Signal()  # After a key is pressed
Ejemplo n.º 29
0
class GainMainThread(Thread):
    MAX_GAIN = 20  # dB

    def __init__(self, files, threads, mode, ref_level, norm_level):
        super().__init__()
        self.setDaemon(True)

        self._futures = {}
        self._running = False
        self._action = GainAction()

        # file -> media {'filename1': [media1, media2], 'filename2': [media3]}
        self.files = files
        self.threads = threads
        self.mode = mode
        self.ref_level = ref_level
        self.norm_level = norm_level

        self.on_progress = Signal()

    def stop(self):
        self._running = False
        for future in self._futures:
            self._futures[future].stop()
            future.cancel()

    def run(self):
        self._running = True

        with ThreadPoolExecutor(max_workers=self.threads) as executor:
            for file in self.files.keys():
                gain = GstGain(file, self.ref_level)
                self._futures[executor.submit(gain.gain)] = gain

            for future in futures_completed(self._futures):
                if self._running:
                    try:
                        self._post_process(*future.result())
                    except Exception:
                        # Call with the value stored in the GstGain object
                        self._post_process(*self._futures[future].result)
                else:
                    break

        if self._running:
            MainActionsHandler.do_action(self._action)
        else:
            logging.info('REPLY-GAIN:: Stopped by user')

        self.on_progress.emit(-1)
        self.on_progress.disconnect()

    def _post_process(self, gained, gain, peak, uri):
        if gained:
            if gain > self.MAX_GAIN:
                gain = self.MAX_GAIN

            if self.mode == 0:
                volume = min(1 / peak, pow(10, gain / 20))
            else:  # (self.mode == 1)
                volume = 1 / peak * pow(10, self.norm_level / 20)

            for media in self.files[uri]:
                self._action.add_media(media, volume)

            logging.info('REPLY-GAIN:: completed ' + uri)
        else:
            logging.error('REPLY-GAIN:: failed  ' + uri)

        self.on_progress.emit(1)
Ejemplo n.º 30
0
    def __init__(self, port_name='default', backend_name=None):
        super().__init__(port_name=port_name, backend_name=backend_name)

        self.alternate_mode = False
        self.new_message = Signal()
        self.new_message_alt = Signal()
Ejemplo n.º 31
0
class Cue(HasProperties):
    """Cue(s) are the base component for implement any kind of live-controllable
    element (live = during a show).

    A cue implement his behavior(s) reimplementing the __start__, __stop__ and
    __pause__ methods.
    Can be triggered calling the execute() method, providing tha action to
    be executed, or calling directly start()/stop() or pause().

    .. note:
        If needed __start__, __stop__ and __pause__ can be asynchronous.

    Cue provide **(and any subclass should do the same)** properties via
    HasProperties/Property specifications.

    :ivar _type_: Cue type (class name). Should NEVER change after init.
    :ivar id: Identify the cue uniquely. Should NEVER change after init.
    :ivar index: Cue position in the view.
    :ivar name: Cue visualized name.
    :ivar description: Cue text description.
    :ivar stylesheet: Cue style, used by the view.
    :ivar duration: The cue duration in milliseconds. (0 means no duration)
    :ivar stop_pause: If True, by default the cue is paused instead of stopped.
    :ivar pre_wait: Cue pre-wait in seconds.
    :ivar post_wait: Cue post-wait in seconds (see note).
    :ivar next_action: What do after post_wait (see note).
    :cvar CueActions: actions supported by the cue (default: CueAction.Start)

    A cue should declare CueAction.Default as supported only if CueAction.Stop
    is also supported.

    .. Note::
        If 'next_action' is set to CueNextAction.AutoFollow value, then the
        'post_wait' value is ignored.

    """

    _type_ = Property()
    id = Property()
    name = Property(default='Untitled')
    index = Property(default=-1)
    description = Property(default='')
    stylesheet = Property(default='')
    duration = Property(default=0)
    stop_pause = Property(default=False)
    pre_wait = Property(default=0)
    post_wait = Property(default=0)
    next_action = Property(default=CueNextAction.DoNothing.value)

    CueActions = (CueAction.Start, )

    def __init__(self, id=None):
        super().__init__()
        self._waiting = Event()
        self._waiting.set()

        self.id = str(uuid4()) if id is None else id
        self._type_ = self.__class__.__name__

        self.pre_wait_enter = Signal()
        self.pre_wait_exit = Signal()
        self.post_wait_enter = Signal()
        self.post_wait_exit = Signal()

        self.started = Signal()
        self.stopped = Signal()
        self.paused = Signal()
        self.error = Signal()
        self.next = Signal()
        self.end = Signal()

        self.stopped.connect(self._waiting.set)
        self.changed('next_action').connect(self.__next_action_changed)

    def execute(self, action=CueAction.Default):
        """Execute the specified action, if supported.

        .. Note::
            Even if not specified in Cue.CueActions, when CueAction.Default
            is given, a "default" action is selected depending on the current
            cue state, if this action is not supported nothing will be done.

        :param action: the action to be performed
        """
        if action == CueAction.Default:
            if self.state == CueState.Running:
                if self.stop_pause and CueAction.Pause in self.CueActions:
                    action = CueAction.Pause
                else:
                    action = CueAction.Stop
            elif self.is_waiting():
                self._waiting.set()
                return
            else:
                action = CueAction.Start

        if action in self.CueActions:
            if action == CueAction.Start:
                self.start()
            elif action == CueAction.Stop:
                self.stop()
            elif action == CueAction.Pause:
                self.pause()

    @async
    @synchronized_method(blocking=True)
    def start(self):
        """Start the cue.

        .. note::
            Calling during pre/post wait has no effect.
        """

        do_wait = self.state == CueState.Stop or self.state == CueState.Error
        # The pre/post waits are done only if going from stop->start or
        # error->start.
        if do_wait and not self.__pre_wait():
            # self.__pre_wait() is executed only if do_wait is True
            # if self.__pre_wait() return False, the wait is been interrupted
            # so the cue doesn't start.
            return

        # Start the cue
        self.__start__()

        if do_wait and self.next_action != CueNextAction.AutoFollow.value:
            # If next-action is AutoFollow no post-wait is executed, in this
            # case higher-level components should watch directly the cue-state
            # signals.
            if self.__post_wait() and self.next_action == CueNextAction.AutoNext.value:
                # If the post-wait is not interrupted and the next-action
                # is AutoNext, than emit the 'next' signal.
                self.next.emit(self)

    @abstractmethod
    def __start__(self):
        pass

    def stop(self):
        """Stop the cue.

        .. note::
            If called during pre/post wait, the wait is interrupted.
        """
        self._waiting.set()  # Stop the wait
        self.__stop__()

    def __stop__(self):
        pass

    def pause(self):
        """Pause the cue.

        .. note::
            Calling during pre/post wait has no effect.
        """
        if not self.is_waiting():
            self.__pause__()

    def __pause__(self):
        pass

    def current_time(self):
        """Return the current execution time if available, otherwise 0.

        :rtype: int
        """
        return 0

    @property
    @abstractmethod
    def state(self):
        """Return the current state.

        During pre/post-wait the cue is considered in Stop state.

        :rtype: CueState
        """

    def is_waiting(self):
        return not self._waiting.is_set()

    def __pre_wait(self):
        """Return False if the wait is interrupted"""
        not_stopped = True
        if self.pre_wait > 0:
            self.pre_wait_enter.emit()
            self._waiting.clear()
            not_stopped = not self._waiting.wait(self.pre_wait)
            self._waiting.set()
            self.pre_wait_exit.emit(not_stopped)

        return not_stopped

    def __post_wait(self):
        """Return False if the wait is interrupted"""
        not_stopped = True
        if self.post_wait > 0:
            self.post_wait_enter.emit()
            self._waiting.clear()
            not_stopped = not self._waiting.wait(self.post_wait)
            self._waiting.set()
            self.post_wait_exit.emit(not_stopped)

        return not_stopped

    def __next_action_changed(self, next_action):
        self.end.disconnect(self.next.emit)
        if next_action == CueNextAction.AutoFollow.value:
            self.end.connect(self.next.emit)
Ejemplo n.º 32
0
class ActionsHandler:
    """Provide a classic undo/redo mechanism based on stacks."""

    MaxStackSize = int(cfg.config['Actions']['MaxStackSize'])

    def __init__(self):
        super().__init__()

        self.action_done = Signal()
        self.action_undone = Signal()
        self.action_redone = Signal()

        self._undo = deque()
        self._redo = deque()
        if self.MaxStackSize > 0:
            self._undo.maxlen = self.MaxStackSize
            self._redo.maxlen = self.MaxStackSize

        self._saved_action = None

    def clear(self):
        """Clear the `undo` and `redo` stacks."""
        self._undo.clear()
        self._redo.clear()
        self._saved_action = None

    def do_action(self, action: Action):
        """Execute the action, and add it the `undo` stack.

        When an action is executed:
         * is logged
         * is appended to the `undo` stack
         * the `redo` stack is cleared to maintain consistency
         * the `action_done` signal is emitted
        """
        action.do()

        self._logging(action, 'Last action: ')
        self._undo.append(action)
        # Clean the redo stack for maintain consistency
        self._redo.clear()

        self.action_done.emit(action)

    def undo_action(self):
        """Undo the last executed action, and add it to the `redo` stack.

        When an action is undone:
         * is removed from the `undo` stack
         * is logged
         * is appended to the `redo` stack
         * the signal `action_undone` is emitted
        """
        if self._undo:
            action = self._undo.pop()
            action.undo()

            self._logging(action, 'Undo: ')
            self._redo.append(action)

            self.action_undone.emit(action)

    def redo_action(self):
        """Redo the last undone action, and add it back to the `undo` stack.

        When an action is redone:
         * is remove from the `redo` stack
         * is logged
         * is added to the `undo` stack
         * the `action_redone` signal is emitted
        """
        if self._redo:
            action = self._redo.pop()
            action.redo()

            self._logging(action, 'Redo: ')
            self._undo.append(action)

            self.action_redone.emit(action)

    def set_saved(self):
        """Set the action at the _top_ of the `undo` stack as `save-point`."""
        if self._undo:
            self._saved_action = self._undo[-1]

    def is_saved(self) -> bool:
        """Return True if the action at the _top_ of the `undo` stack is the
        `save-point`.
        """
        if self._undo:
            return self._undo[-1] is self._saved_action
        else:
            return True

    @staticmethod
    def _logging(action: Action, pre: str):
        message = action.log()
        if message.strip() == '':
            message = type(action).__name__

        logging.info(pre + message)
Ejemplo n.º 33
0
class Cue(HasProperties):
    """Cue(s) are the base component for implement any kind of live-controllable
    element (live = during a show).

    A cue implement his behavior(s) reimplementing __start__, __stop__,
    __pause__ and __interrupt__ methods.

    Cue provide **(and any subclass should do the same)** properties via
    HasProperties/Property specifications.

    :ivar _type_: Cue type (class name). Should NEVER change after init.
    :ivar id: Identify the cue uniquely. Should NEVER change after init.
    :ivar index: Cue position in the view.
    :ivar name: Cue visualized name.
    :ivar description: Cue text description.
    :ivar stylesheet: Cue style, used by the view.
    :ivar duration: The cue duration in milliseconds. (0 means no duration)
    :ivar pre_wait: Cue pre-wait in seconds.
    :ivar post_wait: Cue post-wait in seconds.
    :ivar next_action: What do after post_wait.
    :ivar fadein_type: Fade-In type
    :ivar fadeout_type: Fade-Out type
    :ivar fadein_duration: Fade-In duration in seconds
    :ivar fadeout_duration: Fade-Out duration in seconds
    :ivar default_start_action: action to execute to start
    :ivar default_stop_action: action to execute to stop
    :cvar CueActions: actions supported by the cue (default: CueAction.Start)

    A cue should declare CueAction.Default as supported only if CueAction.Start
    and CueAction.Stop are both supported.
    If CueAction.Stop is supported, CueAction.Interrupt should be supported.

    .. Note::
        If 'next_action' is AutoFollow or DoNothing, the postwait is not
        performed.
    """
    Name = 'Cue'

    _type_ = WriteOnceProperty()
    id = WriteOnceProperty()
    name = Property(default='Untitled')
    index = Property(default=-1)
    description = Property(default='')
    stylesheet = Property(default='')
    duration = Property(default=0)
    pre_wait = Property(default=0)
    post_wait = Property(default=0)
    next_action = Property(default=CueNextAction.DoNothing.value)
    fadein_type = Property(default=FadeInType.Linear.name)
    fadeout_type = Property(default=FadeOutType.Linear.name)
    fadein_duration = Property(default=0)
    fadeout_duration = Property(default=0)
    default_start_action = Property(default=CueAction.Start.value)
    default_stop_action = Property(default=CueAction.Stop.value)

    CueActions = (CueAction.Start,)

    def __init__(self, id=None):
        super().__init__()
        self.id = str(uuid4()) if id is None else id
        self._type_ = self.__class__.__name__

        self._st_lock = Lock()
        self._state = CueState.Stop
        self._prewait = RWait()
        self._postwait = RWait()

        # Pre-Wait signals
        self.prewait_start = self._prewait.start
        self.prewait_ended = self._prewait.ended
        self.prewait_paused = self._prewait.paused
        self.prewait_stopped = self._prewait.stopped

        # Post-Wait signals
        self.postwait_start = self._postwait.start
        self.postwait_ended = self._postwait.ended
        self.postwait_paused = self._postwait.paused
        self.postwait_stopped = self._postwait.stopped

        # Fade signals
        self.fadein_start = Signal()
        self.fadein_end = Signal()
        self.fadeout_start = Signal()
        self.fadeout_end = Signal()

        # Status signals
        self.interrupted = Signal()     # self
        self.started = Signal()         # self
        self.stopped = Signal()         # self
        self.paused = Signal()          # self
        self.error = Signal()           # self, error, details
        self.next = Signal()            # self
        self.end = Signal()             # self

        self.changed('next_action').connect(self.__next_action_changed)

    def execute(self, action=CueAction.Default):
        """Execute the specified action, if supported.

        .. Note::
            Even if not specified in Cue.CueActions, when CueAction.Default
            is given, a "default" action is selected depending on the current
            cue state, if this action is not supported nothing will be done.

        :param action: the action to be performed
        :type action: CueAction
        """
        if action == CueAction.Default:
            if self._state & CueState.IsRunning:
                action = CueAction(self.default_stop_action)
            else:
                action = CueAction(self.default_start_action)

        if action is CueAction.Interrupt:
            self.interrupt()
        elif action is CueAction.FadeOutInterrupt:
            self.interrupt(fade=True)
        elif action in self.CueActions:
            if action == CueAction.Start:
                self.start()
            elif action == CueAction.FadeInStart:
                self.start(fade=self.fadein_duration > 0)
            elif action == CueAction.Stop:
                self.stop()
            elif action == CueAction.FadeOutStop:
                self.stop(fade=self.fadeout_duration > 0)
            elif action == CueAction.Pause:
                self.pause()
            elif action == CueAction.FadeOutPause:
                self.pause(fade=self.fadeout_duration > 0)
            elif action == CueAction.FadeOut:
                duration = config['Cue'].getfloat('FadeActionDuration')
                fade_type = FadeOutType[config['Cue'].get('FadeActionType')]
                self.fadeout(duration, fade_type)
            elif action == CueAction.FadeIn:
                duration = config['Cue'].getfloat('FadeActionDuration')
                fade_type = FadeInType[config['Cue'].get('FadeActionType')]
                self.fadein(duration, fade_type)

    @async_function
    def start(self, fade=False):
        """Start the cue."""

        # If possible acquire the state-lock, otherwise return
        if not self._st_lock.acquire(blocking=False):
            return

        try:
            # If we are already running release and return
            if self._state & CueState.IsRunning:
                return

            state = self._state

            # PreWait
            if self.pre_wait and state & (CueState.IsStopped |
                                          CueState.PreWait_Pause):
                self._state = CueState.PreWait
                # Start the wait, the lock is released during the wait and
                # re-acquired after
                if not self._prewait.wait(self.pre_wait, lock=self._st_lock):
                    # PreWait interrupted, check the state to be correct
                    if self._state & CueState.PreWait:
                        self._state ^= CueState.PreWait
                    return

            # Cue-Start (still locked), the __start__ function should not block
            if state & (CueState.IsStopped |
                        CueState.Pause |
                        CueState.PreWait_Pause):

                running = self.__start__(fade)
                self._state = CueState.Running
                self.started.emit(self)

                if not running:
                    self._ended()

            # PostWait (still locked)
            if state & (CueState.IsStopped |
                        CueState.PreWait_Pause |
                        CueState.PostWait_Pause):
                if self.next_action == CueNextAction.AutoNext:
                    self._state |= CueState.PostWait

                    if self._postwait.wait(self.post_wait, lock=self._st_lock):
                        # PostWait ended
                        self._state ^= CueState.PostWait
                        self.next.emit(self)
                    elif self._state & CueState.PostWait:
                        # PostWait interrupted, check the state to be correct
                        self._state ^= CueState.PostWait

                    # If the cue was only post-waiting we remain with
                    # an invalid state
                    if not self._state:
                        self._state = CueState.Stop
        finally:
            self._st_lock.release()

    def restart(self, fade=False):
        """Restart the cue if paused."""
        # TODO: change to resume
        if self._state & CueState.IsPaused:
            self.start(fade)

    def __start__(self, fade=False):
        """Implement the cue `start` behavior.

        Long running task should not block this function (i.e. the fade should
        be performed in another thread).

        When called from `Cue.start()`, `_st_lock` is acquired.

        If the execution is instantaneous should return False, otherwise
        return True and call the `_ended` function later.

        :param fade: True if a fade should be performed (when supported)
        :type fade: bool
        :return: False if the cue is already terminated, True otherwise
            (e.g. asynchronous execution)
        :rtype: bool
        """
        return False

    @async_function
    def stop(self, fade=False):
        """Stop the cue."""

        # If possible acquire the state-lock, otherwise return
        if not self._st_lock.acquire(blocking=False):
            return

        try:
            # Stop PreWait (if in PreWait(_Pause) nothing else is "running")
            if self._state & (CueState.PreWait | CueState.PreWait_Pause):
                self._state = CueState.Stop
                self._prewait.stop()
            else:
                # Stop PostWait
                if self._state & (CueState.PostWait | CueState.PostWait_Pause):
                    # Remove PostWait or PostWait_Pause state
                    self._state = (
                        (self._state ^ CueState.PostWait) &
                        (self._state ^ CueState.PostWait_Pause)
                    )
                    self._postwait.stop()

                # Stop the cue
                if self._state & (CueState.Running | CueState.Pause):
                    # Here the __stop__ function should release and re-acquire
                    # the state-lock during a fade operation
                    if not self.__stop__(fade):
                        # Stop operation interrupted
                        return

                    # Remove Running or Pause state
                    self._state = (
                        (self._state ^ CueState.Running) &
                        (self._state ^ CueState.Pause)
                    )
                    self._state |= CueState.Stop
                    self.stopped.emit(self)
        finally:
            self._st_lock.release()

    def __stop__(self, fade=False):
        """Implement the cue `stop` behavior.

        Long running task should block this function (i.e. the fade should
        "block" this function), when this happen `_st_lock` must be released and
        then re-acquired.

        If called during a `fadeout` operation this should be interrupted,
        the cue stopped and return `True`.

        :param fade: True if a fade should be performed (when supported)
        :type fade: bool
        :return: False if interrupted, True otherwise
        :rtype: bool
        """
        return False

    @async_function
    def pause(self, fade=False):
        """Pause the cue."""

        # If possible acquire the state-lock, otherwise return
        if not self._st_lock.acquire(blocking=False):
            return

        try:
            # Pause PreWait (if in PreWait nothing else is "running")
            if self._state & CueState.PreWait:
                self._state ^= CueState.PreWait
                self._state |= CueState.PreWait_Pause
                self._prewait.pause()
            else:
                # Pause PostWait
                if self._state & CueState.PostWait:
                    self._state ^= CueState.PostWait
                    self._state |= CueState.PostWait_Pause
                    self._postwait.pause()

                # Pause the cue
                if self._state & CueState.Running:
                    # Here the __pause__ function should release and re-acquire
                    # the state-lock during a fade operation
                    if not self.__pause__(fade):
                        return

                    self._state ^= CueState.Running
                    self._state |= CueState.Pause
                    self.paused.emit(self)
        finally:
            self._st_lock.release()

    def __pause__(self, fade=False):
        """Implement the cue `pause` behavior.

        Long running task should block this function (i.e. the fade should
        "block" this function), when this happen `_st_lock` must be released and
        then re-acquired.

        If called during a `fadeout` operation this should be interrupted,
        the cue paused and return `True`.

        If during the execution the fade operation is interrupted this function
        must return `False`.

        :param fade: True if a fade should be performed (when supported)
        :type fade: bool
        :return: False if interrupted, True otherwise
        :rtype: bool
        """
        return False

    @async_function
    def interrupt(self, fade=False):
        """Interrupt the cue.

        :param fade: True if a fade should be performed (when supported)
        :type fade: bool
        """
        with self._st_lock:
            # Stop PreWait (if in PreWait(_Pause) nothing else is "running")
            if self._state & (CueState.PreWait | CueState.PreWait_Pause):
                self._state = CueState.Stop
                self._prewait.stop()
            else:
                # Stop PostWait
                if self._state & (CueState.PostWait | CueState.PostWait_Pause):
                    # Remove PostWait or PostWait_Pause state
                    self._state = (
                        (self._state ^ CueState.PostWait) &
                        (self._state ^ CueState.PostWait_Pause)
                    )
                    self._postwait.stop()

                # Interrupt the cue
                if self._state & (CueState.Running | CueState.Pause):
                    self.__interrupt__(fade)

                    # Remove Running or Pause state
                    self._state = (
                        (self._state ^ CueState.Running) &
                        (self._state ^ CueState.Pause)
                    )
                    self._state |= CueState.Stop
                    self.interrupted.emit(self)

    def __interrupt__(self, fade=False):
        """Implement the cue `interrupt` behavior.

        Long running task should block this function without releasing
        `_st_lock`.

        :param fade: True if a fade should be performed (when supported)
        :type fade: bool
        """

    def fadein(self, duration, fade_type):
        """Fade-in the cue.

        :param duration: How much the fade should be long (in seconds)
        :type duration: float
        :param fade_type: The fade type
        :type fade_type: FadeInType
        """

    def fadeout(self, duration, fade_type):
        """Fade-out the cue.

        :param duration: How much the fade should be long (in seconds)
        :type duration: float
        :param fade_type: The fade type
        :type fade_type: FadeOutType
        """

    def _ended(self):
        """Remove the Running state, if needed set it to Stop."""
        locked = self._st_lock.acquire(blocking=False)

        if self._state == CueState.Running:
            self._state = CueState.Stop
        else:
            self._state ^= CueState.Running

        self.end.emit(self)

        if locked:
            self._st_lock.release()

    def _error(self, message, details):
        """Remove Running/Pause/Stop state and add Error state."""
        locked = self._st_lock.acquire(blocking=False)

        self._state = (
            (self._state ^ CueState.Running) &
            (self._state ^ CueState.Pause) &
            (self._state ^ CueState.Stop)
        ) | CueState.Error

        self.error.emit(self, message, details)

        if locked:
            self._st_lock.release()

    def current_time(self):
        """Return the current execution time if available, otherwise 0.

        :rtype: int
        """
        return 0

    def prewait_time(self):
        return self._prewait.current_time()

    def postwait_time(self):
        return self._postwait.current_time()

    @property
    def state(self):
        """Return the current state.

        :rtype: int
        """
        return self._state

    def __next_action_changed(self, next_action):
        self.end.disconnect(self.next.emit)
        if next_action == CueNextAction.AutoFollow:
            self.end.connect(self.next.emit)
Ejemplo n.º 34
0
 def __init__(self, model):
     super().__init__(model)
     self.item_moved = Signal()