|  | #!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Carla plugin host (plugin UI)
# Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the GPL.txt file
# ------------------------------------------------------------------------------------------------------------
# Imports (Custom Stuff)
from carla_host import *
from externalui import ExternalUI
# ------------------------------------------------------------------------------------------------------------
# Helper object
class PluginStoreInfo(object):
    __slots__ = [
        'pluginInfo',
        'pluginRealName',
        'audioCountInfo',
        'midiCountInfo',
        'parameterCount',
        'parameterCountInfo',
        'parameterInfoS',
        'parameterDataS',
        'parameterRangeS',
        'parameterValueS',
        'programCount',
        'programCurrent',
        'programNameS',
        'midiProgramCount',
        'midiProgramCurrent',
        'midiProgramDataS',
        'peaks'
    ]
# ------------------------------------------------------------------------------------------------------------
# Host Plugin object
class PluginHost(object):
    def __init__(self, sampleRate):
        object.__init__(self)
        self.fSupportedFileExts = ""
        self.fBufferSize = 0
        self.fSampleRate = sampleRate
        self.fLastError  = ""
        self.fIsRunning  = True
        self.fPluginsInfo = []
    def _add(self, pluginId):
        if len(self.fPluginsInfo) != pluginId:
            return
        info = PluginStoreInfo()
        info.pluginInfo = PyCarlaPluginInfo
        info.pluginRealName = ""
        info.audioCountInfo = PyCarlaPortCountInfo
        info.midiCountInfo  = PyCarlaPortCountInfo
        info.parameterCount = 0
        info.parameterCountInfo = PyCarlaPortCountInfo
        info.parameterInfoS  = []
        info.parameterDataS  = []
        info.parameterRangeS = []
        info.parameterValueS = []
        info.programCount = 0
        info.programCurrent = -1
        info.programNameS = []
        info.midiProgramCount = 0
        info.midiProgramCurrent = -1
        info.midiProgramDataS = []
        info.peaks = [0.0, 0.0, 0.0, 0.0]
        self.fPluginsInfo.append(info)
    def _set_pluginInfo(self, pluginId, info):
        self.fPluginsInfo[pluginId].pluginInfo = info
    def _set_pluginName(self, pluginId, name):
        self.fPluginsInfo[pluginId].pluginInfo['name'] = name
    def _set_pluginRealName(self, pluginId, realName):
        self.fPluginsInfo[pluginId].pluginRealName = realName
    def _set_audioCountInfo(self, pluginId, info):
        self.fPluginsInfo[pluginId].audioCountInfo = info
    def _set_midiCountInfo(self, pluginId, info):
        self.fPluginsInfo[pluginId].midiCountInfo = info
    def _set_parameterCountInfo(self, pluginId, count, info):
        self.fPluginsInfo[pluginId].parameterCount = count
        self.fPluginsInfo[pluginId].parameterCountInfo = info
        # clear
        self.fPluginsInfo[pluginId].parameterInfoS  = []
        self.fPluginsInfo[pluginId].parameterDataS  = []
        self.fPluginsInfo[pluginId].parameterRangeS = []
        self.fPluginsInfo[pluginId].parameterValueS = []
        # add placeholders
        for x in range(count):
            self.fPluginsInfo[pluginId].parameterInfoS.append(PyCarlaParameterInfo)
            self.fPluginsInfo[pluginId].parameterDataS.append(PyParameterData)
            self.fPluginsInfo[pluginId].parameterRangeS.append(PyParameterRanges)
            self.fPluginsInfo[pluginId].parameterValueS.append(0.0)
    def _set_programCount(self, pluginId, count):
        self.fPluginsInfo[pluginId].programCount = count
        # clear
        self.fPluginsInfo[pluginId].programNameS = []
        # add placeholders
        for x in range(count):
            self.fPluginsInfo[pluginId].programNameS.append("")
    def _set_midiProgramCount(self, pluginId, count):
        self.fPluginsInfo[pluginId].midiProgramCount = count
        # clear
        self.fPluginsInfo[pluginId].midiProgramDataS = []
        # add placeholders
        for x in range(count):
            self.fPluginsInfo[pluginId].midiProgramDataS.append(PyMidiProgramData)
    def _set_parameterInfoS(self, pluginId, paramIndex, info):
        if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
            self.fPluginsInfo[pluginId].parameterInfoS[paramIndex] = info
    def _set_parameterDataS(self, pluginId, paramIndex, data):
        if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
            self.fPluginsInfo[pluginId].parameterDataS[paramIndex] = data
    def _set_parameterRangeS(self, pluginId, paramIndex, ranges):
        if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
            self.fPluginsInfo[pluginId].parameterRangeS[paramIndex] = ranges
    def _set_parameterValueS(self, pluginId, paramIndex, value):
        if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
            self.fPluginsInfo[pluginId].parameterValueS[paramIndex] = value
    def _set_parameterDefault(self, pluginId, paramIndex, value):
        if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
            self.fPluginsInfo[pluginId].parameterRangeS[paramIndex]['def'] = value
    def _set_parameterMidiChannel(self, pluginId, paramIndex, channel):
        if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
            self.fPluginsInfo[pluginId].parameterDataS[paramIndex]['midiChannel'] = channel
    def _set_parameterMidiCC(self, pluginId, paramIndex, cc):
        if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
            self.fPluginsInfo[pluginId].parameterDataS[paramIndex]['midiCC'] = cc
    def _set_currentProgram(self, pluginId, pIndex):
        self.fPluginsInfo[pluginId].programCurrent = pIndex
    def _set_currentMidiProgram(self, pluginId, mpIndex):
        self.fPluginsInfo[pluginId].midiProgramCurrent = mpIndex
    def _set_programNameS(self, pluginId, pIndex, name):
        if pIndex < self.fPluginsInfo[pluginId].programCount:
            self.fPluginsInfo[pluginId].programNameS[pIndex] = name
    def _set_midiProgramDataS(self, pluginId, mpIndex, data):
        if mpIndex < self.fPluginsInfo[pluginId].midiProgramCount:
            self.fPluginsInfo[pluginId].midiProgramDataS[mpIndex] = data
    def _set_peaks(self, pluginId, in1, in2, out1, out2):
        self.fPluginsInfo[pluginId].peaks = [in1, in2, out1, out2]
    # -------------------------------------------------------------------
    def get_complete_license_text(self):
        return ""
    def get_supported_file_extensions(self):
        return self.fSupportedFileExts
    # -------------------------------------------------------------------
    def get_engine_driver_count(self):
        return 1
    def get_engine_driver_name(self, index):
        return "Plugin"
    def get_engine_driver_device_names(self, index):
        return []
    def get_engine_driver_device_info(self, index, name):
        return PyEngineDriverDeviceInfo
    # -------------------------------------------------------------------
    def get_internal_plugin_count(self):
        return 0
    def get_internal_plugin_info(self, index):
        return None
    # -------------------------------------------------------------------
    def engine_init(self, driverName, clientName):
        return True
    def engine_close(self):
        return True
    def engine_idle(self):
        if gCarla.gui.idleExternalUI():
            return
        self.fIsRunning = False
        gCarla.gui.d_uiQuit()
    def is_engine_running(self):
        return self.fIsRunning
    def set_engine_about_to_close(self):
        pass
    def set_engine_callback(self, func):
        pass
    def set_engine_option(self, option, value, valueStr):
        gCarla.gui.send(["set_engine_option", option, value, valueStr])
    def set_file_callback(self, func):
        pass
    # -------------------------------------------------------------------
    def set_file_callback(self, func):
        pass
    def load_file(self, filename):
        gCarla.gui.send(["load_file", filename])
        return True
    def load_project(self, filename):
        gCarla.gui.send(["load_project", filename])
        return True
    def save_project(self, filename):
        gCarla.gui.send(["save_project", filename])
        return True
    # -------------------------------------------------------------------
    def patchbay_connect(self, groupIdA, portIdA, groupIdB, portIdB):
        gCarla.gui.send(["patchbay_connect", groupIdA, portIdA, groupIdB, portIdB])
        return True
    def patchbay_disconnect(self, connectionId):
        gCarla.gui.send(["patchbay_disconnect", connectionId])
        return True
    def patchbay_refresh(self):
        gCarla.gui.send(["patchbay_refresh"])
        return True
    # -------------------------------------------------------------------
    def transport_play(self):
        gCarla.gui.send(["transport_play"])
    def transport_pause(self):
        gCarla.gui.send(["transport_pause"])
    def transport_relocate(self, frame):
        gCarla.gui.send(["transport_relocate"])
    def get_current_transport_frame(self):
        return 0
    def get_transport_info(self):
        return PyCarlaTransportInfo
    # -------------------------------------------------------------------
    def add_plugin(self, btype, ptype, filename, name, label, uniqueId, extraPtr):
        gCarla.gui.send(["add_plugin", btype, ptype, filename, name, label, uniqueId])
        return True
    def remove_plugin(self, pluginId):
        gCarla.gui.send(["remove_plugin", pluginId])
        return True
    def remove_all_plugins(self):
        gCarla.gui.send(["remove_all_plugins"])
        return True
    def rename_plugin(self, pluginId, newName):
        gCarla.gui.send(["rename_plugin", pluginId, newName])
        return newName
    def clone_plugin(self, pluginId):
        gCarla.gui.send(["clone_plugin", pluginId])
        return True
    def replace_plugin(self, pluginId):
        gCarla.gui.send(["replace_plugin", pluginId])
        return True
    def switch_plugins(self, pluginIdA, pluginIdB):
        gCarla.gui.send(["switch_plugins", pluginIdA, pluginIdB])
        return True
    # -------------------------------------------------------------------
    def load_plugin_state(self, pluginId, filename):
        gCarla.gui.send(["load_plugin_state", pluginId, filename])
        return True
    def save_plugin_state(self, pluginId, filename):
        gCarla.gui.send(["save_plugin_state", pluginId, filename])
        return True
    # -------------------------------------------------------------------
    def get_plugin_info(self, pluginId):
        return self.fPluginsInfo[pluginId].pluginInfo
    def get_audio_port_count_info(self, pluginId):
        return self.fPluginsInfo[pluginId].audioCountInfo
    def get_midi_port_count_info(self, pluginId):
        return self.fPluginsInfo[pluginId].midiCountInfo
    def get_parameter_count_info(self, pluginId):
        return self.fPluginsInfo[pluginId].parameterCountInfo
    def get_parameter_info(self, pluginId, parameterId):
        return self.fPluginsInfo[pluginId].parameterInfoS[parameterId]
    def get_parameter_scalepoint_info(self, pluginId, parameterId, scalePointId):
        return PyCarlaScalePointInfo
    # -------------------------------------------------------------------
    def get_parameter_data(self, pluginId, parameterId):
        return self.fPluginsInfo[pluginId].parameterDataS[parameterId]
    def get_parameter_ranges(self, pluginId, parameterId):
        return self.fPluginsInfo[pluginId].parameterRangeS[parameterId]
    def get_midi_program_data(self, pluginId, midiProgramId):
        return self.fPluginsInfo[pluginId].midiProgramDataS[midiProgramId]
    def get_custom_data(self, pluginId, customDataId):
        return PyCustomData
    def get_chunk_data(self, pluginId):
        return ""
    # -------------------------------------------------------------------
    def get_parameter_count(self, pluginId):
        return self.fPluginsInfo[pluginId].parameterCount
    def get_program_count(self, pluginId):
        return self.fPluginsInfo[pluginId].programCount
    def get_midi_program_count(self, pluginId):
        return self.fPluginsInfo[pluginId].midiProgramCount
    def get_custom_data_count(self, pluginId):
        return 0
    # -------------------------------------------------------------------
    def get_parameter_text(self, pluginId, parameterId):
        return ""
    def get_program_name(self, pluginId, programId):
        return self.fPluginsInfo[pluginId].programNameS[programId]
    def get_midi_program_name(self, pluginId, midiProgramId):
        return self.fPluginsInfo[pluginId].midiProgramDataS[midiProgramId]['label']
    def get_real_plugin_name(self, pluginId):
        return self.fPluginsInfo[pluginId].pluginRealName
    # -------------------------------------------------------------------
    def get_current_program_index(self, pluginId):
        return self.fPluginsInfo[pluginId].programCurrent
    def get_current_midi_program_index(self, pluginId):
        return self.fPluginsInfo[pluginId].midiProgramCurrent
    def get_default_parameter_value(self, pluginId, parameterId):
        return self.fPluginsInfo[pluginId].parameterRangeS[parameterId]['def']
    def get_current_parameter_value(self, pluginId, parameterId):
        return self.fPluginsInfo[pluginId].parameterValueS[parameterId]
    # TODO
    def get_internal_parameter_value(self, pluginId, parameterId):
        if parameterId == PARAMETER_ACTIVE:
            return 1.0
        elif parameterId == PARAMETER_DRYWET:
            return 1.0
        elif parameterId == PARAMETER_VOLUME:
            return 1.0
        elif parameterId == PARAMETER_BALANCE_LEFT:
            return -1.0
        elif parameterId == PARAMETER_BALANCE_RIGHT:
            return 1.0
        elif parameterId == PARAMETER_PANNING:
            return 0.0
        elif parameterId == PARAMETER_CTRL_CHANNEL:
            return 0.0
        return 0.0
    def get_input_peak_value(self, pluginId, isLeft):
        return self.fPluginsInfo[pluginId].peaks[0 if isLeft else 1]
    def get_output_peak_value(self, pluginId, isLeft):
        return self.fPluginsInfo[pluginId].peaks[2 if isLeft else 3]
    # -------------------------------------------------------------------
    def set_option(self, pluginId, option, yesNo):
        gCarla.gui.send(["set_option", pluginId, option, yesNo])
    def set_active(self, pluginId, onOff):
        gCarla.gui.send(["set_active", pluginId, onOff])
    def set_drywet(self, pluginId, value):
        gCarla.gui.send(["set_drywet", pluginId, value])
    def set_volume(self, pluginId, value):
        gCarla.gui.send(["set_volume", pluginId, value])
    def set_balance_left(self, pluginId, value):
        gCarla.gui.send(["set_balance_left", pluginId, value])
    def set_balance_right(self, pluginId, value):
        gCarla.gui.send(["set_balance_right", pluginId, value])
    def set_panning(self, pluginId, value):
        gCarla.gui.send(["set_panning", pluginId, value])
    def set_ctrl_channel(self, pluginId, channel):
        gCarla.gui.send(["set_ctrl_channel", pluginId, channel])
    # -------------------------------------------------------------------
    def set_parameter_value(self, pluginId, parameterId, value):
        gCarla.gui.send(["set_parameter_value", pluginId, parameterId, value])
    def set_parameter_midi_channel(self, pluginId, parameterId, channel):
        gCarla.gui.send(["set_parameter_midi_channel", pluginId, parameterId, channel])
    def set_parameter_midi_cc(self, pluginId, parameterId, cc):
        gCarla.gui.send(["set_parameter_midi_cc", pluginId, parameterId, cc])
    def set_program(self, pluginId, programId):
        gCarla.gui.send(["set_program", pluginId, programId])
    def set_midi_program(self, pluginId, midiProgramId):
        gCarla.gui.send(["set_midi_program", pluginId, midiProgramId])
    def set_custom_data(self, pluginId, type_, key, value):
        gCarla.gui.send(["set_custom_data", pluginId, type_, key, value])
    def set_chunk_data(self, pluginId, chunkData):
        gCarla.gui.send(["set_chunk_data", pluginId, chunkData])
    # -------------------------------------------------------------------
    def prepare_for_save(self, pluginId):
        gCarla.gui.send(["prepare_for_save", pluginId])
    def reset_parameters(self, pluginId):
        gCarla.gui.send(["reset_parameters", pluginId])
    def randomize_parameters(self, pluginId):
        gCarla.gui.send(["randomize_parameters", pluginId])
    def send_midi_note(self, pluginId, channel, note, velocity):
        gCarla.gui.send(["send_midi_note", pluginId, channel, note, velocity])
    def show_custom_ui(self, pluginId, yesNo):
        gCarla.gui.send(["show_custom_ui", pluginId, yesNo])
    # -------------------------------------------------------------------
    def get_buffer_size(self):
        return self.fBufferSize
    def get_sample_rate(self):
        return self.fSampleRate
    def get_last_error(self):
        return self.fLastError
    def get_host_osc_url_tcp(self):
        return ""
    def get_host_osc_url_udp(self):
        return ""
