def test_nullable(self): @arguments.accept(arguments.nullable(int)) def foo(a): pass foo(None) foo(42) with self.assertRaises(TypeError): foo() with self.assertRaises(TypeError): foo(123.456)
class Scene(object): """ Scene(name, patch, init_patch=None, exit_patch=None) Construct a Scene object to be used with the :func:`run()` function. :param name: a string describing the scene. :param patch: the patch defining the MIDI processing to take place for incoming events. :param init_patch: an optional patch that will be triggered when switching to this scene. :param exit_patch: an optional patch that will be triggered when switching away from this scene. """ @_arguments.accept(None, _arguments.nullable(str), _UNIT_TYPES, _arguments.nullable(_UNIT_TYPES), _arguments.nullable(_UNIT_TYPES)) def __init__(self, name, patch, init_patch=None, exit_patch=None): self.name = name if name else '' self.patch = patch self.init_patch = [init_patch] if init_patch else [] self.exit_patch = [exit_patch] if exit_patch else []
def test_repr(self): self.assertEqual( repr(arguments._make_constraint(int)), 'int') self.assertEqual( repr(arguments._make_constraint(arguments.nullable(int))), 'nullable(int)') self.assertEqual( repr(arguments._make_constraint([int])), '[int]') self.assertEqual( repr(arguments._make_constraint((23, 42))), '(23, 42)') self.assertEqual( repr(arguments._make_constraint((int, float, str))), '(int, float, str)') self.assertEqual( repr(arguments._make_constraint([int, float, str])), '[int, float, str]') self.assertEqual( repr(arguments._make_constraint({int: str})), '{int: str}') self.assertEqual( repr(arguments._make_constraint(arguments.flatten(int))), 'flatten(int)') self.assertEqual( repr(arguments._make_constraint(arguments.each(int, float))), 'each(int, float)') self.assertEqual( repr(arguments._make_constraint(arguments.either(int, str))), 'either(int, str)') self.assertEqual( repr(arguments._make_constraint(lambda x: x / 2)), 'lambda x: x / 2') self.assertEqual( repr(arguments._make_constraint( arguments.condition(lambda x: x < 3))), 'condition(lambda x: x < 3)') def foo(x): x constraint = arguments.either( arguments.each(int, arguments.condition(lambda x: x%2 == 0)), arguments.sequenceof(foo), str, ) reprs = 'either(each(int, condition(lambda x: x%2 == 0)), [foo], str)' self.assertEqual(repr(arguments._make_constraint(constraint)), reprs)
def test_repr(self): self.assertEqual(repr(arguments._make_constraint(int)), 'int') self.assertEqual( repr(arguments._make_constraint(arguments.nullable(int))), 'nullable(int)') self.assertEqual(repr(arguments._make_constraint([int])), '[int]') self.assertEqual(repr(arguments._make_constraint((23, 42))), '(23, 42)') self.assertEqual(repr(arguments._make_constraint((int, float, str))), '(int, float, str)') self.assertEqual(repr(arguments._make_constraint([int, float, str])), '[int, float, str]') self.assertEqual(repr(arguments._make_constraint({int: str})), '{int: str}') self.assertEqual( repr(arguments._make_constraint(arguments.flatten(int))), 'flatten(int)') self.assertEqual( repr(arguments._make_constraint(arguments.each(int, float))), 'each(int, float)') self.assertEqual( repr(arguments._make_constraint(arguments.either(int, str))), 'either(int, str)') self.assertEqual(repr(arguments._make_constraint(lambda x: x / 2)), 'lambda x: x / 2') self.assertEqual( repr( arguments._make_constraint( arguments.condition(lambda x: x < 3))), 'condition(lambda x: x < 3)') def foo(x): x constraint = arguments.either( arguments.each(int, arguments.condition(lambda x: x % 2 == 0)), arguments.sequenceof(foo), str, ) reprs = 'either(each(int, condition(lambda x: x%2 == 0)), [foo], str)' self.assertEqual(repr(arguments._make_constraint(constraint)), reprs)
def run(patch): if (isinstance(patch, dict) and all(not isinstance(k, _constants._EventType) for k in patch.keys())): # bypass the overload mechanism (just this once...) if there's no way # the given dict could be accepted as a split run(scenes=patch) else: e = Engine() e.setup({_util.offset(0): patch}, None, None, None) e.run() @_overload.mark @_arguments.accept({_util.scene_number: _SCENE_TYPES}, _arguments.nullable(_UNIT_TYPES), _arguments.nullable(_UNIT_TYPES), _arguments.nullable(_UNIT_TYPES)) def run(scenes, control=None, pre=None, post=None): e = Engine() e.setup(scenes, control, pre, post) e.run() def switch_scene(scene, subscene=None): """ Switch to the given scene number. """ _TheEngine().switch_scene(scene, subscene)
def Fork(units, **kwargs): """ Units connected in parallel. """ remove_duplicates = (kwargs['remove_duplicates'] if 'remove_duplicates' in kwargs else None) # handle a single list argument differently for backward compatibility if len(units) == 1 and type(units[0]) == list: units = units[0] return _Fork(units, remove_duplicates) @_arguments.accept({ _arguments.nullable(_arguments.reduce_bitmask([_constants._EventType])): _UNIT_TYPES }) def Split(mapping): """ Split(mapping) Split by event type. """ return _Split(mapping) @_arguments.accept([_SELECTOR_TYPES]) def And(conditions): """ Conjunction of multiple filters.
if None in d: f = Chain(~t(k) for k in dd.keys()) r.append(f >> d[None]) return r def _make_threshold(f, patch_lower, patch_upper): return Fork([ f >> patch_lower, ~f >> patch_upper, ]) @_arguments.accept({ _arguments.nullable(_arguments.flatten(_util.port_number, tuple)): _UNIT_TYPES }) def PortSplit(mapping): """ PortSplit(mapping) Split events by input port, with *mapping* being a dictionary of the form ``{ports: patch, ...}``. """ return _make_split(PortFilter, mapping) @_arguments.accept({ _arguments.nullable(_arguments.flatten(_util.channel_number, tuple)): _UNIT_TYPES
def run(patch): if (isinstance(patch, dict) and all(not isinstance(k, _constants._EventType) for k in patch.keys())): # bypass the overload mechanism (just this once...) if there's no way # the given dict could be accepted as a split run(scenes=patch) else: e = Engine() e.setup({_util.offset(0): patch}, None, None, None) e.run() @_overload.mark @_arguments.accept( {_util.scene_number: _SCENE_TYPES}, _arguments.nullable(_UNIT_TYPES), _arguments.nullable(_UNIT_TYPES), _arguments.nullable(_UNIT_TYPES) ) def run(scenes, control=None, pre=None, post=None): e = Engine() e.setup(scenes, control, pre, post) e.run() def switch_scene(scene, subscene=None): """ Switch to the given scene number. """ _TheEngine().switch_scene(scene, subscene)
class MidiEvent(_mididings.MidiEvent): """ MidiEvent(type, port=0, channel=0, data1=0, data2=0, sysex=None) A MIDI event, as seen by Python code. """ @_arguments.accept(None, _constants._EventType, _util.port_number, _util.channel_number, int, int, _arguments.nullable(_util.sysex_data)) def __init__(self, type, port=_util.NoDataOffset(0), channel=_util.NoDataOffset(0), data1=0, data2=0, sysex=None): # use default c'tor, then set data members manually to take advantage # of automatic data offset conversion _mididings.MidiEvent.__init__(self) self.type = type self.port = port self.channel = channel self.data1 = data1 self.data2 = data2 if sysex is not None: self.sysex_ = sysex def __getinitargs__(self): self._finalize() return (self.type, self.port, self.channel, self.data1, self.data2, self.sysex if self.type == _constants.SYSEX else None) def _check_type_attribute(self, type, name): if not self.type & type: message = ("MidiEvent type '%s' has no attribute '%s'" % (self._type_to_string(), name)) raise AttributeError(message) def _type_to_string(self): try: return _constants._EVENT_TYPES[self.type].name except KeyError: return 'NONE' def _sysex_to_hex(self, max_length): data = self.sysex if max_length: m = max(0, max_length // 3) if len(data) > m: return '%s ...' % _misc.sequence_to_hex(data[:m]) return _misc.sequence_to_hex(data) _to_string_mapping = { _constants.NOTEON: lambda self: 'Note On: %3d %3d (%s)' % (self.note, self.velocity, _util.note_name(self.note)), _constants.NOTEOFF: lambda self: 'Note Off: %3d %3d (%s)' % (self.note, self.velocity, _util.note_name(self.note)), _constants.CTRL: lambda self: 'Ctrl: %3d %3d' % (self.ctrl, self.value) + (' (%s)' % _util.controller_name(self.ctrl) if _util.controller_name(self.ctrl) else ''), _constants.PITCHBEND: lambda self: 'Pitchbend: %5d' % self.value, _constants.AFTERTOUCH: lambda self: 'Aftertouch: %3d' % self.value, _constants.POLY_AFTERTOUCH: lambda self: 'Poly Aftertouch: %3d %3d (%s)' % (self.note, self.value, _util.note_name(self.note)), _constants.PROGRAM: lambda self: 'Program: %3d' % self.program, _constants.SYSCM_QFRAME: lambda self: 'SysCm QFrame: %3d' % self.data1, _constants.SYSCM_SONGPOS: lambda self: 'SysCm SongPos:%3d %3d' % (self.data1, self.data2), _constants.SYSCM_SONGSEL: lambda self: 'SysCm SongSel:%3d' % self.data1, _constants.SYSCM_TUNEREQ: lambda self: 'SysCm TuneReq', _constants.SYSRT_CLOCK: lambda self: 'SysRt Clock', _constants.SYSRT_START: lambda self: 'SysRt Start', _constants.SYSRT_CONTINUE: lambda self: 'SysRt Continue', _constants.SYSRT_STOP: lambda self: 'SysRt Stop', _constants.SYSRT_SENSING: lambda self: 'SysRt Sensing', _constants.SYSRT_RESET: lambda self: 'SysRt Reset', _constants.DUMMY: lambda self: 'Dummy', } _repr_mapping = { _constants.NOTEON: lambda self: 'NoteOnEvent(port=%d, channel=%d, note=%d, velocity=%d)' % (self.port, self.channel, self.note, self.velocity), _constants.NOTEOFF: lambda self: 'NoteOffEvent(port=%d, channel=%d, note=%d, velocity=%d)' % (self.port, self.channel, self.note, self.velocity), _constants.CTRL: lambda self: 'CtrlEvent(port=%d, channel=%d, ctrl=%d, value=%d)' % (self.port, self.channel, self.ctrl, self.value), _constants.PITCHBEND: lambda self: 'PitchbendEvent(port=%d, channel=%d, value=%d)' % (self.port, self.channel, self.value), _constants.AFTERTOUCH: lambda self: 'AftertouchEvent(port=%d, channel=%d, value=%d)' % (self.port, self.channel, self.value), _constants.PROGRAM: lambda self: 'ProgramEvent(port=%d, channel=%d, program=%d)' % (self.port, self.channel, self.program), _constants.SYSEX: lambda self: 'SysExEvent(port=%d, sysex=%r)' % (self.port, _misc.bytestring(self._get_sysex())), } def to_string(self, portnames=[], portname_length=0, max_length=0): if len(portnames) > self.port_: port = portnames[self.port_] else: port = str(self.port) header = '[%*s, %2d]' % (max(portname_length, 2), port, self.channel) if self.type_ == _constants.SYSEX: maxsysex = (max_length - len(header) - 25) if max_length else 0 sysexstr = self._sysex_to_hex(maxsysex) desc = 'SysEx: %8d [%s]' % (len(self.sysex), sysexstr) else: desc = MidiEvent._to_string_mapping.get(self.type_, lambda self: 'None')(self) return '%s %s' % (header, desc) def __repr__(self): return MidiEvent._repr_mapping.get( self.type_, # default for types not in _repr_mapping lambda self: 'MidiEvent(%s, %d, %d, %d, %d)' % (self._type_to_string(), self.port, self.channel, self.data1, self. data2))(self) def __eq__(self, other): if not isinstance(other, MidiEvent): return NotImplemented self._finalize() other._finalize() return _mididings.MidiEvent.__eq__(self, other) def __ne__(self, other): if not isinstance(other, MidiEvent): return NotImplemented self._finalize() other._finalize() return _mididings.MidiEvent.__ne__(self, other) def __hash__(self): self._finalize() return _mididings.MidiEvent.__hash__(self) def _finalize(self): if hasattr(self, '_sysex_tmp'): self.sysex_ = _util.sysex_data(self._sysex_tmp) delattr(self, '_sysex_tmp') def _type_getter(self): # return an event type constant, rather than the plain int stored in # self.type_ return _constants._EVENT_TYPES[self.type_] def _type_setter(self, type): self.type_ = type def _get_sysex(self): if hasattr(self, '_sysex_tmp'): return self._sysex_tmp else: return _util.sysex_to_sequence(self.sysex_) def _sysex_getter(self): self._check_type_attribute(_constants.SYSEX, 'sysex') self._sysex_tmp = self._get_sysex() return self._sysex_tmp def _sysex_setter(self, sysex): self._check_type_attribute(_constants.SYSEX, 'sysex') self._sysex_tmp = _util.sysex_to_sequence(sysex) #: The event type, one of the :ref:`event-types` constants. type = property(_type_getter, _type_setter) #: The port number. port = _make_property(_constants.ANY, 'port_', offset=True) #: The channel number. channel = _make_property(_constants.ANY, 'channel_', offset=True) #: The note number, stored in :attr:`data1`. note = _make_property(_constants.NOTE | _constants.POLY_AFTERTOUCH, 'data1', 'note') #: The velocity value, stored in :attr:`data2`. velocity = _make_property(_constants.NOTE, 'data2', 'velocity') #: The controller number, stored in :attr:`data1`. ctrl = _make_property(_constants.CTRL, 'data1', 'ctrl') #: The controller value, stored in :attr:`data2`. value = _make_property( _constants.CTRL | _constants.PITCHBEND | _constants.AFTERTOUCH | _constants.POLY_AFTERTOUCH, 'data2', 'value') #: The program number, stored in :attr:`data2`. #: Unlike :attr:`data2`, this attribute observes the #: :c:data:`data_offset` setting. program = _make_property(_constants.PROGRAM, 'data2', 'program', offset=True) #: SysEx data. sysex = property(_sysex_getter, _sysex_setter)
f = Chain(~t(k) for k in dd.keys()) r.append(f >> d[None]) return r def _make_threshold(f, patch_lower, patch_upper): return Fork([ f >> patch_lower, ~f >> patch_upper, ]) @_arguments.accept({ _arguments.nullable(_arguments.flatten(_util.port_number, tuple)): _UNIT_TYPES }) def PortSplit(mapping): """ PortSplit(mapping) Split events by input port, with *mapping* being a dictionary of the form ``{ports: patch, ...}``. """ return _make_split(PortFilter, mapping) @_arguments.accept({ _arguments.nullable(_arguments.flatten(_util.channel_number, tuple)): _UNIT_TYPES