Browse Source

Started work on proper plugin-bridge support

tags/1.9.4
falkTX 13 years ago
parent
commit
6970cb280e
11 changed files with 475 additions and 53 deletions
  1. +82
    -0
      source/backend/CarlaBridge.hpp
  2. +9
    -1
      source/backend/CarlaEngine.hpp
  3. +0
    -28
      source/backend/CarlaPlugin.hpp
  4. +7
    -0
      source/backend/engine/CarlaEngine.cpp
  5. +2
    -0
      source/backend/engine/CarlaEngine.pro
  6. +183
    -0
      source/backend/engine/CarlaEngineBridge.cpp
  7. +12
    -0
      source/backend/engine/CarlaEngineInternal.hpp
  8. +4
    -0
      source/backend/engine/CarlaEngineOsc.cpp
  9. +1
    -0
      source/backend/engine/Makefile
  10. +167
    -18
      source/backend/plugin/BridgePlugin.cpp
  11. +8
    -6
      source/utils/CarlaShmUtils.hpp

+ 82
- 0
source/backend/CarlaBridge.hpp View File

@@ -0,0 +1,82 @@
/*
* Carla Bridge API
* Copyright (C) 2013 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 GPL.txt file
*/

#ifndef __CARLA_BRIDGE_HPP__
#define __CARLA_BRIDGE_HPP__

#include <semaphore.h>

#define BRIDGE_SHM_RING_BUFFER_SIZE 2048

#ifndef BUILD_BRIDGE
/*!
* TODO.
*/
enum PluginBridgeInfoType {
kPluginBridgeAudioCount,
kPluginBridgeMidiCount,
kPluginBridgeParameterCount,
kPluginBridgeProgramCount,
kPluginBridgeMidiProgramCount,
kPluginBridgePluginInfo,
kPluginBridgeParameterInfo,
kPluginBridgeParameterData,
kPluginBridgeParameterRanges,
kPluginBridgeProgramInfo,
kPluginBridgeMidiProgramInfo,
kPluginBridgeConfigure,
kPluginBridgeSetParameterValue,
kPluginBridgeSetDefaultValue,
kPluginBridgeSetProgram,
kPluginBridgeSetMidiProgram,
kPluginBridgeSetCustomData,
kPluginBridgeSetChunkData,
kPluginBridgeUpdateNow,
kPluginBridgeError
};
#endif

/*!
* TODO.
*/
struct BridgeRingBuffer {
int head;
int tail;
int written;
bool invalidateCommit;
char buf[BRIDGE_SHM_RING_BUFFER_SIZE];
};

/*!
* TODO.
*/
struct BridgeShmControl {
// 32 and 64-bit binaries align semaphores differently.
// Let's make sure there's plenty of room for either one.
union {
sem_t runServer;
char _alignServer[32];
};
union {
sem_t runClient;
char _alignClient[32];
};

BridgeRingBuffer ringBuffer;
};

#endif // __CARLA_BRIDGE_HPP__

+ 9
- 1
source/backend/CarlaEngine.hpp View File

@@ -58,7 +58,12 @@ enum EngineType {
/*!
* Plugin engine type, used to export the engine as a plugin.
*/
kEngineTypePlugin = 3
kEngineTypePlugin = 3,

/*!
* TODO.
*/
kEngineTypeBridge = 4
};

