Esempio n. 1
0
    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)
Esempio n. 2
0
    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)
Esempio n. 3
0
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 []
Esempio n. 4
0
    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)
Esempio n. 5
0
    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)
Esempio n. 6
0
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)

Esempio n. 7
0
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.
Esempio n. 8
0
    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
Esempio n. 9
0
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)
Esempio n. 10
0
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)
Esempio n. 11
0
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.
Esempio n. 12
0
        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