# ------------------------------------------------------------------------------------------------------------
# Main Window
class CarlaMiniW(HostWindow, ExternalUI):
    def __init__(self):
        HostWindow.__init__(self, None)
        ExternalUI.__init__(self)
        if False:
            from carla_patchbay import CarlaPatchbayW
            self.fContainer = CarlaPatchbayW(self)
        else:
            from carla_rack import CarlaRackW
            self.fContainer = CarlaRackW(self)
        self.setupContainer(False)
        self.setWindowTitle(self.fUiName)
        self.showUiIfTesting()
    # -------------------------------------------------------------------
    # ExternalUI Callbacks
    def d_uiShow(self):
        self.show()
    def d_uiHide(self):
        self.hide()
    def d_uiQuit(self):
        self.close()
        app.quit()
    def d_uiTitleChanged(self, uiTitle):
        self.setWindowTitle(uiTitle)
    # -------------------------------------------------------------------
    # Qt events
    def closeEvent(self, event):
        self.closeExternalUI()
        HostWindow.closeEvent(self, event)
    # -------------------------------------------------------------------
    # Custom idler
    def idleExternalUI(self):
        while True:
            if self.fPipeRecv is None:
                return True
            try:
                msg = self.fPipeRecv.readline().strip()
            except IOError:
                return False
            if not msg:
                return True
            elif msg.startswith("PEAKS_"):
                pluginId = int(msg.replace("PEAKS_", ""))
                in1, in2, out1, out2 = [float(i) for i in self.fPipeRecv.readline().strip().split(":")]
                gCarla.host._set_peaks(pluginId, in1, in2, out1, out2)
            elif msg.startswith("PARAMVAL_"):
                pluginId, paramId = [int(i) for i in msg.replace("PARAMVAL_", "").split(":")]
                paramValue = float(self.fPipeRecv.readline().strip())
                gCarla.host._set_parameterValueS(pluginId, paramId, paramValue)
            elif msg.startswith("ENGINE_CALLBACK_"):
                action   = int(msg.replace("ENGINE_CALLBACK_", ""))
                pluginId = int(self.fPipeRecv.readline().strip())
                value1   = int(self.fPipeRecv.readline().strip())
                value2   = int(self.fPipeRecv.readline().strip())
                value3   = float(self.fPipeRecv.readline().strip())
                valueStr = self.fPipeRecv.readline().strip().replace("\r", "\n")
                if action == ENGINE_CALLBACK_PLUGIN_RENAMED:
                    gCarla.host._set_pluginName(pluginId, valueStr)
                elif action == ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED:
                    gCarla.host._set_parameterValueS(pluginId, value1, value3)
                elif action == ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED:
                    gCarla.host._set_parameterDefault(pluginId, value1, value3)
                elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED:
                    gCarla.host._set_parameterMidiCC(pluginId, value1, value2)
                elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED:
                    gCarla.host._set_parameterMidiChannel(pluginId, value1, value2)
                elif action == ENGINE_CALLBACK_PROGRAM_CHANGED:
                    gCarla.host._set_currentProgram(pluginId, value1)
                elif action == ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED:
                    gCarla.host._set_currentMidiProgram(pluginId, value1)
                engineCallback(None, action, pluginId, value1, value2, value3, valueStr)
            elif msg.startswith("PLUGIN_INFO_"):
                pluginId = int(msg.replace("PLUGIN_INFO_", ""))
                gCarla.host._add(pluginId)
                type_, category, hints, uniqueId, optsAvail, optsEnabled = [int(i) for i in self.fPipeRecv.readline().strip().split(":")]
                filename  = self.fPipeRecv.readline().strip().replace("\r", "\n")
                name      = self.fPipeRecv.readline().strip().replace("\r", "\n")
                iconName  = self.fPipeRecv.readline().strip().replace("\r", "\n")
                realName  = self.fPipeRecv.readline().strip().replace("\r", "\n")
                label     = self.fPipeRecv.readline().strip().replace("\r", "\n")
                maker     = self.fPipeRecv.readline().strip().replace("\r", "\n")
                copyright = self.fPipeRecv.readline().strip().replace("\r", "\n")
                pinfo = {
                    'type': type_,
                    'category': category,
                    'hints': hints,
                    'optionsAvailable': optsAvail,
                    'optionsEnabled': optsEnabled,
                    'filename': filename,
                    'name':  name,
                    'label': label,
                    'maker': maker,
                    'copyright': copyright,
                    'iconName': iconName,
                    'patchbayClientId': 0,
                    'uniqueId': uniqueId
                }
                gCarla.host._set_pluginInfo(pluginId, pinfo)
                gCarla.host._set_pluginRealName(pluginId, realName)
            elif msg.startswith("AUDIO_COUNT_"):
                pluginId, ins, outs = [int(i) for i in msg.replace("AUDIO_COUNT_", "").split(":")]
                gCarla.host._set_audioCountInfo(pluginId, {'ins': ins, 'outs': outs})
            elif msg.startswith("MIDI_COUNT_"):
                pluginId, ins, outs = [int(i) for i in msg.replace("MIDI_COUNT_", "").split(":")]
                gCarla.host._set_midiCountInfo(pluginId, {'ins': ins, 'outs': outs})
            elif msg.startswith("PARAMETER_COUNT_"):
                pluginId, ins, outs, count = [int(i) for i in msg.replace("PARAMETER_COUNT_", "").split(":")]
                gCarla.host._set_parameterCountInfo(pluginId, count, {'ins': ins, 'outs': outs})
            elif msg.startswith("PARAMETER_DATA_"):
                pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_DATA_", "").split(":")]
                paramType, paramHints, midiChannel, midiCC = [int(i) for i in self.fPipeRecv.readline().strip().split(":")]
                paramName = self.fPipeRecv.readline().strip().replace("\r", "\n")
                paramUnit = self.fPipeRecv.readline().strip().replace("\r", "\n")
                paramInfo = {
                    'name': paramName,
                    'symbol': "",
                    'unit': paramUnit,
                    'scalePointCount': 0,
                }
                gCarla.host._set_parameterInfoS(pluginId, paramId, paramInfo)
                paramData = {
                    'type': paramType,
                    'hints': paramHints,
                    'index': paramId,
                    'rindex': -1,
                    'midiCC': midiCC,
                    'midiChannel': midiChannel
                }
                gCarla.host._set_parameterDataS(pluginId, paramId, paramData)
            elif msg.startswith("PARAMETER_RANGES_"):
                pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_RANGES_", "").split(":")]
                def_, min_, max_, step, stepSmall, stepLarge = [float(i) for i in self.fPipeRecv.readline().strip().split(":")]
                paramRanges = {
                    'def': def_,
                    'min': min_,
                    'max': max_,
                    'step': step,
                    'stepSmall': stepSmall,
                    'stepLarge': stepLarge
                }
                gCarla.host._set_parameterRangeS(pluginId, paramId, paramRanges)
            elif msg.startswith("PROGRAM_COUNT_"):
                pluginId, count, current = [int(i) for i in msg.replace("PROGRAM_COUNT_", "").split(":")]
                gCarla.host._set_programCount(pluginId, count)
                gCarla.host._set_currentProgram(pluginId, current)
            elif msg.startswith("PROGRAM_NAME_"):
                pluginId, progId = [int(i) for i in msg.replace("PROGRAM_NAME_", "").split(":")]
                progName = self.fPipeRecv.readline().strip().replace("\r", "\n")
                gCarla.host._set_programNameS(pluginId, progId, progName)
            elif msg.startswith("MIDI_PROGRAM_COUNT_"):
                pluginId, count, current = [int(i) for i in msg.replace("MIDI_PROGRAM_COUNT_", "").split(":")]
                gCarla.host._set_midiProgramCount(pluginId, count)
                gCarla.host._set_currentMidiProgram(pluginId, current)
            elif msg.startswith("MIDI_PROGRAM_DATA_"):
                pluginId, midiProgId = [int(i) for i in msg.replace("MIDI_PROGRAM_DATA_", "").split(":")]
                bank, program = [int(i) for i in self.fPipeRecv.readline().strip().split(":")]
                name = self.fPipeRecv.readline().strip().replace("\r", "\n")
                gCarla.host._set_midiProgramDataS(pluginId, midiProgId, {'bank': bank, 'program': program, 'name': name})
            elif msg == "error":
                error = self.fPipeRecv.readline().strip().replace("\r", "\n")
                engineCallback(None, ENGINE_CALLBACK_ERROR, 0, 0, 0, 0.0, error)
            elif msg == "show":
                self.d_uiShow()
            elif msg == "hide":
                self.d_uiHide()
            elif msg == "quit":
                self.fQuitReceived = True
                self.d_uiQuit()
            elif msg == "uiTitle":
                uiTitle = self.fPipeRecv.readline().strip().replace("\r", "\n")
                self.d_uiTitleChanged(uiTitle)
            else:
                print("unknown message: \"" + msg + "\"")
        return True
