Ejemplo n.º 1
0
    def draw_analog_assignments(self, controllers):
        zone = self.ZONE_ASSIGNMENTS
        self.erase_zone(zone)

        # spacing and scaling of text
        width_per_control = self.width
        text_per_control = self.width
        num = len(controllers)
        if num > 0:
            width_per_control = int(round(self.width / num))
            text_per_control = width_per_control - 16  # minus width of control icon

        x = 0
        for k, v in controllers.items():
            control_type = util.DICT_GET(v, Token.TYPE)
            color = util.DICT_GET(v, Token.COLOR)
            if color is None:
                # color not specified for control in config file
                category = util.DICT_GET(v, Token.CATEGORY)
                color = self.get_category_color(category)
            name = k.split(":")[1]
            n = self.shorten_name(name, text_per_control)
            if control_type == Token.KNOB:
                self.draw_knob(n, x, color)
            if control_type == Token.EXPRESSION:
                self.draw_pedal(n, x, color)
            x += width_per_control

        self.refresh_zone(zone)
Ejemplo n.º 2
0
 def update_wifi(self, wifi_status):
     if not self.supports_toolbar:
         return
     if util.DICT_GET(wifi_status, 'hotspot_active'):
         img = "wifi_orange.png"
     elif util.DICT_GET(wifi_status, 'wifi_connected'):
         img = "wifi_silver.png"
     else:
         img = "wifi_gray.png"
     path = os.path.join(self.imagedir, img)
     self.change_tool_img(self.tool_wifi, path)
Ejemplo n.º 3
0
 def get_category_color(self, category):
     color = "Silver"
     if category:
         c = util.DICT_GET(self.category_color_map, category)
         if c:
             color = c if isinstance(c, tuple) else self.valid_color(c)
     return color
Ejemplo n.º 4
0
 def get_pedalboard_bundle_from_mod(self):
     # Assumes the caller has already checked for existence of the file
     mod_bundle = None
     with open(self.pedalboard_modification_file, 'r') as file:
         j = json.load(file)
         mod_bundle = util.DICT_GET(j, 'pedalboard')
     return mod_bundle
Ejemplo n.º 5
0
    def draw_analog_assignments(self, controllers):
        zone = 1
        self.erase_zone(zone)

        exp = Token.NONE
        knob = Token.NONE
        for k, v in controllers.items():
            control_type = util.DICT_GET(v, Token.TYPE)
            s = k.split(":")
            text = "%s:%s" % (self.shorten_name(s[0], self.plugin_width),
                              self.shorten_name(s[1],
                                                self.plugin_width_medium))
            if control_type == Token.EXPRESSION:
                exp = text
            elif control_type == Token.KNOB:
                knob = text

        # Expression Pedal assignment
        self.draw[zone].line(((0, 5), (8, 1)), True, 1)
        self.draw[zone].line(((0, 5), (8, 5)), True, 2)
        self.draw[zone].text((10, 2), exp, True, self.small_font)

        # Tweak knob assignment
        x = 66
        self.draw[zone].ellipse(((x, 0), (x + 6, 6)), True, 1)
        self.draw[zone].line(((x + 3, 0), (x + 3, 2)), False, 1)
        self.draw[zone].text((x + 9, 2), knob, True, self.small_font)

        self.refresh_zone(zone)
Ejemplo n.º 6
0
    def poll_modui_changes(self):
        # This poll looks for changes made via the MOD UI and tries to sync the pi-Stomp hardware

        # Look for a change of pedalboard
        #
        # If the pedalboard_modification_file timestamp has changed, extract the bundle path and set current pedalboard
        #
        # TODO this is an interim solution until better MOD-UI to pi-stomp event communication is added
        #
        if Path(self.pedalboard_modification_file).exists():
            ts = os.path.getmtime(self.pedalboard_modification_file)
            if ts == self.pedalboard_change_timestamp:
                return

            # Timestamp changed
            self.pedalboard_change_timestamp = ts
            self.lcd.draw_info_message("Loading...")
            with open(self.pedalboard_modification_file, 'r') as file:
                j = json.load(file)
                mod_bundle = util.DICT_GET(j, 'pedalboard')
                if mod_bundle:
                    logging.info("Pedalboard changed via MOD from: %s to: %s" %
                                 (self.current.pedalboard.bundle, mod_bundle))
                    pb = self.pedalboards[mod_bundle]
                    self.set_current_pedalboard(pb)
Ejemplo n.º 7
0
 def __init__(self, plugin_info, value, binding):
     self.name = util.DICT_GET(plugin_info, Token.SHORTNAME)  # possibly use name if shortName is None
     if self.name is None:
         self.name = util.DICT_GET(plugin_info, Token.NAME)
     self.symbol = util.DICT_GET(plugin_info, Token.SYMBOL)
     self.minimum = util.DICT_GET(util.DICT_GET(plugin_info, Token.RANGES), Token.MINIMUM)
     self.maximum = util.DICT_GET(util.DICT_GET(plugin_info, Token.RANGES), Token.MAXIMUM)
     self.value = value
     self.binding = binding