/*!
@@ -1008,6 +1013,9 @@ protected:
#endif

private:
#ifdef BUILD_BRIDGE
static CarlaEngine* newBridge(const char* const audioBaseName, const char* const controlBaseName);
#endif
#ifdef WANT_JACK
static CarlaEngine* newJack();
#endif


+ 0
- 28
source/backend/CarlaPlugin.hpp View File

@@ -34,34 +34,6 @@ CARLA_BACKEND_START_NAMESPACE
} // Fix editor indentation
#endif

#if 1//ndef BUILD_BRIDGE
/*!
* TODO.
*/
enum PluginBridgeInfoType {
kPluginBridgeAudioCount,
kPluginBridgeMidiCount,
kPluginBridgeParameterCount,
kPluginBridgeProgramCount,
kPluginBridgeMidiProgramCount,
kPluginBridgePluginInfo,
kPluginBridgeParameterInfo,
kPluginBridgeParameterData,
kPluginBridgeParameterRanges,
kPluginBridgeProgramInfo,
kPluginBridgeMidiProgramInfo,
kPluginBridgeConfigure,
kPluginBridgeSetParameterValue,
kPluginBridgeSetDefaultValue,
kPluginBridgeSetProgram,
kPluginBridgeSetMidiProgram,
kPluginBridgeSetCustomData,
kPluginBridgeSetChunkData,
kPluginBridgeUpdateNow,
kPluginBridgeError
};
#endif

/*!
* TODO.
*/


+ 7
- 0
source/backend/engine/CarlaEngine.cpp View File

@@ -35,6 +35,13 @@ CARLA_BACKEND_START_NAMESPACE
return CarlaEngineProtectedData::getHostWindow(engine);
}

#ifndef BUILD_BRIDGE
void registerEnginePlugin(CarlaEngine* const engine, const unsigned int id, CarlaPlugin* const plugin)
{
CarlaEngineProtectedData::registerEnginePlugin(engine, id, plugin);
}
#endif

// -------------------------------------------------------------------------------------------------------------------
// Carla Engine port (Abstract)



+ 2
- 0
source/backend/engine/CarlaEngine.pro View File

@@ -61,6 +61,7 @@ SOURCES = \
CarlaEngine.cpp \
CarlaEngineOsc.cpp \
CarlaEngineThread.cpp \
CarlaEngineBridge.cpp \
CarlaEngineJack.cpp \
CarlaEnginePlugin.cpp \
CarlaEngineRtAudio.cpp
@@ -72,6 +73,7 @@ HEADERS = \

HEADERS += \
../CarlaBackend.hpp \
../CarlaBridge.hpp \
../CarlaEngine.hpp \
../CarlaPlugin.hpp



+ 183
- 0
source/backend/engine/CarlaEngineBridge.cpp View File

@@ -0,0 +1,183 @@
/*
* Carla Plugin Engine
* Copyright (C) 2012-2013 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 GPL.txt file
*/

#ifdef BUILD_BRIDGE

#include "CarlaEngineInternal.hpp"
#include "CarlaBackendUtils.hpp"
#include "CarlaMIDI.h"

#include "CarlaBridge.hpp"
#include "CarlaShmUtils.hpp"

CARLA_BACKEND_START_NAMESPACE

#if 0
} // Fix editor indentation
#endif

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

