Skip to content

Commit a0f8d06

Browse files
authored
Merge pull request #49 from PedalPi/version-0.3.0
v0.3.0
2 parents b575ce9 + f75445e commit a0f8d06

38 files changed

+1030
-2386
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ python:
1010
sudo: required
1111

1212
install:
13+
- sudo apt-get install -y portaudio19-dev python-all-dev --no-install-recommends
1314
- sudo apt-get install -y lilv-utils calf-plugins guitarix --no-install-recommends
1415
- pip3 install coveralls
1516

CHANGES

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
Version 0.3.0 - released 05/30/17
2+
=================================
3+
- Issue #29 - Secure components close
4+
- Issue #30 - Replace print log to logging
5+
- **Breaking change**: Issues #39 and #5 - Change save method to pluginsmanager (v0.5.0) Autosaver
6+
- Removed BanksDao -> Using now pluginsmanager Autosaver
7+
- Removed Database -> Using now pluginsmanager Persistence
8+
- BanksController, PedalboardController, EffectController, ParamController,
9+
CurrentController changes your API
10+
- Issue #41 - Allows current pedalboard is None
11+
- Issue #40 - If current pedalboard index file is wrong, Application now starts
12+
with the current pedalboard = None
13+
- Issue #11 - Banks with same name not will be replaced when Application initialize
14+
- Issue #17 - Fixes: Remove bank with current pedalboard will be crash (when reload Application)
15+
- Issue #45 - Add plugins manager v0.5.0 support
16+
17+
- Removed BanksController, PedalboardController, EffectController, ParamController, NotificationController
18+
- Implemented :meth:`.Application.register_observer`, :meth:`.Application.unregister_observer`
19+
20+
121
Version 0.2.1 - released 04/14/17
222
=================================
323
- 21fdb32 Issue #30 - Fix move pedalboard notification

