diff options
author | Ben Connors <benconnors@outlook.com> | 2019-10-18 23:01:58 -0400 |
---|---|---|
committer | Ben Connors <benconnors@outlook.com> | 2019-10-18 23:01:58 -0400 |
commit | bd3feef1499353af4410a52ee88dcb07f5dd08c0 (patch) | |
tree | 50c4217338ac5fdf15244aa204eda719ec7b72c7 | |
parent | 269491ffd449b792a9fbb0f1e93a9f8d1f405632 (diff) |
Fix up some bugs/missing features
-rw-r--r-- | blc2/__init__.py | 2 | ||||
-rw-r--r-- | blc2/functions/audio.py | 12 | ||||
-rw-r--r-- | blc2/functions/chaser.py | 36 | ||||
-rw-r--r-- | blc2/functions/function.py | 8 | ||||
-rw-r--r-- | blc2/functions/scene.py | 13 | ||||
-rw-r--r-- | blc2/workspace.py | 6 |
6 files changed, 62 insertions, 15 deletions
diff --git a/blc2/__init__.py b/blc2/__init__.py index 72a362d..24a8009 100644 --- a/blc2/__init__.py +++ b/blc2/__init__.py @@ -1,2 +1,4 @@ from .workspace import Workspace from .topology import Fixture + +__version__ = "v0.0.1" diff --git a/blc2/functions/audio.py b/blc2/functions/audio.py index c30f279..5881e18 100644 --- a/blc2/functions/audio.py +++ b/blc2/functions/audio.py @@ -49,7 +49,10 @@ class Audio(Function): return self._fade_in @fade_in.setter - def fade_in(self, v): + def fade_in(self, v: int): + if not isinstance(v, int): + v = int(v) + if v < 0: raise ValueError("Fades must be nonnegative") @@ -63,6 +66,9 @@ class Audio(Function): @fade_out.setter def fade_out(self, v): + if not isinstance(v, int): + v = int(v) + if v < 0: raise ValueError("Fades must be nonnegative") @@ -87,7 +93,7 @@ class Audio(Function): def duration(self): return self._duration - def _set_duration(self, value, update=True): + def _set_duration(self, value: int, update=True): """Set the duration. This is called by Workspace when the duration for the file has been rechecked; do @@ -105,7 +111,7 @@ class Audio(Function): def copy_data(self, data): return None - def render(self, t, data = None): + def render(self, t: int, data = None): if t > self._actual_duration: return (), (), None return ((), diff --git a/blc2/functions/chaser.py b/blc2/functions/chaser.py index a9e51a7..ea37ca0 100644 --- a/blc2/functions/chaser.py +++ b/blc2/functions/chaser.py @@ -8,7 +8,13 @@ from .function import Function from ..exceptions import LoadError class Chaser(Function): - """Class for chasers.""" + """Class for chasers. + + Chaser data theoretically supports re-use after a step in the Chaser has been deleted; + however, it is recommended to obtain a new copy of the data starting at the desired + step after steps have been moved or deleted (or even changed, in the case of timing + changes). + """ type = CHASER def __init__(self, w, id_ = None, name = None, advance_mode = ONESHOT): @@ -35,6 +41,9 @@ class Chaser(Function): @advance_mode.setter def advance_mode(self, v): + if v not in (ONESHOT, LOOP, RANDOM): + raise ValueError("Invalid advance mode") + if v != self._advance_mode: self._advance_mode = v self._recalculate() @@ -47,7 +56,7 @@ class Chaser(Function): def fade_out(self): return 0 - def get_data(self, start_at=None): #pylint: disable=arguments-differ + def get_data(self, start_at: int = None): #pylint: disable=arguments-differ data = self.ChaserData(self) if start_at is not None: data = self.advance(0, data, n=start_at) @@ -128,7 +137,10 @@ class Chaser(Function): s.index._set_index(i) #pylint: disable=protected-access def register_step(self, step): - """Register a new step.""" + """Register a new step. + + This should only be called by ChaserStep's constructor. + """ if step.index == -1: step._index = len(self._steps) #pylint: disable=protected-access elif step.index is None: @@ -142,8 +154,16 @@ class Chaser(Function): self._fix_indices() self._recalculate() - def move_step(self, step, position): - """Move a step around.""" + def move_step(self, step, position: int): + """Move a step around. + + This should be done by changing the ChaserStep's index. + + A position of -1 or a value greater than the length of the chaser is interpreted as + "make this step last". + """ + if not isinstance(position, int): + position = int(position) if isinstance(step, int): step = self._steps[step] elif step not in self._steps: @@ -171,11 +191,15 @@ class Chaser(Function): step.delete() def delete(self): + """Delete the Chaser. + + Also deletes all steps. + """ for step in self._steps: self.delete_step(step) super().delete() - def advance(self, t, data, n=None): + def advance(self, t: int, data, n=None): """Advance the chaser at the given time. If ``n`` is ``None``, the chaser is advanced one step. Otherwise, it is advanced to diff --git a/blc2/functions/function.py b/blc2/functions/function.py index 21632a7..6a5d92a 100644 --- a/blc2/functions/function.py +++ b/blc2/functions/function.py @@ -25,14 +25,18 @@ class Function(XMLSerializable, metaclass=ABCMeta): It is an error to change Function.type or Function.fade_out_mode in user code. These values are public for informational purposes. + + Type checking and implicit conversion is done wherever possible on functions that + change state (e.g. setting the fades, setting values on a Scene). However, no type + checking or conversion is done on read-only or rendering functions to save time. """ type = FUNCTION fade_out_mode = EXTERNAL def __init__(self, w: "Workspace", id_: int = None, name: str = None): self.w = w - self._id = id_ if id_ is not None else w.next_function_id - self._name = name if name else "%s %s" % (self.type, self.id) + self._id = int(id_) if id_ is not None else w.next_function_id + self._name = str(name) if name else "%s %s" % (self.type, self.id) self.w.register_function(self) diff --git a/blc2/functions/scene.py b/blc2/functions/scene.py index 239df3c..b694b8b 100644 --- a/blc2/functions/scene.py +++ b/blc2/functions/scene.py @@ -89,12 +89,17 @@ class Scene(Function): v = v.items() vn = [] for c, val in v: - val = int(val) - if val < 0 or val > 255: - raise ValueError("Values must be integers on [0,256)") + if val is not None: + val = int(val) + if val < 0 or val > 255: + raise ValueError("Values must be integers on [0,256)") vn.append((c, val)) for c, val in vn: - self._values[c] = val + if val is None: + if c in self._values: + del self._values[c] + else: + self._values[c] = val self._update_render(changed=changed) def update(self, v): diff --git a/blc2/workspace.py b/blc2/workspace.py index 89bda91..5ec5247 100644 --- a/blc2/workspace.py +++ b/blc2/workspace.py @@ -35,6 +35,12 @@ class Workspace(XMLSerializable): Note that all callbacks are executed synchronously: if they require long periods of time to execute, the callback should handle scheduling the actual work on a different thread. + + This library is designed with two user interface "modes" in mind: "run" and "edit". All + functions that edit the Workspace's internal state are considered to be in "edit" mode + and efficiency is less important, as it is not designed with real-time playback in + mind. The read-only functions, and especially `render` are designed with real-time + playback in mind. As such, no editing should be allowed while in "run" mode. """ def __init__(self, name: str, author: str, version: int, modified: dt.datetime): self.name = name |