Browse Source

Merge branch 'develop' of github.com:falkTX/Carla into develop

tags/v2.3.0-RC1
falkTX 4 years ago
parent
commit
b7ba3ca9a9
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
23 changed files with 425 additions and 156 deletions
  1. +6
    -0
      INSTALL.md
  2. +1
    -1
      data/macos/common.env
  3. +4
    -3
      data/macos/env.sh
  4. +2
    -1
      source/Makefile.mk
  5. +2
    -1
      source/backend/CarlaPlugin.hpp
  6. +52
    -10
      source/backend/engine/CarlaEngine.cpp
  7. +20
    -9
      source/backend/engine/CarlaEngineBridge.cpp
  8. +5
    -3
      source/backend/engine/CarlaEngineDummy.cpp
  9. +33
    -15
      source/backend/plugin/CarlaPluginBridge.cpp
  10. +32
    -2
      source/backend/plugin/CarlaPluginJuce.cpp
  11. +57
    -4
      source/backend/plugin/CarlaPluginLV2.cpp
  12. +1
    -0
      source/backend/plugin/CarlaPluginVST2.cpp
  13. +22
    -3
      source/bridges-plugin/CarlaBridgePlugin.cpp
  14. +9
    -0
      source/bridges-ui/CarlaBridgeFormatLV2.cpp
  15. +16
    -0
      source/discovery/carla-discovery.cpp
  16. +12
    -0
      source/frontend/widgets/racklistwidget.py
  17. +108
    -47
      source/native-plugins/audio-base.hpp
  18. +16
    -31
      source/native-plugins/audio-file.cpp
  19. +6
    -24
      source/native-plugins/midi-file.cpp
  20. +4
    -2
      source/utils/CarlaBinaryUtils.hpp
  21. +7
    -0
      source/utils/CarlaMacUtils.cpp
  22. +5
    -0
      source/utils/CarlaMacUtils.hpp
  23. +5
    -0
      source/utils/CarlaMutex.hpp

+ 6
- 0
INSTALL.md View File

@@ -1,5 +1,11 @@
# INSTALL for Carla

NOTE: when using MSYS2 on Windows, an additional step is necessary in order
to solve an issue with symbolic links to some dependency folders before build:
```
$ make msys2fix
```

