def __init__(self): self.hmi_initialized = False self.host_initialized = False self.pedalboard_initialized = False self._playback_1_connected_ports = [] self._playback_2_connected_ports = [] self._tuner = False self._tuner_port = 1 self._peakmeter = False self.monitor_server = None self.current_bank = None self.jack_bufsize = DEFAULT_JACK_BUFSIZE self.effect_index = EffectIndex() self._pedalboard = Pedalboard() #Protocol.register_cmd_callback("banks", self.hmi_list_banks) #Protocol.register_cmd_callback("pedalboards", self.hmi_list_pedalboards) Protocol.register_cmd_callback("hw_con", self.hardware_connected) Protocol.register_cmd_callback("hw_dis", self.hardware_disconnected) Protocol.register_cmd_callback("control_set", self.hmi_parameter_set) Protocol.register_cmd_callback("control_get", self.parameter_get) Protocol.register_cmd_callback("control_next", self.parameter_addressing_next) Protocol.register_cmd_callback("peakmeter", self.peakmeter_set) Protocol.register_cmd_callback("tuner", self.tuner_set) Protocol.register_cmd_callback("tuner_input", self.tuner_set_input) #Protocol.register_cmd_callback("pedalboard_save", self.save_current_pedalboard) #Protocol.register_cmd_callback("pedalboard_reset", self.reset_current_pedalboard) Protocol.register_cmd_callback("jack_cpu_load", self.jack_cpu_load) # self.host = factory(Host, FakeHost, DEV_HOST, # "unix:///tmp/ingen.sock", self.host_callback) self.host = Host(os.environ.get("MOD_INGEN_SOCKET_URI", "unix:///tmp/ingen.sock"), self.host_callback) self.hmi = factory(HMI, FakeHMI, DEV_HMI, HMI_SERIAL_PORT, HMI_BAUD_RATE, self.hmi_callback) self.recorder = Recorder() self.player = Player() self.bundlepath = None self.mute_state = True self.recording = None self.instances = [] self.instance_mapper = InstanceIdMapper() self.screenshot_generator = ScreenshotGenerator() self.engine_samplerate = 48000 # default value self._clipmeter = Clipmeter(self.hmi) self.websockets = [] self._load_pb_hack = None self._app_save_callback = None
class Session(object): def __init__(self): self.hmi_initialized = False self.host_initialized = False self.pedalboard_initialized = False self._playback_1_connected_ports = [] self._playback_2_connected_ports = [] self._tuner = False self._tuner_port = 1 self._peakmeter = False self.monitor_server = None self.current_bank = None self.jack_bufsize = DEFAULT_JACK_BUFSIZE self.effect_index = EffectIndex() self._pedalboard = Pedalboard() #Protocol.register_cmd_callback("banks", self.hmi_list_banks) #Protocol.register_cmd_callback("pedalboards", self.hmi_list_pedalboards) Protocol.register_cmd_callback("hw_con", self.hardware_connected) Protocol.register_cmd_callback("hw_dis", self.hardware_disconnected) Protocol.register_cmd_callback("control_set", self.hmi_parameter_set) Protocol.register_cmd_callback("control_get", self.parameter_get) Protocol.register_cmd_callback("control_next", self.parameter_addressing_next) Protocol.register_cmd_callback("peakmeter", self.peakmeter_set) Protocol.register_cmd_callback("tuner", self.tuner_set) Protocol.register_cmd_callback("tuner_input", self.tuner_set_input) #Protocol.register_cmd_callback("pedalboard_save", self.save_current_pedalboard) #Protocol.register_cmd_callback("pedalboard_reset", self.reset_current_pedalboard) Protocol.register_cmd_callback("jack_cpu_load", self.jack_cpu_load) # self.host = factory(Host, FakeHost, DEV_HOST, # "unix:///tmp/ingen.sock", self.host_callback) self.host = Host(os.environ.get("MOD_INGEN_SOCKET_URI", "unix:///tmp/ingen.sock"), self.host_callback) self.hmi = factory(HMI, FakeHMI, DEV_HMI, HMI_SERIAL_PORT, HMI_BAUD_RATE, self.hmi_callback) self.recorder = Recorder() self.player = Player() self.bundlepath = None self.mute_state = True self.recording = None self.instances = [] self.instance_mapper = InstanceIdMapper() self.engine_samplerate = 48000 # default value self._clipmeter = Clipmeter(self.hmi) self.websockets = [] self._load_pb_hack = None self._save_waiter = None def reconnect(self): self.host.open_connection(self.host_callback) def websocket_opened(self, ws): self.websockets.append(ws) self.host.get("/graph") @gen.engine def host_callback(self): self.host_initialized = True def port_value_cb(instance, port, value): instance_id = self.instance_mapper.map(instance) if self._pedalboard.data['instances'].get(instance_id, False): self._pedalboard.parameter_set(instance_id, port, value) addrs = self._pedalboard.data['instances'][instance_id]['addressing'] addr = addrs.get(port, None) if addr: addr['value'] = value act = addr['actuator'] self.parameter_addressing_load(*act) def position_cb(instance, x, y): pass def plugin_add_cb(instance, uri, x, y): if not instance in self.instances: self._pedalboard.add_instance(uri, self.instance_mapper.map(instance), x=x, y=y) self.instances.append(instance) def delete_cb(instance): if instance in self.instances: self.instances.remove(instance) def connection_add_cb(instance_a, port_a, instance_b, port_b): pass def connection_delete_cb(instance_a, port_a, instance_b, port_b): pass def msg_cb(msg): for ws in self.websockets: ws.write_message(msg) def sr_cb(value): self.engine_samplerate = value self.host.msg_callback = msg_cb self.host.samplerate_value_callback = sr_cb yield gen.Task(lambda callback: self.host.get_engine_info(callback=callback)) # Add ports for i in range(1, INGEN_NUM_AUDIO_INS+1): yield gen.Task(lambda callback: self.host.add_external_port("Audio In %i" % i, "Input", "Audio", callback=callback)) for i in range(1, INGEN_NUM_AUDIO_OUTS+1): yield gen.Task(lambda callback: self.host.add_external_port("Audio Out %i" % i, "Output", "Audio", callback=callback)) for i in range(2, INGEN_NUM_MIDI_INS+1): yield gen.Task(lambda callback: self.host.add_external_port("MIDI In %i" % i, "Input", "MIDI", callback=callback)) for i in range(2, INGEN_NUM_MIDI_OUTS+1): yield gen.Task(lambda callback: self.host.add_external_port("MIDI Out %i" % i, "Output", "MIDI", callback=callback)) yield gen.Task(lambda callback: self.host.initial_setup(callback=callback)) self.host.position_callback = position_cb self.host.port_value_callback = port_value_cb self.host.plugin_add_callback = plugin_add_cb self.host.delete_callback = delete_cb self.host.connection_add_callback = connection_add_cb self.host.connection_delete_callback = connection_delete_cb def hmi_callback(self): if self.host_initialized: self.restore_last_pedalboard() logging.info("hmi initialized") self.hmi_initialized = True def reset(self, callback): gen = iter(copy.deepcopy(self.instances)) def remove_all_plugins(r=True): try: self.remove(next(gen), remove_all_plugins) except StopIteration: callback(r) remove_all_plugins() def save_pedalboard(self, bundlepath, title, callback): def callback2(ok): self.bundlepath = bundlepath if ok else None callback(ok) self.host.set_pedalboard_name(title) self.host.save(os.path.join(bundlepath, "%s.ttl" % symbolify(title)), callback2) def load_pedalboard(self, bundlepath): # TODO self.bundlepath = bundlepath if self._load_pb_hack is not None: self._load_pb_hack(bundlepath) def setup_monitor(self): if self.monitor_server is None: from mod.monitor import MonitorServer self.monitor_server = MonitorServer() self.monitor_server.listen(12345) self.set_monitor("localhost", 12345, 1, self.add_tools) def add_tools(self, resp): if resp: self.add(CLIPMETER_URI, CLIPMETER_IN, self.setup_clipmeter_in, True) self.add(CLIPMETER_URI, CLIPMETER_OUT, self.setup_clipmeter_out, True) def setup_clipmeter_in(self, resp): if resp: self.connect("system:capture_1", "effect_%d:%s" % (CLIPMETER_IN, CLIPMETER_L), lambda r:None, True) self.connect("system:capture_2", "effect_%d:%s" % (CLIPMETER_IN, CLIPMETER_R), lambda r:None, True) self.parameter_monitor(CLIPMETER_IN, CLIPMETER_MON_L, ">=", 0, lambda r:None) self.parameter_monitor(CLIPMETER_IN, CLIPMETER_MON_R, ">=", 0, lambda r:None) def setup_clipmeter_out(self, resp): if resp: self.parameter_monitor(CLIPMETER_OUT, CLIPMETER_MON_L, ">=", 0, lambda r:None) self.parameter_monitor(CLIPMETER_OUT, CLIPMETER_MON_R, ">=", 0, lambda r:None) def tuner_set_input(self, input, callback): # TODO: implement self.disconnect("system:capture_%s" % self._tuner_port, "effect_%d:%s" % (TUNER, TUNER_PORT), lambda r:r, True) self._tuner_port = input self.connect("system:capture_%s" % input, "effect_%d:%s" % (TUNER, TUNER_PORT), callback, True) def tuner_set(self, status, callback): if "on" in status: self.tuner_on(callback) elif "off" in status: self.tuner_off(callback) def tuner_on(self, cb): def mon_tuner(ok): if ok: self.parameter_monitor(TUNER, TUNER_MON_PORT, ">=", 0, cb) def setup_tuner(ok): if ok: self._tuner = True self.connect("system:capture_%s" % self._tuner_port, "effect_%d:%s" % (TUNER, TUNER_PORT), mon_tuner, True) def mute_callback(): self.add(TUNER_URI, TUNER, setup_tuner, True) self.mute(mute_callback) def tuner_off(self, cb): def callback(): self.remove(TUNER, cb, True) self._tuner = False self.unmute(callback) def peakmeter_set(self, status, callback): if "on" in status: self.peakmeter_on(callback) elif "off" in status: self.peakmeter_off(callback) def peakmeter_on(self, cb): def mon_peak_in_l(ok): if ok: self.parameter_monitor(PEAKMETER_IN, PEAKMETER_MON_VALUE_L, ">=", -30, cb) self.parameter_monitor(PEAKMETER_IN, PEAKMETER_MON_PEAK_L, ">=", -30, cb) def mon_peak_in_r(ok): if ok: self.parameter_monitor(PEAKMETER_IN, PEAKMETER_MON_VALUE_R, ">=", -30, lambda r:None) self.parameter_monitor(PEAKMETER_IN, PEAKMETER_MON_PEAK_R, ">=", -30, lambda r:None) def mon_peak_out_l(ok): if ok: self.parameter_monitor(PEAKMETER_OUT, PEAKMETER_MON_VALUE_L, ">=", -30, lambda r:None) self.parameter_monitor(PEAKMETER_OUT, PEAKMETER_MON_PEAK_L, ">=", -30, lambda r:None) def mon_peak_out_r(ok): if ok: self.parameter_monitor(PEAKMETER_OUT, PEAKMETER_MON_VALUE_R, ">=", -30, lambda r:None) self.parameter_monitor(PEAKMETER_OUT, PEAKMETER_MON_PEAK_R, ">=", -30, lambda r:None) def setup_peak_in(ok): if ok: self.connect("system:capture_1", "effect_%d:%s" % (PEAKMETER_IN, PEAKMETER_L), mon_peak_in_l, True) self.connect("system:capture_2", "effect_%d:%s" % (PEAKMETER_IN, PEAKMETER_R), mon_peak_in_r, True) def setup_peak_out(ok): if ok: self._peakmeter = True for port in self._playback_1_connected_ports: self.connect(port, "effect_%d:%s" % (PEAKMETER_OUT, PEAKMETER_L), mon_peak_out_l, True) for port in self._playback_2_connected_ports: self.connect(port, "effect_%d:%s" % (PEAKMETER_OUT, PEAKMETER_R), mon_peak_out_r, True) self.add(PEAKMETER_URI, PEAKMETER_IN, setup_peak_in, True) self.add(PEAKMETER_URI, PEAKMETER_OUT, setup_peak_out, True) def peakmeter_off(self, cb): self.remove(PEAKMETER_IN, cb, True) self.remove(PEAKMETER_OUT, lambda r: None, True) self._tuner = False def hardware_connected(self, hwtyp, hwid, callback): callback(True) #open(os.path.join(HARDWARE_DIR, "%d_%d" % (hwtyp, hwid)), 'w') #callback(True) def hardware_disconnected(self, hwtype, hwid, callback): callback(True) #if os.path.exist(): # os.remove(os.path.join(HARDWARE_DIR, "%d_%d" % (hwtyp, hwid)), callback) #callback(True) # host commands def add(self, objid, instance, x, y, callback, loaded=False): self.host.add(objid, instance, x, y, callback) def remove(self, instance, callback, loaded=False): """ affected_actuators = [] if not loaded: affected_actuators = self._pedalboard.remove_instance(instance_id) def bufsize_callback(bufsize_changed): callback(True) def change_bufsize(ok): self.change_bufsize(self._pedalboard.get_bufsize(), bufsize_callback) def _callback(ok): if ok: self.hmi.control_rm(instance_id, ":all", change_bufsize) for addr in affected_actuators: self.parameter_addressing_load(*addr) else: change_bufsize(ok) """ if instance == "-1": self.reset(callback) else: self.host.remove(instance, callback) def bypass(self, instance, value, callback, loaded=False): value = 1 if int(value) > 0 else 0 #if not loaded: # self._pedalboard.bypass(instance_id, value) #self.recorder.bypass(instance, value) self.host.bypass(instance, value, callback) def connect(self, port_from, port_to, callback, loaded=False): #if not loaded: # self._pedalboard.connect(port_from, port_to) # Cases below happen because we just save instance ID in pedalboard connection structure, not whole string #if not 'system' in port_from and not 'effect' in port_from: # port_from = "effect_%s" % port_from #if not 'system' in port_to and not 'effect' in port_to: # port_to = "effect_%s" % port_to #if "system" in port_to: # def cb(result): # if result: # if port_to == "system:playback_1": # self.connect(port_from, "effect_%d:%s" % (CLIPMETER_OUT, CLIPMETER_L), lambda r: r, True) # self._playback_1_connected_ports.append(port_from) # if self._peakmeter: # self.connect(port_from, "effect_%d:%s" % (PEAKMETER_OUT, PEAKMETER_L), lambda r: r, True) # elif port_to == "system:playback_2": # self.connect(port_from, "effect_%d:%s" % (CLIPMETER_OUT, CLIPMETER_R), lambda r: r, True) # self._playback_2_connected_ports.append(port_from) # if self._peakmeter: # self.connect(port_from, "effect_%d:%s" % (PEAKMETER_OUT, PEAKMETER_R), lambda r: r, True) # callback(result) #else: # cb = callback self.host.connect(port_from, port_to, callback) def format_port(self, port): if not 'system' in port and not 'effect' in port: port = "effect_%s" % port return port def disconnect(self, port_from, port_to, callback, loaded=False): """if not loaded: self._pedalboard.disconnect(port_from, port_to) port_from = self.format_port(port_from) port_to = self.format_port(port_to) if "system" in port_to: def cb(result): if result: if port_to == "system:playback_1": self.disconnect(port_from, "effect_%d:%s" % (CLIPMETER_OUT, CLIPMETER_L), lambda r: r, True) if self._peakmeter: self.disconnect(port_from, "effect_%d:%s" % (PEAKMETER_OUT, PEAKMETER_L), lambda r: r, True) try: self._playback_1_connected_ports.remove(port_from) except ValueError: pass elif port_to == "system:playback_2": self.disconnect(port_from, "effect_%d:%s" % (CLIPMETER_OUT, CLIPMETER_R), lambda r: r, True) if self._peakmeter: self.disconnect(port_from, "effect_%d:%s" % (PEAKMETER_OUT, PEAKMETER_R), lambda r: r, True) try: self._playback_2_connected_ports.remove(port_from) except ValueError: pass callback(result) else: cb = callback """ self.host.disconnect(port_from, port_to, callback) def hmi_parameter_set(self, instance_id, port_id, value, callback): #self.browser.send(instance_id, port_id, value) self.parameter_set(instance_id, port_id, value, callback) def preset_load(self, instance_id, url, callback): self.host.preset_load(instance_id, url, callback) def parameter_set(self, port, value, callback, loaded=False): if port == ":bypass": # self.bypass(instance_id, value, callback) return #self.recorder.parameter(instance, port_id, value) self.host.param_set(port, value, callback) def parameter_get(self, port, callback): self.host.param_get(port, callback) def set_monitor(self, addr, port, status, callback): self.host.monitor(addr, port, status, callback) def parameter_monitor(self, instance_id, port_id, op, value, callback): self.host.param_monitor(instance_id, port_id, op, value, callback) # TODO: jack cpu load with ingen def jack_cpu_load(self, callback=lambda result: None): def cb(result): if result['ok']: pass #self.browser.send(99999, 'cpu_load', round(result['value'])) self.host.cpu_load(cb) # END host commands # hmi commands def start_session(self, callback=None): self._playback_1_connected_ports = [] self._playback_2_connected_ports = [] def verify(resp): if callback: callback(resp) else: assert resp self.bank_address(0, 0, 1, 0, 0, lambda r: None) self.bank_address(0, 0, 1, 1, 0, lambda r: None) self.bank_address(0, 0, 1, 2, 0, lambda r: None) self.bank_address(0, 0, 1, 3, 0, lambda r: None) self.hmi.ui_con(verify) def end_session(self, callback): self.hmi.ui_dis(callback) def bypass_address(self, instance_id, hardware_type, hardware_id, actuator_type, actuator_id, value, label, callback, loaded=False): self.parameter_address(instance_id, ":bypass", 'switch', label, 6, "none", value, 1, 0, 0, hardware_type, hardware_id, actuator_type, actuator_id, [], callback, loaded) def parameter_addressing_next(self, hardware_type, hardware_id, actuator_type, actuator_id, callback): addrs = self._pedalboard.addressings[(hardware_type, hardware_id, actuator_type, actuator_id)] if len(addrs['addrs']) > 0: addrs['idx'] = (addrs['idx'] + 1) % len(addrs['addrs']) callback(True) self.parameter_addressing_load(hardware_type, hardware_id, actuator_type, actuator_id, addrs['idx']) return True #elif len(addrs['addrs']) <= 0: # self.hmi.control_clean(hardware_type, hardware_id, actuator_type, actuator_id) callback(True) return False def parameter_addressing_load(self, hw_type, hw_id, act_type, act_id, idx=None): addrs = self._pedalboard.addressings[(hw_type, hw_id, act_type, act_id)] if idx == None: idx = addrs['idx'] try: addressing = addrs['addrs'][idx] except IndexError: return self.hmi.control_add(addressing['instance_id'], addressing['port_id'], addressing['label'], addressing['type'], addressing['unit'], addressing['value'], addressing['maximum'], addressing['minimum'], addressing['steps'], addressing['actuator'][0], addressing['actuator'][1], addressing['actuator'][2], addressing['actuator'][3], len(addrs['addrs']), idx+1, addressing.get('options', [])) def parameter_address(self, port, addressing_type, label, ctype, unit, current_value, maximum, minimum, steps, hardware_type, hardware_id, actuator_type, actuator_id, options, callback, loaded=False): # TODO the IHM parameters set by hardware.js should be here! # The problem is that we need port data, and getting it now is expensive """ instance_id: effect instance port_id: control port addressing_type: 'range', 'switch' or 'tap_tempo' label: lcd display label ctype: 0 linear, 1 logarithm, 2 enumeration, 3 toggled, 4 trigger, 5 tap tempo, 6 bypass unit: string representing the parameter unit (hz, bpm, seconds, etc) hardware_type: the hardware model hardware_id: the id of the hardware where we find this actuator actuator_type: the encoder button type actuator_id: the encoder button number options: array of options, each one being a tuple (value, label) """ instance_id = self.instance_mapper.map(port.split("/")[0]) port_id = port.split("/")[1] if (hardware_type == -1 and hardware_id == -1 and actuator_type == -1 and actuator_id == -1): if not loaded: a = self._pedalboard.parameter_unaddress(instance_id, port_id) if a: if not self.parameter_addressing_next(a[0], a[1], a[2], a[3], callback): self.hmi.control_rm(instance_id, port_id, lambda r:None) else: callback(True) else: self.hmi.control_rm(instance_id, port_id, callback) return if not loaded: old = self._pedalboard.parameter_address(instance_id, port_id, addressing_type, label, ctype, unit, current_value, maximum, minimum, steps, hardware_type, hardware_id, actuator_type, actuator_id, options) self.hmi.control_add(instance_id, port_id, label, ctype, unit, current_value, maximum, minimum, steps, hardware_type, hardware_id, actuator_type, actuator_id, len(self._pedalboard.addressings[(hardware_type, hardware_id, actuator_type, actuator_id)]['addrs']), len(self._pedalboard.addressings[(hardware_type, hardware_id, actuator_type, actuator_id)]['addrs']), options, callback) if old: self.parameter_addressing_load(*old) else: callback(True) def bank_address(self, hardware_type, hardware_id, actuator_type, actuator_id, function, callback): """ Function is an integer, meaning: - 0: Nothing (unaddress) - 1: True bypass - 2: Pedalboard up - 3: Pedalboard down """ self.hmi.bank_config(hardware_type, hardware_id, actuator_type, actuator_id, function, callback) def ping(self, callback): self.hmi.ping(callback) def effect_position(self, instance, x, y): self.host.set_position(instance, x, y) #self._pedalboard.set_position(instance, x, y) def pedalboard_size(self, width, height): self.host.set_pedalboard_size(width, height) def clipmeter(self, pos, value): self._clipmeter.set(pos, value) def peakmeter(self, pos, value, peak, callback=None): cb = callback if not cb: cb = lambda r: r self.hmi.peakmeter(pos, value, peak, cb) def tuner(self, value, callback=None): cb = callback if not cb: cb = lambda r: r freq, note, cents = find_freqnotecents(value) self.hmi.tuner(freq, note, cents, cb) def start_recording(self): if self.player.playing: self.player.stop() self.recorder.start(self._pedalboard) def stop_recording(self): if self.recorder.recording: self.recording = self.recorder.stop() return self.recording def start_playing(self, stop_callback): if self.recorder.recording: self.recording = self.recorder.stop() def stop(): self.unmute(stop_callback) def schedule_stop(): ioloop.IOLoop.instance().add_timeout(timedelta(seconds=0.5), stop) def play(): self.player.play(self.recording['handle'], schedule_stop) self.mute(play) def stop_playing(self): self.player.stop() def reset_recording(self): self.recording = None def mute(self, callback): self.set_audio_state(False, callback) def unmute(self, callback): self.set_audio_state(True, callback) def set_audio_state(self, state, callback): if self.mute_state == state: return callback() self.mute_state = state connections = self._pedalboard.data['connections'] queue = [] for connection in connections: if connection[2] == 'system' and connection[3].startswith('playback'): port_from = self.format_port(':'.join([str(x) for x in connection[:2]])) port_to = self.format_port(':'.join([str(x) for x in connection[2:]])) queue.append([port_from, port_to]) def consume(result=None): if len(queue) == 0: return callback() nxt = queue.pop(0) if state: self.host.connect(nxt[0], nxt[1], consume) else: self.host.disconnect(nxt[0], nxt[1], consume) consume() def serialize_pedalboard(self): return self._pedalboard.serialize() def xrun(self, callback=None): cb = callback if not cb: cb = lambda r: r self.hmi.xrun(cb)