Skip to content

Commit

Permalink
Merge pull request #48 from PedalPi/issue-45-plugins-manager-v0.5.0
Browse files Browse the repository at this point in the history
Issue 45 plugins manager v0.5.0
  • Loading branch information
SrMouraSilva authored May 30, 2017
2 parents a22283c + 41732d0 commit f75445e
Show file tree
Hide file tree
Showing 27 changed files with 612 additions and 1,622 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ python:
sudo: required

install:
- sudo apt-get install -y portaudio19-dev python-all-dev --no-install-recommends
- sudo apt-get install -y lilv-utils calf-plugins guitarix --no-install-recommends
- pip3 install coveralls

Expand Down
14 changes: 12 additions & 2 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
Version 0.3.0 - released 05//17
Version 0.3.0 - released 05/30/17
=================================
- Issue #29 - Secure components close
- Issue #30 - Replace print log to logging
- **Breaking change**: Issue #39 - Change save method to pluginsmanager (v0.5.0) Autosaver
- **Breaking change**: Issues #39 and #5 - Change save method to pluginsmanager (v0.5.0) Autosaver
- Removed BanksDao -> Using now pluginsmanager Autosaver
- Removed Database -> Using now pluginsmanager Persistence
- BanksController, PedalboardController, EffectController, ParamController,
CurrentController changes your API
- Issue #41 - Allows current pedalboard is None
- Issue #40 - If current pedalboard index file is wrong, Application now starts
with the current pedalboard = None
- Issue #11 - Banks with same name not will be replaced when Application initialize
- Issue #17 - Fixes: Remove bank with current pedalboard will be crash (when reload Application)
- Issue #45 - Add plugins manager v0.5.0 support

- Removed BanksController, PedalboardController, EffectController, ParamController, NotificationController
- Implemented :meth:`.Application.register_observer`, :meth:`.Application.unregister_observer`


Version 0.2.1 - released 04/14/17
=================================
Expand Down
57 changes: 40 additions & 17 deletions application/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,14 @@
from shutil import copytree
from unittest.mock import MagicMock

from application.controller.banks_controller import BanksController
from application.component.components_observer import ComponentsObserver
from application.component.current_pedalboard_observer import CurrentPedalboardObserver
from application.controller.component_data_controller import ComponentDataController
from application.controller.current_controller import CurrentController
from application.controller.device_controller import DeviceController
from application.controller.effect_controller import EffectController
from application.controller.notification_controller import NotificationController
from application.controller.param_controller import ParamController
from application.controller.pedalboard_controller import PedalboardController
from application.controller.plugins_controller import PluginsController

from pluginsmanager.mod_host.mod_host import ModHost
from pluginsmanager.observer.autosaver.autosaver import Autosaver
from pluginsmanager.observer.mod_host.mod_host import ModHost

logging.basicConfig(format='[%(asctime)s] %(levelname)s - %(message)s', stream=sys.stdout, level=logging.DEBUG)

