def _start_backend(): global _TheBackend if _TheBackend is None: _TheBackend = _mididings.create_backend( _setup.get_config('backend'), _setup.get_config('client_name'), _setup._in_portnames, _setup._out_portnames) if _TheBackend: _TheBackend.connect_ports(_setup._in_port_connections, _setup._out_port_connections)
def _start_backend(): global _TheBackend if _TheBackend is None: _TheBackend = _mididings.create_backend( _setup.get_config('backend'), _setup.get_config('client_name'), _setup._in_portnames, _setup._out_portnames ) if _TheBackend: _TheBackend.connect_ports(_setup._in_port_connections, _setup._out_port_connections)
def run(self): self._quit = _threading.Event() # delay before actually sending any midi data (give qjackctl # patchbay time to react...) self._start_delay() self._call_hooks('on_start') initial_scene, initial_subscene = \ self._parse_scene_number(_setup.get_config('initial_scene')) # start the actual event processing self.start(initial_scene, initial_subscene) try: # wait() with no timeout also blocks KeyboardInterrupt, but # a very long timeout doesn't. weird... while not self._quit.isSet(): self._quit.wait(86400) except KeyboardInterrupt: pass finally: self._call_hooks('on_exit') global _TheEngine _TheEngine = None
def _start_delay(self): delay = _setup.get_config('start_delay') if delay is not None: if delay > 0: _time.sleep(delay) else: raw_input("press enter to start midi processing...")
def note_number(note, allow_end=False): """ note_number(note) Convert note name to note number. :param note: any valid :ref:`note description <notes>` (name or number). :return: MIDI note number. """ if isinstance(note, int): r = note elif isinstance(note, str): note = note.lower() # find first digit for i in range(len(note)): if note[i].isdigit() or note[i] == '-': break try: name = note[:i] octave = int(note[i:]) r = (_NOTE_NUMBERS[name] + (octave + _setup.get_config('octave_offset')) * 12) except Exception: raise ValueError("invalid note name '%s'" % note) else: raise TypeError("note must be an integer or string") end = 128 if not allow_end else 129 if not (0 <= r < end): raise ValueError("note number %d is out of range" % r) return r
def run_patch(self, patch, events): """ Run the given events through the given patch, return the list of resulting events. """ r = self.run_scenes({setup.get_config('data_offset'): patch}, events) return list(itertools.chain(*r))
def run_patch(self, patch, events): """ Run the given events through the given patch, return the list of resulting events. """ r = self.run_scenes({ setup.get_config('data_offset'): patch }, events) return list(itertools.chain(*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 actual(n): """ Subtract current data offset to get the "real" value used on the C++ side. """ if isinstance(n, NoDataOffset): return int(n) else: return n - _setup.get_config('data_offset')
def __init__(self): _start_backend() verbose = not _setup.get_config('silent') # initialize C++ base class _mididings.Engine.__init__(self, _TheBackend, verbose) self._scenes = {}
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 get_client_id(): """ Return client id """ if _setup.get_config('backend') == 'alsa': return _TheEngine().get_client_id() uuid = _TheEngine().get_client_uuid() if uuid.isdigit(): return int(uuid) return uuid
def send_config(self): for p in self.notify_ports: # send data offset _liblo.send(p, '/mididings/data_offset', _setup.get_config('data_offset')) # send list of scenes _liblo.send(p, '/mididings/begin_scenes') s = _engine.scenes() for n in sorted(s.keys()): _liblo.send(p, '/mididings/add_scene', n, s[n][0], *s[n][1]) _liblo.send(p, '/mididings/end_scenes')
def note_name(note): """ Get note name from note number. :param note: a MIDI note number. :return: note name as a string. """ if not isinstance(note, int): raise TypeError("note must be an integer") return _NOTE_NAMES[note % 12] + str((note // 12) - _setup.get_config('octave_offset'))
def note_name(note): """ Get note name from note number. :param note: a MIDI note number. :return: note name as a string. """ if not isinstance(note, int): raise TypeError("note must be an integer") return _NOTE_NAMES[note % 12] + str( (note // 12) - _setup.get_config('octave_offset'))
def wrapper(self, f, *args, **kwargs): # XXX: avoid circular import from mididings.setup import get_config if (not (hasattr(f, '_already_used') and f._already_used) and not get_config('silent')): if self.replacement: print("%s() is deprecated, please use %s() instead" % (f.__name__, self.replacement)) else: print("%s() is deprecated" % f.__name__) f._already_used = True return f(*args, **kwargs)
def scene_switch_callback(self, scene, subscene): # scene and subscene parameters are the actual numbers without offset! if scene == -1: # no scene specified, use current scene = _mididings.Engine.current_scene(self) if subscene == -1: # no subscene specified, use first subscene = 0 # save actual subscene index subscene_index = subscene # add data offset to scene/subscene numbers scene = _util.offset(scene) subscene = _util.offset(subscene) found = (scene in self._scenes and (not subscene_index or subscene_index < len(self._scenes[scene][1]))) # get string representation of scene/subscene number if (subscene_index or (scene in self._scenes and len(self._scenes[scene][1]))): number = "%d.%d" % (scene, subscene) else: number = str(scene) if not _setup.get_config('silent'): if found: # get scene/subscene name scene_data = self._scenes[scene] if scene_data[1]: name = "%s - %s" % (scene_data[0], scene_data[1][subscene_index]) else: name = scene_data[0] scene_desc = (("%s: %s" % (number, name)) if name else str(number)) print("switching to scene %s" % scene_desc) else: print("no such scene: %s" % number) if found: self._call_hooks('on_switch_scene', scene, subscene)
def offset(n): """ Add current data offset. """ return n + _setup.get_config('data_offset')
def check_patch(self, patch, d): """ Test the given patch. d must be a mapping from events to the expected list of resulting events. """ self.check_scenes({ setup.get_config('data_offset'): patch }, d)
def check_patch(self, patch, d): """ Test the given patch. d must be a mapping from events to the expected list of resulting events. """ self.check_scenes({setup.get_config('data_offset'): patch}, d)