def _parse_port_connections(ports, out): if not _misc.issequence(ports): return {} connections = {} for n, port in enumerate(ports): if not _misc.issequence(port) or len(port) <= 1 or port[1] is None: continue portname = port[0] if port[0] is None: portname = _default_portname(n, out) connections[portname] = port[1:] return connections
def _parse_portnames(ports, out): if not _misc.issequence(ports): return [_default_portname(n, out) for n in range(ports)] portnames = [] for n, port in enumerate(ports): if _misc.issequence(port): if port[0] is None: portnames.append(_default_portname(n, out)) else: portnames.append(port[0]) else: portnames.append(port) return portnames
def __call__(self, arg): if not misc.issequence(arg): raise TypeError("not a sequence") try: t = type(arg) if not isinstance(arg, types.GeneratorType) else list return t(self.what(value) for value in arg) except (TypeError, ValueError) as ex: raise type(ex)("illegal item in sequence: %s" % str(ex))
def __call__(self, arg): if not misc.issequence(arg): raise TypeError("not a sequence") if len(arg) != len(self.what): raise ValueError("expected sequence of %d items, got %d" % (len(self.what), len(arg))) try: t = type(arg) if not isinstance(arg, types.GeneratorType) else list return t(what(value) for what, value in zip(self.what, arg)) except (TypeError, ValueError) as ex: raise type(ex)("illegal item in sequence: %s" % str(ex))
def sysex_manufacturer(manufacturer): if not _misc.issequence(manufacturer, True): manufacturer = [manufacturer] manid = sysex_to_sequence(manufacturer) if len(manid) not in (1, 3): raise ValueError("manufacturer id must be either one or three bytes") elif len(manid) == 3 and manid[0] != 0x00: raise ValueError("three-byte manufacturer id must" " start with null byte") elif any(c > 0x7f for c in manid): raise ValueError("manufacturer id out of range") return manid
def sysex_manufacturer(manufacturer): if not _misc.issequence(manufacturer, True): manufacturer = [manufacturer] manid = sysex_to_bytearray(manufacturer) if len(manid) not in (1, 3): raise ValueError("manufacturer id must be either one or three bytes") elif len(manid) == 3 and manid[0] != 0x00: raise ValueError("three-byte manufacturer id must start with 0x00") else: for c in manid: if c > 0x7f: raise ValueError("manufacturer id byte %#x is out of range" % c) return manid
def _parse_scene_number(self, number): if number in self._scenes: # single scene number, no subscene return (_util.actual(number), -1) elif (_misc.issequence(number) and len(number) > 1 and number[0] in self._scenes): # scene/subscene numbers as tuple... if _util.actual(number[1]) < len(self._scenes[number[0]][1]): # both scene and subscene numbers are valid return (_util.actual(number[0]), _util.actual(number[1])) # subscene number is invalid return (_util.actual(number[0]), -1) # no such scene return (-1, -1)
def make_event(self, *args, **kwargs): """ Create a new MIDI event. Attributes can be specified in args or kwargs, unspecified attributes are filled with random values. """ type, port, channel, data1, data2, sysex = \ itertools.islice(itertools.chain(args, itertools.repeat(None)), 6) for k, v in kwargs.items(): if k == 'type': type = v if k == 'port': port = v elif k == 'channel': channel = v elif k in ('data1', 'note', 'ctrl'): data1 = v elif k in ('data2', 'velocity', 'value'): data2 = v elif k == 'program': data2 = v - setup.get_config('data_offset') elif k == 'sysex': sysex = v if type is None: if channel is None: type = random.choice( list(set(constants._EVENT_TYPES.values()) - set([DUMMY]))) else: type = random.choice([ NOTEON, NOTEOFF, CTRL, PITCHBEND, AFTERTOUCH, POLY_AFTERTOUCH, PROGRAM ]) elif type == NOTE: type = random.choice([NOTEON, NOTEOFF]) elif misc.issequence(type): type = random.choice(type) if port is None: port = random.randrange(0, 42) + setup.get_config('data_offset') if channel is None: channel = random.randrange(0, 16) + setup.get_config('data_offset') if data1 is None: data1 = random.randrange(0, 128) if data2 is None: data2 = (random.randrange(1, 128) if type == NOTEON else 0 if type == NOTEOFF else random.randrange(0, 128)) if type == SYSEX and sysex is None: sysex = [0xf0] + [ random.randrange(0, 128) for n in range(random.randrange(1024)) ] + [0xf7] return MidiEvent(type, port, channel, data1, data2, sysex)
def _run_scenes_impl(self, scenes, events): # set up a dummy engine setup._config_impl(backend='dummy') e = engine.Engine() e.setup(scenes, None, None, None) r = [] # allow input to be a single event, as well as a sequence of events if not misc.issequence(events): events = [events] # process each event, append each list of output events to the # returned list of lists for ev in events: ret = e.process_event(ev)[:] for rev in ret: rev.__class__ = MidiEvent r.append(ret) return r
def make_event(self, *args, **kwargs): """ Create a new MIDI event. Attributes can be specified in args or kwargs, unspecified attributes are filled with random values. """ type, port, channel, data1, data2, sysex = \ itertools.islice(itertools.chain(args, itertools.repeat(None)), 6) for k, v in kwargs.items(): if k == 'type': type = v if k == 'port': port = v elif k == 'channel': channel = v elif k in ('data1', 'note', 'ctrl'): data1 = v elif k in ('data2', 'velocity', 'value'): data2 = v elif k == 'program': data2 = v - setup.get_config('data_offset') elif k == 'sysex': sysex = v if type is None: if channel is None: type = random.choice(list(set(constants._EVENT_TYPES.values()) - set([DUMMY]))) else: type = random.choice([NOTEON, NOTEOFF, CTRL, PITCHBEND, AFTERTOUCH, POLY_AFTERTOUCH, PROGRAM]) elif type == NOTE: type = random.choice([NOTEON, NOTEOFF]) elif misc.issequence(type): type = random.choice(type) if port is None: port = random.randrange(0, 42) + setup.get_config('data_offset') if channel is None: channel = random.randrange(0, 16) + setup.get_config('data_offset') if data1 is None: data1 = random.randrange(0, 128) if data2 is None: data2 = (random.randrange(1, 128) if type == NOTEON else 0 if type == NOTEOFF else random.randrange(0, 128)) if type == SYSEX and sysex is None: sysex = [0xf0] + [random.randrange(0, 128) for n in range(random.randrange(1024))] + [0xf7] return MidiEvent(type, port, channel, data1, data2, sysex)
def do_call(ev): # add additional properties that don't exist on the C++ side ev.__class__ = _event.MidiEvent # call the function ret = function(ev) if ret is None or async: return None elif isinstance(ret, _types.GeneratorType): # function is a generator, build list ret = list(ret) elif not _misc.issequence(ret): ret = [ret] for ev in ret: ev._finalize() return ret
def Harmonize(tonic, scale, interval, non_harmonic='below'): """ A diatonic harmonizer. :param tonic: The tonic of the scale, as a note name. :param scale: The type/mode, of the scale, one of: ``'major'``, ``'minor'``, ``'minor_harmonic'``, ``'ionian'``, ``'dorian'``, ``'phrygian'``, ``'lydian'``, ``'mixolydian'``, ``'aeolian'``, ``'locrian'``. :param interval: The number of steps to transpose the notes by (as an integer), or one of these interval names: ``'unison'``, ``'second'``, ``'third'``, ``'fourth'``, ``'fifth'``, ``'sixth'``, ``'seventh'``, ``'octave'``, ``'ninth'``, ``'tenth'``, ``'eleventh'``, ``'twelfth'``, ``'thirteenth'``. It is also possible to pass a list of intervals, to create multiple harmonized voices. :param non_harmonic: What to do with out-of-scale notes: - ``'below'``: Transpose by the same interval as the next on-scale - ``'above'``: Transpose by the same interval as the next on-scale - ``'skip'``: Ignore note. - ``'same'``: Output note as is, without transposing it. """ t = _util.tonic_note_number(tonic) if _misc.issequence(scale): shift = 0 elif isinstance(scale, str): if scale == 'major': scale = _MAJOR_SCALE shift = 0 elif scale == 'minor': scale = _MAJOR_SCALE shift = 5 elif scale == 'minor_harmonic': scale = _HARMONIC_MINOR_SCALE shift = 0 elif scale in _MODES: shift = _MODES.index(scale) scale = _MAJOR_SCALE # shift scale to the correct mode s = ([x - scale[shift] for x in scale[shift:]] + [x + 12 - scale[shift] for x in scale[:shift]]) if not _misc.issequence(interval): interval = [interval] # convert all interval names to numbers iv = [(_INTERVALS.index(x) if x in _INTERVALS else x) for x in interval] # python version: # f = [ _m.Process(_Harmonizer(t, s, i, non_harmonic)) for i in iv ] # pure mididings version: f = [] for i in iv: h = _Harmonizer(t, s, i, non_harmonic) # get offset for each key offsets = [(x, h.note_offset(x)) for x in range(128)] # group by offset groups = _itertools.groupby(sorted(offsets, key=_itemgetter(1)), key=_itemgetter(1)) # create one KeyFilter()/Transpose() pair for each offset for off, keys in groups: if off is not None: f.append(_m.KeyFilter(notes=[k[0] for k in keys]) >> _m.Transpose(off)) return _m.Filter(_m.NOTE) % f
def Harmonize(tonic, scale, interval, non_harmonic='below'): """ A diatonic harmonizer. :param tonic: The tonic of the scale, as a note name. :param scale: The type/mode, of the scale, one of: ``'major'``, ``'minor'``, ``'minor_harmonic'``, ``'ionian'``, ``'dorian'``, ``'phrygian'``, ``'lydian'``, ``'mixolydian'``, ``'aeolian'``, ``'locrian'``. :param interval: The number of steps to transpose the notes by (as an integer), or one of these interval names: ``'unison'``, ``'second'``, ``'third'``, ``'fourth'``, ``'fifth'``, ``'sixth'``, ``'seventh'``, ``'octave'``, ``'ninth'``, ``'tenth'``, ``'eleventh'``, ``'twelfth'``, ``'thirteenth'``. It is also possible to pass a list of intervals, to create multiple harmonized voices. :param non_harmonic: What to do with out-of-scale notes: - ``'below'``: Transpose by the same interval as the next on-scale - ``'above'``: Transpose by the same interval as the next on-scale - ``'skip'``: Ignore note. - ``'same'``: Output note as is, without transposing it. """ t = _util.tonic_note_number(tonic) if _misc.issequence(scale): shift = 0 elif isinstance(scale, str): if scale == 'major': scale = _MAJOR_SCALE shift = 0 elif scale == 'minor': scale = _MAJOR_SCALE shift = 5 elif scale == 'minor_harmonic': scale = _HARMONIC_MINOR_SCALE shift = 0 elif scale in _MODES: shift = _MODES.index(scale) scale = _MAJOR_SCALE # shift scale to the correct mode s = ([x - scale[shift] for x in scale[shift:]] + [x + 12 - scale[shift] for x in scale[:shift]]) if not _misc.issequence(interval): interval = [interval] # convert all interval names to numbers iv = [(_INTERVALS.index(x) if x in _INTERVALS else x) for x in interval] # python version: # f = [ _m.Process(_Harmonizer(t, s, i, non_harmonic)) for i in iv ] # pure mididings version: f = [] for i in iv: h = _Harmonizer(t, s, i, non_harmonic) # get offset for each key offsets = [(x, h.note_offset(x)) for x in range(128)] # group by offset groups = _itertools.groupby(sorted(offsets, key=_itemgetter(1)), key=_itemgetter(1)) # create one KeyFilter()/Transpose() pair for each offset for off, keys in groups: if off is not None: f.append( _m.KeyFilter(notes=[k[0] for k in keys]) >> _m.Transpose(off)) return _m.Filter(_m.NOTE) % f
def __init__(self, port=56418, notify_ports=[56419]): self.port = port if _misc.issequence(notify_ports): self.notify_ports = notify_ports else: self.notify_ports = [notify_ports]