class CarlaEngineBridge : public CarlaEngine
{
public:
CarlaEngineBridge(const char* const audioBaseName, const char* const controlBaseName)
: CarlaEngine()
{
carla_debug("CarlaEngineBridge::CarlaEngineBridge()");

fShmAudioPool.filename = "/carla-bridge_shm_" + audioBaseName;
fShmControl.filename = "/carla-bridge_shc_" + controlBaseName;
}

~CarlaEngineBridge()
{
carla_debug("CarlaEngineBridge::~CarlaEngineBridge()");
}

// -------------------------------------
// CarlaEngine virtual calls

bool init(const char* const clientName)
{
carla_debug("CarlaEngineBridge::init(\"%s\")", clientName);

char tmpFileBase[60];

// SHM Audio Pool
{
fShmAudioPool.shm = carla_shm_attach((const char*)fShmAudioPool.filename);

if (! carla_is_shm_valid(fShmAudioPool.shm))
{
_cleanup();
carla_stdout("Failed to open or create shared memory file #1");
return false;
}
}

// SHM Control
{
fShmControl.shm = carla_shm_attach((const char*)fShmControl.filename);

if (! carla_is_shm_valid(fShmControl.shm))
{
_cleanup();
carla_stdout("Failed to open or create shared memory file #2");
return false;
}

if (! carla_shm_map<ShmControl>(fShmControl.shm, fShmControl.data))
{
_cleanup();
carla_stdout("Failed to mmap shared memory file");
return false;
}
}

CarlaEngine::init(fName);
return true;
}

bool close()
{
carla_debug("CarlaEnginePlugin::close()");
CarlaEngine::close();

_cleanup();

return true;
}

bool isRunning() const
{
return true;
}

bool isOffline() const
{
return false;
}

EngineType type() const
{
return kEngineTypeBridge;
}

private:
struct BridgeAudioPool {
CarlaString filename;
float* data;
size_t size;
shm_t shm;

BridgeAudioPool()
: data(nullptr),
size(0)
{
carla_shm_init(shm);
}
} fShmAudioPool;

struct BridgeControl {
CarlaString filename;
ShmControl* data;
shm_t shm;

BridgeControl()
: data(nullptr)
{
carla_shm_init(shm);
}

} fShmControl;

void _cleanup()
{
if (fShmAudioPool.filename.isNotEmpty())
fShmAudioPool.filename.clear();

if (fShmControl.filename.isNotEmpty())
fShmControl.filename.clear();

// delete data
fShmAudioPool.data = nullptr;
fShmAudioPool.size = 0;

// and again
fShmControl.data = nullptr;

if (carla_is_shm_valid(fShmAudioPool.shm))
carla_shm_close(fShmAudioPool.shm);

if (carla_is_shm_valid(fShmControl.shm))
carla_shm_close(fShmControl.shm);
}

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineBridge)
};

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

CarlaEngine* CarlaEngine::newBridge(const char* const audioBaseName, const char* const controlBaseName)
{
return new CarlaEngineBridge(audioBaseName, controlBaseName);
}

CARLA_BACKEND_END_NAMESPACE

#endif // BUILD_BRIDGE

+ 12
- 0
source/backend/engine/CarlaEngineInternal.hpp View File

@@ -47,6 +47,8 @@ const char* EngineType2Str(const EngineType type)
return "kEngineTypeRtAudio";
case kEngineTypePlugin:
return "kEngineTypePlugin";
case kEngineTypeBridge:
return "kEngineTypeBridge";
}

carla_stderr("CarlaBackend::EngineType2Str(%i) - invalid type", type);
@@ -204,6 +206,16 @@ struct CarlaEngineProtectedData {
(void)engine;
#endif
}

#ifndef BUILD_BRIDGE
static void registerEnginePlugin(CarlaEngine* const engine, const unsigned int id, CarlaPlugin* const plugin)
{
CARLA_ASSERT(id < engine->kData->curPluginCount);

if (id < engine->kData->curPluginCount)
engine->kData->plugins[id].plugin = plugin;
}
#endif
};

CARLA_BACKEND_END_NAMESPACE


+ 4
- 0
source/backend/engine/CarlaEngineOsc.cpp View File

@@ -21,6 +21,10 @@
#include "CarlaPlugin.hpp"
#include "CarlaMIDI.h"

#ifndef BUILD_BRIDGE
# include "CarlaBridge.hpp"
#endif

CARLA_BACKEND_START_NAMESPACE

#ifndef BUILD_BRIDGE


+ 1
- 0
source/backend/engine/Makefile View File

@@ -42,6 +42,7 @@ endif

OBJS = \
CarlaEngine.cpp.o \
CarlaEngineBridge.cpp.o \
CarlaEngineJack.cpp.o \
CarlaEnginePlugin.cpp.o \
CarlaEngineRtAudio.cpp.o \


+ 167
- 18
source/backend/plugin/BridgePlugin.cpp View File

@@ -17,8 +17,13 @@

#include "CarlaPluginInternal.hpp"

#if 1//ndef BUILD_BRIDGE
#ifndef BUILD_BRIDGE

#include "CarlaBridge.hpp"
#include "CarlaShmUtils.hpp"

#include <cerrno>
#include <ctime>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QStringList>
@@ -49,6 +54,55 @@

CARLA_BACKEND_START_NAMESPACE

// -------------------------------------------------------------------------------------------------------------------
// Engine Helpers

