Signed-off-by: falkTX <falktx@falktx.com>tags/v2.1-rc1
@@ -88,7 +88,12 @@ | |||||
</row> | </row> | ||||
<row> | <row> | ||||
<property name="text"> | <property name="text"> | ||||
<string>paths</string> | |||||
<string>file-paths</string> | |||||
</property> | |||||
</row> | |||||
<row> | |||||
<property name="text"> | |||||
<string>plugin-paths</string> | |||||
</property> | </property> | ||||
</row> | </row> | ||||
<row> | <row> | ||||
@@ -186,7 +191,7 @@ | |||||
</item> | </item> | ||||
<item row="4" column="0"> | <item row="4" column="0"> | ||||
<property name="text"> | <property name="text"> | ||||
<string>Paths</string> | |||||
<string>File Paths</string> | |||||
</property> | </property> | ||||
<property name="font"> | <property name="font"> | ||||
<font> | <font> | ||||
@@ -203,6 +208,24 @@ | |||||
</property> | </property> | ||||
</item> | </item> | ||||
<item row="5" column="0"> | <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"> | <property name="text"> | ||||
<string>Wine</string> | <string>Wine</string> | ||||
</property> | </property> | ||||
@@ -220,7 +243,7 @@ | |||||
<set>ItemIsSelectable|ItemIsEnabled</set> | <set>ItemIsSelectable|ItemIsEnabled</set> | ||||
</property> | </property> | ||||
</item> | </item> | ||||
<item row="6" column="0"> | |||||
<item row="7" column="0"> | |||||
<property name="text"> | <property name="text"> | ||||
<string>Experimental</string> | <string>Experimental</string> | ||||
</property> | </property> | ||||
@@ -1647,7 +1670,253 @@ | |||||
<zorder>group_osc_udp_port</zorder> | <zorder>group_osc_udp_port</zorder> | ||||
<zorder>group_osc_core</zorder> | <zorder>group_osc_core</zorder> | ||||
</widget> | </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"> | <layout class="QVBoxLayout" name="verticalLayout_19"> | ||||
<property name="margin"> | <property name="margin"> | ||||
<number>2</number> | <number>2</number> | ||||
@@ -1657,7 +1926,7 @@ | |||||
<item> | <item> | ||||
<widget class="QLabel" name="label_18"> | <widget class="QLabel" name="label_18"> | ||||
<property name="text"> | <property name="text"> | ||||
<string><b>Paths</b></string> | |||||
<string><b>Plugin Paths</b></string> | |||||
</property> | </property> | ||||
<property name="alignment"> | <property name="alignment"> | ||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> | <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> | ||||
@@ -2749,5 +3018,37 @@ This mode is not available for VST plugins.</string> | |||||
</hint> | </hint> | ||||
</hints> | </hints> | ||||
</connection> | </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> | </connections> | ||||
</ui> | </ui> |
@@ -488,6 +488,30 @@ typedef enum { | |||||
} BinaryType; | } 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 */ | * Plugin Type */ | ||||
@@ -1233,79 +1257,85 @@ typedef enum { | |||||
*/ | */ | ||||
ENGINE_OPTION_OSC_PORT_UDP = 16, | 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. | * Set path used for a specific plugin type. | ||||
* Uses value as the plugin format, valueStr as actual path. | * Uses value as the plugin format, valueStr as actual path. | ||||
* @see PluginType | * @see PluginType | ||||
*/ | */ | ||||
ENGINE_OPTION_PLUGIN_PATH = 17, | |||||
ENGINE_OPTION_PLUGIN_PATH = 18, | |||||
/*! | /*! | ||||
* Set path to the binary files. | * Set path to the binary files. | ||||
* Default unset. | * Default unset. | ||||
* @note Must be set for plugin and UI bridges to work | * @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. | * Set path to the resource files. | ||||
* Default unset. | * Default unset. | ||||
* @note Must be set for some internal plugins to work | * @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. | * Prevent bad plugin and UI behaviour. | ||||
* @note: Linux only | * @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. | * 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. | * 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) | #if !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) && !defined(CARLA_OS_WIN) | ||||
/*! | /*! | ||||
* Set path to wine executable. | * Set path to wine executable. | ||||
*/ | */ | ||||
ENGINE_OPTION_WINE_EXECUTABLE = 23, | |||||
ENGINE_OPTION_WINE_EXECUTABLE = 24, | |||||
/*! | /*! | ||||
* Enable automatic wineprefix detection. | * 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. | * 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. | * 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. | * Base realtime priority for Wine threads. | ||||
*/ | */ | ||||
ENGINE_OPTION_WINE_BASE_RT_PRIO = 27, | |||||
ENGINE_OPTION_WINE_BASE_RT_PRIO = 28, | |||||
/*! | /*! | ||||
* Wine server realtime priority. | * Wine server realtime priority. | ||||
*/ | */ | ||||
ENGINE_OPTION_WINE_SERVER_RT_PRIO = 28, | |||||
ENGINE_OPTION_WINE_SERVER_RT_PRIO = 29, | |||||
#endif | #endif | ||||
/*! | /*! | ||||
* Capture console output into debug callbacks. | * Capture console output into debug callbacks. | ||||
*/ | */ | ||||
ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT = 29 | |||||
ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT = 30 | |||||
} EngineOption; | } EngineOption; | ||||
@@ -249,6 +249,9 @@ struct CARLA_API EngineOptions { | |||||
int oscPortUDP; | int oscPortUDP; | ||||
#endif | #endif | ||||
const char* pathAudio; | |||||
const char* pathMIDI; | |||||
const char* pathLADSPA; | const char* pathLADSPA; | ||||
const char* pathDSSI; | const char* pathDSSI; | ||||
const char* pathLV2; | 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")) | if (const char* const uiBridgesTimeout = std::getenv("ENGINE_OPTION_UI_BRIDGES_TIMEOUT")) | ||||
engine->setOption(CB::ENGINE_OPTION_UI_BRIDGES_TIMEOUT, std::atoi(uiBridgesTimeout), nullptr); | 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")) | if (const char* const pathLADSPA = std::getenv("ENGINE_OPTION_PLUGIN_PATH_LADSPA")) | ||||
engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH, CB::PLUGIN_LADSPA, pathLADSPA); | 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_TCP, gStandalone.engineOptions.oscPortTCP, nullptr); | ||||
engine->setOption(CB::ENGINE_OPTION_OSC_PORT_UDP, gStandalone.engineOptions.oscPortUDP, 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) | if (gStandalone.engineOptions.pathLADSPA != nullptr) | ||||
engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH, CB::PLUGIN_LADSPA, gStandalone.engineOptions.pathLADSPA); | 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; | gStandalone.engineOptions.oscPortUDP = value; | ||||
break; | 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: | case CB::ENGINE_OPTION_PLUGIN_PATH: | ||||
CARLA_SAFE_ASSERT_RETURN(value > CB::PLUGIN_NONE,); | CARLA_SAFE_ASSERT_RETURN(value > CB::PLUGIN_NONE,); | ||||
CARLA_SAFE_ASSERT_RETURN(value <= CB::PLUGIN_SFZ,); | CARLA_SAFE_ASSERT_RETURN(value <= CB::PLUGIN_SFZ,); | ||||
@@ -1740,6 +1740,34 @@ void CarlaEngine::setOption(const EngineOption option, const int value, const ch | |||||
#endif | #endif | ||||
break; | 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: | case ENGINE_OPTION_PLUGIN_PATH: | ||||
CARLA_SAFE_ASSERT_RETURN(value > PLUGIN_NONE,); | CARLA_SAFE_ASSERT_RETURN(value > PLUGIN_NONE,); | ||||
CARLA_SAFE_ASSERT_RETURN(value <= PLUGIN_SFZ,); | 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; | pData->options.pathSFZ = nullptr; | ||||
break; | break; | ||||
default: | 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; | ||||
} | } | ||||
break; | break; | ||||
@@ -208,6 +208,8 @@ EngineOptions::EngineOptions() noexcept | |||||
oscPortTCP(22752), | oscPortTCP(22752), | ||||
oscPortUDP(22752), | oscPortUDP(22752), | ||||
#endif | #endif | ||||
pathAudio(nullptr), | |||||
pathMIDI(nullptr), | |||||
pathLADSPA(nullptr), | pathLADSPA(nullptr), | ||||
pathDSSI(nullptr), | pathDSSI(nullptr), | ||||
pathLV2(nullptr), | pathLV2(nullptr), | ||||
@@ -232,61 +234,61 @@ EngineOptions::~EngineOptions() noexcept | |||||
delete[] audioDriver; | delete[] audioDriver; | ||||
audioDriver = nullptr; | audioDriver = nullptr; | ||||
} | } | ||||
if (audioDevice != nullptr) | if (audioDevice != nullptr) | ||||
{ | { | ||||
delete[] audioDevice; | delete[] audioDevice; | ||||
audioDevice = nullptr; | audioDevice = nullptr; | ||||
} | } | ||||
if (pathAudio != nullptr) | |||||
{ | |||||
delete[] pathAudio; | |||||
pathAudio = nullptr; | |||||
} | |||||
if (pathMIDI != nullptr) | |||||
{ | |||||
delete[] pathMIDI; | |||||
pathMIDI = nullptr; | |||||
} | |||||
if (pathLADSPA != nullptr) | if (pathLADSPA != nullptr) | ||||
{ | { | ||||
delete[] pathLADSPA; | delete[] pathLADSPA; | ||||
pathLADSPA = nullptr; | pathLADSPA = nullptr; | ||||
} | } | ||||
if (pathDSSI != nullptr) | if (pathDSSI != nullptr) | ||||
{ | { | ||||
delete[] pathDSSI; | delete[] pathDSSI; | ||||
pathDSSI = nullptr; | pathDSSI = nullptr; | ||||
} | } | ||||
if (pathLV2 != nullptr) | if (pathLV2 != nullptr) | ||||
{ | { | ||||
delete[] pathLV2; | delete[] pathLV2; | ||||
pathLV2 = nullptr; | pathLV2 = nullptr; | ||||
} | } | ||||
if (pathVST2 != nullptr) | if (pathVST2 != nullptr) | ||||
{ | { | ||||
delete[] pathVST2; | delete[] pathVST2; | ||||
pathVST2 = nullptr; | pathVST2 = nullptr; | ||||
} | } | ||||
if (pathVST3 != nullptr) | if (pathVST3 != nullptr) | ||||
{ | { | ||||
delete[] pathVST3; | delete[] pathVST3; | ||||
pathVST3 = nullptr; | pathVST3 = nullptr; | ||||
} | } | ||||
if (pathSF2 != nullptr) | if (pathSF2 != nullptr) | ||||
{ | { | ||||
delete[] pathSF2; | delete[] pathSF2; | ||||
pathSF2 = nullptr; | pathSF2 = nullptr; | ||||
} | } | ||||
if (pathSFZ != nullptr) | if (pathSFZ != nullptr) | ||||
{ | { | ||||
delete[] pathSFZ; | delete[] pathSFZ; | ||||
pathSFZ = nullptr; | pathSFZ = nullptr; | ||||
} | } | ||||
if (binaryDir != nullptr) | if (binaryDir != nullptr) | ||||
{ | { | ||||
delete[] binaryDir; | delete[] binaryDir; | ||||
binaryDir = nullptr; | binaryDir = nullptr; | ||||
} | } | ||||
if (resourceDir != nullptr) | if (resourceDir != nullptr) | ||||
{ | { | ||||
delete[] resourceDir; | delete[] resourceDir; | ||||
@@ -1636,6 +1636,9 @@ public: | |||||
CarlaEngineNative* const engine = handlePtr; | CarlaEngineNative* const engine = handlePtr; | ||||
return (intptr_t)(CarlaEngine*)engine; | return (intptr_t)(CarlaEngine*)engine; | ||||
} | } | ||||
case NATIVE_PLUGIN_OPCODE_IDLE: | |||||
//handlePtr->idle(); | |||||
return 0; | |||||
} | } | ||||
return 0; | return 0; | ||||
@@ -252,6 +252,7 @@ public: | |||||
fIsOffline(false), | fIsOffline(false), | ||||
fIsUiAvailable(false), | fIsUiAvailable(false), | ||||
fIsUiVisible(false), | fIsUiVisible(false), | ||||
fNeedsIdle(false), | |||||
fInlineDisplayNeedsRedraw(false), | fInlineDisplayNeedsRedraw(false), | ||||
fInlineDisplayLastRedrawTime(0), | fInlineDisplayLastRedrawTime(0), | ||||
fAudioAndCvInBuffers(nullptr), | fAudioAndCvInBuffers(nullptr), | ||||
@@ -921,6 +922,12 @@ public: | |||||
void idle() override | void idle() override | ||||
{ | { | ||||
if (fNeedsIdle) | |||||
{ | |||||
fNeedsIdle = false; | |||||
fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_IDLE, 0, 0, nullptr, 0.0f); | |||||
} | |||||
if (fInlineDisplayNeedsRedraw) | if (fInlineDisplayNeedsRedraw) | ||||
{ | { | ||||
// TESTING | // TESTING | ||||
@@ -2555,7 +2562,8 @@ protected: | |||||
return pData->engine->runFileCallback(FILE_CALLBACK_SAVE, isDir, title, filter); | 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)", | carla_debug("CarlaPluginNative::handleDispatcher(%i, %i, " P_INTPTR ", %p, %f)", | ||||
opcode, index, value, ptr, static_cast<double>(opt)); | opcode, index, value, ptr, static_cast<double>(opt)); | ||||
@@ -2603,12 +2611,26 @@ protected: | |||||
CARLA_SAFE_ASSERT_RETURN(index >= 0, 0); | CARLA_SAFE_ASSERT_RETURN(index >= 0, 0); | ||||
pData->engine->touchPluginParameter(pData->id, static_cast<uint32_t>(index), value != 0); | pData->engine->touchPluginParameter(pData->id, static_cast<uint32_t>(index), value != 0); | ||||
break; | 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; | return ret; | ||||
// unused for now | // unused for now | ||||
(void)ptr; | |||||
(void)opt; | (void)opt; | ||||
} | } | ||||
@@ -2792,6 +2814,8 @@ private: | |||||
bool fIsOffline; | bool fIsOffline; | ||||
bool fIsUiAvailable; | bool fIsUiAvailable; | ||||
bool fIsUiVisible; | bool fIsUiVisible; | ||||
volatile bool fNeedsIdle; | |||||
bool fInlineDisplayNeedsRedraw; | bool fInlineDisplayNeedsRedraw; | ||||
int64_t fInlineDisplayLastRedrawTime; | int64_t fInlineDisplayLastRedrawTime; | ||||
@@ -387,6 +387,19 @@ BINARY_WIN64 = 4 | |||||
# Other binary type. | # Other binary type. | ||||
BINARY_OTHER = 5 | 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 | ||||
# 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) | # @note Valid ports begin at 1024 and end at 32767 (inclusive) | ||||
ENGINE_OPTION_OSC_PORT_UDP = 16 | 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. | # Set path used for a specific plugin type. | ||||
# Uses value as the plugin format, valueStr as actual path. | # Uses value as the plugin format, valueStr as actual path. | ||||
# @see PluginType | # @see PluginType | ||||
ENGINE_OPTION_PLUGIN_PATH = 17 | |||||
ENGINE_OPTION_PLUGIN_PATH = 18 | |||||
# Set path to the binary files. | # Set path to the binary files. | ||||
# Default unset. | # Default unset. | ||||
# @note Must be set for plugin and UI bridges to work | # @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. | # Set path to the resource files. | ||||
# Default unset. | # Default unset. | ||||
# @note Must be set for some internal plugins to work | # @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. | # Prevent bad plugin and UI behaviour. | ||||
# @note: Linux only | # @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. | # 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. | # 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. | # Set path to wine executable. | ||||
ENGINE_OPTION_WINE_EXECUTABLE = 23 | |||||
ENGINE_OPTION_WINE_EXECUTABLE = 24 | |||||
# Enable automatic wineprefix detection. | # 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. | # 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. | # 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. | # Base realtime priority for Wine threads. | ||||
ENGINE_OPTION_WINE_BASE_RT_PRIO = 27 | |||||
ENGINE_OPTION_WINE_BASE_RT_PRIO = 28 | |||||
# Wine server realtime priority. | # Wine server realtime priority. | ||||
ENGINE_OPTION_WINE_SERVER_RT_PRIO = 28 | |||||
ENGINE_OPTION_WINE_SERVER_RT_PRIO = 29 | |||||
# Capture console output into debug callbacks | # Capture console output into debug callbacks | ||||
ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT = 29 | |||||
ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT = 30 | |||||
# ------------------------------------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------------------------------------ | ||||
# Engine Process Mode | # Engine Process Mode | ||||
@@ -3101,6 +3101,15 @@ def setEngineSettings(host): | |||||
setHostSettings(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 | # plugin paths | ||||
@@ -324,19 +324,24 @@ class CarlaSettingsW(QDialog): | |||||
TAB_INDEX_CANVAS = 1 | TAB_INDEX_CANVAS = 1 | ||||
TAB_INDEX_ENGINE = 2 | TAB_INDEX_ENGINE = 2 | ||||
TAB_INDEX_OSC = 3 | 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, | # Single and Multiple client mode is only for JACK, | ||||
# but we still want to match QComboBox index to backend defines, | # but we still want to match QComboBox index to backend defines, | ||||
@@ -377,7 +382,8 @@ class CarlaSettingsW(QDialog): | |||||
if host.isControl: | if host.isControl: | ||||
self.ui.lw_page.hideRow(self.TAB_INDEX_ENGINE) | 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.ch_exp_export_lv2.hide() | ||||
self.ui.group_experimental_engine.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_sf2.currentRowChanged.connect(self.slot_pluginPathRowChanged) | ||||
self.ui.lw_sfz.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_main_experimental.toggled.connect(self.slot_enableExperimental) | ||||
self.ui.ch_exp_wine_bridges.toggled.connect(self.slot_enableWineBridges) | self.ui.ch_exp_wine_bridges.toggled.connect(self.slot_enableWineBridges) | ||||
self.ui.cb_exp_plugin_bridges.toggled.connect(self.slot_pluginBridgesToggled) | 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_sf2.setCurrentRow(0) | ||||
self.ui.lw_sfz.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.ui.lw_page.setCurrentCell(0, 0) | ||||
self.slot_filePathTabChanged(0) | |||||
self.slot_pluginPathTabChanged(0) | |||||
self.adjustSize() | self.adjustSize() | ||||
# -------------------------------------------------------------------------------------------------------- | # -------------------------------------------------------------------------------------------------------- | ||||
@@ -602,7 +621,24 @@ class CarlaSettingsW(QDialog): | |||||
self.ui.rb_osc_udp_port_specific.setChecked(True) | 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)) | ladspas = toList(settings.value(CARLA_KEY_PATHS_LADSPA, CARLA_DEFAULT_LADSPA_PATH)) | ||||
dssis = toList(settings.value(CARLA_KEY_PATHS_DSSI, CARLA_DEFAULT_DSSI_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()) | 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 = [] | ladspas = [] | ||||
dssis = [] | dssis = [] | ||||
@@ -934,12 +988,24 @@ class CarlaSettingsW(QDialog): | |||||
self.ui.rb_osc_udp_port_specific.setChecked(True) | 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() | curIndex = self.ui.tw_paths.currentIndex() | ||||
if curIndex == self.PATH_INDEX_LADSPA: | |||||
if curIndex == self.PLUGINPATH_INDEX_LADSPA: | |||||
paths = CARLA_DEFAULT_LADSPA_PATH | paths = CARLA_DEFAULT_LADSPA_PATH | ||||
paths.sort() | paths.sort() | ||||
self.ui.lw_ladspa.clear() | self.ui.lw_ladspa.clear() | ||||
@@ -948,7 +1014,7 @@ class CarlaSettingsW(QDialog): | |||||
if not path: continue | if not path: continue | ||||
self.ui.lw_ladspa.addItem(path) | self.ui.lw_ladspa.addItem(path) | ||||
elif curIndex == self.PATH_INDEX_DSSI: | |||||
elif curIndex == self.PLUGINPATH_INDEX_DSSI: | |||||
paths = CARLA_DEFAULT_DSSI_PATH | paths = CARLA_DEFAULT_DSSI_PATH | ||||
paths.sort() | paths.sort() | ||||
self.ui.lw_dssi.clear() | self.ui.lw_dssi.clear() | ||||
@@ -957,7 +1023,7 @@ class CarlaSettingsW(QDialog): | |||||
if not path: continue | if not path: continue | ||||
self.ui.lw_dssi.addItem(path) | self.ui.lw_dssi.addItem(path) | ||||
elif curIndex == self.PATH_INDEX_LV2: | |||||
elif curIndex == self.PLUGINPATH_INDEX_LV2: | |||||
paths = CARLA_DEFAULT_LV2_PATH | paths = CARLA_DEFAULT_LV2_PATH | ||||
paths.sort() | paths.sort() | ||||
self.ui.lw_lv2.clear() | self.ui.lw_lv2.clear() | ||||
@@ -966,7 +1032,7 @@ class CarlaSettingsW(QDialog): | |||||
if not path: continue | if not path: continue | ||||
self.ui.lw_lv2.addItem(path) | self.ui.lw_lv2.addItem(path) | ||||
elif curIndex == self.PATH_INDEX_VST2: | |||||
elif curIndex == self.PLUGINPATH_INDEX_VST2: | |||||
paths = CARLA_DEFAULT_VST2_PATH | paths = CARLA_DEFAULT_VST2_PATH | ||||
paths.sort() | paths.sort() | ||||
self.ui.lw_vst.clear() | self.ui.lw_vst.clear() | ||||
@@ -975,7 +1041,7 @@ class CarlaSettingsW(QDialog): | |||||
if not path: continue | if not path: continue | ||||
self.ui.lw_vst.addItem(path) | self.ui.lw_vst.addItem(path) | ||||
elif curIndex == self.PATH_INDEX_VST3: | |||||
elif curIndex == self.PLUGINPATH_INDEX_VST3: | |||||
paths = CARLA_DEFAULT_VST3_PATH | paths = CARLA_DEFAULT_VST3_PATH | ||||
paths.sort() | paths.sort() | ||||
self.ui.lw_vst3.clear() | self.ui.lw_vst3.clear() | ||||
@@ -984,7 +1050,7 @@ class CarlaSettingsW(QDialog): | |||||
if not path: continue | if not path: continue | ||||
self.ui.lw_vst3.addItem(path) | self.ui.lw_vst3.addItem(path) | ||||
elif curIndex == self.PATH_INDEX_SF2: | |||||
elif curIndex == self.PLUGINPATH_INDEX_SF2: | |||||
paths = CARLA_DEFAULT_SF2_PATH | paths = CARLA_DEFAULT_SF2_PATH | ||||
paths.sort() | paths.sort() | ||||
self.ui.lw_sf2.clear() | self.ui.lw_sf2.clear() | ||||
@@ -993,7 +1059,7 @@ class CarlaSettingsW(QDialog): | |||||
if not path: continue | if not path: continue | ||||
self.ui.lw_sf2.addItem(path) | self.ui.lw_sf2.addItem(path) | ||||
elif curIndex == self.PATH_INDEX_SFZ: | |||||
elif curIndex == self.PLUGINPATH_INDEX_SFZ: | |||||
paths = CARLA_DEFAULT_SFZ_PATH | paths = CARLA_DEFAULT_SFZ_PATH | ||||
paths.sort() | paths.sort() | ||||
self.ui.lw_sfz.clear() | self.ui.lw_sfz.clear() | ||||
@@ -1113,57 +1179,57 @@ class CarlaSettingsW(QDialog): | |||||
curIndex = self.ui.tw_paths.currentIndex() | curIndex = self.ui.tw_paths.currentIndex() | ||||
if curIndex == self.PATH_INDEX_LADSPA: | |||||
if curIndex == self.PLUGINPATH_INDEX_LADSPA: | |||||
self.ui.lw_ladspa.addItem(newPath) | self.ui.lw_ladspa.addItem(newPath) | ||||
elif curIndex == self.PATH_INDEX_DSSI: | |||||
elif curIndex == self.PLUGINPATH_INDEX_DSSI: | |||||
self.ui.lw_dssi.addItem(newPath) | self.ui.lw_dssi.addItem(newPath) | ||||
elif curIndex == self.PATH_INDEX_LV2: | |||||
elif curIndex == self.PLUGINPATH_INDEX_LV2: | |||||
self.ui.lw_lv2.addItem(newPath) | self.ui.lw_lv2.addItem(newPath) | ||||
elif curIndex == self.PATH_INDEX_VST2: | |||||
elif curIndex == self.PLUGINPATH_INDEX_VST2: | |||||
self.ui.lw_vst.addItem(newPath) | self.ui.lw_vst.addItem(newPath) | ||||
elif curIndex == self.PATH_INDEX_VST3: | |||||
elif curIndex == self.PLUGINPATH_INDEX_VST3: | |||||
self.ui.lw_vst3.addItem(newPath) | self.ui.lw_vst3.addItem(newPath) | ||||
elif curIndex == self.PATH_INDEX_SF2: | |||||
elif curIndex == self.PLUGINPATH_INDEX_SF2: | |||||
self.ui.lw_sf2.addItem(newPath) | self.ui.lw_sf2.addItem(newPath) | ||||
elif curIndex == self.PATH_INDEX_SFZ: | |||||
elif curIndex == self.PLUGINPATH_INDEX_SFZ: | |||||
self.ui.lw_sfz.addItem(newPath) | self.ui.lw_sfz.addItem(newPath) | ||||
@pyqtSlot() | @pyqtSlot() | ||||
def slot_removePluginPath(self): | def slot_removePluginPath(self): | ||||
curIndex = self.ui.tw_paths.currentIndex() | 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()) | 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()) | 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()) | 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()) | 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()) | 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()) | 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()) | self.ui.lw_sfz.takeItem(self.ui.lw_sfz.currentRow()) | ||||
@pyqtSlot() | @pyqtSlot() | ||||
def slot_changePluginPath(self): | def slot_changePluginPath(self): | ||||
curIndex = self.ui.tw_paths.currentIndex() | 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() | 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() | 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() | 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() | 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() | 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() | 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() | currentPath = self.ui.lw_sfz.currentItem().text() | ||||
else: | else: | ||||
currentPath = "" | currentPath = "" | ||||
@@ -1173,38 +1239,38 @@ class CarlaSettingsW(QDialog): | |||||
if not newPath: | if not newPath: | ||||
return | return | ||||
if curIndex == self.PATH_INDEX_LADSPA: | |||||
if curIndex == self.PLUGINPATH_INDEX_LADSPA: | |||||
self.ui.lw_ladspa.currentItem().setText(newPath) | 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) | 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) | 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) | 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) | 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) | 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) | self.ui.lw_sfz.currentItem().setText(newPath) | ||||
# -------------------------------------------------------------------------------------------------------- | # -------------------------------------------------------------------------------------------------------- | ||||
@pyqtSlot(int) | @pyqtSlot(int) | ||||
def slot_pluginPathTabChanged(self, index): | def slot_pluginPathTabChanged(self, index): | ||||
if index == self.PATH_INDEX_LADSPA: | |||||
if index == self.PLUGINPATH_INDEX_LADSPA: | |||||
row = self.ui.lw_ladspa.currentRow() | row = self.ui.lw_ladspa.currentRow() | ||||
elif index == self.PATH_INDEX_DSSI: | |||||
elif index == self.PLUGINPATH_INDEX_DSSI: | |||||
row = self.ui.lw_dssi.currentRow() | row = self.ui.lw_dssi.currentRow() | ||||
elif index == self.PATH_INDEX_LV2: | |||||
elif index == self.PLUGINPATH_INDEX_LV2: | |||||
row = self.ui.lw_lv2.currentRow() | row = self.ui.lw_lv2.currentRow() | ||||
elif index == self.PATH_INDEX_VST2: | |||||
elif index == self.PLUGINPATH_INDEX_VST2: | |||||
row = self.ui.lw_vst.currentRow() | row = self.ui.lw_vst.currentRow() | ||||
elif index == self.PATH_INDEX_VST3: | |||||
elif index == self.PLUGINPATH_INDEX_VST3: | |||||
row = self.ui.lw_vst3.currentRow() | row = self.ui.lw_vst3.currentRow() | ||||
elif index == self.PATH_INDEX_SF2: | |||||
elif index == self.PLUGINPATH_INDEX_SF2: | |||||
row = self.ui.lw_sf2.currentRow() | row = self.ui.lw_sf2.currentRow() | ||||
elif index == self.PATH_INDEX_SFZ: | |||||
elif index == self.PLUGINPATH_INDEX_SFZ: | |||||
row = self.ui.lw_sfz.currentRow() | row = self.ui.lw_sfz.currentRow() | ||||
else: | else: | ||||
row = -1 | 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): | def done(self, r): | ||||
QDialog.done(self, r) | QDialog.done(self, r) | ||||
self.close() | 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_NUMBER = "OSC/UDPNumber" | ||||
CARLA_KEY_OSC_UDP_PORT_RANDOM = "OSC/UDPRandom" | 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_LADSPA = "Paths/LADSPA" | ||||
CARLA_KEY_PATHS_DSSI = "Paths/DSSI" | CARLA_KEY_PATHS_DSSI = "Paths/DSSI" | ||||
CARLA_KEY_PATHS_LV2 = "Paths/LV2" | CARLA_KEY_PATHS_LV2 = "Paths/LV2" | ||||
@@ -303,7 +306,7 @@ if CARLA_DEFAULT_AUDIO_DRIVER == "JACK": | |||||
else: | else: | ||||
CARLA_DEFAULT_PROCESS_MODE = ENGINE_PROCESS_MODE_PATCHBAY | CARLA_DEFAULT_PROCESS_MODE = ENGINE_PROCESS_MODE_PATCHBAY | ||||
CARLA_DEFAULT_TRANSPORT_MODE = ENGINE_TRANSPORT_MODE_INTERNAL | CARLA_DEFAULT_TRANSPORT_MODE = ENGINE_TRANSPORT_MODE_INTERNAL | ||||
# OSC | # OSC | ||||
CARLA_DEFAULT_OSC_ENABLED = not WINDOWS | CARLA_DEFAULT_OSC_ENABLED = not WINDOWS | ||||
CARLA_DEFAULT_OSC_TCP_PORT_ENABLED = True | 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_PREVENT_BAD_BEHAVIOUR = False | ||||
CARLA_DEFAULT_EXPERIMENTAL_LOAD_LIB_GLOBAL = 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) | # Default Plugin Folders (get) | ||||
@@ -65,7 +65,8 @@ typedef enum { | |||||
NATIVE_PLUGIN_USES_TIME = 1 << 10, | NATIVE_PLUGIN_USES_TIME = 1 << 10, | ||||
NATIVE_PLUGIN_USES_PARENT_ID = 1 << 11, /** can set transient hint to parent */ | NATIVE_PLUGIN_USES_PARENT_ID = 1 << 11, /** can set transient hint to parent */ | ||||
NATIVE_PLUGIN_HAS_INLINE_DISPLAY = 1 << 12, | 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; | } NativePluginHints; | ||||
typedef enum { | typedef enum { | ||||
@@ -96,21 +97,24 @@ typedef enum { | |||||
NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED = 2, /** uses opt */ | NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED = 2, /** uses opt */ | ||||
NATIVE_PLUGIN_OPCODE_OFFLINE_CHANGED = 3, /** uses value (0=off, 1=on) */ | NATIVE_PLUGIN_OPCODE_OFFLINE_CHANGED = 3, /** uses value (0=off, 1=on) */ | ||||
NATIVE_PLUGIN_OPCODE_UI_NAME_CHANGED = 4, /** uses ptr */ | 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; | } NativePluginDispatcherOpcode; | ||||
typedef enum { | 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; | } NativeHostDispatcherOpcode; | ||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
@@ -27,7 +27,7 @@ | |||||
* @{ | * @{ | ||||
*/ | */ | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Native Plugin Class | // Native Plugin Class | ||||
class NativePluginClass | class NativePluginClass | ||||
@@ -225,6 +225,13 @@ protected: | |||||
pHost->dispatcher(pHost->handle, NATIVE_HOST_OPCODE_HOST_IDLE, 0, 0, nullptr, 0.0f); | 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() | void hostQueueDrawInlineDisplay() | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(pHost != nullptr,); | 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); | 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 | // Plugin parameter calls | ||||
@@ -394,6 +412,8 @@ protected: | |||||
return nullptr; | return nullptr; | ||||
} | } | ||||
virtual void idle() {} | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
private: | private: | ||||
@@ -521,6 +541,9 @@ public: | |||||
return 0; | return 0; | ||||
case NATIVE_PLUGIN_OPCODE_GET_INTERNAL_HANDLE: | case NATIVE_PLUGIN_OPCODE_GET_INTERNAL_HANDLE: | ||||
return 0; | return 0; | ||||
case NATIVE_PLUGIN_OPCODE_IDLE: | |||||
handlePtr->idle(); | |||||
return 0; | |||||
} | } | ||||
return 0; | return 0; | ||||
@@ -542,7 +565,7 @@ public: | |||||
/**@}*/ | /**@}*/ | ||||
// --------------------------------------------------------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// -Weffc++ compat ext widget | // -Weffc++ compat ext widget | ||||
extern "C" { | extern "C" { | ||||
@@ -559,7 +582,7 @@ typedef struct _NativeInlineDisplayImageSurfaceCompat { | |||||
} | } | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#define PluginClassEND(ClassName) \ | #define PluginClassEND(ClassName) \ | ||||
public: \ | public: \ | ||||
@@ -597,6 +620,6 @@ public: \ | |||||
ClassName::_render_inline_display, \ | ClassName::_render_inline_display, \ | ||||
0, 0 | 0, 0 | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#endif // CARLA_NATIVE_HPP_INCLUDED | #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 | bool add (const ElementType& newElement) noexcept | ||||
{ | { | ||||
if (! data.ensureAllocatedSize (numUsed + 1)) | |||||
if (! data.ensureAllocatedSize (static_cast<size_t>(numUsed + 1))) | |||||
return false; | return false; | ||||
new (data.elements + numUsed++) ElementType (newElement); | new (data.elements + numUsed++) ElementType (newElement); | ||||
@@ -3,7 +3,7 @@ | |||||
This file is part of the Water library. | This file is part of the Water library. | ||||
Copyright (c) 2016 ROLI Ltd. | 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 | Permission is granted to use this software under the terms of the ISC license | ||||
http://www.isc.org/downloads/software-support-policy/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. | then a shared object will be created automatically. | ||||
*/ | */ | ||||
SharedResourcePointer() | SharedResourcePointer() | ||||
: sharedObject(nullptr) | |||||
{ | { | ||||
initialise(); | initialise(); | ||||
} | } | ||||
SharedResourcePointer(const char* const v1, const char* const v2) | |||||
: sharedObject(nullptr) | |||||
{ | |||||
initialise_v2(v1, v2); | |||||
} | |||||
SharedResourcePointer (const SharedResourcePointer&) | SharedResourcePointer (const SharedResourcePointer&) | ||||
: sharedObject(nullptr) | |||||
{ | { | ||||
initialise(); | initialise(); | ||||
} | } | ||||
@@ -140,7 +148,7 @@ private: | |||||
static SharedObjectHolder& getSharedObjectHolder() noexcept | 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); | return *reinterpret_cast<SharedObjectHolder*> (holder); | ||||
} | } | ||||
@@ -157,6 +165,17 @@ private: | |||||
sharedObject = holder.sharedInstance; | 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 | // There's no need to assign to a SharedResourcePointer because every | ||||
// instance of the class is exactly the same! | // instance of the class is exactly the same! | ||||
SharedResourcePointer& operator= (const SharedResourcePointer&) WATER_DELETED_FUNCTION; | SharedResourcePointer& operator= (const SharedResourcePointer&) WATER_DELETED_FUNCTION; | ||||
@@ -47,7 +47,7 @@ namespace water { | |||||
class SpinLock | class SpinLock | ||||
{ | { | ||||
public: | public: | ||||
inline SpinLock() noexcept {} | |||||
inline SpinLock() noexcept : lock() {} | |||||
inline ~SpinLock() noexcept {} | inline ~SpinLock() noexcept {} | ||||
/** Acquires the lock. | /** Acquires the lock. | ||||
@@ -237,6 +237,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { | |||||
|NATIVE_PLUGIN_HAS_INLINE_DISPLAY | |NATIVE_PLUGIN_HAS_INLINE_DISPLAY | ||||
|NATIVE_PLUGIN_HAS_UI | |NATIVE_PLUGIN_HAS_UI | ||||
|NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | |NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | ||||
|NATIVE_PLUGIN_REQUESTS_IDLE | |||||
|NATIVE_PLUGIN_USES_TIME), | |NATIVE_PLUGIN_USES_TIME), | ||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | ||||
/* audioIns */ 0, | /* audioIns */ 0, | ||||
@@ -260,6 +261,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | ||||
|NATIVE_PLUGIN_HAS_UI | |NATIVE_PLUGIN_HAS_UI | ||||
|NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | |NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | ||||
|NATIVE_PLUGIN_REQUESTS_IDLE | |||||
|NATIVE_PLUGIN_USES_STATE | |NATIVE_PLUGIN_USES_STATE | ||||
|NATIVE_PLUGIN_USES_TIME), | |NATIVE_PLUGIN_USES_TIME), | ||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | ||||
@@ -12,22 +12,35 @@ | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
* GNU General Public License for more details. | * 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 "CarlaString.hpp" | ||||
#include "audio-base.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 AbstractAudioPlayer | ||||
{ | { | ||||
public: | public: | ||||
AudioFilePlugin(const NativeHostDescriptor* const host) | AudioFilePlugin(const NativeHostDescriptor* const host) | ||||
: NativePluginClass(host), | |||||
: NativePluginWithMidiPrograms(host, fPrograms, 2), | |||||
AbstractAudioPlayer(), | AbstractAudioPlayer(), | ||||
fLoopMode(true), | fLoopMode(true), | ||||
fDoProcess(false), | fDoProcess(false), | ||||
@@ -35,6 +48,7 @@ public: | |||||
fMaxFrame(0), | fMaxFrame(0), | ||||
fPool(), | fPool(), | ||||
fThread(this), | fThread(this), | ||||
fPrograms(hostGetFilePath("audio"), audiofilesWildcard), | |||||
fInlineDisplay() {} | fInlineDisplay() {} | ||||
~AudioFilePlugin() override | ~AudioFilePlugin() override | ||||
@@ -116,8 +130,8 @@ protected: | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Plugin process calls | // 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()); | const NativeTimeInfo* const timePos(getTimeInfo()); | ||||
@@ -254,6 +268,14 @@ protected: | |||||
uiClosed(); | uiClosed(); | ||||
} | } | ||||
// ------------------------------------------------------------------- | |||||
// Plugin state calls | |||||
void setStateFromFile(const char* const filename) override | |||||
{ | |||||
loadFilename(filename); | |||||
} | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Plugin dispatcher calls | // Plugin dispatcher calls | ||||
@@ -374,6 +396,8 @@ private: | |||||
AudioFilePool fPool; | AudioFilePool fPool; | ||||
AudioFileThread fThread; | AudioFileThread fThread; | ||||
NativeMidiPrograms fPrograms; | |||||
struct InlineDisplay : NativeInlineDisplayImageSurfaceCompat { | struct InlineDisplay : NativeInlineDisplayImageSurfaceCompat { | ||||
float lastValuesL[32]; | float lastValuesL[32]; | ||||
float lastValuesR[32]; | float lastValuesR[32]; | ||||
@@ -454,6 +478,7 @@ static const NativePluginDescriptor audiofileDesc = { | |||||
|NATIVE_PLUGIN_HAS_INLINE_DISPLAY | |NATIVE_PLUGIN_HAS_INLINE_DISPLAY | ||||
|NATIVE_PLUGIN_HAS_UI | |NATIVE_PLUGIN_HAS_UI | ||||
|NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | |NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | ||||
|NATIVE_PLUGIN_REQUESTS_IDLE | |||||
|NATIVE_PLUGIN_USES_TIME), | |NATIVE_PLUGIN_USES_TIME), | ||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | ||||
/* audioIns */ 0, | /* audioIns */ 0, | ||||
@@ -15,7 +15,7 @@ | |||||
* For a full copy of the GNU General Public License see the doc/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 "midi-base.hpp" | #include "midi-base.hpp" | ||||
#include "water/files/FileInputStream.h" | #include "water/files/FileInputStream.h" | ||||
@@ -23,15 +23,16 @@ | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
class MidiFilePlugin : public NativePluginClass, | |||||
class MidiFilePlugin : public NativePluginWithMidiPrograms<FileMIDI>, | |||||
public AbstractMidiPlayer | public AbstractMidiPlayer | ||||
{ | { | ||||
public: | public: | ||||
MidiFilePlugin(const NativeHostDescriptor* const host) | MidiFilePlugin(const NativeHostDescriptor* const host) | ||||
: NativePluginClass(host), | |||||
: NativePluginWithMidiPrograms(host, fPrograms, 0), | |||||
fMidiOut(this), | fMidiOut(this), | ||||
fNeedsAllNotesOff(false), | fNeedsAllNotesOff(false), | ||||
fWasPlayingBefore(false) {} | |||||
fWasPlayingBefore(false), | |||||
fPrograms(hostGetFilePath("midi"), "*.mid;*.midi") {} | |||||
protected: | protected: | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -51,7 +52,7 @@ protected: | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Plugin process calls | // 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()); | const NativeTimeInfo* const timePos(getTimeInfo()); | ||||
@@ -116,6 +117,11 @@ protected: | |||||
fMidiOut.setState(data); | fMidiOut.setState(data); | ||||
} | } | ||||
void setStateFromFile(const char* const filename) override | |||||
{ | |||||
_loadMidiFile(filename); | |||||
} | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// AbstractMidiPlayer calls | // AbstractMidiPlayer calls | ||||
@@ -140,6 +146,7 @@ private: | |||||
MidiPattern fMidiOut; | MidiPattern fMidiOut; | ||||
bool fNeedsAllNotesOff; | bool fNeedsAllNotesOff; | ||||
bool fWasPlayingBefore; | bool fWasPlayingBefore; | ||||
NativeMidiPrograms fPrograms; | |||||
void _loadMidiFile(const char* const filename) | void _loadMidiFile(const char* const filename) | ||||
{ | { | ||||
@@ -223,6 +230,7 @@ static const NativePluginDescriptor midifileDesc = { | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | ||||
|NATIVE_PLUGIN_HAS_UI | |NATIVE_PLUGIN_HAS_UI | ||||
|NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | |NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | ||||
|NATIVE_PLUGIN_REQUESTS_IDLE | |||||
|NATIVE_PLUGIN_USES_STATE | |NATIVE_PLUGIN_USES_STATE | ||||
|NATIVE_PLUGIN_USES_TIME), | |NATIVE_PLUGIN_USES_TIME), | ||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | ||||
@@ -79,6 +79,23 @@ const char* BinaryType2Str(const BinaryType type) noexcept | |||||
return nullptr; | 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 | static inline | ||||
const char* PluginType2Str(const PluginType type) noexcept | const char* PluginType2Str(const PluginType type) noexcept | ||||
{ | { | ||||
@@ -337,6 +354,8 @@ const char* EngineOption2Str(const EngineOption option) noexcept | |||||
return "ENGINE_OPTION_OSC_PORT_UDP"; | return "ENGINE_OPTION_OSC_PORT_UDP"; | ||||
case ENGINE_OPTION_OSC_PORT_TCP: | case ENGINE_OPTION_OSC_PORT_TCP: | ||||
return "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: | case ENGINE_OPTION_PLUGIN_PATH: | ||||
return "ENGINE_OPTION_PLUGIN_PATH"; | return "ENGINE_OPTION_PLUGIN_PATH"; | ||||
case ENGINE_OPTION_PATH_BINARIES: | case ENGINE_OPTION_PATH_BINARIES: | ||||