Expand All @@ -47,7 +43,7 @@ class Application(object):
for control::
>>> from application.application import Application
>>> from application.controller.CurrentController import CurrentController
>>> from application.controller.current_controller import CurrentController
>>> application = Application()
>>> current_controller = application.controller(CurrentController)
Expand All @@ -69,16 +65,27 @@ class Application(object):
"""

def __init__(self, path_data="data/", address="localhost", test=False):
path_data = Path(path_data)
self.mod_host = self._initialize(address, test)

# Data
path_data = Path(path_data)
self.path_data = self._initialize_data(path_data)
self.autosaver = Autosaver(str(path_data / Path('banks')))
self.manager = self.autosaver.load(DeviceController.sys_effect)

# Controllers
self.components = []
self.controllers = self._load_controllers()

self._configure_controllers(self.controllers)

# Observers
self.components_observer = ComponentsObserver(self.manager)
current_pedalboard_observer = CurrentPedalboardObserver(self.controller(CurrentController))

self.manager.register(self.components_observer)
self.manager.register(current_pedalboard_observer)

def _initialize(self, address, test=False):
mod_host = ModHost(address)
if test:
Expand All @@ -105,14 +112,9 @@ def _load_controllers(self):
controllers = {}

list_controllers = [
BanksController,
ComponentDataController,
CurrentController,
DeviceController,
EffectController,
NotificationController,
ParamController,
PedalboardController,
PluginsController,
]

Expand All @@ -128,16 +130,35 @@ def _configure_controllers(self, controllers):

def register(self, component):
"""
Register a :class:`Component` extended class into Application.
Register a :class:`.Component` extended class into Application.
The components will be loaded when application is loaded (after `start` method is called).
:param Component component: A module to be loaded when the Application is loaded
"""
self.components.append(component)

def register_observer(self, observer):
"""
Register a :class:`.ApplicationObserver` specialization into Application.
The observer will receive calls when changes occurs in system, like
banks creation, current pedalboard changes.
:param ApplicationObserver observer: The observer who will receive the changes notifications
"""
self.components_observer.register(observer)

def unregister_observer(self, observer):
"""
Unregister an observer in :class:`.Application`.
The observer not will be more notified of the changes requested in the application API.
:param ApplicationObserver observer: The observer who will not receive further changes notification
"""
self.components_observer.unregister(observer)

def start(self):
"""
Start this API, initializing the components.
Start the application, initializing your components.
"""
current_pedalboard = self.controller(CurrentController).pedalboard
if current_pedalboard is None:
Expand All @@ -156,6 +177,9 @@ def start(self):
atexit.register(self.stop)

def stop(self):
"""
Stop the application, closing your components.
"""
for component in self.components:
component.close()
self.log('Stopping component - {}', component.__class__.__name__)
Expand Down Expand Up @@ -186,4 +210,3 @@ def dao(self, dao):

def log(self, message, *args, **kwargs):
logging.info(message.format(*args, **kwargs))
#print('[' + time.strftime('%Y-%m-%d %H:%M:%S') + ']', *args, **kwargs)
33 changes: 4 additions & 29 deletions application/component/application_observer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

from abc import ABCMeta, abstractmethod
from pluginsmanager.model.updates_observer import UpdatesObserver
from pluginsmanager.observer.updates_observer import UpdatesObserver


class ApplicationObserver(UpdatesObserver, metaclass=ABCMeta):
Expand All @@ -23,40 +23,15 @@ class ApplicationObserver(UpdatesObserver, metaclass=ABCMeta):
Your methods are called when occurs any change in Bank, Pedalboard, Effect, etc.
To do this, it is necessary that the :class:`.ApplicationObserver` objects
be registered in some manager, so that it reports the changes. An
example of a manager is :class:`.NotificationController`.
:class:`.NotificationController`, comparing with, :class:`.UpdatesObserver`
add TOKEN. Each observer should have a unique token. This token will differentiate who
is making requests so the manager does not notify you back.
For example, if a component requires the manager to have an effect change its
state (``effect.active = not effect.active``), it is not necessary for the manager
to inform the component of the change. If the component was informed, it might not know
that it was the one that requested the change and possibly would update its interface
erroneously.
be registered in application (using :meth:`.Application.register_observer`
or :meth:`.Component.register_observer`), so that it reports the changes.
"""

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

@property
@abstractmethod
def token(self):
"""
Observer token identifier.
:return: string for token identifier or None if is not necessary identify the observer
(it will receive all notification)
"""
pass

@abstractmethod
def on_current_pedalboard_changed(self, pedalboard, token=None):
def on_current_pedalboard_changed(self, pedalboard, **kwargs):
"""
Called when the current pedalboard is changed
:param Pedalboard pedalboard: New current pedalboard
:param string token: Request token identifier
"""
pass
19 changes: 6 additions & 13 deletions application/component/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@

from abc import ABCMeta, abstractmethod

from application.controller.notification_controller import NotificationController


class Component(metaclass=ABCMeta):

Expand All @@ -42,21 +40,16 @@ def controller(self, controller):

def register_observer(self, observer):
"""
Register an observer in :class:`.Application` by :class:`.NotificationController`.
Observers will be notified of the changes requested in the application API.
Obs: If a observer contains a *token* and the request informs the same *token*
the observer not will be notified.
Calls :meth:`.Application.register_observer`.
:param UpdatesObserver observer:
:param ApplicationObserver observer: The observer who will receive the changes notifications
"""
self.controller(NotificationController).register(observer)
self.application.register_observer(observer)

