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: | |||