diff --git a/iipyper/iipyper/__init__.py b/iipyper/iipyper/__init__.py index fdab666..0f433aa 100644 --- a/iipyper/iipyper/__init__.py +++ b/iipyper/iipyper/__init__.py @@ -1,4 +1,6 @@ import asyncio +import functools +import threading import fire @@ -6,19 +8,33 @@ from .osc import * _loop_fns = [] -# decorator to make a function loop -def repeat(time): + +def repeat(_time): + """ + decorator to repeat function every 'time' seconds + """ # close the decorator over time argument def decorator(f): # define the coroutine - async def g(): + @functools.wraps(f) + async def g(*args, **kwargs): # call `f` every `time` seconds while True: - f() - await asyncio.sleep(time) + t1 = time.time() + f(*args, **kwargs) + t2 = time.time() + delta_t = t2 - t1 + sleep_time = _time - delta_t + + if (sleep_time < 0): + print("Warning: repeat@ sleep time < 0") + await asyncio.sleep(0) + else: + await asyncio.sleep(sleep_time) + # track the coroutine in a global list _loop_fns.append(g) - + return f return decorator diff --git a/mrp/mrp/mrp.py b/mrp/mrp/mrp.py index 3157ee7..664736b 100644 --- a/mrp/mrp/mrp.py +++ b/mrp/mrp/mrp.py @@ -278,6 +278,30 @@ def quality_update(self, note, quality, value, relative=False, channel=None): print('quality_update(): "quality" is not a string:', quality) return None + def quality_update_all(self, quality, value, relative=False, channel=None): + """ + Update quality of all active notes to a new value. + + Example + quality_update_all('brightness', 0.5) + + Args + quality (string): name of quality to update, must be same as key in osc_paths + value (float): value of quality + relative (bool): replace the value or add it to the current value + channel (int): which MIDI channel to send on + """ + if isinstance(quality, str): + active_notes = self.note_on_numbers() + changed_notes = [] + for note in active_notes: + changed_note = self.quality_update(self, note, quality, value, relative, channel) + changed_notes.append(changed_note) + return changed_notes + else: + print('quality_update(): "quality" is not a string:', quality) + return None + def qualities_update(self, note, qualities, relative=False, channel=None): """ Update a note's qualities to a new set of values. @@ -302,7 +326,7 @@ def qualities_update(self, note, qualities, relative=False, channel=None): channel = self.settings['channel'] tmp = self.notes[self.note_index(note)] for q, v in qualities.items(): - if isinstance(value, list) or isinstance(value, np.ndarray): # e.g. /harmonics/raw + if isinstance(v, list) or isinstance(v, np.ndarray): # e.g. /harmonics/raw if relative is True: print('quality_update(): relative updating of lists not supported') else: @@ -325,7 +349,35 @@ def qualities_update(self, note, qualities, relative=False, channel=None): else: print('quality_update(): "qualities" is not an object:', note, qualities) return None + + def qualities_update_all(self, qualities, relative=False, channel=None): + """ + Update the qualities for all active notes to a new set of values. + Example + qualities_update_all({ + 'brightness': 0.5, + 'intensity': 0.6, + 'harmonics_raw': [0.2, 0.3, 0.4] + }) + + Args + qualities (dict): dict of qualities in key (string):value (float) pairs to update, + must be same as key in osc_paths + relative (bool): replace the value or add it to the current value + channel (int): which MIDI channel to send on + """ + if isinstance(qualities, dict): + active_notes = self.note_on_numbers() + changed_notes = [] + for note in active_notes: + changed_note = self.qualities_update(self, qualities, relative, channel) + changed_notes.append(changed_note) + return changed_notes + else: + print('quality_update(): "qualities" is not an object:', note, qualities) + return None + """ /mrp/pedal """ @@ -422,7 +474,7 @@ def note_on_numbers(self): return numbers of notes that are on """ on_numbers = [] - for note in enumerate(self.notes): + for note in self.notes: if note['status'] == NOTE_ON: on_numbers.append(note['midi']['number']) return on_numbers