Ejemplo n.º 8
0
 def update_lcd_title(self):
     invert_pb = False
     invert_pre = False
     if self.top_encoder_mode == TopEncoderMode.PEDALBOARD_SELECT:
         invert_pb = True
     if self.top_encoder_mode == TopEncoderMode.PRESET_SELECT:
         invert_pre = True
     self.lcd.draw_title(
         self.current.pedalboard.title,
         util.DICT_GET(self.current.presets, self.current.preset_index),
         invert_pb, invert_pre)
Ejemplo n.º 9
0
    def create_analog_controls(self, cfg):
        if cfg is None or (Token.HARDWARE
                           not in cfg) or (Token.ANALOG_CONTROLLERS
                                           not in cfg[Token.HARDWARE]):
            return

        midi_channel = self.__get_real_midi_channel(cfg)
        cfg_c = cfg[Token.HARDWARE][Token.ANALOG_CONTROLLERS]
        if cfg_c is None:
            return
        for c in cfg_c:
            if Util.DICT_GET(c, Token.DISABLE) is True:
                continue

            adc_input = Util.DICT_GET(c, Token.ADC_INPUT)
            midi_cc = Util.DICT_GET(c, Token.MIDI_CC)
            threshold = Util.DICT_GET(c, Token.THRESHOLD)
            control_type = Util.DICT_GET(c, Token.TYPE)

            if adc_input is None:
                logging.error("Analog control specified without %s" %
                              Token.ADC_INPUT)
                continue
            if midi_cc is None:
                logging.error("Analog control specified without %s" %
                              Token.MIDI_CC)
                continue
            if threshold is None:
                threshold = 16  # Default, 1024 is full scale

            control = AnalogMidiControl.AnalogMidiControl(
                self.spi, adc_input, threshold, midi_cc, midi_channel,
                self.midiout, control_type, c)
            self.analog_controls.append(control)
            key = format("%d:%d" % (midi_channel, midi_cc))
            self.controllers[key] = control
Ejemplo n.º 10
0
    def create_footswitches(self, cfg):
        if cfg is None or (Token.HARDWARE
                           not in cfg) or (Token.FOOTSWITCHES
                                           not in cfg[Token.HARDWARE]):
            return

        cfg_fs = cfg[Token.HARDWARE][Token.FOOTSWITCHES]
        if cfg_fs is None:
            return

        midi_channel = self.__get_real_midi_channel(cfg)
        idx = 0
        for f in cfg_fs:
            if Util.DICT_GET(f, Token.DISABLE) is True:
                continue

            di = Util.DICT_GET(f, Token.DEBOUNCE_INPUT)
            if self.debounce_map and di in self.debounce_map:
                gpio_input = self.debounce_map[di]
            else:
                gpio_input = Util.DICT_GET(f, Token.GPIO_INPUT)

            gpio_output = Util.DICT_GET(f, Token.GPIO_OUTPUT)
            midi_cc = Util.DICT_GET(f, Token.MIDI_CC)
            id = Util.DICT_GET(f, Token.ID)

            if gpio_input is None:
                logging.error("Switch specified without %s or %s" %
                              (Token.DEBOUNCE_INPUT, Token.GPIO_INPUT))
                continue

            fs = Footswitch.Footswitch(id if id else idx,
                                       gpio_input,
                                       gpio_output,
                                       midi_cc,
                                       midi_channel,
                                       self.midiout,
                                       refresh_callback=self.refresh_callback)
            self.footswitches.append(fs)
            idx += 1
