Browse Source

Initial work for file type paths, use it for audio and midi plugins

Signed-off-by: falkTX <falktx@falktx.com>
tags/v2.1-rc1
falkTX 5 years ago
parent
commit
2cb6fa1960
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
22 changed files with 1036 additions and 138 deletions
  1. +306
    -5
      resources/ui/carla_settings.ui
  2. +43
    -13
      source/backend/CarlaBackend.h
  3. +3
    -0
      source/backend/CarlaEngine.hpp
  4. +32
    -0
      source/backend/CarlaStandalone.cpp
  5. +30
    -1
      source/backend/engine/CarlaEngine.cpp
  6. +12
    -10
      source/backend/engine/CarlaEngineData.cpp
  7. +3
    -0
      source/backend/engine/CarlaEngineNative.cpp
  8. +26
    -2
      source/backend/plugin/CarlaPluginNative.cpp
  9. +30
    -13
      source/frontend/carla_backend.py
  10. +9
    -0
      source/frontend/carla_host.py
  11. +193
    -60
      source/frontend/carla_settings.py
  12. +10
    -1
      source/frontend/carla_shared.py
  13. +17
    -13
      source/includes/CarlaNative.h
  14. +27
    -4
      source/includes/CarlaNative.hpp
  15. +206
    -0
      source/includes/CarlaNativePrograms.hpp
  16. +1
    -1
      source/modules/water/containers/Array.h
  17. +21
    -2
      source/modules/water/memory/SharedResourcePointer.h
  18. +1
    -1
      source/modules/water/threads/SpinLock.h
  19. +2
    -0
      source/native-plugins/_data.cpp
  20. +32
    -7
      source/native-plugins/audio-file.cpp
  21. +13
    -5
      source/native-plugins/midi-file.cpp
  22. +19
    -0
      source/utils/CarlaBackendUtils.hpp

+ 306
- 5
resources/ui/carla_settings.ui View File

@@ -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>&lt;b&gt;File Paths&lt;/b&gt;</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 &quot;audiofile&quot; 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 &quot;midifile&quot; 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>&lt;b&gt;Paths&lt;/b&gt;</string>
<string>&lt;b&gt;Plugin Paths&lt;/b&gt;</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>

+ 43
- 13
source/backend/CarlaBackend.h View File

@@ -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;




+ 3
- 0
source/backend/CarlaEngine.hpp View File

@@ -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;


+ 32
- 0
source/backend/CarlaStandalone.cpp View File

@@ -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,);


+ 30
- 1
source/backend/engine/CarlaEngine.cpp View File

@@ -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;


+ 12
- 10
source/backend/engine/CarlaEngineData.cpp View File

@@ -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;


+ 3
- 0
source/backend/engine/CarlaEngineNative.cpp View File

@@ -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;


+ 26
- 2
source/backend/plugin/CarlaPluginNative.cpp View File

@@ -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;




+ 30
- 13
source/frontend/carla_backend.py View File

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


+ 9
- 0
source/frontend/carla_host.py View File

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




+ 193
- 60
source/frontend/carla_settings.py View File

@@ -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()


+ 10
- 1
source/frontend/carla_shared.py View File

@@ -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)




+ 17
- 13
source/includes/CarlaNative.h View File

@@ -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
- 4
source/includes/CarlaNative.hpp View File

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

+ 206
- 0
source/includes/CarlaNativePrograms.hpp View File

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

+ 1
- 1
source/modules/water/containers/Array.h View File

@@ -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);


+ 21
- 2
source/modules/water/memory/SharedResourcePointer.h View File

@@ -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;


+ 1
- 1
source/modules/water/threads/SpinLock.h View File

@@ -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.


+ 2
- 0
source/native-plugins/_data.cpp View File

@@ -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,


+ 32
- 7
source/native-plugins/audio-file.cpp View File

@@ -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,


+ 13
- 5
source/native-plugins/midi-file.cpp View File

@@ -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,


+ 19
- 0
source/utils/CarlaBackendUtils.hpp View File

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


Loading…
Cancel
Save