# ------------------------------------------------------------------------------------------------------------
# Main
if __name__ == '__main__':
    # -------------------------------------------------------------
    # App initialization
    app = CarlaApplication("Carla2-Plugin")
    # -------------------------------------------------------------
    # Set-up custom signal handling
    setUpSignals()
    # -------------------------------------------------------------
    # Init plugin host data
    gCarla.isControl   = False
    gCarla.isLocal     = True
    gCarla.isPlugin    = True
    gCarla.processMode = ENGINE_PROCESS_MODE_CONTINUOUS_RACK
    # -------------------------------------------------------------
    # Create GUI first
    gCarla.gui = CarlaMiniW()
    # -------------------------------------------------------------
    # Init plugin host now
    gCarla.host = PluginHost(gCarla.gui.d_getSampleRate())
    initHost("Carla-Plugin")
    # simulate an engire started callback
    engineCallback(None, ENGINE_CALLBACK_ENGINE_STARTED, 0, ENGINE_PROCESS_MODE_CONTINUOUS_RACK, ENGINE_TRANSPORT_MODE_PLUGIN, 0.0, "Plugin")
    # -------------------------------------------------------------
    # App-Loop
    ret = app.exec_()
    # disable parenting
    gCarla.host.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID, 0, "0")
    sys.exit(ret)
 |