Ejemplo n.º 11
0
    def load_bundle(self, bundlepath, plugin_dict):
        # Load the bundle, return the single plugin for the pedalboard
        plugin = self.get_pedalboard_plugin(self.world, bundlepath)

        # check if the plugin is a pedalboard
        def fill_in_type(node):
            if node is not None and node.is_uri():
                return node
            return None

        u = self.world.new_uri(
            "http://www.w3.org/1999/02/22-rdf-syntax-ns#type")
        plugin_types = [
            i for i in util.LILV_FOREACH(plugin.get_value(u), fill_in_type)
        ]
        if "http://moddevices.com/ns/modpedal#Pedalboard" not in plugin_types:
            raise Exception(
                'get_pedalboard_info(%s) - plugin has no mod:Pedalboard type'.
                format(bundlepath))

        # Walk ports starting from capture1 to determine general plugin order
        # TODO can this be generalized to use the chase_tail function?
        plugin_order = []
        ports = plugin.get_value(self.uri_port)
        for port in ports:
            if port is None:
                continue
            tail = self.world.get(None, self.uri_tail,
                                  port)  # TODO could end up being capture2
            if tail is None:
                continue
            head = self.world.get(tail, self.uri_head, None)
            if head is not None:
                block = self.world.get(None, self.uri_port, head)
                if block is not None:
                    self.chase_tail(block, plugin_order)
            break

        # Iterate blocks (plugins)
        plugins_unordered = {}
        plugins_extra = []
        blocks = plugin.get_value(self.uri_block)
        for block in blocks:
            if block is None or block.is_blank():
                continue

            # Add plugin data (from plugin registry) to global plugin dictionary
            plugin_info = {}
            prototype = self.world.find_nodes(block,
                                              self.world.ns.lv2.prototype,
                                              None)
            if len(prototype) > 0:
                logging.debug("prototype %s" % prototype[0])
                plugin_uri = str(prototype[0])  # plugin.get_uri()
                if plugin_uri not in plugin_dict:
                    plugin_info = self.get_plugin_data(plugin_uri)
                    if plugin_info:
                        logging.debug("added %s" % plugin_uri)
                        plugin_dict[plugin_uri] = plugin_info
                else:
                    plugin_info = plugin_dict[plugin_uri]
                #category = util.DICT_GET(plugin_info, Token.CATEGORY)

            # Extract Parameter data
            instance_id = str(block.get_path()).replace(bundlepath, "", 1)
            nodes = self.world.find_nodes(block, self.world.ns.lv2.port, None)
            parameters = {}
            if len(nodes) > 0:
                # These are the port nodes used to define parameter controls
                for port in nodes:
                    param_value = self.world.get(port, self.uri_value, None)
                    logging.debug("port: %s  value: %s" % (port, param_value))
                    binding = self.world.get(port, self.world.ns.midi.binding,
                                             None)
                    if binding is not None:
                        controller_num = self.world.get(
                            binding, self.world.ns.midi.controllerNumber, None)
                        channel = self.world.get(binding,
                                                 self.world.ns.midi.channel,
                                                 None)
                        if (controller_num is not None) and (channel
                                                             is not None):
                            binding = "%d:%d" % (self.world.new_int(
                                channel), self.world.new_int(controller_num))
                            logging.debug("  binding %s" % binding)
                    path = str(port)
                    symbol = os.path.basename(path)
                    value = None
                    if param_value is not None:
                        if param_value.is_float():
                            value = float(self.world.new_float(param_value))
                        elif param_value.is_int():
                            value = int(self.world.new_int(param_value))
                        else:
                            value = str(value)
                    # Bypass "parameter" is a special case without an entry in the plugin definition
                    if symbol == Token.COLON_BYPASS:
                        info = {
                            "shortName": "bypass",
                            "symbol": symbol,
                            "ranges": {
                                "minimum": 0,
                                "maximum": 1
                            }
                        }  # TODO tokenize
                        v = False if value is 0 else True
                        param = Parameter.Parameter(info, v, binding)
                        parameters[symbol] = param
                        continue  # don't try to find matching symbol in plugin_dict
                    # Try to find a matching symbol in plugin_dict to obtain the remaining param details
                    try:
                        plugin_params = plugin_info[Token.PORTS][
                            Token.CONTROL][Token.INPUT]
                    except KeyError:
                        logging.warning(
                            "plugin port info not found, could be missing LV2 for: %s",
                            instance_id)
                        continue
                    for pp in plugin_params:
                        sym = util.DICT_GET(pp, Token.SYMBOL)
                        if sym == symbol:
                            #logging.debug("PARAM: %s %s %s" % (util.DICT_GET(pp, 'name'), info[uri], category))
                            param = Parameter.Parameter(pp, value, binding)
                            logging.debug("Param: %s %s %4.2f %4.2f %s" %
                                          (param.name, param.symbol,
                                           param.minimum, value, binding))
                            parameters[symbol] = param

                    #logging.debug("  Label: %s" % label)
            inst = Plugin.Plugin(instance_id, parameters, plugin_info)

            try:
                index = plugin_order.index(block)
                plugins_unordered[index] = inst
            except:
                plugins_extra.append(inst)
            #logging.debug("dump: %s" % inst.to_json())

        # Add "extra" plugins (those not part of the tail_chase order) to the plugins_unordered dict
        max_index = len(plugins_unordered)
        for e in plugins_extra:
            plugins_unordered[max_index] = e
            max_index = max_index + 1

        # Sort the dictionary based on their order index and add to the pedalboard.plugin list
        # TODO improve the creation (tail chasing, sorting, dict>list conversion)
        if max_index > 0:
            sorted_dict = dict(
                sorted(plugins_unordered.items(), key=operator.itemgetter(0)))
            for i in range(0, len(sorted_dict)):
                val = sorted_dict.get(i)
                if val is not None:
                    self.plugins.append(val)

        # Done obtaining relevant lilv for the pedalboard
        return