Signed-off-by: falkTX <falktx@falktx.com>tags/v2.1-rc1
| @@ -88,7 +88,12 @@ | |||
| </row> | |||
| <row> | |||
| <property name="text"> | |||
| <string>paths</string> | |||
| <string>file-paths</string> | |||
| </property> | |||
| </row> | |||
| <row> | |||
| <property name="text"> | |||
| <string>plugin-paths</string> | |||
| </property> | |||
| </row> | |||
| <row> | |||
| @@ -186,7 +191,7 @@ | |||
| </item> | |||
| <item row="4" column="0"> | |||
| <property name="text"> | |||
| <string>Paths</string> | |||
| <string>File Paths</string> | |||
| </property> | |||
| <property name="font"> | |||
| <font> | |||
| @@ -203,6 +208,24 @@ | |||
| </property> | |||
| </item> | |||
| <item row="5" column="0"> | |||
| <property name="text"> | |||
| <string>Plugin Paths</string> | |||
| </property> | |||
| <property name="font"> | |||
| <font> | |||
| <weight>75</weight> | |||
| <bold>true</bold> | |||
| </font> | |||
| </property> | |||
| <property name="icon"> | |||
| <iconset resource="../resources.qrc"> | |||
| <normaloff>:/scalable/folder.svgz</normaloff>:/scalable/folder.svgz</iconset> | |||
| </property> | |||
| <property name="flags"> | |||
| <set>ItemIsSelectable|ItemIsEnabled</set> | |||
| </property> | |||
| </item> | |||
| <item row="6" column="0"> | |||
| <property name="text"> | |||
| <string>Wine</string> | |||
| </property> | |||
| @@ -220,7 +243,7 @@ | |||
| <set>ItemIsSelectable|ItemIsEnabled</set> | |||
| </property> | |||
| </item> | |||
| <item row="6" column="0"> | |||
| <item row="7" column="0"> | |||
| <property name="text"> | |||
| <string>Experimental</string> | |||
| </property> | |||
| @@ -1647,7 +1670,253 @@ | |||
| <zorder>group_osc_udp_port</zorder> | |||
| <zorder>group_osc_core</zorder> | |||
| </widget> | |||
| <widget class="QWidget" name="page_paths"> | |||
| <widget class="QWidget" name="page_filepaths"> | |||
| <layout class="QVBoxLayout" name="verticalLayout_30"> | |||
| <property name="margin"> | |||
| <number>2</number> | |||
| </property> | |||
| <item> | |||
| <layout class="QHBoxLayout" name="horizontalLayout_8"> | |||
| <item> | |||
| <widget class="QLabel" name="label_24"> | |||
| <property name="text"> | |||
| <string><b>File Paths</b></string> | |||
| </property> | |||
| <property name="alignment"> | |||
| <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> | |||
| </property> | |||
| </widget> | |||
| </item> | |||
| <item> | |||
| <spacer name="horizontalSpacer_10"> | |||
| <property name="orientation"> | |||
| <enum>Qt::Horizontal</enum> | |||
| </property> | |||
| <property name="sizeHint" stdset="0"> | |||
| <size> | |||
| <width>40</width> | |||
| <height>20</height> | |||
| </size> | |||
| </property> | |||
| </spacer> | |||
| </item> | |||
| <item> | |||
| <widget class="QLabel" name="label_31"> | |||
| <property name="maximumSize"> | |||
| <size> | |||
| <width>48</width> | |||
| <height>48</height> | |||
| </size> | |||
| </property> | |||
| <property name="text"> | |||
| <string notr="true"/> | |||
| </property> | |||
| <property name="pixmap"> | |||
| <pixmap resource="../resources.qrc">:/scalable/folder.svgz</pixmap> | |||
| </property> | |||
| <property name="scaledContents"> | |||
| <bool>true</bool> | |||
| </property> | |||
| <property name="alignment"> | |||
| <set>Qt::AlignHCenter|Qt::AlignTop</set> | |||
| </property> | |||
| <property name="wordWrap"> | |||
| <bool>true</bool> | |||
| </property> | |||
| </widget> | |||
| </item> | |||
| </layout> | |||
| </item> | |||
| <item> | |||
| <layout class="QHBoxLayout" name="horizontalLayout_19"> | |||
| <item> | |||
| <widget class="QComboBox" name="cb_filepaths"> | |||
| <property name="minimumSize"> | |||
| <size> | |||
| <width>120</width> | |||
| <height>0</height> | |||
| </size> | |||
| </property> | |||
| <item> | |||
| <property name="text"> | |||
| <string>Audio</string> | |||
| </property> | |||
| </item> | |||
| <item> | |||
| <property name="text"> | |||
| <string>MIDI</string> | |||
| </property> | |||
| </item> | |||
| </widget> | |||
| </item> | |||
| <item> | |||
| <widget class="QStackedWidget" name="tw_filepaths_info"> | |||
| <property name="sizePolicy"> | |||
| <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> | |||
| <horstretch>0</horstretch> | |||
| <verstretch>0</verstretch> | |||
| </sizepolicy> | |||
| </property> | |||
| <property name="currentIndex"> | |||
| <number>0</number> | |||
| </property> | |||
| <widget class="QWidget" name="tw_filepaths_info_audio"> | |||
| <layout class="QHBoxLayout" name="horizontalLayout_20"> | |||
| <property name="spacing"> | |||
| <number>0</number> | |||
| </property> | |||
| <property name="margin"> | |||
| <number>0</number> | |||
| </property> | |||
| <item> | |||
| <widget class="QLabel" name="label_12"> | |||
| <property name="text"> | |||
| <string>Used for the "audiofile" plugin</string> | |||
| </property> | |||
| </widget> | |||
| </item> | |||
| </layout> | |||
| </widget> | |||
| <widget class="QWidget" name="tw_filepaths_info_midi"> | |||
| <layout class="QHBoxLayout" name="horizontalLayout_26"> | |||
| <property name="spacing"> | |||
| <number>0</number> | |||
| </property> | |||
| <property name="margin"> | |||
| <number>0</number> | |||
| </property> | |||
| <item> | |||
| <widget class="QLabel" name="label_13"> | |||
| <property name="text"> | |||
| <string>Used for the "midifile" plugin</string> | |||
| </property> | |||
| </widget> | |||
| </item> | |||
| </layout> | |||
| </widget> | |||
| </widget> | |||
| </item> | |||
| <item> | |||
| <spacer name="horizontalSpacer_23"> | |||
| <property name="orientation"> | |||
| <enum>Qt::Horizontal</enum> | |||
| </property> | |||
| <property name="sizeHint" stdset="0"> | |||
| <size> | |||
| <width>20</width> | |||
| <height>20</height> | |||
| </size> | |||
| </property> | |||
| </spacer> | |||
| </item> | |||
| </layout> | |||
| </item> | |||
| <item> | |||
| <layout class="QHBoxLayout" name="horizontalLayout_16"> | |||
| <item> | |||
| <widget class="QStackedWidget" name="tw_filepaths"> | |||
| <property name="currentIndex"> | |||
| <number>0</number> | |||
| </property> | |||
| <widget class="QWidget" name="tw_filepaths_audio"> | |||
| <layout class="QVBoxLayout" name="verticalLayout_18"> | |||
| <property name="spacing"> | |||
| <number>0</number> | |||
| </property> | |||
| <property name="margin"> | |||
| <number>0</number> | |||
| </property> | |||
| <item> | |||
| <widget class="QListWidget" name="lw_files_audio"/> | |||
| </item> | |||
| </layout> | |||
| </widget> | |||
| <widget class="QWidget" name="tw_filepaths_midi"> | |||
| <layout class="QVBoxLayout" name="verticalLayout_23"> | |||
| <property name="spacing"> | |||
| <number>0</number> | |||
| </property> | |||
| <property name="margin"> | |||
| <number>0</number> | |||
| </property> | |||
| <item> | |||
| <widget class="QListWidget" name="lw_files_midi"/> | |||
| </item> | |||
| </layout> | |||
| </widget> | |||
| </widget> | |||
| </item> | |||
| <item> | |||
| <layout class="QVBoxLayout" name="verticalLayout_29"> | |||
| <item> | |||
| <widget class="QPushButton" name="b_filepaths_add"> | |||
| <property name="text"> | |||
| <string>Add...</string> | |||
| </property> | |||
| <property name="icon"> | |||
| <iconset resource="../resources.qrc"> | |||
| <normaloff>:/16x16/list-add.svgz</normaloff>:/16x16/list-add.svgz</iconset> | |||
| </property> | |||
| </widget> | |||
| </item> | |||
| <item> | |||
| <widget class="QPushButton" name="b_filepaths_remove"> | |||
| <property name="text"> | |||
| <string>Remove</string> | |||
| </property> | |||
| <property name="icon"> | |||
| <iconset resource="../resources.qrc"> | |||
| <normaloff>:/16x16/list-remove.svgz</normaloff>:/16x16/list-remove.svgz</iconset> | |||
| </property> | |||
| </widget> | |||
| </item> | |||
| <item> | |||
| <spacer name="verticalSpacer_6"> | |||
| <property name="orientation"> | |||
| <enum>Qt::Vertical</enum> | |||
| </property> | |||
| <property name="sizeType"> | |||
| <enum>QSizePolicy::Fixed</enum> | |||
| </property> | |||
| <property name="sizeHint" stdset="0"> | |||
| <size> | |||
| <width>20</width> | |||
| <height>20</height> | |||
| </size> | |||
| </property> | |||
| </spacer> | |||
| </item> | |||
| <item> | |||
| <widget class="QPushButton" name="b_filepaths_change"> | |||
| <property name="text"> | |||
| <string>Change...</string> | |||
| </property> | |||
| <property name="icon"> | |||
| <iconset resource="../resources.qrc"> | |||
| <normaloff>:/16x16/edit-rename.svgz</normaloff>:/16x16/edit-rename.svgz</iconset> | |||
| </property> | |||
| </widget> | |||
| </item> | |||
| <item> | |||
| <spacer name="verticalSpacer_8"> | |||
| <property name="orientation"> | |||
| <enum>Qt::Vertical</enum> | |||
| </property> | |||
| <property name="sizeHint" stdset="0"> | |||
| <size> | |||
| <width>20</width> | |||
| <height>40</height> | |||
| </size> | |||
| </property> | |||
| </spacer> | |||
| </item> | |||
| </layout> | |||
| </item> | |||
| </layout> | |||
| </item> | |||
| </layout> | |||
| </widget> | |||
| <widget class="QWidget" name="page_pluginpaths"> | |||
| <layout class="QVBoxLayout" name="verticalLayout_19"> | |||
| <property name="margin"> | |||
| <number>2</number> | |||
| @@ -1657,7 +1926,7 @@ | |||
| <item> | |||
| <widget class="QLabel" name="label_18"> | |||
| <property name="text"> | |||
| <string><b>Paths</b></string> | |||
| <string><b>Plugin Paths</b></string> | |||
| </property> | |||
| <property name="alignment"> | |||
| <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> | |||
| @@ -2749,5 +3018,37 @@ This mode is not available for VST plugins.</string> | |||
| </hint> | |||
| </hints> | |||
| </connection> | |||
| <connection> | |||
| <sender>cb_filepaths</sender> | |||
| <signal>currentIndexChanged(int)</signal> | |||
| <receiver>tw_filepaths</receiver> | |||
| <slot>setCurrentIndex(int)</slot> | |||
| <hints> | |||
| <hint type="sourcelabel"> | |||
| <x>258</x> | |||
| <y>79</y> | |||
| </hint> | |||
| <hint type="destinationlabel"> | |||
| <x>350</x> | |||
| <y>312</y> | |||
| </hint> | |||
| </hints> | |||
| </connection> | |||
| <connection> | |||
| <sender>cb_filepaths</sender> | |||
| <signal>currentIndexChanged(int)</signal> | |||
| <receiver>tw_filepaths_info</receiver> | |||
| <slot>setCurrentIndex(int)</slot> | |||
| <hints> | |||
| <hint type="sourcelabel"> | |||
| <x>258</x> | |||
| <y>79</y> | |||
| </hint> | |||
| <hint type="destinationlabel"> | |||
| <x>409</x> | |||
| <y>79</y> | |||
| </hint> | |||
| </hints> | |||
| </connection> | |||
| </connections> | |||
| </ui> | |||
| @@ -488,6 +488,30 @@ typedef enum { | |||
| } BinaryType; | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * File Type */ | |||
| /*! | |||
| * File type. | |||
| */ | |||
| typedef enum { | |||
| /*! | |||
| * Null file type. | |||
| */ | |||
| FILE_NONE = 0, | |||
| /*! | |||
| * Audio file. | |||
| */ | |||
| FILE_AUDIO = 1, | |||
| /*! | |||
| * MIDI file. | |||
| */ | |||
| FILE_MIDI = 2 | |||
| } FileType; | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * Plugin Type */ | |||
| @@ -1233,79 +1257,85 @@ typedef enum { | |||
| */ | |||
| ENGINE_OPTION_OSC_PORT_UDP = 16, | |||
| /*! | |||
| * Set path used for a specific file type. | |||
| * Uses value as the file format, valueStr as actual path. | |||
| */ | |||
| ENGINE_OPTION_FILE_PATH = 17, | |||
| /*! | |||
| * Set path used for a specific plugin type. | |||
| * Uses value as the plugin format, valueStr as actual path. | |||
| * @see PluginType | |||
| */ | |||
| ENGINE_OPTION_PLUGIN_PATH = 17, | |||
| ENGINE_OPTION_PLUGIN_PATH = 18, | |||
| /*! | |||
| * Set path to the binary files. | |||
| * Default unset. | |||
| * @note Must be set for plugin and UI bridges to work | |||
| */ | |||
| ENGINE_OPTION_PATH_BINARIES = 18, | |||
| ENGINE_OPTION_PATH_BINARIES = 19, | |||
| /*! | |||
| * Set path to the resource files. | |||
| * Default unset. | |||
| * @note Must be set for some internal plugins to work | |||
| */ | |||
| ENGINE_OPTION_PATH_RESOURCES = 19, | |||
| ENGINE_OPTION_PATH_RESOURCES = 20, | |||
| /*! | |||
| * Prevent bad plugin and UI behaviour. | |||
| * @note: Linux only | |||
| */ | |||
| ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR = 20, | |||
| ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR = 21, | |||
| /*! | |||
| * Set UI scaling used in frontend, so backend can do the same for plugin UIs. | |||
| */ | |||
| ENGINE_OPTION_FRONTEND_UI_SCALE = 21, | |||
| ENGINE_OPTION_FRONTEND_UI_SCALE = 22, | |||
| /*! | |||
| * Set frontend winId, used to define as parent window for plugin UIs. | |||
| */ | |||
| ENGINE_OPTION_FRONTEND_WIN_ID = 22, | |||
| ENGINE_OPTION_FRONTEND_WIN_ID = 23, | |||
| #if !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) && !defined(CARLA_OS_WIN) | |||
| /*! | |||
| * Set path to wine executable. | |||
| */ | |||
| ENGINE_OPTION_WINE_EXECUTABLE = 23, | |||
| ENGINE_OPTION_WINE_EXECUTABLE = 24, | |||
| /*! | |||
| * Enable automatic wineprefix detection. | |||
| */ | |||
| ENGINE_OPTION_WINE_AUTO_PREFIX = 24, | |||
| ENGINE_OPTION_WINE_AUTO_PREFIX = 25, | |||
| /*! | |||
| * Fallback wineprefix to use if automatic detection fails or is disabled, and WINEPREFIX is not set. | |||
| */ | |||
| ENGINE_OPTION_WINE_FALLBACK_PREFIX = 25, | |||
| ENGINE_OPTION_WINE_FALLBACK_PREFIX = 26, | |||
| /*! | |||
| * Enable realtime priority for Wine application and server threads. | |||
| */ | |||
| ENGINE_OPTION_WINE_RT_PRIO_ENABLED = 26, | |||
| ENGINE_OPTION_WINE_RT_PRIO_ENABLED = 27, | |||
| /*! | |||
| * Base realtime priority for Wine threads. | |||
| */ | |||
| ENGINE_OPTION_WINE_BASE_RT_PRIO = 27, | |||
| ENGINE_OPTION_WINE_BASE_RT_PRIO = 28, | |||
| /*! | |||
| * Wine server realtime priority. | |||
| */ | |||
| ENGINE_OPTION_WINE_SERVER_RT_PRIO = 28, | |||
| ENGINE_OPTION_WINE_SERVER_RT_PRIO = 29, | |||
| #endif | |||
| /*! | |||
| * Capture console output into debug callbacks. | |||
| */ | |||
| ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT = 29 | |||
| ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT = 30 | |||
| } EngineOption; | |||
| @@ -249,6 +249,9 @@ struct CARLA_API EngineOptions { | |||
| int oscPortUDP; | |||
| #endif | |||
| const char* pathAudio; | |||
| const char* pathMIDI; | |||
| const char* pathLADSPA; | |||
| const char* pathDSSI; | |||
| const char* pathLV2; | |||
| @@ -208,6 +208,12 @@ static void carla_engine_init_common(CarlaEngine* const engine) | |||
| if (const char* const uiBridgesTimeout = std::getenv("ENGINE_OPTION_UI_BRIDGES_TIMEOUT")) | |||
| engine->setOption(CB::ENGINE_OPTION_UI_BRIDGES_TIMEOUT, std::atoi(uiBridgesTimeout), nullptr); | |||
| if (const char* const pathAudio = std::getenv("ENGINE_OPTION_FILE_PATH_AUDIO")) | |||
| engine->setOption(CB::ENGINE_OPTION_FILE_PATH, CB::FILE_AUDIO, pathAudio); | |||
| if (const char* const pathMIDI = std::getenv("ENGINE_OPTION_FILE_PATH_MIDI")) | |||
| engine->setOption(CB::ENGINE_OPTION_FILE_PATH, CB::FILE_MIDI, pathMIDI); | |||
| if (const char* const pathLADSPA = std::getenv("ENGINE_OPTION_PLUGIN_PATH_LADSPA")) | |||
| engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH, CB::PLUGIN_LADSPA, pathLADSPA); | |||
| @@ -265,6 +271,12 @@ static void carla_engine_init_common(CarlaEngine* const engine) | |||
| engine->setOption(CB::ENGINE_OPTION_OSC_PORT_TCP, gStandalone.engineOptions.oscPortTCP, nullptr); | |||
| engine->setOption(CB::ENGINE_OPTION_OSC_PORT_UDP, gStandalone.engineOptions.oscPortUDP, nullptr); | |||
| if (gStandalone.engineOptions.pathAudio != nullptr) | |||
| engine->setOption(CB::ENGINE_OPTION_FILE_PATH, CB::FILE_AUDIO, gStandalone.engineOptions.pathAudio); | |||
| if (gStandalone.engineOptions.pathMIDI != nullptr) | |||
| engine->setOption(CB::ENGINE_OPTION_FILE_PATH, CB::FILE_MIDI, gStandalone.engineOptions.pathMIDI); | |||
| if (gStandalone.engineOptions.pathLADSPA != nullptr) | |||
| engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH, CB::PLUGIN_LADSPA, gStandalone.engineOptions.pathLADSPA); | |||
| @@ -733,6 +745,26 @@ void carla_set_engine_option(EngineOption option, int value, const char* valueSt | |||
| gStandalone.engineOptions.oscPortUDP = value; | |||
| break; | |||
| case CB::ENGINE_OPTION_FILE_PATH: | |||
| CARLA_SAFE_ASSERT_RETURN(value > CB::FILE_NONE,); | |||
| CARLA_SAFE_ASSERT_RETURN(value <= CB::FILE_MIDI,); | |||
| CARLA_SAFE_ASSERT_RETURN(valueStr != nullptr,); | |||
| switch (value) | |||
| { | |||
| case CB::FILE_AUDIO: | |||
| if (gStandalone.engineOptions.pathAudio != nullptr) | |||
| delete[] gStandalone.engineOptions.pathAudio; | |||
| gStandalone.engineOptions.pathAudio = carla_strdup_safe(valueStr); | |||
| break; | |||
| case CB::FILE_MIDI: | |||
| if (gStandalone.engineOptions.pathMIDI != nullptr) | |||
| delete[] gStandalone.engineOptions.pathMIDI; | |||
| gStandalone.engineOptions.pathMIDI = carla_strdup_safe(valueStr); | |||
| break; | |||
| } | |||
| break; | |||
| case CB::ENGINE_OPTION_PLUGIN_PATH: | |||
| CARLA_SAFE_ASSERT_RETURN(value > CB::PLUGIN_NONE,); | |||
| CARLA_SAFE_ASSERT_RETURN(value <= CB::PLUGIN_SFZ,); | |||
| @@ -1740,6 +1740,34 @@ void CarlaEngine::setOption(const EngineOption option, const int value, const ch | |||
| #endif | |||
| break; | |||
| case ENGINE_OPTION_FILE_PATH: | |||
| CARLA_SAFE_ASSERT_RETURN(value > FILE_NONE,); | |||
| CARLA_SAFE_ASSERT_RETURN(value <= FILE_MIDI,); | |||
| switch (value) | |||
| { | |||
| case FILE_AUDIO: | |||
| if (pData->options.pathAudio != nullptr) | |||
| delete[] pData->options.pathAudio; | |||
| if (valueStr != nullptr) | |||
| pData->options.pathAudio = carla_strdup_safe(valueStr); | |||
| else | |||
| pData->options.pathAudio = nullptr; | |||
| break; | |||
| case FILE_MIDI: | |||
| if (pData->options.pathMIDI != nullptr) | |||
| delete[] pData->options.pathMIDI; | |||
| if (valueStr != nullptr) | |||
| pData->options.pathMIDI = carla_strdup_safe(valueStr); | |||
| else | |||
| pData->options.pathMIDI = nullptr; | |||
| break; | |||
| default: | |||
| return carla_stderr("CarlaEngine::setOption(%i:%s, %i, \"%s\") - Invalid file type", | |||
| option, EngineOption2Str(option), value, valueStr); | |||
| break; | |||
| } | |||
| break; | |||
| case ENGINE_OPTION_PLUGIN_PATH: | |||
| CARLA_SAFE_ASSERT_RETURN(value > PLUGIN_NONE,); | |||
| CARLA_SAFE_ASSERT_RETURN(value <= PLUGIN_SFZ,); | |||
| @@ -1803,7 +1831,8 @@ void CarlaEngine::setOption(const EngineOption option, const int value, const ch | |||
| pData->options.pathSFZ = nullptr; | |||
| break; | |||
| default: | |||
| return carla_stderr("CarlaEngine::setOption(%i:%s, %i, \"%s\") - Invalid plugin type", option, EngineOption2Str(option), value, valueStr); | |||
| return carla_stderr("CarlaEngine::setOption(%i:%s, %i, \"%s\") - Invalid plugin type", | |||
| option, EngineOption2Str(option), value, valueStr); | |||
| break; | |||
| } | |||
| break; | |||
| @@ -208,6 +208,8 @@ EngineOptions::EngineOptions() noexcept | |||
| oscPortTCP(22752), | |||
| oscPortUDP(22752), | |||
| #endif | |||
| pathAudio(nullptr), | |||
| pathMIDI(nullptr), | |||
| pathLADSPA(nullptr), | |||
| pathDSSI(nullptr), | |||
| pathLV2(nullptr), | |||
| @@ -232,61 +234,61 @@ EngineOptions::~EngineOptions() noexcept | |||
| delete[] audioDriver; | |||
| audioDriver = nullptr; | |||
| } | |||
| if (audioDevice != nullptr) | |||
| { | |||
| delete[] audioDevice; | |||
| audioDevice = nullptr; | |||
| } | |||
| if (pathAudio != nullptr) | |||
| { | |||
| delete[] pathAudio; | |||
| pathAudio = nullptr; | |||
| } | |||
| if (pathMIDI != nullptr) | |||
| { | |||
| delete[] pathMIDI; | |||
| pathMIDI = nullptr; | |||
| } | |||
| if (pathLADSPA != nullptr) | |||
| { | |||
| delete[] pathLADSPA; | |||
| pathLADSPA = nullptr; | |||
| } | |||
| if (pathDSSI != nullptr) | |||
| { | |||
| delete[] pathDSSI; | |||
| pathDSSI = nullptr; | |||
| } | |||
| if (pathLV2 != nullptr) | |||
| { | |||
| delete[] pathLV2; | |||
| pathLV2 = nullptr; | |||
| } | |||
| if (pathVST2 != nullptr) | |||
| { | |||
| delete[] pathVST2; | |||
| pathVST2 = nullptr; | |||
| } | |||
| if (pathVST3 != nullptr) | |||
| { | |||
| delete[] pathVST3; | |||
| pathVST3 = nullptr; | |||
| } | |||
| if (pathSF2 != nullptr) | |||
| { | |||
| delete[] pathSF2; | |||
| pathSF2 = nullptr; | |||
| } | |||
| if (pathSFZ != nullptr) | |||
| { | |||
| delete[] pathSFZ; | |||
| pathSFZ = nullptr; | |||
| } | |||
| if (binaryDir != nullptr) | |||
| { | |||
| delete[] binaryDir; | |||
| binaryDir = nullptr; | |||
| } | |||
| if (resourceDir != nullptr) | |||
| { | |||
| delete[] resourceDir; | |||
| @@ -1636,6 +1636,9 @@ public: | |||
| CarlaEngineNative* const engine = handlePtr; | |||
| return (intptr_t)(CarlaEngine*)engine; | |||
| } | |||
| case NATIVE_PLUGIN_OPCODE_IDLE: | |||
| //handlePtr->idle(); | |||
| return 0; | |||
| } | |||
| return 0; | |||
| @@ -252,6 +252,7 @@ public: | |||
| fIsOffline(false), | |||
| fIsUiAvailable(false), | |||
| fIsUiVisible(false), | |||
| fNeedsIdle(false), | |||
| fInlineDisplayNeedsRedraw(false), | |||
| fInlineDisplayLastRedrawTime(0), | |||
| fAudioAndCvInBuffers(nullptr), | |||
| @@ -921,6 +922,12 @@ public: | |||
| void idle() override | |||
| { | |||
| if (fNeedsIdle) | |||
| { | |||
| fNeedsIdle = false; | |||
| fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_IDLE, 0, 0, nullptr, 0.0f); | |||
| } | |||
| if (fInlineDisplayNeedsRedraw) | |||
| { | |||
| // TESTING | |||
| @@ -2555,7 +2562,8 @@ protected: | |||
| return pData->engine->runFileCallback(FILE_CALLBACK_SAVE, isDir, title, filter); | |||
| } | |||
| intptr_t handleDispatcher(const NativeHostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt) | |||
| intptr_t handleDispatcher(const NativeHostDispatcherOpcode opcode, | |||
| const int32_t index, const intptr_t value, void* const ptr, const float opt) | |||
| { | |||
| carla_debug("CarlaPluginNative::handleDispatcher(%i, %i, " P_INTPTR ", %p, %f)", | |||
| opcode, index, value, ptr, static_cast<double>(opt)); | |||
| @@ -2603,12 +2611,26 @@ protected: | |||
| CARLA_SAFE_ASSERT_RETURN(index >= 0, 0); | |||
| pData->engine->touchPluginParameter(pData->id, static_cast<uint32_t>(index), value != 0); | |||
| break; | |||
| case NATIVE_HOST_OPCODE_REQUEST_IDLE: | |||
| fNeedsIdle = true; | |||
| break; | |||
| case NATIVE_HOST_OPCODE_GET_FILE_PATH: | |||
| CARLA_SAFE_ASSERT_RETURN(ptr != nullptr, 0); | |||
| { | |||
| const EngineOptions& opts(pData->engine->getOptions()); | |||
| const char* const filetype = (const char*)ptr; | |||
| if (std::strcmp(filetype, "audio") == 0) | |||
| return static_cast<intptr_t>((uintptr_t)opts.pathAudio); | |||
| if (std::strcmp(filetype, "midi") == 0) | |||
| return static_cast<intptr_t>((uintptr_t)opts.pathMIDI); | |||
| } | |||
| break; | |||
| } | |||
| return ret; | |||
| // unused for now | |||
| (void)ptr; | |||
| (void)opt; | |||
| } | |||
| @@ -2792,6 +2814,8 @@ private: | |||
| bool fIsOffline; | |||
| bool fIsUiAvailable; | |||
| bool fIsUiVisible; | |||
| volatile bool fNeedsIdle; | |||
| bool fInlineDisplayNeedsRedraw; | |||
| int64_t fInlineDisplayLastRedrawTime; | |||
| @@ -387,6 +387,19 @@ BINARY_WIN64 = 4 | |||
| # Other binary type. | |||
| BINARY_OTHER = 5 | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # File Type | |||
| # File type. | |||
| # Null file type. | |||
| FILE_NONE = 0 | |||
| # Audio file. | |||
| FILE_AUDIO = 1 | |||
| # MIDI file. | |||
| FILE_MIDI = 2 | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Plugin Type | |||
| # Plugin type. | |||
| @@ -885,51 +898,55 @@ ENGINE_OPTION_OSC_PORT_TCP = 15 | |||
| # @note Valid ports begin at 1024 and end at 32767 (inclusive) | |||
| ENGINE_OPTION_OSC_PORT_UDP = 16 | |||
| # Set path used for a specific file type. | |||
| # Uses value as the file format, valueStr as actual path. | |||
| ENGINE_OPTION_FILE_PATH = 17 | |||
| # Set path used for a specific plugin type. | |||
| # Uses value as the plugin format, valueStr as actual path. | |||
| # @see PluginType | |||
| ENGINE_OPTION_PLUGIN_PATH = 17 | |||
| ENGINE_OPTION_PLUGIN_PATH = 18 | |||
| # Set path to the binary files. | |||
| # Default unset. | |||
| # @note Must be set for plugin and UI bridges to work | |||
| ENGINE_OPTION_PATH_BINARIES = 18 | |||
| ENGINE_OPTION_PATH_BINARIES = 19 | |||
| # Set path to the resource files. | |||
| # Default unset. | |||
| # @note Must be set for some internal plugins to work | |||
| ENGINE_OPTION_PATH_RESOURCES = 19 | |||
| ENGINE_OPTION_PATH_RESOURCES = 20 | |||
| # Prevent bad plugin and UI behaviour. | |||
| # @note: Linux only | |||
| ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR = 20 | |||
| ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR = 21 | |||
| # Set UI scaling used in frontend, so backend can do the same for plugin UIs. | |||
| ENGINE_OPTION_FRONTEND_UI_SCALE = 21 | |||
| ENGINE_OPTION_FRONTEND_UI_SCALE = 22 | |||
| # Set frontend winId, used to define as parent window for plugin UIs. | |||
| ENGINE_OPTION_FRONTEND_WIN_ID = 22 | |||
| ENGINE_OPTION_FRONTEND_WIN_ID = 23 | |||
| # Set path to wine executable. | |||
| ENGINE_OPTION_WINE_EXECUTABLE = 23 | |||
| ENGINE_OPTION_WINE_EXECUTABLE = 24 | |||
| # Enable automatic wineprefix detection. | |||
| ENGINE_OPTION_WINE_AUTO_PREFIX = 24 | |||
| ENGINE_OPTION_WINE_AUTO_PREFIX = 25 | |||
| # Fallback wineprefix to use if automatic detection fails or is disabled, and WINEPREFIX is not set. | |||
| ENGINE_OPTION_WINE_FALLBACK_PREFIX = 25 | |||
| ENGINE_OPTION_WINE_FALLBACK_PREFIX = 26 | |||
| # Enable realtime priority for Wine application and server threads. | |||
| ENGINE_OPTION_WINE_RT_PRIO_ENABLED = 26 | |||
| ENGINE_OPTION_WINE_RT_PRIO_ENABLED = 27 | |||
| # Base realtime priority for Wine threads. | |||
| ENGINE_OPTION_WINE_BASE_RT_PRIO = 27 | |||
| ENGINE_OPTION_WINE_BASE_RT_PRIO = 28 | |||
| # Wine server realtime priority. | |||
| ENGINE_OPTION_WINE_SERVER_RT_PRIO = 28 | |||
| ENGINE_OPTION_WINE_SERVER_RT_PRIO = 29 | |||
| # Capture console output into debug callbacks | |||
| ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT = 29 | |||
| ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT = 30 | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Engine Process Mode | |||
| @@ -3101,6 +3101,15 @@ def setEngineSettings(host): | |||
| setHostSettings(host) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # file paths | |||
| FILE_PATH_AUDIO = toList(settings.value(CARLA_KEY_PATHS_AUDIO, CARLA_DEFAULT_FILE_PATH_AUDIO)) | |||
| FILE_PATH_MIDI = toList(settings.value(CARLA_KEY_PATHS_MIDI, CARLA_DEFAULT_FILE_PATH_MIDI)) | |||
| host.set_engine_option(ENGINE_OPTION_FILE_PATH, FILE_AUDIO, splitter.join(FILE_PATH_AUDIO)) | |||
| host.set_engine_option(ENGINE_OPTION_FILE_PATH, FILE_MIDI, splitter.join(FILE_PATH_MIDI)) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # plugin paths | |||
| @@ -324,19 +324,24 @@ class CarlaSettingsW(QDialog): | |||
| TAB_INDEX_CANVAS = 1 | |||
| TAB_INDEX_ENGINE = 2 | |||
| TAB_INDEX_OSC = 3 | |||
| TAB_INDEX_PATHS = 4 | |||
| TAB_INDEX_WINE = 5 | |||
| TAB_INDEX_EXPERIMENTAL = 6 | |||
| TAB_INDEX_NONE = 7 | |||
| # Path indexes | |||
| PATH_INDEX_LADSPA = 0 | |||
| PATH_INDEX_DSSI = 1 | |||
| PATH_INDEX_LV2 = 2 | |||
| PATH_INDEX_VST2 = 3 | |||
| PATH_INDEX_VST3 = 4 | |||
| PATH_INDEX_SF2 = 5 | |||
| PATH_INDEX_SFZ = 6 | |||
| TAB_INDEX_FILEPATHS = 4 | |||
| TAB_INDEX_PLUGINPATHS = 5 | |||
| TAB_INDEX_WINE = 6 | |||
| TAB_INDEX_EXPERIMENTAL = 7 | |||
| TAB_INDEX_NONE = 8 | |||
| # File Path indexes | |||
| FILEPATH_INDEX_AUDIO = 0 | |||
| FILEPATH_INDEX_MIDI = 1 | |||
| # Plugin Path indexes | |||
| PLUGINPATH_INDEX_LADSPA = 0 | |||
| PLUGINPATH_INDEX_DSSI = 1 | |||
| PLUGINPATH_INDEX_LV2 = 2 | |||
| PLUGINPATH_INDEX_VST2 = 3 | |||
| PLUGINPATH_INDEX_VST3 = 4 | |||
| PLUGINPATH_INDEX_SF2 = 5 | |||
| PLUGINPATH_INDEX_SFZ = 6 | |||
| # Single and Multiple client mode is only for JACK, | |||
| # but we still want to match QComboBox index to backend defines, | |||
| @@ -377,7 +382,8 @@ class CarlaSettingsW(QDialog): | |||
| if host.isControl: | |||
| self.ui.lw_page.hideRow(self.TAB_INDEX_ENGINE) | |||
| self.ui.lw_page.hideRow(self.TAB_INDEX_PATHS) | |||
| self.ui.lw_page.hideRow(self.TAB_INDEX_FILEPATHS) | |||
| self.ui.lw_page.hideRow(self.TAB_INDEX_PLUGINPATHS) | |||
| self.ui.ch_exp_export_lv2.hide() | |||
| self.ui.group_experimental_engine.hide() | |||
| @@ -450,6 +456,13 @@ class CarlaSettingsW(QDialog): | |||
| self.ui.lw_sf2.currentRowChanged.connect(self.slot_pluginPathRowChanged) | |||
| self.ui.lw_sfz.currentRowChanged.connect(self.slot_pluginPathRowChanged) | |||
| self.ui.b_filepaths_add.clicked.connect(self.slot_addFilePath) | |||
| self.ui.b_filepaths_remove.clicked.connect(self.slot_removeFilePath) | |||
| self.ui.b_filepaths_change.clicked.connect(self.slot_changeFilePath) | |||
| self.ui.cb_filepaths.currentIndexChanged.connect(self.slot_filePathTabChanged) | |||
| self.ui.lw_files_audio.currentRowChanged.connect(self.slot_filePathRowChanged) | |||
| self.ui.lw_files_midi.currentRowChanged.connect(self.slot_filePathRowChanged) | |||
| self.ui.ch_main_experimental.toggled.connect(self.slot_enableExperimental) | |||
| self.ui.ch_exp_wine_bridges.toggled.connect(self.slot_enableWineBridges) | |||
| self.ui.cb_exp_plugin_bridges.toggled.connect(self.slot_pluginBridgesToggled) | |||
| @@ -468,8 +481,14 @@ class CarlaSettingsW(QDialog): | |||
| self.ui.lw_sf2.setCurrentRow(0) | |||
| self.ui.lw_sfz.setCurrentRow(0) | |||
| self.ui.lw_files_audio.setCurrentRow(0) | |||
| self.ui.lw_files_midi.setCurrentRow(0) | |||
| self.ui.lw_page.setCurrentCell(0, 0) | |||
| self.slot_filePathTabChanged(0) | |||
| self.slot_pluginPathTabChanged(0) | |||
| self.adjustSize() | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| @@ -602,7 +621,24 @@ class CarlaSettingsW(QDialog): | |||
| self.ui.rb_osc_udp_port_specific.setChecked(True) | |||
| # ---------------------------------------------------------------------------------------------------- | |||
| # Paths | |||
| # File Paths | |||
| audioPaths = toList(settings.value(CARLA_KEY_PATHS_AUDIO, CARLA_DEFAULT_FILE_PATH_AUDIO)) | |||
| midiPaths = toList(settings.value(CARLA_KEY_PATHS_MIDI, CARLA_DEFAULT_FILE_PATH_MIDI)) | |||
| audioPaths.sort() | |||
| midiPaths.sort() | |||
| for audioPath in audioPaths: | |||
| if not audioPath: continue | |||
| self.ui.lw_files_audio.addItem(audioPath) | |||
| for midiPath in midiPaths: | |||
| if not midiPath: continue | |||
| self.ui.lw_files_midi.addItem(midiPath) | |||
| # ---------------------------------------------------------------------------------------------------- | |||
| # Plugin Paths | |||
| ladspas = toList(settings.value(CARLA_KEY_PATHS_LADSPA, CARLA_DEFAULT_LADSPA_PATH)) | |||
| dssis = toList(settings.value(CARLA_KEY_PATHS_DSSI, CARLA_DEFAULT_DSSI_PATH)) | |||
| @@ -794,7 +830,25 @@ class CarlaSettingsW(QDialog): | |||
| settings.setValue(CARLA_KEY_OSC_UDP_PORT_NUMBER, self.ui.sb_osc_udp_port_number.value()) | |||
| # ---------------------------------------------------------------------------------------------------- | |||
| # Paths | |||
| # File Paths | |||
| audioPaths = [] | |||
| midiPaths = [] | |||
| for i in range(self.ui.lw_files_audio.count()): | |||
| audioPaths.append(self.ui.lw_files_audio.item(i).text()) | |||
| for i in range(self.ui.lw_files_midi.count()): | |||
| midiPaths.append(self.ui.lw_files_midi.item(i).text()) | |||
| self.host.set_engine_option(ENGINE_OPTION_FILE_PATH, FILE_AUDIO, splitter.join(audioPaths)) | |||
| self.host.set_engine_option(ENGINE_OPTION_FILE_PATH, FILE_MIDI, splitter.join(midiPaths)) | |||
| settings.setValue(CARLA_KEY_PATHS_AUDIO, audioPaths) | |||
| settings.setValue(CARLA_KEY_PATHS_MIDI, midiPaths) | |||
| # ---------------------------------------------------------------------------------------------------- | |||
| # Plugin Paths | |||
| ladspas = [] | |||
| dssis = [] | |||
| @@ -934,12 +988,24 @@ class CarlaSettingsW(QDialog): | |||
| self.ui.rb_osc_udp_port_specific.setChecked(True) | |||
| # ---------------------------------------------------------------------------------------------------- | |||
| # Paths | |||
| # Plugin Paths | |||
| elif currentRow == self.TAB_INDEX_FILEPATHS: | |||
| curIndex = self.ui.tw_filepaths.currentIndex() | |||
| if curIndex == self.FILEPATH_INDEX_AUDIO: | |||
| self.ui.lw_files_audio.clear() | |||
| elif curIndex == self.FILEPATH_INDEX_MIDI: | |||
| self.ui.lw_files_midi.clear() | |||
| # ---------------------------------------------------------------------------------------------------- | |||
| # Plugin Paths | |||
| elif currentRow == self.TAB_INDEX_PATHS: | |||
| elif currentRow == self.TAB_INDEX_PLUGINPATHS: | |||
| curIndex = self.ui.tw_paths.currentIndex() | |||
| if curIndex == self.PATH_INDEX_LADSPA: | |||
| if curIndex == self.PLUGINPATH_INDEX_LADSPA: | |||
| paths = CARLA_DEFAULT_LADSPA_PATH | |||
| paths.sort() | |||
| self.ui.lw_ladspa.clear() | |||
| @@ -948,7 +1014,7 @@ class CarlaSettingsW(QDialog): | |||
| if not path: continue | |||
| self.ui.lw_ladspa.addItem(path) | |||
| elif curIndex == self.PATH_INDEX_DSSI: | |||
| elif curIndex == self.PLUGINPATH_INDEX_DSSI: | |||
| paths = CARLA_DEFAULT_DSSI_PATH | |||
| paths.sort() | |||
| self.ui.lw_dssi.clear() | |||
| @@ -957,7 +1023,7 @@ class CarlaSettingsW(QDialog): | |||
| if not path: continue | |||
| self.ui.lw_dssi.addItem(path) | |||
| elif curIndex == self.PATH_INDEX_LV2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_LV2: | |||
| paths = CARLA_DEFAULT_LV2_PATH | |||
| paths.sort() | |||
| self.ui.lw_lv2.clear() | |||
| @@ -966,7 +1032,7 @@ class CarlaSettingsW(QDialog): | |||
| if not path: continue | |||
| self.ui.lw_lv2.addItem(path) | |||
| elif curIndex == self.PATH_INDEX_VST2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_VST2: | |||
| paths = CARLA_DEFAULT_VST2_PATH | |||
| paths.sort() | |||
| self.ui.lw_vst.clear() | |||
| @@ -975,7 +1041,7 @@ class CarlaSettingsW(QDialog): | |||
| if not path: continue | |||
| self.ui.lw_vst.addItem(path) | |||
| elif curIndex == self.PATH_INDEX_VST3: | |||
| elif curIndex == self.PLUGINPATH_INDEX_VST3: | |||
| paths = CARLA_DEFAULT_VST3_PATH | |||
| paths.sort() | |||
| self.ui.lw_vst3.clear() | |||
| @@ -984,7 +1050,7 @@ class CarlaSettingsW(QDialog): | |||
| if not path: continue | |||
| self.ui.lw_vst3.addItem(path) | |||
| elif curIndex == self.PATH_INDEX_SF2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_SF2: | |||
| paths = CARLA_DEFAULT_SF2_PATH | |||
| paths.sort() | |||
| self.ui.lw_sf2.clear() | |||
| @@ -993,7 +1059,7 @@ class CarlaSettingsW(QDialog): | |||
| if not path: continue | |||
| self.ui.lw_sf2.addItem(path) | |||
| elif curIndex == self.PATH_INDEX_SFZ: | |||
| elif curIndex == self.PLUGINPATH_INDEX_SFZ: | |||
| paths = CARLA_DEFAULT_SFZ_PATH | |||
| paths.sort() | |||
| self.ui.lw_sfz.clear() | |||
| @@ -1113,57 +1179,57 @@ class CarlaSettingsW(QDialog): | |||
| curIndex = self.ui.tw_paths.currentIndex() | |||
| if curIndex == self.PATH_INDEX_LADSPA: | |||
| if curIndex == self.PLUGINPATH_INDEX_LADSPA: | |||
| self.ui.lw_ladspa.addItem(newPath) | |||
| elif curIndex == self.PATH_INDEX_DSSI: | |||
| elif curIndex == self.PLUGINPATH_INDEX_DSSI: | |||
| self.ui.lw_dssi.addItem(newPath) | |||
| elif curIndex == self.PATH_INDEX_LV2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_LV2: | |||
| self.ui.lw_lv2.addItem(newPath) | |||
| elif curIndex == self.PATH_INDEX_VST2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_VST2: | |||
| self.ui.lw_vst.addItem(newPath) | |||
| elif curIndex == self.PATH_INDEX_VST3: | |||
| elif curIndex == self.PLUGINPATH_INDEX_VST3: | |||
| self.ui.lw_vst3.addItem(newPath) | |||
| elif curIndex == self.PATH_INDEX_SF2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_SF2: | |||
| self.ui.lw_sf2.addItem(newPath) | |||
| elif curIndex == self.PATH_INDEX_SFZ: | |||
| elif curIndex == self.PLUGINPATH_INDEX_SFZ: | |||
| self.ui.lw_sfz.addItem(newPath) | |||
| @pyqtSlot() | |||
| def slot_removePluginPath(self): | |||
| curIndex = self.ui.tw_paths.currentIndex() | |||
| if curIndex == self.PATH_INDEX_LADSPA: | |||
| if curIndex == self.PLUGINPATH_INDEX_LADSPA: | |||
| self.ui.lw_ladspa.takeItem(self.ui.lw_ladspa.currentRow()) | |||
| elif curIndex == self.PATH_INDEX_DSSI: | |||
| elif curIndex == self.PLUGINPATH_INDEX_DSSI: | |||
| self.ui.lw_dssi.takeItem(self.ui.lw_dssi.currentRow()) | |||
| elif curIndex == self.PATH_INDEX_LV2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_LV2: | |||
| self.ui.lw_lv2.takeItem(self.ui.lw_lv2.currentRow()) | |||
| elif curIndex == self.PATH_INDEX_VST2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_VST2: | |||
| self.ui.lw_vst.takeItem(self.ui.lw_vst.currentRow()) | |||
| elif curIndex == self.PATH_INDEX_VST3: | |||
| elif curIndex == self.PLUGINPATH_INDEX_VST3: | |||
| self.ui.lw_vst3.takeItem(self.ui.lw_vst3.currentRow()) | |||
| elif curIndex == self.PATH_INDEX_SF2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_SF2: | |||
| self.ui.lw_sf2.takeItem(self.ui.lw_sf2.currentRow()) | |||
| elif curIndex == self.PATH_INDEX_SFZ: | |||
| elif curIndex == self.PLUGINPATH_INDEX_SFZ: | |||
| self.ui.lw_sfz.takeItem(self.ui.lw_sfz.currentRow()) | |||
| @pyqtSlot() | |||
| def slot_changePluginPath(self): | |||
| curIndex = self.ui.tw_paths.currentIndex() | |||
| if curIndex == self.PATH_INDEX_LADSPA: | |||
| if curIndex == self.PLUGINPATH_INDEX_LADSPA: | |||
| currentPath = self.ui.lw_ladspa.currentItem().text() | |||
| elif curIndex == self.PATH_INDEX_DSSI: | |||
| elif curIndex == self.PLUGINPATH_INDEX_DSSI: | |||
| currentPath = self.ui.lw_dssi.currentItem().text() | |||
| elif curIndex == self.PATH_INDEX_LV2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_LV2: | |||
| currentPath = self.ui.lw_lv2.currentItem().text() | |||
| elif curIndex == self.PATH_INDEX_VST2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_VST2: | |||
| currentPath = self.ui.lw_vst.currentItem().text() | |||
| elif curIndex == self.PATH_INDEX_VST3: | |||
| elif curIndex == self.PLUGINPATH_INDEX_VST3: | |||
| currentPath = self.ui.lw_vst3.currentItem().text() | |||
| elif curIndex == self.PATH_INDEX_SF2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_SF2: | |||
| currentPath = self.ui.lw_sf2.currentItem().text() | |||
| elif curIndex == self.PATH_INDEX_SFZ: | |||
| elif curIndex == self.PLUGINPATH_INDEX_SFZ: | |||
| currentPath = self.ui.lw_sfz.currentItem().text() | |||
| else: | |||
| currentPath = "" | |||
| @@ -1173,38 +1239,38 @@ class CarlaSettingsW(QDialog): | |||
| if not newPath: | |||
| return | |||
| if curIndex == self.PATH_INDEX_LADSPA: | |||
| if curIndex == self.PLUGINPATH_INDEX_LADSPA: | |||
| self.ui.lw_ladspa.currentItem().setText(newPath) | |||
| elif curIndex == self.PATH_INDEX_DSSI: | |||
| elif curIndex == self.PLUGINPATH_INDEX_DSSI: | |||
| self.ui.lw_dssi.currentItem().setText(newPath) | |||
| elif curIndex == self.PATH_INDEX_LV2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_LV2: | |||
| self.ui.lw_lv2.currentItem().setText(newPath) | |||
| elif curIndex == self.PATH_INDEX_VST2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_VST2: | |||
| self.ui.lw_vst.currentItem().setText(newPath) | |||
| elif curIndex == self.PATH_INDEX_VST3: | |||
| elif curIndex == self.PLUGINPATH_INDEX_VST3: | |||
| self.ui.lw_vst3.currentItem().setText(newPath) | |||
| elif curIndex == self.PATH_INDEX_SF2: | |||
| elif curIndex == self.PLUGINPATH_INDEX_SF2: | |||
| self.ui.lw_sf2.currentItem().setText(newPath) | |||
| elif curIndex == self.PATH_INDEX_SFZ: | |||
| elif curIndex == self.PLUGINPATH_INDEX_SFZ: | |||
| self.ui.lw_sfz.currentItem().setText(newPath) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| @pyqtSlot(int) | |||
| def slot_pluginPathTabChanged(self, index): | |||
| if index == self.PATH_INDEX_LADSPA: | |||
| if index == self.PLUGINPATH_INDEX_LADSPA: | |||
| row = self.ui.lw_ladspa.currentRow() | |||
| elif index == self.PATH_INDEX_DSSI: | |||
| elif index == self.PLUGINPATH_INDEX_DSSI: | |||
| row = self.ui.lw_dssi.currentRow() | |||
| elif index == self.PATH_INDEX_LV2: | |||
| elif index == self.PLUGINPATH_INDEX_LV2: | |||
| row = self.ui.lw_lv2.currentRow() | |||
| elif index == self.PATH_INDEX_VST2: | |||
| elif index == self.PLUGINPATH_INDEX_VST2: | |||
| row = self.ui.lw_vst.currentRow() | |||
| elif index == self.PATH_INDEX_VST3: | |||
| elif index == self.PLUGINPATH_INDEX_VST3: | |||
| row = self.ui.lw_vst3.currentRow() | |||
| elif index == self.PATH_INDEX_SF2: | |||
| elif index == self.PLUGINPATH_INDEX_SF2: | |||
| row = self.ui.lw_sf2.currentRow() | |||
| elif index == self.PATH_INDEX_SFZ: | |||
| elif index == self.PLUGINPATH_INDEX_SFZ: | |||
| row = self.ui.lw_sfz.currentRow() | |||
| else: | |||
| row = -1 | |||
| @@ -1221,6 +1287,73 @@ class CarlaSettingsW(QDialog): | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| @pyqtSlot() | |||
| def slot_addFilePath(self): | |||
| newPath = QFileDialog.getExistingDirectory(self, self.tr("Add Path"), "", QFileDialog.ShowDirsOnly) | |||
| if not newPath: | |||
| return | |||
| curIndex = self.ui.tw_filepaths.currentIndex() | |||
| if curIndex == self.FILEPATH_INDEX_AUDIO: | |||
| self.ui.lw_files_audio.addItem(newPath) | |||
| elif curIndex == self.FILEPATH_INDEX_MIDI: | |||
| self.ui.lw_files_midi.addItem(newPath) | |||
| @pyqtSlot() | |||
| def slot_removeFilePath(self): | |||
| curIndex = self.ui.tw_filepaths.currentIndex() | |||
| if curIndex == self.FILEPATH_INDEX_AUDIO: | |||
| self.ui.lw_files_audio.takeItem(self.ui.lw_files_audio.currentRow()) | |||
| elif curIndex == self.FILEPATH_INDEX_MIDI: | |||
| self.ui.lw_files_midi.takeItem(self.ui.lw_files_midi.currentRow()) | |||
| @pyqtSlot() | |||
| def slot_changeFilePath(self): | |||
| curIndex = self.ui.tw_filepaths.currentIndex() | |||
| if curIndex == self.FILEPATH_INDEX_AUDIO: | |||
| currentPath = self.ui.lw_files_audio.currentItem().text() | |||
| elif curIndex == self.FILEPATH_INDEX_MIDI: | |||
| currentPath = self.ui.lw_files_midi.currentItem().text() | |||
| else: | |||
| currentPath = "" | |||
| newPath = QFileDialog.getExistingDirectory(self, self.tr("Add Path"), currentPath, QFileDialog.ShowDirsOnly) | |||
| if not newPath: | |||
| return | |||
| if curIndex == self.FILEPATH_INDEX_AUDIO: | |||
| self.ui.lw_files_audio.currentItem().setText(newPath) | |||
| elif curIndex == self.FILEPATH_INDEX_MIDI: | |||
| self.ui.lw_files_midi.currentItem().setText(newPath) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| @pyqtSlot(int) | |||
| def slot_filePathTabChanged(self, index): | |||
| if index == self.FILEPATH_INDEX_AUDIO: | |||
| row = self.ui.lw_files_audio.currentRow() | |||
| elif index == self.FILEPATH_INDEX_MIDI: | |||
| row = self.ui.lw_files_midi.currentRow() | |||
| else: | |||
| row = -1 | |||
| check = bool(row >= 0) | |||
| self.ui.b_filepaths_remove.setEnabled(check) | |||
| self.ui.b_filepaths_change.setEnabled(check) | |||
| @pyqtSlot(int) | |||
| def slot_filePathRowChanged(self, row): | |||
| check = bool(row >= 0) | |||
| self.ui.b_filepaths_remove.setEnabled(check) | |||
| self.ui.b_filepaths_change.setEnabled(check) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| def done(self, r): | |||
| QDialog.done(self, r) | |||
| self.close() | |||
| @@ -222,6 +222,9 @@ CARLA_KEY_OSC_UDP_PORT_ENABLED = "OSC/UDPEnabled" | |||
| CARLA_KEY_OSC_UDP_PORT_NUMBER = "OSC/UDPNumber" | |||
| CARLA_KEY_OSC_UDP_PORT_RANDOM = "OSC/UDPRandom" | |||
| CARLA_KEY_PATHS_AUDIO = "Paths/Audio" | |||
| CARLA_KEY_PATHS_MIDI = "Paths/MIDI" | |||
| CARLA_KEY_PATHS_LADSPA = "Paths/LADSPA" | |||
| CARLA_KEY_PATHS_DSSI = "Paths/DSSI" | |||
| CARLA_KEY_PATHS_LV2 = "Paths/LV2" | |||
| @@ -303,7 +306,7 @@ if CARLA_DEFAULT_AUDIO_DRIVER == "JACK": | |||
| else: | |||
| CARLA_DEFAULT_PROCESS_MODE = ENGINE_PROCESS_MODE_PATCHBAY | |||
| CARLA_DEFAULT_TRANSPORT_MODE = ENGINE_TRANSPORT_MODE_INTERNAL | |||
| # OSC | |||
| CARLA_DEFAULT_OSC_ENABLED = not WINDOWS | |||
| CARLA_DEFAULT_OSC_TCP_PORT_ENABLED = True | |||
| @@ -329,6 +332,12 @@ CARLA_DEFAULT_EXPERIMENTAL_LV2_EXPORT = False | |||
| CARLA_DEFAULT_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR = False | |||
| CARLA_DEFAULT_EXPERIMENTAL_LOAD_LIB_GLOBAL = False | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Default File Folders | |||
| CARLA_DEFAULT_FILE_PATH_AUDIO = [] | |||
| CARLA_DEFAULT_FILE_PATH_MIDI = [] | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Default Plugin Folders (get) | |||
| @@ -65,7 +65,8 @@ typedef enum { | |||
| NATIVE_PLUGIN_USES_TIME = 1 << 10, | |||
| NATIVE_PLUGIN_USES_PARENT_ID = 1 << 11, /** can set transient hint to parent */ | |||
| NATIVE_PLUGIN_HAS_INLINE_DISPLAY = 1 << 12, | |||
| NATIVE_PLUGIN_USES_CONTROL_VOLTAGE = 1 << 13 | |||
| NATIVE_PLUGIN_USES_CONTROL_VOLTAGE = 1 << 13, | |||
| NATIVE_PLUGIN_REQUESTS_IDLE = 1 << 15, | |||
| } NativePluginHints; | |||
| typedef enum { | |||
| @@ -96,21 +97,24 @@ typedef enum { | |||
| NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED = 2, /** uses opt */ | |||
| NATIVE_PLUGIN_OPCODE_OFFLINE_CHANGED = 3, /** uses value (0=off, 1=on) */ | |||
| NATIVE_PLUGIN_OPCODE_UI_NAME_CHANGED = 4, /** uses ptr */ | |||
| NATIVE_PLUGIN_OPCODE_GET_INTERNAL_HANDLE = 5 /** nothing */ | |||
| NATIVE_PLUGIN_OPCODE_GET_INTERNAL_HANDLE = 5, /** nothing */ | |||
| NATIVE_PLUGIN_OPCODE_IDLE = 6 /** nothing */ | |||
| } NativePluginDispatcherOpcode; | |||
| typedef enum { | |||
| NATIVE_HOST_OPCODE_NULL = 0, /** nothing */ | |||
| NATIVE_HOST_OPCODE_UPDATE_PARAMETER = 1, /** uses index, -1 for all */ | |||
| NATIVE_HOST_OPCODE_UPDATE_MIDI_PROGRAM = 2, /** uses index, -1 for all; may use value for channel */ | |||
| NATIVE_HOST_OPCODE_RELOAD_PARAMETERS = 3, /** nothing */ | |||
| NATIVE_HOST_OPCODE_RELOAD_MIDI_PROGRAMS = 4, /** nothing */ | |||
| NATIVE_HOST_OPCODE_RELOAD_ALL = 5, /** nothing */ | |||
| NATIVE_HOST_OPCODE_UI_UNAVAILABLE = 6, /** nothing */ | |||
| NATIVE_HOST_OPCODE_HOST_IDLE = 7, /** nothing */ | |||
| NATIVE_HOST_OPCODE_INTERNAL_PLUGIN = 8, /** nothing */ | |||
| NATIVE_HOST_OPCODE_QUEUE_INLINE_DISPLAY = 9, /** nothing */ | |||
| NATIVE_HOST_OPCODE_UI_TOUCH_PARAMETER = 10 /** uses index, value as bool */ | |||
| NATIVE_HOST_OPCODE_NULL = 0, /** nothing */ | |||
| NATIVE_HOST_OPCODE_UPDATE_PARAMETER = 1, /** uses index, -1 for all */ | |||
| NATIVE_HOST_OPCODE_UPDATE_MIDI_PROGRAM = 2, /** uses index, -1 for all; may use value for channel */ | |||
| NATIVE_HOST_OPCODE_RELOAD_PARAMETERS = 3, /** nothing */ | |||
| NATIVE_HOST_OPCODE_RELOAD_MIDI_PROGRAMS = 4, /** nothing */ | |||
| NATIVE_HOST_OPCODE_RELOAD_ALL = 5, /** nothing */ | |||
| NATIVE_HOST_OPCODE_UI_UNAVAILABLE = 6, /** nothing */ | |||
| NATIVE_HOST_OPCODE_HOST_IDLE = 7, /** nothing */ | |||
| NATIVE_HOST_OPCODE_INTERNAL_PLUGIN = 8, /** nothing */ | |||
| NATIVE_HOST_OPCODE_QUEUE_INLINE_DISPLAY = 9, /** nothing */ | |||
| NATIVE_HOST_OPCODE_UI_TOUCH_PARAMETER = 10, /** uses index, value as bool */ | |||
| NATIVE_HOST_OPCODE_REQUEST_IDLE = 11, /** nothing */ | |||
| NATIVE_HOST_OPCODE_GET_FILE_PATH = 12 /** uses ptr as string for file type */ | |||
| } NativeHostDispatcherOpcode; | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| @@ -27,7 +27,7 @@ | |||
| * @{ | |||
| */ | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Native Plugin Class | |||
| class NativePluginClass | |||
| @@ -225,6 +225,13 @@ protected: | |||
| pHost->dispatcher(pHost->handle, NATIVE_HOST_OPCODE_HOST_IDLE, 0, 0, nullptr, 0.0f); | |||
| } | |||
| void hostRequestIdle() const | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(pHost != nullptr,); | |||
| pHost->dispatcher(pHost->handle, NATIVE_HOST_OPCODE_REQUEST_IDLE, 0, 0, nullptr, 0.0f); | |||
| } | |||
| void hostQueueDrawInlineDisplay() | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(pHost != nullptr,); | |||
| @@ -232,6 +239,17 @@ protected: | |||
| pHost->dispatcher(pHost->handle, NATIVE_HOST_OPCODE_QUEUE_INLINE_DISPLAY, 0, 0, nullptr, 0.0f); | |||
| } | |||
| const char* hostGetFilePath(const char* const filetype) const | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(pHost != nullptr, nullptr); | |||
| return (const char*)(uintptr_t)pHost->dispatcher(pHost->handle, | |||
| NATIVE_HOST_OPCODE_GET_FILE_PATH, | |||
| 0, 0, | |||
| (void*)const_cast<char*>(filetype), | |||
| 0.0f); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin parameter calls | |||
| @@ -394,6 +412,8 @@ protected: | |||
| return nullptr; | |||
| } | |||
| virtual void idle() {} | |||
| // ------------------------------------------------------------------- | |||
| private: | |||
| @@ -521,6 +541,9 @@ public: | |||
| return 0; | |||
| case NATIVE_PLUGIN_OPCODE_GET_INTERNAL_HANDLE: | |||
| return 0; | |||
| case NATIVE_PLUGIN_OPCODE_IDLE: | |||
| handlePtr->idle(); | |||
| return 0; | |||
| } | |||
| return 0; | |||
| @@ -542,7 +565,7 @@ public: | |||
| /**@}*/ | |||
| // --------------------------------------------------------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // -Weffc++ compat ext widget | |||
| extern "C" { | |||
| @@ -559,7 +582,7 @@ typedef struct _NativeInlineDisplayImageSurfaceCompat { | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| #define PluginClassEND(ClassName) \ | |||
| public: \ | |||
| @@ -597,6 +620,6 @@ public: \ | |||
| ClassName::_render_inline_display, \ | |||
| 0, 0 | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| #endif // CARLA_NATIVE_HPP_INCLUDED | |||
| @@ -0,0 +1,206 @@ | |||
| /* | |||
| * Carla Native Plugin API (C++) | |||
| * Copyright (C) 2012-2019 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 doc/GPL.txt file. | |||
| */ | |||
| #ifndef CARLA_NATIVE_PROGRAMS_HPP_INCLUDED | |||
| #define CARLA_NATIVE_PROGRAMS_HPP_INCLUDED | |||
| #include "CarlaNative.hpp" | |||
| #include "CarlaMathUtils.hpp" | |||
| #include "CarlaMutex.hpp" | |||
| #include "water/files/File.h" | |||
| #include "water/memory/SharedResourcePointer.h" | |||
| #include "water/text/StringArray.h" | |||
| using water::Array; | |||
| using water::File; | |||
| using water::SharedResourcePointer; | |||
| using water::String; | |||
| using water::StringArray; | |||
| /*! | |||
| * @defgroup CarlaNativeAPI Carla Native API | |||
| * @{ | |||
| */ | |||
| // ----------------------------------------------------------------------- | |||
| // ... | |||
| enum FileType { | |||
| FileNone, | |||
| FileAudio, | |||
| FileMIDI, | |||
| }; | |||
| template <FileType FileType> | |||
| struct NativePluginPresetManager { | |||
| StringArray filenames; | |||
| NativePluginPresetManager(const char* const paths, const char* const wildcard) | |||
| : filenames() | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(paths != nullptr,); | |||
| CARLA_SAFE_ASSERT_RETURN(wildcard != nullptr,); | |||
| if (paths[0] == '\0' || wildcard[0] == '\0') | |||
| return; | |||
| const StringArray splitPaths(StringArray::fromTokens(paths, CARLA_OS_SPLIT_STR, "")); | |||
| for (String *it = splitPaths.begin(), *end = splitPaths.end(); it != end; ++it) | |||
| { | |||
| Array<File> results; | |||
| if (File(*it).findChildFiles(results, File::findFiles|File::ignoreHiddenFiles, true, wildcard) > 0) | |||
| { | |||
| for (File *it2 = results.begin(), *end2 = results.end(); it2 != end2; ++it2) | |||
| filenames.add(it2->getFullPathName()); | |||
| } | |||
| } | |||
| filenames.sort(true); | |||
| } | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // Native Plugin with MIDI programs class | |||
| template <FileType FileType> | |||
| class NativePluginWithMidiPrograms : public NativePluginClass | |||
| { | |||
| public: | |||
| typedef SharedResourcePointer<NativePluginPresetManager<FileType>> NativeMidiPrograms; | |||
| NativePluginWithMidiPrograms(const NativeHostDescriptor* const host, | |||
| const NativeMidiPrograms& programs, | |||
| const uint32_t numOutputs) | |||
| : NativePluginClass(host), | |||
| fRetMidiProgram(), | |||
| fRetMidiProgramName(), | |||
| fNextFilename(nullptr), | |||
| fProgramChangeMutex(), | |||
| kPrograms(programs), | |||
| kNumOutputs(numOutputs) {} | |||
| protected: | |||
| // ------------------------------------------------------------------- | |||
| // New Plugin program calls | |||
| virtual void setStateFromFile(const char* filename) = 0; | |||
| virtual void process2(const float** inBuffer, float** outBuffer, uint32_t frames, | |||
| const NativeMidiEvent* midiEvents, uint32_t midiEventCount) = 0; | |||
| // ------------------------------------------------------------------- | |||
| // Plugin midi-program calls | |||
| uint32_t getMidiProgramCount() const override | |||
| { | |||
| const NativePluginPresetManager<FileType>& pm(kPrograms.get()); | |||
| return static_cast<uint32_t>(pm.filenames.size()); | |||
| } | |||
| const NativeMidiProgram* getMidiProgramInfo(const uint32_t uindex) const override | |||
| { | |||
| const int index = static_cast<int>(uindex); | |||
| const NativePluginPresetManager<FileType>& pm(kPrograms.get()); | |||
| CARLA_SAFE_ASSERT_RETURN(index < pm.filenames.size(), nullptr); | |||
| fRetMidiProgramName = File(pm.filenames.strings.getUnchecked(index)).getFileNameWithoutExtension(); | |||
| fRetMidiProgram.bank = 0; | |||
| fRetMidiProgram.program = uindex; | |||
| fRetMidiProgram.name = fRetMidiProgramName.toRawUTF8(); | |||
| return &fRetMidiProgram; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin state calls | |||
| void setMidiProgram(const uint8_t, const uint32_t, const uint32_t program) override | |||
| { | |||
| const int iprogram = static_cast<int>(program); | |||
| const NativePluginPresetManager<FileType>& pm(kPrograms.get()); | |||
| CARLA_SAFE_ASSERT_RETURN(iprogram < pm.filenames.size(),); | |||
| const char* const filename(pm.filenames.strings.getUnchecked(iprogram).toRawUTF8()); | |||
| const CarlaMutexLocker cml(fProgramChangeMutex); | |||
| if (isOffline()) | |||
| { | |||
| setStateFromFile(filename); | |||
| } | |||
| else | |||
| { | |||
| fNextFilename = filename; | |||
| hostRequestIdle(); | |||
| } | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin process calls | |||
| void process(const float** const inBuffer, float** const outBuffer, uint32_t frames, | |||
| const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override | |||
| { | |||
| const CarlaMutexTryLocker cmtl(fProgramChangeMutex, isOffline()); | |||
| if (cmtl.wasLocked()) | |||
| { | |||
| process2(inBuffer, outBuffer, frames, midiEvents, midiEventCount); | |||
| } | |||
| else | |||
| { | |||
| for (uint32_t i=0; i<kNumOutputs; ++i) | |||
| carla_zeroFloats(outBuffer[i], frames); | |||
| } | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin dispatcher calls | |||
| void idle() override | |||
| { | |||
| if (const char* const filename = fNextFilename) | |||
| { | |||
| const CarlaMutexLocker cml(fProgramChangeMutex); | |||
| fNextFilename = nullptr; | |||
| setStateFromFile(filename); | |||
| } | |||
| } | |||
| private: | |||
| mutable NativeMidiProgram fRetMidiProgram; | |||
| mutable String fRetMidiProgramName; | |||
| const char* fNextFilename; | |||
| CarlaMutex fProgramChangeMutex; | |||
| const NativeMidiPrograms& kPrograms; | |||
| const uint32_t kNumOutputs; | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NativePluginWithMidiPrograms) | |||
| }; | |||
| /**@}*/ | |||
| // ----------------------------------------------------------------------- | |||
| #endif // CARLA_NATIVE_PROGRAMS_HPP_INCLUDED | |||
| @@ -373,7 +373,7 @@ public: | |||
| */ | |||
| bool add (const ElementType& newElement) noexcept | |||
| { | |||
| if (! data.ensureAllocatedSize (numUsed + 1)) | |||
| if (! data.ensureAllocatedSize (static_cast<size_t>(numUsed + 1))) | |||
| return false; | |||
| new (data.elements + numUsed++) ElementType (newElement); | |||
| @@ -3,7 +3,7 @@ | |||
| This file is part of the Water library. | |||
| Copyright (c) 2016 ROLI Ltd. | |||
| Copyright (C) 2017 Filipe Coelho <falktx@falktx.com> | |||
| Copyright (C) 2017-2019 Filipe Coelho <falktx@falktx.com> | |||
| Permission is granted to use this software under the terms of the ISC license | |||
| http://www.isc.org/downloads/software-support-policy/isc-license/ | |||
| @@ -94,11 +94,19 @@ public: | |||
| then a shared object will be created automatically. | |||
| */ | |||
| SharedResourcePointer() | |||
| : sharedObject(nullptr) | |||
| { | |||
| initialise(); | |||
| } | |||
| SharedResourcePointer(const char* const v1, const char* const v2) | |||
| : sharedObject(nullptr) | |||
| { | |||
| initialise_v2(v1, v2); | |||
| } | |||
| SharedResourcePointer (const SharedResourcePointer&) | |||
| : sharedObject(nullptr) | |||
| { | |||
| initialise(); | |||
| } | |||
| @@ -140,7 +148,7 @@ private: | |||
| static SharedObjectHolder& getSharedObjectHolder() noexcept | |||
| { | |||
| static void* holder [(sizeof (SharedObjectHolder) + sizeof(void*) - 1) / sizeof(void*)] = { 0 }; | |||
| static void* holder [(sizeof (SharedObjectHolder) + sizeof(void*) - 1) / sizeof(void*)] = { nullptr }; | |||
| return *reinterpret_cast<SharedObjectHolder*> (holder); | |||
| } | |||
| @@ -157,6 +165,17 @@ private: | |||
| sharedObject = holder.sharedInstance; | |||
| } | |||
| void initialise_v2(const char* const v1, const char* const v2) | |||
| { | |||
| SharedObjectHolder& holder = getSharedObjectHolder(); | |||
| const SpinLock::ScopedLockType sl (holder.lock); | |||
| if (++(holder.refCount) == 1) | |||
| holder.sharedInstance = new SharedObjectType(v1, v2); | |||
| sharedObject = holder.sharedInstance; | |||
| } | |||
| // There's no need to assign to a SharedResourcePointer because every | |||
| // instance of the class is exactly the same! | |||
| SharedResourcePointer& operator= (const SharedResourcePointer&) WATER_DELETED_FUNCTION; | |||
| @@ -47,7 +47,7 @@ namespace water { | |||
| class SpinLock | |||
| { | |||
| public: | |||
| inline SpinLock() noexcept {} | |||
| inline SpinLock() noexcept : lock() {} | |||
| inline ~SpinLock() noexcept {} | |||
| /** Acquires the lock. | |||
| @@ -237,6 +237,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { | |||
| |NATIVE_PLUGIN_HAS_INLINE_DISPLAY | |||
| |NATIVE_PLUGIN_HAS_UI | |||
| |NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | |||
| |NATIVE_PLUGIN_REQUESTS_IDLE | |||
| |NATIVE_PLUGIN_USES_TIME), | |||
| /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||
| /* audioIns */ 0, | |||
| @@ -260,6 +261,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { | |||
| /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||
| |NATIVE_PLUGIN_HAS_UI | |||
| |NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | |||
| |NATIVE_PLUGIN_REQUESTS_IDLE | |||
| |NATIVE_PLUGIN_USES_STATE | |||
| |NATIVE_PLUGIN_USES_TIME), | |||
| /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||
| @@ -12,22 +12,35 @@ | |||
| * 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 | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #include "CarlaNative.hpp" | |||
| #include "CarlaNativePrograms.hpp" | |||
| #include "CarlaString.hpp" | |||
| #include "audio-base.hpp" | |||
| #define PROGRAM_COUNT 16 | |||
| static const char* const audiofilesWildcard = | |||
| #ifdef HAVE_SNDFILE | |||
| "*.aif;*.aifc;*.aiff;*.au;*.bwf;*.flac;*.htk;*.iff;*.mat4;*.mat5;*.oga;*.ogg;" | |||
| "*.paf;*.pvf;*.pvf5;*.sd2;*.sf;*.snd;*.svx;*.vcc;*.w64;*.wav;*.xi;" | |||
| #endif | |||
| #ifdef HAVE_FFMPEG | |||
| "*.3g2;*.3gp;*.aac;*.ac3;*.amr;*.ape;*.mp2;*.mp3;*.mpc;*.wma;" | |||
| # ifndef HAVE_SNDFILE | |||
| "*.flac;*.oga;*.ogg;*.w64;*.wav;" | |||
| # endif | |||
| #endif | |||
| ; | |||
| // ----------------------------------------------------------------------- | |||
| class AudioFilePlugin : public NativePluginClass, | |||
| class AudioFilePlugin : public NativePluginWithMidiPrograms<FileAudio>, | |||
| public AbstractAudioPlayer | |||
| { | |||
| public: | |||
| AudioFilePlugin(const NativeHostDescriptor* const host) | |||
| : NativePluginClass(host), | |||
| : NativePluginWithMidiPrograms(host, fPrograms, 2), | |||
| AbstractAudioPlayer(), | |||
| fLoopMode(true), | |||
| fDoProcess(false), | |||
| @@ -35,6 +48,7 @@ public: | |||
| fMaxFrame(0), | |||
| fPool(), | |||
| fThread(this), | |||
| fPrograms(hostGetFilePath("audio"), audiofilesWildcard), | |||
| fInlineDisplay() {} | |||
| ~AudioFilePlugin() override | |||
| @@ -116,8 +130,8 @@ protected: | |||
| // ------------------------------------------------------------------- | |||
| // Plugin process calls | |||
| void process(const float**, float** const outBuffer, const uint32_t frames, | |||
| const NativeMidiEvent*, uint32_t) override | |||
| void process2(const float**, float** const outBuffer, const uint32_t frames, | |||
| const NativeMidiEvent*, uint32_t) override | |||
| { | |||
| const NativeTimeInfo* const timePos(getTimeInfo()); | |||
| @@ -254,6 +268,14 @@ protected: | |||
| uiClosed(); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin state calls | |||
| void setStateFromFile(const char* const filename) override | |||
| { | |||
| loadFilename(filename); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin dispatcher calls | |||
| @@ -374,6 +396,8 @@ private: | |||
| AudioFilePool fPool; | |||
| AudioFileThread fThread; | |||
| NativeMidiPrograms fPrograms; | |||
| struct InlineDisplay : NativeInlineDisplayImageSurfaceCompat { | |||
| float lastValuesL[32]; | |||
| float lastValuesR[32]; | |||
| @@ -454,6 +478,7 @@ static const NativePluginDescriptor audiofileDesc = { | |||
| |NATIVE_PLUGIN_HAS_INLINE_DISPLAY | |||
| |NATIVE_PLUGIN_HAS_UI | |||
| |NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | |||
| |NATIVE_PLUGIN_REQUESTS_IDLE | |||
| |NATIVE_PLUGIN_USES_TIME), | |||
| /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||
| /* audioIns */ 0, | |||
| @@ -15,7 +15,7 @@ | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #include "CarlaNative.hpp" | |||
| #include "CarlaNativePrograms.hpp" | |||
| #include "midi-base.hpp" | |||
| #include "water/files/FileInputStream.h" | |||
| @@ -23,15 +23,16 @@ | |||
| // ----------------------------------------------------------------------- | |||
| class MidiFilePlugin : public NativePluginClass, | |||
| class MidiFilePlugin : public NativePluginWithMidiPrograms<FileMIDI>, | |||
| public AbstractMidiPlayer | |||
| { | |||
| public: | |||
| MidiFilePlugin(const NativeHostDescriptor* const host) | |||
| : NativePluginClass(host), | |||
| : NativePluginWithMidiPrograms(host, fPrograms, 0), | |||
| fMidiOut(this), | |||
| fNeedsAllNotesOff(false), | |||
| fWasPlayingBefore(false) {} | |||
| fWasPlayingBefore(false), | |||
| fPrograms(hostGetFilePath("midi"), "*.mid;*.midi") {} | |||
| protected: | |||
| // ------------------------------------------------------------------- | |||
| @@ -51,7 +52,7 @@ protected: | |||
| // ------------------------------------------------------------------- | |||
| // Plugin process calls | |||
| void process(const float**, float**, const uint32_t frames, const NativeMidiEvent* const, const uint32_t) override | |||
| void process2(const float**, float**, const uint32_t frames, const NativeMidiEvent* const, const uint32_t) override | |||
| { | |||
| const NativeTimeInfo* const timePos(getTimeInfo()); | |||
| @@ -116,6 +117,11 @@ protected: | |||
| fMidiOut.setState(data); | |||
| } | |||
| void setStateFromFile(const char* const filename) override | |||
| { | |||
| _loadMidiFile(filename); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // AbstractMidiPlayer calls | |||
| @@ -140,6 +146,7 @@ private: | |||
| MidiPattern fMidiOut; | |||
| bool fNeedsAllNotesOff; | |||
| bool fWasPlayingBefore; | |||
| NativeMidiPrograms fPrograms; | |||
| void _loadMidiFile(const char* const filename) | |||
| { | |||
| @@ -223,6 +230,7 @@ static const NativePluginDescriptor midifileDesc = { | |||
| /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||
| |NATIVE_PLUGIN_HAS_UI | |||
| |NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | |||
| |NATIVE_PLUGIN_REQUESTS_IDLE | |||
| |NATIVE_PLUGIN_USES_STATE | |||
| |NATIVE_PLUGIN_USES_TIME), | |||
| /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||
| @@ -79,6 +79,23 @@ const char* BinaryType2Str(const BinaryType type) noexcept | |||
| return nullptr; | |||
| } | |||
| static inline | |||
| const char* FileType2Str(const FileType type) noexcept | |||
| { | |||
| switch (type) | |||
| { | |||
| case FILE_NONE: | |||
| return "FILE_NONE"; | |||
| case FILE_AUDIO: | |||
| return "FILE_AUDIO"; | |||
| case FILE_MIDI: | |||
| return "FILE_MIDI"; | |||
| } | |||
| carla_stderr("CarlaBackend::FileType2Str(%i) - invalid type", type); | |||
| return nullptr; | |||
| } | |||
| static inline | |||
| const char* PluginType2Str(const PluginType type) noexcept | |||
| { | |||
| @@ -337,6 +354,8 @@ const char* EngineOption2Str(const EngineOption option) noexcept | |||
| return "ENGINE_OPTION_OSC_PORT_UDP"; | |||
| case ENGINE_OPTION_OSC_PORT_TCP: | |||
| return "ENGINE_OPTION_OSC_PORT_TCP"; | |||
| case ENGINE_OPTION_FILE_PATH: | |||
| return "ENGINE_OPTION_FILE_PATH"; | |||
| case ENGINE_OPTION_PLUGIN_PATH: | |||
| return "ENGINE_OPTION_PLUGIN_PATH"; | |||
| case ENGINE_OPTION_PATH_BINARIES: | |||