extern void registerEnginePlugin(CarlaEngine* const engine, const unsigned int id, CarlaPlugin* const plugin);

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

shm_t shm_mkstemp(char* const fileBase)
{
static const char charSet[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";

const int size = (fileBase != nullptr) ? std::strlen(fileBase) : 0;

shm_t shm;
carla_shm_init(shm);

if (size < 6)
{
errno = EINVAL;
return shm;
}

if (std::strcmp(fileBase + size - 6, "XXXXXX") != 0)
{
errno = EINVAL;
return shm;
}

std::srand(std::time(NULL));

while (true)
{
for (int c = size - 6; c < size; c++)
{
// Note the -1 to avoid the trailing '\0' in charSet.
fileBase[c] = charSet[std::rand() % (sizeof(charSet) - 1)];
}

shm_t shm = carla_shm_create(fileBase);

if (carla_is_shm_valid(shm) || errno != EEXIST)
return shm;
}
}

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

struct BridgeParamInfo {
float value;
CarlaString name;
@@ -75,7 +129,6 @@ public:
kData->osc.thread.setMode(CarlaPluginThread::PLUGIN_THREAD_BRIDGE);
}

#if 0
~BridgePlugin()
{
carla_debug("BridgePlugin::~BridgePlugin()");
@@ -83,6 +136,7 @@ public:
kData->singleMutex.lock();
kData->masterMutex.lock();

#if 0
if (osc.data.target)
{
osc_send_hide(&osc.data);
@@ -103,8 +157,8 @@ public:
}

info.chunk.clear();
}
#endif
}

// -------------------------------------------------------------------
// Information (base)
@@ -909,11 +963,16 @@ public:

carla_debug("BridgePlugin::delete_buffers() - end");
}
#endif

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

bool init(const char* const filename, const char* const name, const char* const label, const char* const bridgeBinary)
{
CARLA_ASSERT(kData->engine != nullptr);
CARLA_ASSERT(kData->client == nullptr);
CARLA_ASSERT(filename != nullptr);

// ---------------------------------------------------------------
// first checks

@@ -934,46 +993,109 @@ public:
return false;
}

m_filename = strdup(filename);
// ---------------------------------------------------------------
// set info

if (name != nullptr)
fName = kData->engine->getNewUniquePluginName(name);

fFilename = filename;

// ---------------------------------------------------------------
// SHM Audio Pool
{
char tmpFileBase[60];

if (name)
m_name = x_engine->getUniquePluginName(name);
std::sprintf(tmpFileBase, "/carla-bridge_shm_XXXXXX");

fShmAudioPool.shm = shm_mkstemp(tmpFileBase);

if (! carla_is_shm_valid(fShmAudioPool.shm))
{
//_cleanup();
carla_stdout("Failed to open or create shared memory file #1");
return false;
}

fShmAudioPool.filename = tmpFileBase;
}

// ---------------------------------------------------------------
// SHM Control
{
char tmpFileBase[60];
std::sprintf(tmpFileBase, "/carla-bridge_shc_XXXXXX");

fShmControl.shm = shm_mkstemp(tmpFileBase);

if (! carla_is_shm_valid(fShmControl.shm))
{
//_cleanup();
carla_stdout("Failed to open or create shared memory file #2");
return false;
}

fShmControl.filename = tmpFileBase;

if (! carla_shm_map<BridgeShmControl>(fShmControl.shm, fShmControl.data))
{
//_cleanup();
carla_stdout("Failed to mmap shared memory file");
return false;
}

std::memset(fShmControl.data, 0, sizeof(BridgeShmControl));

if (sem_init(&fShmControl.data->runServer, 1, 0) != 0)
{
//_cleanup();
carla_stdout("Failed to initialize shared memory semaphore #1");
return false;
}

if (sem_init(&fShmControl.data->runClient, 1, 0) != 0)
{
//_cleanup();
carla_stdout("Failed to initialize shared memory semaphore #2");
return false;
}
}

