Browse Source

Implement automatic find of plugin wineprefix

Thanks to Jan Ypma for some base code
Closes #332
Closes #374
tags/1.9.8
falkTX 7 years ago
parent
commit
68bd68b6f1
3 changed files with 158 additions and 89 deletions
  1. +0
    -3
      resources/ui/carla_settings.ui
  2. +97
    -62
      source/backend/plugin/CarlaPluginBridge.cpp
  3. +61
    -24
      source/carla_database.py

+ 0
- 3
resources/ui/carla_settings.ui View File

@@ -1478,9 +1478,6 @@
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="cb_wine_prefix_detect">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Auto-detect Wine prefix based on plugin filename</string>
</property>


+ 97
- 62
source/backend/plugin/CarlaPluginBridge.cpp View File

@@ -30,7 +30,7 @@

#include <ctime>

// -------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------

using juce::ChildProcess;
using juce::File;
@@ -41,12 +41,27 @@ using juce::Time;

CARLA_BACKEND_START_NAMESPACE

// -------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
// Fallback data

static const ExternalMidiNote kExternalMidiNoteFallback = { -1, 0, 0 };

// -------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------

static String findWinePrefix(const String filename, const int recursionLimit = 10)
{
if (recursionLimit == 0 || filename.length() < 5 || ! filename.contains("/"))
return "";

const String path(filename.upToLastOccurrenceOf("/", false, false));

if (File(path + "/dosdevices").isDirectory())
return path;

return findWinePrefix(path, recursionLimit-1);
}

// ---------------------------------------------------------------------------------------------------------------------

