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>
<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>&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">
<property name="margin">
<number>2</number>
@@ -1657,7 +1926,7 @@
<item>
<widget class="QLabel" name="label_18">
<property name="text">
<string>&lt;b&gt;Paths&lt;/b&gt;</string>
<string>&lt;b&gt;Plugin Paths&lt;/b&gt;</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>

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

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



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

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


+ 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"))
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,);


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


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

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


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

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


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

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



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

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


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

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



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

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


+ 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_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)



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

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

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

+ 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
{
if (! data.ensureAllocatedSize (numUsed + 1))
if (! data.ensureAllocatedSize (static_cast<size_t>(numUsed + 1)))
return false;
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.
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;


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

@@ -47,7 +47,7 @@ namespace water {
class SpinLock
{
public:
inline SpinLock() noexcept {}
inline SpinLock() noexcept : lock() {}
inline ~SpinLock() noexcept {}
/** 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_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,


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

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


+ 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.
*/

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


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

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


Loading…
Cancel
Save