// register plugin now so we can receive OSC (and wait for it)
x_engine->__bridgePluginRegister(m_id, this);
registerEnginePlugin(kData->engine, fId, this);

osc.thread->setOscData(bridgeBinary, label, getPluginTypeString(m_type));
osc.thread->start();
kData->osc.thread.setOscData(bridgeBinary, label, getPluginTypeAsString(fPluginType));
kData->osc.thread.start();

for (int i=0; i < 200; i++)
{
if (m_initiated || osc.thread->isFinished())
if (fInitiated || ! kData->osc.thread.isRunning())
break;
carla_msleep(50);
}

if (! m_initiated)
if (! fInitiated)
{
// unregister so it gets handled properly
x_engine->__bridgePluginRegister(m_id, nullptr);
registerEnginePlugin(kData->engine, fId, nullptr);

osc.thread->terminate();
x_engine->setLastError("Timeout while waiting for a response from plugin-bridge\n(or the plugin crashed on initialization?)");
kData->osc.thread.terminate();
kData->engine->setLastError("Timeout while waiting for a response from plugin-bridge\n(or the plugin crashed on initialization?)");
return false;
}
else if (m_initError)
else if (fInitError)
{
// unregister so it gets handled properly
x_engine->__bridgePluginRegister(m_id, nullptr);
registerEnginePlugin(kData->engine, fId, nullptr);

osc.thread->quit();
kData->osc.thread.stop();
// last error was set before
return false;
}

return true;
}
#endif

private:
const BinaryType fBinaryType;
@@ -983,6 +1105,33 @@ private:
bool fInitError;
bool fSaved;

struct BridgeAudioPool {
CarlaString filename;
float* data;
size_t size;
shm_t shm;

BridgeAudioPool()
: data(nullptr),
size(0)
{
carla_shm_init(shm);
}
} fShmAudioPool;

struct BridgeControl {
CarlaString filename;
BridgeShmControl* data;
shm_t shm;

BridgeControl()
: data(nullptr)
{
carla_shm_init(shm);
}

} fShmControl;

struct Info {
uint32_t aIns, aOuts;
uint32_t mIns, mOuts;


+ 8
- 6
source/utils/CarlaShmUtils.hpp View File

@@ -35,7 +35,7 @@ typedef int shm_t;
// shared memory calls

static inline
bool carla_is_shm_valid(shm_t shm)
bool carla_is_shm_valid(const shm_t& shm)
{
#ifdef CARLA_OS_WIN
return (shm.shm != nullptr && shm.shm != INVALID_HANDLE_VALUE);
@@ -105,7 +105,7 @@ void carla_shm_close(shm_t& shm)
}

static inline
void* carla_shm_map(shm_t shm, const size_t size)
void* carla_shm_map(shm_t& shm, const size_t size)
{
CARLA_ASSERT(carla_is_shm_valid(shm));
CARLA_ASSERT(size > 0);
@@ -129,12 +129,13 @@ void* carla_shm_map(shm_t shm, const size_t size)

return ptr;
#else
ftruncate(shm, size);
return mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0);
#endif
}

static inline
void carla_shm_unmap(const shm_t shm, void* const ptr, const size_t size)
void carla_shm_unmap(const shm_t& shm, void* const ptr, const size_t size)
{
CARLA_ASSERT(carla_is_shm_valid(shm));
CARLA_ASSERT(ptr != nullptr);
@@ -177,14 +178,15 @@ void carla_shm_unmap(const shm_t shm, void* const ptr, const size_t size)

template<typename T>
static inline
void carla_shm_map(shm_t shm, T* value)
bool carla_shm_map(shm_t& shm, T* value)
{
value = carla_shm_map(shm, sizeof(value));
value = (T*)carla_shm_map(shm, sizeof(value));
return (value != nullptr);
}

template<typename T>
static inline
void carla_shm_unmap(const shm_t shm, T* value)
void carla_shm_unmap(const shm_t& shm, T* value)
{
carla_shm_unmap(shm, value, sizeof(value));
value = nullptr;


Loading…
Cancel
Save