README.rst

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ Create the script file that contains the code to run the application (as example
6666
application.start()
6767
6868
from signal import pause
69-
pause()
69+
try:
70+
pause()
71+
except KeyboardInterrupt:
72+
application.stop()
7073
7174
Download, compile and install `mod-host`_. Mod-host is a *LV2 host for Jack controllable via socket or command line*.
7275
It is developed by `Mod Devices`_, a company that also develops professional equipment for musicians.
@@ -132,6 +135,14 @@ To add a component in your configuration file, download it and register it befor
132135
# Start application
133136
application.start()
134137
138+
# Don't stop application
139+
from signal import pause
140+
try:
141+
pause()
142+
except KeyboardInterrupt:
143+
# Stop components with safety
144+
application.stop()
145+
135146
Each component needs a configuration to work.
136147
Pay attention to your documentation for details on how to set it up and use it.
137148

application/application.py

Lines changed: 80 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,24 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import time
15+
import atexit
16+
import logging
1617
import os
17-
from shutil import copytree
18+
import sys
1819
from pathlib import Path
20+
from shutil import copytree
21+
from unittest.mock import MagicMock
1922

20-
from application.controller.banks_controller import BanksController
21-
from application.controller.current_controller import CurrentController
23+
from application.component.components_observer import ComponentsObserver
24+
from application.component.current_pedalboard_observer import CurrentPedalboardObserver
2225
from application.controller.component_data_controller import ComponentDataController
26+
from application.controller.current_controller import CurrentController
2327
from application.controller.device_controller import DeviceController
24-
from application.controller.effect_controller import EffectController
25-
from application.controller.notification_controller import NotificationController
26-
from application.controller.param_controller import ParamController
27-
from application.controller.pedalboard_controller import PedalboardController
2828
from application.controller.plugins_controller import PluginsController
29+
from pluginsmanager.observer.autosaver.autosaver import Autosaver
30+
from pluginsmanager.observer.mod_host.mod_host import ModHost
2931

30-
from pluginsmanager.mod_host.mod_host import ModHost
31-
32-
from unittest.mock import MagicMock
32+
logging.basicConfig(format='[%(asctime)s] %(levelname)s - %(message)s', stream=sys.stdout, level=logging.DEBUG)
3333

3434

3535
class Application(object):
@@ -43,16 +43,16 @@ class Application(object):
4343
for control::
4444
4545
>>> from application.application import Application
46-
>>> from application.controller.CurrentController import CurrentController
46+
>>> from application.controller.current_controller import CurrentController
4747
4848
>>> application = Application()
4949
>>> current_controller = application.controller(CurrentController)
5050
51-
>>> print(current_controller.current_pedalboard)
51+
>>> print(current_controller.pedalboard)
5252
<Pedalboard object as Shows with 2 effects at 0x7fa3bcb49be0>
5353
5454
>>> current_controller.to_next_pedalboard()
55-
>>> current_controller.current_pedalboard
55+
>>> current_controller.pedalboard
5656
<Pedalboard object as Shows 2 with 1 effects at 0x7fa3bbcdecf8>
5757
5858
For more details see the Controllers extended classes.
@@ -67,12 +67,25 @@ class Application(object):
6767
def __init__(self, path_data="data/", address="localhost", test=False):
6868
self.mod_host = self._initialize(address, test)
6969

70+
# Data
71+
path_data = Path(path_data)
7072
self.path_data = self._initialize_data(path_data)
73+
self.autosaver = Autosaver(str(path_data / Path('banks')))
74+
self.manager = self.autosaver.load(DeviceController.sys_effect)
75+
76+
# Controllers
7177
self.components = []
7278
self.controllers = self._load_controllers()
7379

7480
self._configure_controllers(self.controllers)
7581

82+
# Observers
83+
self.components_observer = ComponentsObserver(self.manager)
84+
current_pedalboard_observer = CurrentPedalboardObserver(self.controller(CurrentController))
85+
86+
self.manager.register(self.components_observer)
87+
self.manager.register(current_pedalboard_observer)
88+
7689
def _initialize(self, address, test=False):
7790
mod_host = ModHost(address)
7891
if test:
@@ -83,34 +96,25 @@ def _initialize(self, address, test=False):
8396
return mod_host
8497

8598
def _initialize_data(self, path):
86-
if not os.path.exists(path):
99+
str_path = str(path)
100+
if not os.path.exists(str_path):
87101
default_path_data = os.path.dirname(os.path.abspath(__file__)) / Path('data')
88102

89103
ignore_files = lambda d, files: [f for f in files if (Path(d) / Path(f)).is_file() and f.endswith('.py')]
90-
copytree(str(default_path_data), str(os.path.abspath(path)), ignore=ignore_files)
104+
copytree(str(default_path_data), str(os.path.abspath(str_path)), ignore=ignore_files)
91105

92106
self.log('Data - Create initial data')
93107

94-
self.log('Data - Loads', os.path.abspath(path))
108+
self.log('Data - Loads {}', os.path.abspath(str_path))
95109
return path
96110

97-
def _teste(self, d, files):
98-
for f in files:
99-
print(f)
100-
return
101-
102111
def _load_controllers(self):
103112
controllers = {}
104113

105114
list_controllers = [
106-
BanksController,
107115
ComponentDataController,
108116
CurrentController,
109117
DeviceController,
110-
EffectController,
111-
NotificationController,
112-
ParamController,
113-
PedalboardController,
114118
PluginsController,
115119
]
116120

@@ -122,28 +126,69 @@ def _load_controllers(self):
122126
def _configure_controllers(self, controllers):
123127
for controller in list(controllers.values()):
124128
controller.configure()
125-
self.log('Load controller -', controller.__class__.__name__)
129+
self.log('Load controller - {}', controller.__class__.__name__)
126130

127131
def register(self, component):
128132
"""
129-
Register a :class:`Component` extended class into Application.
133+
Register a :class:`.Component` extended class into Application.
130134
The components will be loaded when application is loaded (after `start` method is called).
131135
132136
:param Component component: A module to be loaded when the Application is loaded
133137
"""
134138
self.components.append(component)
135139

140+
def register_observer(self, observer):
141+
"""
142+
Register a :class:`.ApplicationObserver` specialization into Application.
143+
The observer will receive calls when changes occurs in system, like
144+
banks creation, current pedalboard changes.
145+
146+
:param ApplicationObserver observer: The observer who will receive the changes notifications
147+
"""
148+
self.components_observer.register(observer)
149+
150+
def unregister_observer(self, observer):
151+
"""
152+
Unregister an observer in :class:`.Application`.
153+
The observer not will be more notified of the changes requested in the application API.
154+
155+
:param ApplicationObserver observer: The observer who will not receive further changes notification
156+
"""
157+
self.components_observer.unregister(observer)
158+
136159
def start(self):
137160
"""
138-
Start this API, initializing the components.
161+
Start the application, initializing your components.
139162
"""
140-
current_pedalboard = self.controller(CurrentController).current_pedalboard
141-
self.log('Load current pedalboard -', '"' + current_pedalboard.name + '"')
163+
current_pedalboard = self.controller(CurrentController).pedalboard
164+
if current_pedalboard is None:
165+
self.log('Not exists any current pedalboard.')
166+
self.log('Use CurrentController to set the current pedalboard')
167+
else:
168+
self.log('Load current pedalboard - "{}"', current_pedalboard.name)
169+
142170
self.mod_host.pedalboard = current_pedalboard
143171

144172
for component in self.components:
145173
component.init()
146-
self.log('Load component -', component.__class__.__name__)
174+
self.log('Load component - {}', component.__class__.__name__)
175+
176+
self.log('Components loaded')
177+
atexit.register(self.stop)
178+
179+
def stop(self):
180+
"""
181+
Stop the application, closing your components.
182+
"""
183+
for component in self.components:
184+
component.close()
185+
self.log('Stopping component - {}', component.__class__.__name__)
186+
187+
for controller in self.controllers.values():
188+
controller.close()
189+
self.log('Stopping controller - {}', controller.__class__.__name__)
190+
191+
atexit.unregister(self.stop)
147192

148193
def controller(self, controller):
149194
"""
@@ -163,5 +208,5 @@ def dao(self, dao):
163208
"""
164209
return dao(self.path_data)
165210

166-
def log(self, *args, **kwargs):
167-
print('[' + time.strftime('%Y-%m-%d %H:%M:%S') + ']', *args, **kwargs)
211+
def log(self, message, *args, **kwargs):
212+
logging.info(message.format(*args, **kwargs))

application/component/application_observer.py

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,44 +13,25 @@
1313
# limitations under the License.
1414

1515
from abc import ABCMeta, abstractmethod
16-
from pluginsmanager.model.updates_observer import UpdatesObserver
16+
from pluginsmanager.observer.updates_observer import UpdatesObserver
1717

1818

1919
class ApplicationObserver(UpdatesObserver, metaclass=ABCMeta):
2020
"""
21-
The :class:`ApplicationObserver` extends :class:`UpdatesObserver`.
21+
The :class:`.ApplicationObserver` extends :class:`.UpdatesObserver`.
2222
It is an abstract class definition for treatment of changes in some class model.
2323
Your methods are called when occurs any change in Bank, Pedalboard, Effect, etc.
2424
25-
To do this, it is necessary that the :class:`ApplicationObserver` objects
26-
be registered in some manager, so that it reports the changes. An
27-
example of a manager is :class:`NotificationController`.
28-
29-
:class:`NotificationController`, comparing with, :class:`UpdatesObserver`
30-
add TOKEN. Each observer should have a unique token. This token will differentiate who
31-
is making requests so the manager does not notify you back.
32-
33-
For example, if a component requires the manager to have an effect change its
34-
state (`effect.active = not effect.active`), it is not necessary for the manager
35-
to inform the component of the change. If the component was informed, it might not know
36-
that it was the one that requested the change and possibly would update its interface
37-
erroneously.
25+
To do this, it is necessary that the :class:`.ApplicationObserver` objects
26+
be registered in application (using :meth:`.Application.register_observer`
27+
or :meth:`.Component.register_observer`), so that it reports the changes.
3828
"""
3929

40-
def __init__(self):
41-
super(ApplicationObserver, self).__init__()
42-
43-
@property
4430
@abstractmethod
45-
def token(self):
31+
def on_current_pedalboard_changed(self, pedalboard, **kwargs):
4632
"""
47-
Observer token identifier.
48-
:return: string for token identifier
49-
or None if is not necessary identify the observer
50-
(it will receive all notification)
51-
"""
52-
return None
33+
Called when the current pedalboard is changed
5334
54-
@abstractmethod
55-
def on_current_pedalboard_changed(self, pedalboard, token=None):
35+
:param Pedalboard pedalboard: New current pedalboard
36+
"""
5637
pass

application/component/component.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
from abc import ABCMeta, abstractmethod
1616

17-
from application.controller.notification_controller import NotificationController
18-
1917

2018
class Component(metaclass=ABCMeta):
2119

@@ -29,26 +27,29 @@ def init(self):
2927
"""
3028
pass
3129

30+
def close(self):
31+
"""
32+
Method called when the application is requested to quit.
33+
Classes components must implement to safely finish their
34+
activities.
35+
"""
36+
pass
37+
3238
def controller(self, controller):
3339
return self.application.controller(controller)
3440

3541
def register_observer(self, observer):
3642
"""
37-
Register an observer in :class:`Application` by :class:`NotificationController`.
38-
Observers will be notified of the changes requested in the application API.
39-
40-
Obs: If a observer contains a _token_ and the request informs the same _token_
41-
the observer not will be notified.
43+
Calls :meth:`.Application.register_observer`.
4244
43-
:param UpdatesObserver observer:
45+
:param ApplicationObserver observer: The observer who will receive the changes notifications
4446
"""
45-
self.controller(NotificationController).register(observer)
47+
self.application.register_observer(observer)
4648

4749
def unregister_observer(self, observer):
4850
"""
49-
Unregister an observer in :class:`Application` by :class:`NotificationController`.
50-
The observer not will be more notified of the changes requested in the application API.
51+
Calls :meth:`.Application.unregister_observer`.
5152
52-
:param UpdatesObserver observer:
53+
:param ApplicationObserver observer: The observer who will not receive further changes notification
5354
"""
54-
self.controller(NotificationController).unregister(observer)
55+
self.application.unregister_observer(observer)

0 commit comments

Comments
 (0)