struct BridgeParamInfo {
float value;
@@ -63,7 +78,7 @@ struct BridgeParamInfo {
CARLA_DECLARE_NON_COPY_STRUCT(BridgeParamInfo)
};

// -------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------

class CarlaPluginBridgeThread : public CarlaThread
{
@@ -77,12 +92,16 @@ public:
fShmIds(),
fProcess() {}

void setData(const char* const binary, const char* const label, const char* const shmIds) noexcept
void setData(const char* const winePrefix,
const char* const binary,
const char* const label,
const char* const shmIds) noexcept
{
CARLA_SAFE_ASSERT_RETURN(binary != nullptr && binary[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(shmIds != nullptr && shmIds[0] != '\0',);
CARLA_SAFE_ASSERT(! isThreadRunning());

fWinePrefix = winePrefix;
fBinary = binary;
fShmIds = shmIds;

@@ -135,41 +154,6 @@ protected:
arguments.add(options.wine.executable);
else
arguments.add("wine");

#if 0
if (options.wine.autoPrefix)
{
// TODO
}
else
#endif
if (std::getenv("WINEPREFIX") == nullptr &&
options.wine.fallbackPrefix != nullptr &&
options.wine.fallbackPrefix[0] != '\0')
{
carla_setenv("WINEPREFIX", options.wine.fallbackPrefix);
}

if (options.wine.rtPrio)
{
carla_setenv("STAGING_SHARED_MEMORY", "1");

std::snprintf(strBuf, STR_MAX, "%i", options.wine.baseRtPrio);
carla_setenv("STAGING_RT_PRIORITY_BASE", strBuf);
carla_setenv("WINE_RT", strBuf);

std::snprintf(strBuf, STR_MAX, "%i", options.wine.serverRtPrio);
carla_setenv("STAGING_RT_PRIORITY_SERVER", strBuf);
carla_setenv("WINE_SVR_RT", strBuf);
}
else
{
carla_unsetenv("STAGING_SHARED_MEMORY");
carla_unsetenv("STAGING_RT_PRIORITY_BASE");
carla_unsetenv("STAGING_RT_PRIORITY_SERVER");
carla_unsetenv("WINE_RT");
carla_unsetenv("WINE_SVR_RT");
}
}
#endif

@@ -265,7 +249,37 @@ protected:
carla_setenv("ENGINE_OPTION_FRONTEND_WIN_ID", strBuf);

carla_setenv("ENGINE_BRIDGE_SHM_IDS", fShmIds.toRawUTF8());
carla_setenv("WINEDEBUG", "-all");

#ifndef CARLA_OS_WIN
if (fWinePrefix.isNotEmpty())
{
carla_setenv("WINEDEBUG", "-all");
carla_setenv("WINEPREFIX", fWinePrefix.toRawUTF8());

if (options.wine.rtPrio)
{
carla_setenv("STAGING_SHARED_MEMORY", "1");

std::snprintf(strBuf, STR_MAX, "%i", options.wine.baseRtPrio);
carla_setenv("STAGING_RT_PRIORITY_BASE", strBuf);
carla_setenv("WINE_RT", strBuf);

std::snprintf(strBuf, STR_MAX, "%i", options.wine.serverRtPrio);
carla_setenv("STAGING_RT_PRIORITY_SERVER", strBuf);
carla_setenv("WINE_SVR_RT", strBuf);
}
else
{
carla_unsetenv("STAGING_SHARED_MEMORY");
carla_unsetenv("STAGING_RT_PRIORITY_BASE");
carla_unsetenv("STAGING_RT_PRIORITY_SERVER");
carla_unsetenv("WINE_RT");
carla_unsetenv("WINE_SVR_RT");
}

carla_stdout("Using WINEPREFIX '%s'", fWinePrefix.toRawUTF8());
}
#endif

carla_stdout("starting plugin bridge, command is:\n%s \"%s\" \"%s\" \"%s\" " P_INT64,
fBinary.toRawUTF8(), getPluginTypeAsString(kPlugin->getType()), filename.toRawUTF8(), fLabel.toRawUTF8(), kPlugin->getUniqueId());
@@ -319,6 +333,7 @@ private:
CarlaEngine* const kEngine;
CarlaPlugin* const kPlugin;

String fWinePrefix;
String fBinary;
String fLabel;
String fShmIds;
@@ -328,7 +343,7 @@ private:
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginBridgeThread)
};

// -------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------

class CarlaPluginBridge : public CarlaPlugin
{
@@ -2027,25 +2042,17 @@ public:
fShmNonRtServerControl.readCustomData(chunkFilePath, chunkFilePathSize);

String realChunkFilePath(chunkFilePath);
carla_stdout("chunk save path BEFORE => %s", realChunkFilePath.toRawUTF8());

#ifndef CARLA_OS_WIN
// Using Wine, fix temp dir
if (fBinaryType == BINARY_WIN32 || fBinaryType == BINARY_WIN64)
{
// Get WINEPREFIX
String wineDir;
if (const char* const WINEPREFIX = getenv("WINEPREFIX"))
wineDir = String(WINEPREFIX);
else
wineDir = File::getSpecialLocation(File::userHomeDirectory).getFullPathName() + "/.wine";

const StringArray driveLetterSplit(StringArray::fromTokens(realChunkFilePath, ":/", ""));
carla_stdout("chunk save path BEFORE => %s", realChunkFilePath.toRawUTF8());

realChunkFilePath = wineDir;
realChunkFilePath = fWinePrefix;
realChunkFilePath += "/drive_";
realChunkFilePath += driveLetterSplit[0].toLowerCase();
realChunkFilePath += "/";
realChunkFilePath += driveLetterSplit[1];

realChunkFilePath = realChunkFilePath.replace("\\", "/");
@@ -2054,12 +2061,10 @@ public:
#endif

File chunkFile(realChunkFilePath);
CARLA_SAFE_ASSERT_BREAK(chunkFile.existsAsFile());

if (chunkFile.existsAsFile())
{
fInfo.chunk = carla_getChunkFromBase64String(chunkFile.loadFileAsString().toRawUTF8());
chunkFile.deleteFile();
}
fInfo.chunk = carla_getChunkFromBase64String(chunkFile.loadFileAsString().toRawUTF8());
chunkFile.deleteFile();
} break;

case kPluginBridgeNonRtServerSetLatency:
@@ -2193,8 +2198,8 @@ public:
}

// ---------------------------------------------------------------

// initial values

fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientNull);
fShmNonRtClientControl.writeUInt(static_cast<uint32_t>(sizeof(BridgeRtClientData)));
fShmNonRtClientControl.writeUInt(static_cast<uint32_t>(sizeof(BridgeNonRtClientData)));
@@ -2210,7 +2215,32 @@ public:
fShmRtClientControl.writeOpcode(kPluginBridgeRtClientNull);
fShmRtClientControl.commitWrite();

// ---------------------------------------------------------------
// set wine prefix

if (fBridgeBinary.contains(".exe", true))
{
const EngineOptions& options(pData->engine->getOptions());

if (options.wine.autoPrefix)
fWinePrefix = findWinePrefix(pData->filename);

if (fWinePrefix.isEmpty())
{
const char* const envWinePrefix(std::getenv("WINEPREFIX"));

if (envWinePrefix != nullptr && envWinePrefix[0] != '\0')
fWinePrefix = envWinePrefix;
else if (options.wine.fallbackPrefix != nullptr && options.wine.fallbackPrefix[0] != '\0')
fWinePrefix = options.wine.fallbackPrefix;
else
fWinePrefix = File::getSpecialLocation(File::userHomeDirectory).getFullPathName() + "/.wine";
}
}

// ---------------------------------------------------------------
// init bridge thread

{
char shmIdsStr[6*4+1];
carla_zeroChars(shmIdsStr, 6*4+1);
@@ -2220,10 +2250,13 @@ public:
std::strncpy(shmIdsStr+6*2, &fShmNonRtClientControl.filename[fShmNonRtClientControl.filename.length()-6], 6);
std::strncpy(shmIdsStr+6*3, &fShmNonRtServerControl.filename[fShmNonRtServerControl.filename.length()-6], 6);

fBridgeThread.setData(bridgeBinary, label, shmIdsStr);
fBridgeThread.setData(fWinePrefix.toRawUTF8(), bridgeBinary, label, shmIdsStr);
fBridgeThread.startThread();
}

// ---------------------------------------------------------------
// wait for bridge to start

fInitiated = false;
fLastPongTime = Time::currentTimeMillis();
CARLA_SAFE_ASSERT(fLastPongTime > 0);
@@ -2314,6 +2347,8 @@ private:
BridgeNonRtClientControl fShmNonRtClientControl;
BridgeNonRtServerControl fShmNonRtServerControl;

String fWinePrefix;

struct Info {
uint32_t aIns, aOuts;
uint32_t cvIns, cvOuts;
@@ -2381,7 +2416,7 @@ private:

CARLA_BACKEND_END_NAMESPACE

// -------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------

CARLA_BACKEND_START_NAMESPACE

@@ -2414,10 +2449,10 @@ CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, P

CARLA_BACKEND_END_NAMESPACE

// -------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------

#ifndef BUILD_BRIDGE
# include "CarlaBridgeUtils.cpp"
#endif

// -------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------

+ 61
- 24
source/carla_database.py View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-

# Carla plugin database code
# Copyright (C) 2011-2016 Filipe Coelho <falktx@falktx.com>
# Copyright (C) 2011-2017 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
@@ -162,7 +162,18 @@ PyPluginInfo = {
global gDiscoveryProcess
gDiscoveryProcess = None

def runCarlaDiscovery(itype, stype, filename, tool, isWine=False):
def findWinePrefix(filename, recursionLimit = 10):
if recursionLimit == 0 or len(filename) < 5 or "/" not in filename:
return ""

path = filename[:filename.rfind("/")]

if os.path.isdir(path + "/dosdevices"):
return path

return findWinePrefix(path, recursionLimit-1)

def runCarlaDiscovery(itype, stype, filename, tool, wineSettings=None):
if not os.path.exists(tool):
qWarning("runCarlaDiscovery() - tool '%s' does not exist" % tool)
return
@@ -173,9 +184,26 @@ def runCarlaDiscovery(itype, stype, filename, tool, isWine=False):
command.append("env")
command.append("LANG=C")
command.append("LD_PRELOAD=")
if isWine:
if wineSettings is not None:
command.append("WINEDEBUG=-all")
command.append("wine")

if wineSettings['autoPrefix']:
winePrefix = findWinePrefix(filename)
else:
winePrefix = ""

if not winePrefix:
envWinePrefix = os.getenv("WINEPREFIX")

if envWinePrefix:
winePrefix = envWinePrefix
elif wineSettings['fallbackPrefix']:
winePrefix = os.path.expanduser(wineSettings['fallbackPrefix'])
else:
winePrefix = os.path.expanduser("~/.wine")

command.append("WINEPREFIX=" + winePrefix)
command.append(wineSettings['executable'] if wineSettings['executable'] else "wine")

command.append(tool)
command.append(stype)
@@ -314,32 +342,32 @@ def checkPluginCached(desc, ptype):

return plugins

def checkPluginLADSPA(filename, tool, isWine=False):
return runCarlaDiscovery(PLUGIN_LADSPA, "LADSPA", filename, tool, isWine)
def checkPluginLADSPA(filename, tool, wineSettings=None):
return runCarlaDiscovery(PLUGIN_LADSPA, "LADSPA", filename, tool, wineSettings)

def checkPluginDSSI(filename, tool, isWine=False):
return runCarlaDiscovery(PLUGIN_DSSI, "DSSI", filename, tool, isWine)
def checkPluginDSSI(filename, tool, wineSettings=None):
return runCarlaDiscovery(PLUGIN_DSSI, "DSSI", filename, tool, wineSettings)

def checkPluginLV2(filename, tool, isWine=False):
return runCarlaDiscovery(PLUGIN_LV2, "LV2", filename, tool, isWine)
def checkPluginLV2(filename, tool, wineSettings=None):
return runCarlaDiscovery(PLUGIN_LV2, "LV2", filename, tool, wineSettings)

def checkPluginVST2(filename, tool, isWine=False):
return runCarlaDiscovery(PLUGIN_VST2, "VST2", filename, tool, isWine)
def checkPluginVST2(filename, tool, wineSettings=None):
return runCarlaDiscovery(PLUGIN_VST2, "VST2", filename, tool, wineSettings)

def checkPluginVST3(filename, tool, isWine=False):
return runCarlaDiscovery(PLUGIN_VST3, "VST3", filename, tool, isWine)
def checkPluginVST3(filename, tool, wineSettings=None):
return runCarlaDiscovery(PLUGIN_VST3, "VST3", filename, tool, wineSettings)

def checkPluginAU(tool):
return runCarlaDiscovery(PLUGIN_AU, "AU", ":all", tool)
return runCarlaDiscovery(None, PLUGIN_AU, "AU", ":all", tool)

def checkFileGIG(filename, tool):
return runCarlaDiscovery(PLUGIN_GIG, "GIG", filename, tool)
return runCarlaDiscovery(None, PLUGIN_GIG, "GIG", filename, tool)

def checkFileSF2(filename, tool):
return runCarlaDiscovery(PLUGIN_SF2, "SF2", filename, tool)
return runCarlaDiscovery(None, PLUGIN_SF2, "SF2", filename, tool)

def checkFileSFZ(filename, tool):
return runCarlaDiscovery(PLUGIN_SFZ, "SFZ", filename, tool)
return runCarlaDiscovery(None, PLUGIN_SFZ, "SFZ", filename, tool)

# ----------------------------------------------------------------------------------------------------------------------
# Separate Thread for Plugin Search
@@ -371,9 +399,19 @@ class SearchPluginsThread(QThread):

if WINDOWS:
toolNative = "carla-discovery-win64.exe" if kIs64bit else "carla-discovery-win32.exe"
self.fWineSettings = None

else:
toolNative = "carla-discovery-native"

settings = QSettings("falkTX", "Carla2")
self.fWineSettings = {
'executable' : settings.value(CARLA_KEY_WINE_EXECUTABLE, CARLA_DEFAULT_WINE_EXECUTABLE, type=str),
'autoPrefix' : settings.value(CARLA_KEY_WINE_AUTO_PREFIX, CARLA_DEFAULT_WINE_AUTO_PREFIX, type=bool),
'fallbackPrefix': settings.value(CARLA_KEY_WINE_FALLBACK_PREFIX, CARLA_DEFAULT_WINE_FALLBACK_PREFIX, type=str)
}
del settings

self.fToolNative = os.path.join(pathBinaries, toolNative)

if not os.path.exists(self.fToolNative):
@@ -713,7 +751,7 @@ class SearchPluginsThread(QThread):
percent = ( float(i) / len(ladspaBinaries) ) * self.fCurPercentValue
self._pluginLook((self.fLastCheckValue + percent) * 0.9, ladspa)

plugins = checkPluginLADSPA(ladspa, tool, isWine)
plugins = checkPluginLADSPA(ladspa, tool, self.fWineSettings if isWine else None)
if plugins:
self.fLadspaPlugins.append(plugins)

@@ -746,7 +784,7 @@ class SearchPluginsThread(QThread):
percent = ( float(i) / len(dssiBinaries) ) * self.fCurPercentValue
self._pluginLook(self.fLastCheckValue + percent, dssi)

plugins = checkPluginDSSI(dssi, tool, isWine)
plugins = checkPluginDSSI(dssi, tool, self.fWineSettings if isWine else None)
if plugins:
self.fDssiPlugins.append(plugins)

@@ -785,7 +823,7 @@ class SearchPluginsThread(QThread):
percent = ( float(i) / len(vst2Binaries) ) * self.fCurPercentValue
self._pluginLook(self.fLastCheckValue + percent, vst2)

plugins = checkPluginVST2(vst2, tool, isWine)
plugins = checkPluginVST2(vst2, tool, self.fWineSettings if isWine else None)
if plugins:
self.fVstPlugins.append(plugins)

@@ -824,7 +862,7 @@ class SearchPluginsThread(QThread):
percent = ( float(i) / len(vst3Binaries) ) * self.fCurPercentValue
self._pluginLook(self.fLastCheckValue + percent, vst3)

plugins = checkPluginVST3(vst3, tool, isWine)
plugins = checkPluginVST3(vst3, tool, self.fWineSettings if isWine else None)
if plugins:
self.fVst3Plugins.append(plugins)

@@ -928,8 +966,7 @@ class PluginRefreshW(QDialog):

if False:
# kdevelop likes this :)
host = CarlaHostNull()
self.host = host
self.host = host = CarlaHostNull()

# --------------------------------------------------------------------------------------------------------------
# Internal stuff


Loading…
Cancel
Save