To install Carla, simply run as usual:
```
$ make


+ 1
- 1
data/macos/common.env View File

@@ -1,6 +1,6 @@
#!/bin/bash

if [ "$(uname -m)" = "arm64" ]; then
if [ "$(uname -m)" = "arm64" ] || [ "$(uname -r)" = "20.1.0" ]; then
MACOS_UNIVERSAL=1
else
MACOS_UNIVERSAL=0


+ 4
- 3
data/macos/env.sh View File

@@ -13,7 +13,7 @@ fi

export CC=clang
export CXX=clang++
export CFLAGS="-I${TARGETDIR}/carla64/include -mmacosx-version-min=${MACOS_VERSION_MIN}"
export CFLAGS="-I${TARGETDIR}/carla64/include -mmacosx-version-min=${MACOS_VERSION_MIN} -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_12"
export CFLAGS="${CFLAGS} -mtune=generic -msse -msse2"
export LDFLAGS="-L${TARGETDIR}/carla64/lib -stdlib=libc++"
unset CPPFLAGS
@@ -21,9 +21,10 @@ unset CPPFLAGS
if [ "${MACOS_UNIVERSAL}" -eq 1 ]; then
export CFLAGS="${CFLAGS} -arch x86_64 -arch arm64"
export LDFLAGS="${LDFLAGS} -arch x86_64 -arch arm64"
export MACOS_UNIVERSAL="true"
else
export CFLAGS="${CFLAGS} -m${ARCH}"
export LDFLAGS="${LDFLAGS} -m${ARCH}"
export CFLAGS="${CFLAGS} -m64"
export LDFLAGS="${LDFLAGS} -m64"
fi

export CXXFLAGS="${CFLAGS} -stdlib=libc++ -Wno-unknown-pragmas -Wno-unused-private-field -Werror=auto-var-id"


+ 2
- 1
source/Makefile.mk View File

@@ -359,7 +359,8 @@ ifeq ($(shell $(PKG_CONFIG) --exists libmagic && echo true),true)
HAVE_LIBMAGIC = true
else
# old libmagic versions don't have a pkg-config file, so we need to call the compiler to test it
HAVE_LIBMAGIC = $(shell echo '\#include <magic.h>' | $(CC) $(CFLAGS) -x c -w -c - -o /dev/null 2>/dev/null && echo true)
CFLAGS_WITHOUT_ARCH = $(subst -arch arm64,,$(CFLAGS))
HAVE_LIBMAGIC = $(shell echo '\#include <magic.h>' | $(CC) $(CFLAGS_WITHOUT_ARCH) -x c -w -c - -o /dev/null 2>/dev/null && echo true)
endif

endif


+ 2
- 1
source/backend/CarlaPlugin.hpp View File

@@ -964,7 +964,8 @@ public:

static CarlaPluginPtr newNative(const Initializer& init);
static CarlaPluginPtr newBridge(const Initializer& init,
BinaryType btype, PluginType ptype, const char* bridgeBinary);
BinaryType btype, PluginType ptype,
const char* binaryArchName, const char* bridgeBinary);

static CarlaPluginPtr newLADSPA(const Initializer& init, const LADSPA_RDF_Descriptor* rdfDescriptor);
static CarlaPluginPtr newDSSI(const Initializer& init);


+ 52
- 10
source/backend/engine/CarlaEngine.cpp View File

@@ -44,6 +44,13 @@
#include "water/xml/XmlDocument.h"
#include "water/xml/XmlElement.h"

#ifdef CARLA_OS_MAC
# include "CarlaMacUtils.hpp"
# if defined(CARLA_OS_64BIT) && defined(HAVE_LIBMAGIC) && ! defined(BUILD_BRIDGE_ALTERNATIVE_ARCH)
# define ADAPT_FOR_APPLE_SILLICON
# endif
#endif

#include <map>

// FIXME Remove on 2.1 release
@@ -560,12 +567,27 @@ bool CarlaEngine::addPlugin(const BinaryType btype,
bridgeBinary.clear();
}

const bool canBeBridged = ptype != PLUGIN_INTERNAL
&& ptype != PLUGIN_DLS
&& ptype != PLUGIN_GIG
&& ptype != PLUGIN_SF2
&& ptype != PLUGIN_SFZ
&& ptype != PLUGIN_JACK;

// Prefer bridges for some specific plugins
const bool preferBridges = pData->options.preferPluginBridges;
bool preferBridges = pData->options.preferPluginBridges;
const char* needsArchBridge = nullptr;

#if 0 // ndef BUILD_BRIDGE
if (! preferBridges)
#ifdef CARLA_OS_MAC
// Plugin might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
if (canBeBridged && ptype != PLUGIN_LV2 && ptype != PLUGIN_AU)
removeFileFromQuarantine(filename);
#endif

#ifndef BUILD_BRIDGE
if (canBeBridged && ! preferBridges)
{
# if 0
if (ptype == PLUGIN_LV2 && label != nullptr)
{
if (std::strncmp(label, "http://calf.sourceforge.net/plugins/", 36) == 0 ||
@@ -575,19 +597,39 @@ bool CarlaEngine::addPlugin(const BinaryType btype,
preferBridges = true;
}
}
# endif
# ifdef ADAPT_FOR_APPLE_SILLICON
// see if this binary needs bridging
if (ptype == PLUGIN_VST2)
{
if (const char* const vst2Binary = findBinaryInBundle(filename))
{
const CarlaMagic magic;
if (const char* const output = magic.getFileDescription(vst2Binary))
{
# ifdef __aarch64__
if (std::strstr(output, "arm64") == nullptr && std::strstr(output, "x86_64") != nullptr)
needsArchBridge = "x86_64";
# else
if (std::strstr(output, "x86_64") == nullptr && std::strstr(output, "arm64") != nullptr)
needsArchBridge = "arm64";
# endif
}
}
}
else if (ptype == PLUGIN_VST3)
{
// TODO
}
# endif
}
#endif // ! BUILD_BRIDGE

const bool canBeBridged = ptype != PLUGIN_INTERNAL
&& ptype != PLUGIN_SF2
&& ptype != PLUGIN_SFZ
&& ptype != PLUGIN_JACK;

if (canBeBridged && (btype != BINARY_NATIVE || (preferBridges && bridgeBinary.isNotEmpty())))
if (canBeBridged && (needsArchBridge || btype != BINARY_NATIVE || (preferBridges && bridgeBinary.isNotEmpty())))
{
if (bridgeBinary.isNotEmpty())
{
plugin = CarlaPlugin::newBridge(initializer, btype, ptype, bridgeBinary);
plugin = CarlaPlugin::newBridge(initializer, btype, ptype, needsArchBridge, bridgeBinary);
}
else
{


+ 20
- 9
source/backend/engine/CarlaEngineBridge.cpp View File

@@ -143,49 +143,56 @@ public:

if (! fShmAudioPool.attachClient(fBaseNameAudioPool))
{
carla_stderr("Failed to attach to audio pool shared memory");
pData->close();
setLastError("Failed to attach to audio pool shared memory");
return false;
}

if (! fShmRtClientControl.attachClient(fBaseNameRtClientControl))
{
pData->close();
clear();
carla_stderr("Failed to attach to rt client control shared memory");
setLastError("Failed to attach to rt client control shared memory");
return false;
}

if (! fShmRtClientControl.mapData())
{
pData->close();
clear();
carla_stderr("Failed to map rt client control shared memory");
setLastError("Failed to map rt client control shared memory");
return false;
}

if (! fShmNonRtClientControl.attachClient(fBaseNameNonRtClientControl))
{
pData->close();
clear();
carla_stderr("Failed to attach to non-rt client control shared memory");
setLastError("Failed to attach to non-rt client control shared memory");
return false;
}

if (! fShmNonRtClientControl.mapData())
{
pData->close();
clear();
carla_stderr("Failed to map non-rt control client shared memory");
setLastError("Failed to map non-rt control client shared memory");
return false;
}

if (! fShmNonRtServerControl.attachClient(fBaseNameNonRtServerControl))
{
pData->close();
clear();
carla_stderr("Failed to attach to non-rt server control shared memory");
setLastError("Failed to attach to non-rt server control shared memory");
return false;
}

if (! fShmNonRtServerControl.mapData())
{
pData->close();
clear();
carla_stderr("Failed to map non-rt control server shared memory");
setLastError("Failed to map non-rt control server shared memory");
return false;
}

@@ -210,7 +217,9 @@ public:
shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) ||
shmNonRtServerDataSize != sizeof(BridgeNonRtServerData))
{
carla_stderr2("CarlaEngineBridge: data size mismatch");
pData->close();
clear();
setLastError("Shared memory data size mismatch");
return false;
}

@@ -222,7 +231,9 @@ public:

if (pData->bufferSize == 0 || carla_isZero(pData->sampleRate))
{
carla_stderr2("CarlaEngineBridge: invalid empty state");
pData->close();
clear();
setLastError("Shared memory has invalid data");
return false;
}



+ 5
- 3
source/backend/engine/CarlaEngineDummy.cpp View File

@@ -232,9 +232,11 @@ protected:
carla_zeroFloats(audioIns[1], bufferSize);
carla_zeroStructs(pData->events.in, kMaxEngineEventInternalCount);

int64_t oldTime, newTime;

while (! shouldThreadExit())
{
const int64_t oldTime = getTimeInMicroseconds();
oldTime = getTimeInMicroseconds();

const PendingRtEventsRunner prt(this, bufferSize, true);

@@ -244,7 +246,7 @@ protected:

pData->graph.process(pData, audioIns, audioOuts, bufferSize);

const int64_t newTime = getTimeInMicroseconds();
newTime = getTimeInMicroseconds();
CARLA_SAFE_ASSERT_CONTINUE(newTime >= oldTime);

const int64_t remainingTime = cycleTime - (newTime - oldTime);
@@ -267,7 +269,7 @@ protected:
std::free(audioOuts[0]);
std::free(audioOuts[1]);

carla_stdout("CarlaEngineDummy audio thread finished");
carla_stdout("CarlaEngineDummy audio thread finished with %u Xruns", pData->xruns);
}

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


+ 33
- 15
source/backend/plugin/CarlaPluginBridge.cpp View File

@@ -91,7 +91,8 @@ public:
: CarlaThread("CarlaPluginBridgeThread"),
kEngine(engine),
kPlugin(plugin),
fBinary(),
fBinaryArchName(),
fBridgeBinary(),
fLabel(),
fShmIds(),
#ifndef CARLA_OS_WIN
@@ -103,18 +104,20 @@ public:
#ifndef CARLA_OS_WIN
const char* const winePrefix,
#endif
const char* const binary,
const char* const binaryArchName,
const char* const bridgeBinary,
const char* const label,
const char* const shmIds) noexcept
{
CARLA_SAFE_ASSERT_RETURN(binary != nullptr && binary[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(bridgeBinary != nullptr && bridgeBinary[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(shmIds != nullptr && shmIds[0] != '\0',);
CARLA_SAFE_ASSERT(! isThreadRunning());

#ifndef CARLA_OS_WIN
fWinePrefix = winePrefix;
#endif
fBinary = binary;
fBinaryArchName = binaryArchName;
fBridgeBinary = bridgeBinary;
fShmIds = shmIds;

if (label != nullptr)
@@ -160,7 +163,7 @@ protected:

#ifndef CARLA_OS_WIN
// start with "wine" if needed
if (fBinary.endsWithIgnoreCase(".exe"))
if (fBridgeBinary.endsWithIgnoreCase(".exe"))
{
String wineCMD;

@@ -168,7 +171,7 @@ protected:
{
wineCMD = options.wine.executable;

if (fBinary.endsWithIgnoreCase("64.exe")
if (fBridgeBinary.endsWithIgnoreCase("64.exe")
&& options.wine.executable[0] == CARLA_OS_SEP
&& File(wineCMD + "64").existsAsFile())
wineCMD += "64";
@@ -182,8 +185,18 @@ protected:
}
#endif

// binary
arguments.add(fBinary);
#ifdef CARLA_OS_MAC
// setup binary arch
if (fBinaryArchName.isNotEmpty())
{
arguments.add("arch");
arguments.add("-arch");
arguments.add(fBinaryArchName);
}
#endif

// bridge binary
arguments.add(fBridgeBinary);

// plugin type
arguments.add(getPluginTypeAsString(kPlugin->getType()));
@@ -309,7 +322,7 @@ protected:
#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());
fBridgeBinary.toRawUTF8(), getPluginTypeAsString(kPlugin->getType()), filename.toRawUTF8(), fLabel.toRawUTF8(), kPlugin->getUniqueId());

started = fProcess->start(arguments);
}
@@ -361,7 +374,8 @@ private:
CarlaEngine* const kEngine;
CarlaPlugin* const kPlugin;

String fBinary;
String fBinaryArchName;
String fBridgeBinary;
String fLabel;
String fShmIds;
#ifndef CARLA_OS_WIN
@@ -2543,6 +2557,7 @@ public:
const char* const label,
const int64_t uniqueId,
const uint options,
const char* const binaryArchName,
const char* const bridgeBinary)
{
CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false);
@@ -2652,7 +2667,7 @@ public:
#ifndef CARLA_OS_WIN
fWinePrefix.toRawUTF8(),
#endif
bridgeBinary, label, shmIdsStr);
binaryArchName, bridgeBinary, label, shmIdsStr);
}

if (! restartBridgeThread())
@@ -3136,11 +3151,14 @@ CARLA_BACKEND_END_NAMESPACE
CARLA_BACKEND_START_NAMESPACE

CarlaPluginPtr CarlaPlugin::newBridge(const Initializer& init,
BinaryType btype, PluginType ptype, const char* bridgeBinary)
const BinaryType btype,
const PluginType ptype,
const char* const binaryArchName,
const char* bridgeBinary)
{
carla_debug("CarlaPlugin::newBridge({%p, \"%s\", \"%s\", \"%s\"}, %s, %s, \"%s\")",
carla_debug("CarlaPlugin::newBridge({%p, \"%s\", \"%s\", \"%s\"}, %s, %s, \"%s\", \"%s\")",
init.engine, init.filename, init.name, init.label,
BinaryType2Str(btype), PluginType2Str(ptype), bridgeBinary);
BinaryType2Str(btype), PluginType2Str(ptype), binaryArchName, bridgeBinary);

if (bridgeBinary == nullptr || bridgeBinary[0] == '\0')
{
@@ -3156,7 +3174,7 @@ CarlaPluginPtr CarlaPlugin::newBridge(const Initializer& init,

std::shared_ptr<CarlaPluginBridge> plugin(new CarlaPluginBridge(init.engine, init.id, btype, ptype));

if (! plugin->init(plugin, init.filename, init.name, init.label, init.uniqueId, init.options, bridgeBinary))
if (! plugin->init(plugin, init.filename, init.name, init.label, init.uniqueId, init.options, binaryArchName, bridgeBinary))
return nullptr;

return plugin;


+ 32
- 2
source/backend/plugin/CarlaPluginJuce.cpp View File

@@ -1378,7 +1378,28 @@ public:
fDesc.name = label;
}

fFormatManager.addDefaultFormats();
/**/ if (std::strcmp(format, "AU") == 0)
{
#if JUCE_PLUGINHOST_AU
fFormatManager.addFormat(new juce::AudioUnitPluginFormat());
#endif
}
else if (std::strcmp(format, "VST2") == 0)
{
#if JUCE_PLUGINHOST_VST
fFormatManager.addFormat(new juce::VSTPluginFormat());
#endif
}
else if (std::strcmp(format, "VST3") == 0)
{
#if JUCE_PLUGINHOST_VST3
fFormatManager.addFormat(new juce::VST3PluginFormat());
#endif
}
else
{
fFormatManager.addDefaultFormats();
}

{
juce::OwnedArray<juce::PluginDescription> pluginDescriptions;
@@ -1389,12 +1410,18 @@ public:

for (int i = 0; i < fFormatManager.getNumFormats(); ++i)
{
juce::AudioPluginFormat* const apformat = fFormatManager.getFormat(i);
CARLA_SAFE_ASSERT_CONTINUE(apformat != nullptr);

carla_debug("Trying to load '%s' plugin with format '%s'", fileOrIdentifier.toRawUTF8(), apformat->getName().toRawUTF8());

try {
plist.scanAndAddFile(fileOrIdentifier, true, pluginDescriptions, *fFormatManager.getFormat(i));
plist.scanAndAddFile(fileOrIdentifier, true, pluginDescriptions, *apformat);
} CARLA_SAFE_EXCEPTION_CONTINUE("scanAndAddFile")

if (sac.wasTriggered())
{
carla_stderr("WARNING: Caught exception while scanning file, will not load this plugin");
pluginDescriptions.clearQuick(false);
break;
}
@@ -1426,7 +1453,10 @@ public:
} CARLA_SAFE_EXCEPTION("createPluginInstance")

if (sac.wasTriggered())
{
fInstance = nullptr;
carla_stderr("WARNING: Caught exception while instantiating, will not load this plugin");
}
}

if (fInstance == nullptr)


+ 57
- 4
source/backend/plugin/CarlaPluginLV2.cpp View File

@@ -41,6 +41,14 @@ extern "C" {
#include "water/files/File.h"
#include "water/misc/Time.h"

#ifdef CARLA_OS_MAC
# include "CarlaMacUtils.hpp"
# if defined(CARLA_OS_64BIT) && defined(HAVE_LIBMAGIC) && ! defined(BUILD_BRIDGE_ALTERNATIVE_ARCH)
# define ADAPT_FOR_APPLE_SILLICON
# include "CarlaBinaryUtils.hpp"
# endif
#endif

#include <string>
#include <vector>

@@ -6249,7 +6257,8 @@ public:

public:
bool init(const CarlaPluginPtr plugin,
const char* const name, const char* const uri, const uint options)
const char* const name, const char* const uri, const uint options,
const char*& needsArchBridge)
{
CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false);

@@ -6293,9 +6302,36 @@ public:
return false;
}

#ifdef ADAPT_FOR_APPLE_SILLICON
// ---------------------------------------------------------------
// check if we can open this binary, might need a bridge

{
const CarlaMagic magic;

if (const char* const output = magic.getFileDescription(fRdfDescriptor->Binary))
{
# ifdef __aarch64__
if (std::strstr(output, "arm64") == nullptr && std::strstr(output, "x86_64") != nullptr)
needsArchBridge = "x86_64";
# else
if (std::strstr(output, "x86_64") == nullptr && std::strstr(output, "arm64") != nullptr)
needsArchBridge = "arm64";
# endif
if (needsArchBridge != nullptr)
return false;
}
}
#endif // ADAPT_FOR_APPLE_SILLICON

// ---------------------------------------------------------------
// open DLL

#ifdef CARLA_OS_MAC
// Binary might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
removeFileFromQuarantine(fRdfDescriptor->Binary);
#endif

if (! pData->libOpen(fRdfDescriptor->Binary))
{
pData->engine->setLastError(pData->libError(fRdfDescriptor->Binary));
@@ -6712,6 +6748,9 @@ public:
initUi();

return true;

// might be unused
(void)needsArchBridge;
}

// -------------------------------------------------------------------
@@ -6961,6 +7000,11 @@ public:
// ---------------------------------------------------------------
// open UI DLL

#ifdef CARLA_OS_MAC
// Binary might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
removeFileFromQuarantine(fUI.rdfDescriptor->Binary);
#endif

if (! pData->uiLibOpen(fUI.rdfDescriptor->Binary, canDelete))
{
carla_stderr2("Could not load UI library, error was:\n%s", pData->libError(fUI.rdfDescriptor->Binary));
@@ -8103,10 +8147,19 @@ CarlaPluginPtr CarlaPlugin::newLV2(const Initializer& init)

std::shared_ptr<CarlaPluginLV2> plugin(new CarlaPluginLV2(init.engine, init.id));

if (! plugin->init(plugin, init.name, init.label, init.options))
return nullptr;
const char* needsArchBridge = nullptr;
if (plugin->init(plugin, init.name, init.label, init.options, needsArchBridge))
return plugin;

if (needsArchBridge != nullptr)
{
CarlaString bridgeBinary(init.engine->getOptions().binaryDir);
bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-native";

return CarlaPlugin::newBridge(init, BINARY_NATIVE, PLUGIN_LV2, needsArchBridge, bridgeBinary);
}

return plugin;
return nullptr;
}

// used in CarlaStandalone.cpp


+ 1
- 0
source/backend/plugin/CarlaPluginVST2.cpp View File

@@ -17,6 +17,7 @@

#include "CarlaPluginInternal.hpp"
#include "CarlaEngine.hpp"
#include "AppConfig.h"

#if defined(USING_JUCE) && JUCE_PLUGINHOST_VST
# define USE_JUCE_FOR_VST2


+ 22
- 3
source/bridges-plugin/CarlaBridgePlugin.cpp View File

@@ -68,6 +68,7 @@
#include "jackbridge/JackBridge.hpp"

#include "water/files/File.h"
#include "water/misc/Time.h"

using CarlaBackend::CarlaEngine;
using CarlaBackend::EngineCallbackOpcode;
@@ -238,7 +239,7 @@ public:
{
carla_debug("CarlaBridgePlugin::~CarlaBridgePlugin()");

if (! fUsingExec)
if (fEngine != nullptr && ! fUsingExec)
carla_engine_close(gHostHandle);
}

@@ -281,6 +282,15 @@ public:

gIsInitiated = true;

const bool testing = std::getenv("CARLA_BRIDGE_TESTING") != nullptr;
int64_t timeToEnd = 0;

if (testing)
{
timeToEnd = water::Time::currentTimeMillis() + 10 * 1000;
fEngine->transportPlay();
}

#if defined(USING_JUCE) && (defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN))
# ifndef CARLA_OS_WIN
static const int argc = 0;
@@ -298,6 +308,8 @@ public:
# else
carla_msleep(5);
# endif
if (testing && timeToEnd - water::Time::currentTimeMillis() < 0)
break;
}
#endif

@@ -332,7 +344,7 @@ protected:
}

private:
const CarlaEngine* fEngine;
CarlaEngine* fEngine;

#ifdef USING_JUCE
const juce::ScopedJuceInitialiser_GUI fJuceInitialiser;
@@ -649,7 +661,14 @@ int main(int argc, char* argv[])

if (const CarlaPluginInfo* const pluginInfo = carla_get_plugin_info(gHostHandle, 0))
{
if (pluginInfo->hints & CarlaBackend::PLUGIN_HAS_CUSTOM_UI)
if (itype == CarlaBackend::PLUGIN_INTERNAL && (std::strcmp(label, "audiofile") == 0 || std::strcmp(label, "midifile") == 0))
{
if (file.exists())
carla_set_custom_data(gHostHandle, 0,
CarlaBackend::CUSTOM_DATA_TYPE_STRING,
"file", file.getFullPathName().toRawUTF8());
}
else if (pluginInfo->hints & CarlaBackend::PLUGIN_HAS_CUSTOM_UI)
{
#ifdef HAVE_X11
if (std::getenv("DISPLAY") != nullptr)


+ 9
- 0
source/bridges-ui/CarlaBridgeFormatLV2.cpp View File

@@ -25,6 +25,10 @@

#include "water/files/File.h"

#ifdef CARLA_OS_MAC
# include "CarlaMacUtils.hpp"
#endif

#include <string>
#include <vector>

@@ -512,6 +516,11 @@ public:
// ------------------------------------------------------------------------------------------------------------
// open DLL

#ifdef CARLA_OS_MAC
// Binary might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
CarlaBackend::removeFileFromQuarantine(fRdfUiDescriptor->Binary);
#endif

if (! libOpen(fRdfUiDescriptor->Binary))
{
carla_stderr("Failed to load UI binary, error was:\n%s", libError());


+ 16
- 0
source/discovery/carla-discovery.cpp View File

@@ -63,6 +63,7 @@
# undef Component
# undef MemoryBlock
# undef Point
# include "CarlaMacUtils.cpp"
#endif

#ifdef CARLA_OS_WIN
@@ -1753,6 +1754,21 @@ int main(int argc, char* argv[])
}
#endif

#ifdef CARLA_OS_MAC
// Plugin might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
switch (type)
{
case PLUGIN_LADSPA:
case PLUGIN_DSSI:
case PLUGIN_VST2:
case PLUGIN_VST3:
removeFileFromQuarantine(filename);
break;
default:
break;
}
#endif

switch (type)
{
case PLUGIN_LADSPA:


+ 12
- 0
source/frontend/widgets/racklistwidget.py View File

@@ -252,6 +252,12 @@ class RackListWidget(QListWidget):
self.clearFocus()

def isDragUrlValid(self, filename):
if not filename:
return False

if filename[-1] == '/':
filename = filename[:-1]

lfilename = filename.lower()

if os.path.isdir(filename):
@@ -333,6 +339,12 @@ class RackListWidget(QListWidget):

filename = url.toLocalFile()

if not filename:
continue

if filename[-1] == '/':
filename = filename[:-1]

if not self.host.load_file(filename):
CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"),
self.tr("Failed to load file"),


+ 108
- 47
source/native-plugins/audio-base.hpp View File

@@ -97,21 +97,14 @@ struct AudioFilePool {
CARLA_DECLARE_NON_COPY_STRUCT(AudioFilePool)
};

class AbstractAudioPlayer
{
public:
virtual ~AbstractAudioPlayer() {}
virtual uint64_t getLastFrame() const = 0;
};

class AudioFileThread : public CarlaThread
{
public:
AudioFileThread(AbstractAudioPlayer* const player)
AudioFileThread()
: CarlaThread("AudioFileThread"),
kPlayer(player),
fEntireFileLoaded(false),
fLoopingMode(true),
fNeedsFrame(0),
fNeedsRead(false),
fQuitNow(true),
fFilePtr(nullptr),
@@ -120,10 +113,9 @@ public:
fPollTempData(nullptr),
fPollTempSize(0),
fPool(),
fMutex()
fMutex(),
fSignal()
{
CARLA_ASSERT(kPlayer != nullptr);

static bool adInitiated = false;

if (! adInitiated)
@@ -168,16 +160,19 @@ public:
if (fPollTempData == nullptr)
return;

fNeedsRead = true;
fNeedsFrame = 0;
fNeedsRead = false;
fQuitNow = false;
startThread();
}

void stopNow()
{
fNeedsFrame = 0;
fNeedsRead = false;
fQuitNow = true;

fSignal.signal();
stopThread(1000);

const CarlaMutexLocker cml(fMutex);
@@ -209,9 +204,14 @@ public:
fLoopingMode = on;
}

void setNeedsRead() noexcept
void setNeedsRead(const uint64_t frame) noexcept
{
if (fEntireFileLoaded)
return;

fNeedsFrame = frame;
fNeedsRead = true;
fSignal.signal();
}

bool loadFilename(const char* const filename, const uint32_t sampleRate)
@@ -295,24 +295,73 @@ public:
carla_copyFloats(pool.buffer[1], fPool.buffer[1], fPool.numFrames);
}

bool tryPutData(AudioFilePool& pool, const uint64_t framePos, const uint32_t frames)
bool tryPutData(float* const out1, float* const out2, uint64_t framePos, const uint32_t frames)
{
CARLA_SAFE_ASSERT_RETURN(pool.numFrames == fPool.numFrames, false);
CARLA_SAFE_ASSERT_RETURN(fPool.numFrames != 0, false);

if (framePos >= fPool.numFrames)
return false;
if (framePos >= fNumFileFrames)
{
if (fLoopingMode)
framePos %= fNumFileFrames;
else
return false;
}

uint64_t frameDiff;
const uint64_t numFramesNearEnd = fPool.numFrames*3/4;

#if 1
const CarlaMutexLocker cml(fMutex);
/*
#else
const CarlaMutexTryLocker cmtl(fMutex);
if (! cmtl.wasLocked())
return false;
*/
{
for (int i=0; i<5; ++i)
{
pthread_yield();
if (cmtl.tryAgain())
break;
if (i == 4)
return false;
}
}
#endif

pool.startFrame = fPool.startFrame;
if (framePos < fPool.startFrame)
{
if (fPool.startFrame + fPool.numFrames <= fNumFileFrames)
{
setNeedsRead(framePos);
return false;
}

carla_copyFloats(pool.buffer[0] + framePos, fPool.buffer[0] + framePos, frames);
carla_copyFloats(pool.buffer[1] + framePos, fPool.buffer[1] + framePos, frames);
frameDiff = framePos + (fNumFileFrames - fPool.startFrame);

if (frameDiff + frames >= fPool.numFrames)
{
setNeedsRead(framePos);
return false;
}

carla_copyFloats(out1, fPool.buffer[0] + frameDiff, frames);
carla_copyFloats(out2, fPool.buffer[1] + frameDiff, frames);
}
else
{
frameDiff = framePos - fPool.startFrame;

if (frameDiff + frames >= fPool.numFrames)
{
setNeedsRead(framePos);
return false;
}

carla_copyFloats(out1, fPool.buffer[0] + frameDiff, frames);
carla_copyFloats(out2, fPool.buffer[1] + frameDiff, frames);
}

if (frameDiff > numFramesNearEnd)
setNeedsRead(framePos + frames);

return true;
}
@@ -372,17 +421,19 @@ public:
if (fNumFileFrames == 0 || fFileNfo.channels == 0 || fFilePtr == nullptr)
{
carla_debug("R: no song loaded");
fNeedsFrame = 0;
fNeedsRead = false;
return;
}
if (fPollTempData == nullptr)
{
carla_debug("R: nothing to poll");
fNeedsFrame = 0;
fNeedsRead = false;
return;
}

uint64_t lastFrame = kPlayer->getLastFrame();
uint64_t lastFrame = fNeedsFrame;
int64_t readFrameCheck;

if (lastFrame >= fNumFileFrames)
@@ -398,6 +449,7 @@ public:
else
{
carla_debug("R: transport out of bounds");
fNeedsFrame = 0;
fNeedsRead = false;
return;
}
@@ -428,6 +480,7 @@ public:
if (rv < 0)
{
carla_stderr("R: ad_read failed");
fNeedsFrame = 0;
fNeedsRead = false;
return;
}
@@ -442,36 +495,46 @@ public:
rv += ad_read(fFilePtr, fPollTempData+urv, fPollTempSize-urv);
}

carla_debug("R: reading %li frames at frame %lu", rv, readFrameCheck);

// local copy
const uint32_t poolNumFrame = fPool.numFrames;
const int64_t fileFrames = fFileNfo.frames;
const bool isMonoFile = fFileNfo.channels == 1;
float* const pbuffer0 = fPool.buffer[0];
float* const pbuffer1 = fPool.buffer[1];
const float* const tmpbuf = fPollTempData;

// lock, and put data asap
const CarlaMutexLocker cml(fMutex);

do {
for (; i < fPool.numFrames && j < rv; ++j)
for (; i < poolNumFrame && j < rv; ++j)
{
if (fFileNfo.channels == 1)
if (isMonoFile)
{
fPool.buffer[0][i] = fPollTempData[j];
fPool.buffer[1][i] = fPollTempData[j];
pbuffer0[i] = pbuffer1[i] = tmpbuf[j];
i++;
}
else
{
if (j % 2 == 0)
{
fPool.buffer[0][i] = fPollTempData[j];
pbuffer0[i] = tmpbuf[j];
}
else
{
fPool.buffer[1][i] = fPollTempData[j];
i++;
pbuffer1[i] = tmpbuf[j];
++i;
}
}
}

if (i >= fPool.numFrames)
if (i >= poolNumFrame) {
break;
}

if (rv == fFileNfo.frames)
if (rv == fileFrames)
{
// full file read
j = 0;
@@ -481,14 +544,14 @@ public:
{
carla_debug("read break, not enough space");

carla_zeroFloats(fPool.buffer[0] + i, fPool.numFrames - i);
carla_zeroFloats(fPool.buffer[1] + i, fPool.numFrames - i);
carla_zeroFloats(pbuffer0, poolNumFrame - i);
carla_zeroFloats(pbuffer1, poolNumFrame - i);
break;
}

} while (i < fPool.numFrames);
} while (i < poolNumFrame);

fPool.startFrame = lastFrame;
fPool.startFrame = readFrame;
}

fNeedsRead = false;
@@ -497,25 +560,22 @@ public:
protected:
void run() override
{
const uint64_t numFramesNearEnd = fPool.numFrames*3/4;
uint64_t lastFrame;

while (! fQuitNow)
{
lastFrame = kPlayer->getLastFrame();

if (fNeedsRead || lastFrame < fPool.startFrame || lastFrame - fPool.startFrame >= numFramesNearEnd)
if (fNeedsRead)
readPoll();

carla_msleep(50);
if (fQuitNow)
break;

fSignal.wait();
}
}

private:
AbstractAudioPlayer* const kPlayer;

bool fEntireFileLoaded;
bool fLoopingMode;
volatile uint64_t fNeedsFrame;
volatile bool fNeedsRead;
volatile bool fQuitNow;

@@ -529,6 +589,7 @@ private:

AudioFilePool fPool;
CarlaMutex fMutex;
CarlaSignal fSignal;

CARLA_DECLARE_NON_COPY_STRUCT(AudioFileThread)
};


+ 16
- 31
source/native-plugins/audio-file.cpp View File

@@ -41,19 +41,17 @@ static const char* const audiofilesWildcard =

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

class AudioFilePlugin : public NativePluginWithMidiPrograms<FileAudio>,
public AbstractAudioPlayer
class AudioFilePlugin : public NativePluginWithMidiPrograms<FileAudio>
{
public:
AudioFilePlugin(const NativeHostDescriptor* const host)
: NativePluginWithMidiPrograms<FileAudio>(host, fPrograms, 2),
AbstractAudioPlayer(),
fLoopMode(true),
fDoProcess(false),
fLastFrame(0),
fWasPlayingBefore(false),
fMaxFrame(0),
fPool(),
fThread(this),
fThread(),
fPrograms(hostGetFilePath("audio"), audiofilesWildcard)
#ifndef __MOD_DEVICES__
, fInlineDisplay()
@@ -67,11 +65,6 @@ public:
fPool.destroy();
}

uint64_t getLastFrame() const override
{
return fLastFrame;
}

protected:
// -------------------------------------------------------------------
// Plugin parameter calls
@@ -126,7 +119,6 @@ protected:

fLoopMode = b;
fThread.setLoopingMode(b);
fThread.setNeedsRead();
}

void setCustomData(const char* const key, const char* const value) override
@@ -151,8 +143,7 @@ protected:

if (! fDoProcess)
{
//carla_stderr("P: no process");
fLastFrame = timePos->frame;
// carla_stderr("P: no process");
carla_zeroFloats(out1, frames);
carla_zeroFloats(out2, frames);
return;
@@ -161,23 +152,26 @@ protected:
// not playing
if (! timePos->playing)
{
//carla_stderr("P: not playing");
if (timePos->frame == 0 && fLastFrame > 0)
fThread.setNeedsRead();
// carla_stderr("P: not playing");
if (timePos->frame == 0 && fWasPlayingBefore)
fThread.setNeedsRead(timePos->frame);

fLastFrame = timePos->frame;
carla_zeroFloats(out1, frames);
carla_zeroFloats(out2, frames);
fWasPlayingBefore = false;
return;
}
else
{
fWasPlayingBefore = true;
}

// out of reach
if ((timePos->frame < fPool.startFrame || timePos->frame >= fMaxFrame) && !fLoopMode)
{
if (timePos->frame < fPool.startFrame)
fThread.setNeedsRead();
fThread.setNeedsRead(timePos->frame);

fLastFrame = timePos->frame;
carla_zeroFloats(out1, frames);
carla_zeroFloats(out2, frames);

@@ -236,15 +230,7 @@ protected:
}
else
{
// NOTE: timePos->frame is always >= fPool.startFrame
const uint64_t poolStartFrame = timePos->frame - fThread.getPoolStartFrame();

if (fThread.tryPutData(fPool, poolStartFrame, frames))
{
carla_copyFloats(out1, fPool.buffer[0]+poolStartFrame, frames);
carla_copyFloats(out2, fPool.buffer[1]+poolStartFrame, frames);
}
else
if (! fThread.tryPutData(out1, out2, timePos->frame, frames))
{
carla_zeroFloats(out1, frames);
carla_zeroFloats(out2, frames);
@@ -262,11 +248,10 @@ protected:
if (! fInlineDisplay.pending)
{
fInlineDisplay.pending = true;
// FIXME this is not supposed to be here, but in some idle callback
hostQueueDrawInlineDisplay();
}
#endif

fLastFrame = timePos->frame;
}

// -------------------------------------------------------------------
@@ -411,8 +396,8 @@ protected:
private:
bool fLoopMode;
bool fDoProcess;
bool fWasPlayingBefore;

volatile uint64_t fLastFrame;
uint32_t fMaxFrame;

AudioFilePool fPool;


+ 6
- 24
source/native-plugins/midi-file.cpp View File

@@ -185,35 +185,17 @@ private:
CARLA_SAFE_ASSERT_CONTINUE(midiEventHolder != nullptr);

const MidiMessage& midiMessage(midiEventHolder->message);
//const double time(track->getEventTime(i)*sampleRate);
const int dataSize(midiMessage.getRawDataSize());

const int dataSize = midiMessage.getRawDataSize();
if (dataSize <= 0 || dataSize > MAX_EVENT_DATA_SIZE)
continue;
if (midiMessage.isActiveSense())
continue;
if (midiMessage.isMetaEvent())
continue;
if (midiMessage.isMidiStart())
continue;
if (midiMessage.isMidiContinue())
continue;
if (midiMessage.isMidiStop())
continue;
if (midiMessage.isMidiClock())
continue;
if (midiMessage.isSongPositionPointer())
continue;
if (midiMessage.isQuarterFrame())
continue;
if (midiMessage.isFullFrame())
continue;
if (midiMessage.isMidiMachineControlMessage())
continue;
if (midiMessage.isSysEx())

const uint8_t* const data = midiMessage.getRawData();
if (! MIDI_IS_CHANNEL_MESSAGE(data[0]))
continue;

const double time(midiMessage.getTimeStamp()*sampleRate);
const double time = midiMessage.getTimeStamp() * sampleRate;
// const double time = track->getEventTime(i) * sampleRate;
CARLA_SAFE_ASSERT_CONTINUE(time >= 0.0);

fMidiOut.addRaw(static_cast<uint64_t>(time), midiMessage.getRawData(), static_cast<uint8_t>(dataSize));


+ 4
- 2
source/utils/CarlaBinaryUtils.hpp View File

@@ -112,9 +112,11 @@ BinaryType getBinaryTypeFromFile(const char* const filename)
// We just assume what architectures are more important, and check for them first
if (std::strstr(output, "x86_64") != nullptr)
return BINARY_POSIX64;
if (std::strstr(output, "i386"))
if (std::strstr(output, "arm64") != nullptr)
return BINARY_POSIX64;
if (std::strstr(output, "i386") != nullptr)
return BINARY_POSIX32;
if (std::strstr(output, "ppc"))
if (std::strstr(output, "ppc") != nullptr)
return BINARY_OTHER;
}



+ 7
- 0
source/utils/CarlaMacUtils.cpp View File

@@ -20,6 +20,8 @@
#include "CarlaMacUtils.hpp"
#include "CarlaString.hpp"

#include <sys/xattr.h>

#import <Foundation/Foundation.h>

CARLA_BACKEND_START_NAMESPACE
@@ -54,6 +56,11 @@ const char* findBinaryInBundle(const char* const bundleDir)
return ret.buffer();
}

bool removeFileFromQuarantine(const char* const filename)
{
return removexattr(filename, "com.apple.quarantine", 0) == 0;
}

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

AutoNSAutoreleasePool::AutoNSAutoreleasePool()


+ 5
- 0
source/utils/CarlaMacUtils.hpp View File

@@ -33,6 +33,11 @@ CARLA_BACKEND_START_NAMESPACE
*/
const char* findBinaryInBundle(const char* const bundleDir);

/*
* ...
*/
bool removeFileFromQuarantine(const char* const filename);

/*
* ...
*/


+ 5
- 0
source/utils/CarlaMutex.hpp View File

@@ -325,6 +325,11 @@ public:
return !fLocked;
}

bool tryAgain() const noexcept
{
return fMutex.tryLock();
}

private:
const Mutex& fMutex;
const bool fLocked;


Loading…
Cancel
Save