def unregister_observer(self, observer):
"""
Unregister an observer in :class:`.Application` by :class:`.NotificationController`.
The observer not will be more notified of the changes requested in the application API.
Calls :meth:`.Application.unregister_observer`.
:param UpdatesObserver observer:
:param ApplicationObserver observer: The observer who will not receive further changes notification
"""
self.controller(NotificationController).unregister(observer)
self.application.unregister_observer(observer)
70 changes: 70 additions & 0 deletions application/component/components_observer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Copyright 2017 SrMouraSilva
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from application.component.application_observer import ApplicationObserver


class ComponentsObserver(ApplicationObserver):

def __init__(self, manager):
super(ComponentsObserver, self).__init__()
self.observers = []
self._manager = manager

def register(self, observer):
self.observers.append(observer)
observer.manager = self.manager

def unregister(self, observer):
observer.manager = None
self.observers.remove(observer)

@property
def scope(self):
return self._manager.observer_manager.scope

def on_bank_updated(self, bank, update_type, index, origin, **kwargs):
for observer in self.observers:
if observer != self.scope:
observer.on_bank_updated(bank, update_type, index=index, origin=origin, **kwargs)

def on_pedalboard_updated(self, pedalboard, update_type, index, origin, **kwargs):
for observer in self.observers:
if observer != self.scope:
observer.on_pedalboard_updated(pedalboard, update_type, index=index, origin=origin, **kwargs)

def on_effect_updated(self, effect, update_type, index, origin, **kwargs):
for observer in self.observers:
if observer != self.scope:
observer.on_effect_updated(effect, update_type, index=index, origin=origin, **kwargs)

def on_effect_status_toggled(self, effect, **kwargs):
for observer in self.observers:
if observer != self.scope:
observer.on_effect_status_toggled(effect, **kwargs)

def on_param_value_changed(self, param, **kwargs):
for observer in self.observers:
if observer != self.scope:
observer.on_param_value_changed(param, **kwargs)

def on_connection_updated(self, connection, update_type, pedalboard, **kwargs):
for observer in self.observers:
if observer != self.scope:
observer.on_connection_updated(connection, update_type, pedalboard=pedalboard, **kwargs)

def on_current_pedalboard_changed(self, pedalboard, **kwargs):
for observer in self.observers:
if observer != self.scope:
observer.on_current_pedalboard_changed(pedalboard, **kwargs)
66 changes: 66 additions & 0 deletions application/component/current_pedalboard_observer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright 2017 SrMouraSilva
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from application.component.application_observer import ApplicationObserver
from pluginsmanager.observer.update_type import UpdateType


class CurrentPedalboardObserver(ApplicationObserver):
"""
This viewer allows change the current pedalboard
if it is updated or removed or if your bank is updated or removed.
"""

def __init__(self, current_controller):
"""
:param CurrentController current_controller:
"""
super(CurrentPedalboardObserver, self).__init__()
self._current_controller = current_controller

def on_bank_updated(self, bank, update_type, index, origin, **kwargs):
if update_type == UpdateType.UPDATED:
old_bank = kwargs['old']
if old_bank == self._current_controller.bank:
self._current_controller.set_bank(bank, try_preserve_index=True)

elif update_type == UpdateType.DELETED:
if bank == self._current_controller.bank:
next_bank_index = self._current_controller.next_bank_index(index-1)
new_current_bank = origin.banks[next_bank_index]

self._current_controller.set_bank(new_current_bank)

def on_pedalboard_updated(self, pedalboard, update_type, index, origin, **kwargs):
if update_type == UpdateType.UPDATED:
old_pedalboard = kwargs['old']

if pedalboard == self._current_controller.pedalboard \
or old_pedalboard == self._current_controller.pedalboard:
self._current_controller.set_pedalboard(pedalboard, notify=False, force=True)

def on_effect_status_toggled(self, effect, **kwargs):
pass

def on_connection_updated(self, connection, update_type, pedalboard, **kwargs):
pass

def on_param_value_changed(self, param, **kwargs):
pass

def on_effect_updated(self, effect, update_type, index, origin, **kwargs):
pass

def on_current_pedalboard_changed(self, pedalboard, **kwargs):
pass
Loading

0 comments on commit f75445e

Please sign in to comment.