Browse Source

Continue work for plugin bridges

tags/1.9.4
falkTX 12 years ago
parent
commit
5e64e56939
12 changed files with 480 additions and 441 deletions
  1. +1
    -0
      source/backend/engine/CarlaEngine.pro
  2. +148
    -86
      source/backend/engine/CarlaEngineBridge.cpp
  3. +1
    -0
      source/backend/engine/CarlaEngineJack.cpp
  4. +1
    -0
      source/backend/engine/distrho/DistrhoPluginInfo.h
  5. +239
    -144
      source/backend/plugin/BridgePlugin.cpp
  6. +2
    -0
      source/backend/plugin/CarlaPlugin.pro
  7. +1
    -1
      source/libs/distrho/DistrhoUIExternal.hpp
  8. +3
    -3
      source/libs/distrho/src/DistrhoPluginVST.cpp
  9. +2
    -0
      source/libs/jackbridge/JackBridge.hpp
  10. +31
    -9
      source/libs/jackbridge/JackBridge2.cpp
  11. +15
    -8
      source/libs/jackbridge/Makefile
  12. +36
    -190
      source/utils/CarlaBridgeUtils.hpp

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

@@ -78,6 +78,7 @@ HEADERS += \
../../includes/CarlaDefines.hpp \
../../includes/CarlaMIDI.h \
../../utils/CarlaMutex.hpp \
../../utils/CarlaRingBuffer.hpp \
../../utils/CarlaString.hpp \
../../utils/CarlaThread.hpp \
../../utils/CarlaUtils.hpp \


+ 148
- 86
source/backend/engine/CarlaEngineBridge.cpp View File

@@ -37,6 +37,111 @@ CARLA_BACKEND_START_NAMESPACE

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

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

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

~BridgeAudioPool()
{
// should be cleared by now
CARLA_ASSERT(data == nullptr);

clear();
}

bool attach()
{
#ifdef CARLA_OS_WIN
// TESTING!
shm = carla_shm_attach_linux((const char*)filename);
#else
shm = carla_shm_attach((const char*)filename);
#endif

return carla_is_shm_valid(shm);
}

void clear()
{
filename.clear();

data = nullptr;

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

struct BridgeControl : public RingBufferControl {
CarlaString filename;
BridgeShmControl* data;
shm_t shm;

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

~BridgeControl()
{
// should be cleared by now
CARLA_ASSERT(data == nullptr);

clear();
}

bool attach()
{
#ifdef CARLA_OS_WIN
// TESTING!
shm = carla_shm_attach_linux((const char*)filename);
#else
shm = carla_shm_attach((const char*)filename);
#endif

return carla_is_shm_valid(shm);
}

void clear()
{
filename.clear();

data = nullptr;

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

bool mapData()
{
CARLA_ASSERT(data == nullptr);

if (carla_shm_map<BridgeShmControl>(shm, data))
{
setRingBuffer(&data->ringBuffer, false);
return true;
}

return false;
}

PluginBridgeOpcode readOpcode()
{
return static_cast<PluginBridgeOpcode>(readInt());
}
};

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

class CarlaEngineBridge : public CarlaEngine,
public QThread
{
@@ -69,16 +174,8 @@ public:

// SHM Audio Pool
{
#ifdef CARLA_OS_WIN
// TESTING!
fShmAudioPool.shm = carla_shm_attach_linux((const char*)fShmAudioPool.filename);
#else
fShmAudioPool.shm = carla_shm_attach((const char*)fShmAudioPool.filename);
#endif

if (! carla_is_shm_valid(fShmAudioPool.shm))
if (! fShmAudioPool.attach())
{
_cleanup();
carla_stdout("Failed to open or create shared memory file #1");
return false;
}
@@ -86,24 +183,20 @@ public:

// SHM Control
{
#ifdef CARLA_OS_WIN
// TESTING!
fShmControl.shm = carla_shm_attach_linux((const char*)fShmControl.filename);
#else
fShmControl.shm = carla_shm_attach((const char*)fShmControl.filename);
#endif

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

if (! carla_shm_map<BridgeShmControl>(fShmControl.shm, fShmControl.data))
if (! fShmControl.mapData())
{
_cleanup();
carla_stdout("Failed to mmap shared memory file");
// clear
fShmControl.clear();
fShmAudioPool.clear();
return false;
}
}
@@ -111,14 +204,14 @@ public:
// Read values from memory
PluginBridgeOpcode opcode;

opcode = rdwr_readOpcode(&fShmControl.data->ringBuffer);
CARLA_ASSERT(opcode == kPluginBridgeOpcodeSetBufferSize);
fBufferSize = rdwr_readInt(&fShmControl.data->ringBuffer);
opcode = fShmControl.readOpcode();
CARLA_ASSERT_INT(opcode == kPluginBridgeOpcodeSetBufferSize, opcode);
fBufferSize = fShmControl.readInt();
carla_stderr("BufferSize: %i", fBufferSize);

opcode = rdwr_readOpcode(&fShmControl.data->ringBuffer);
CARLA_ASSERT(opcode == kPluginBridgeOpcodeSetSampleRate);
fSampleRate = rdwr_readFloat(&fShmControl.data->ringBuffer);
opcode = fShmControl.readOpcode();
CARLA_ASSERT_INT(opcode == kPluginBridgeOpcodeSetSampleRate, opcode);
fSampleRate = fShmControl.readFloat();
carla_stderr("SampleRate: %f", fSampleRate);

fQuitNow = false;
@@ -137,7 +230,8 @@ public:
fQuitNow = true;
QThread::wait();

_cleanup();
fShmControl.clear();
fShmAudioPool.clear();

return true;
}
@@ -163,21 +257,29 @@ public:
void run()
{
// TODO - set RT permissions
carla_debug("CarlaEngineBridge::run()");

while (! fQuitNow)
{
carla_debug("CarlaEngineBridge::run() - try wait");

if (! jackbridge_sem_timedwait(&fShmControl.data->runServer, 5))
{
if (errno != ETIMEDOUT)
continue;

fQuitNow = true;
return;
if (errno == ETIMEDOUT)
{
fIsRunning = false;
fQuitNow = true;
return;
}
}

while (rdwr_dataAvailable(&fShmControl.data->ringBuffer))
carla_debug("CarlaEngineBridge::run() - connected");

while (fShmControl.dataAvailable())
{
const PluginBridgeOpcode opcode(rdwr_readOpcode(&fShmControl.data->ringBuffer));
const PluginBridgeOpcode opcode(fShmControl.readOpcode());

carla_debug("CarlaEngineBridge::run() - got opcode: %s", PluginBridgeOpcode2str(opcode));

switch (opcode)
{
@@ -186,29 +288,29 @@ public:

case kPluginBridgeOpcodeSetAudioPool:
{
const int poolSize(rdwr_readInt(&fShmControl.data->ringBuffer));
const long poolSize(fShmControl.readLong());
fShmAudioPool.data = (float*)carla_shm_map(fShmAudioPool.shm, poolSize);
break;
}

case kPluginBridgeOpcodeSetBufferSize:
{
const int bufferSize(rdwr_readInt(&fShmControl.data->ringBuffer));
const int bufferSize(fShmControl.readInt());
bufferSizeChanged(bufferSize);
break;
}

case kPluginBridgeOpcodeSetSampleRate:
{
const float sampleRate(rdwr_readFloat(&fShmControl.data->ringBuffer));
const float sampleRate(fShmControl.readFloat());
sampleRateChanged(sampleRate);
break;
}

case kPluginBridgeOpcodeSetParameter:
{
const int index(rdwr_readInt(&fShmControl.data->ringBuffer));
const float value(rdwr_readFloat(&fShmControl.data->ringBuffer));
const int index(fShmControl.readInt());
const float value(fShmControl.readFloat());

CarlaPlugin* const plugin(getPluginUnchecked(0));

@@ -223,7 +325,7 @@ public:

case kPluginBridgeOpcodeSetProgram:
{
const int index(rdwr_readInt(&fShmControl.data->ringBuffer));
const int index(fShmControl.readInt());

CarlaPlugin* const plugin(getPluginUnchecked(0));

@@ -238,7 +340,7 @@ public:

case kPluginBridgeOpcodeSetMidiProgram:
{
const int index(rdwr_readInt(&fShmControl.data->ringBuffer));
const int index(fShmControl.readInt());

CarlaPlugin* const plugin(getPluginUnchecked(0));

@@ -254,13 +356,13 @@ public:
case kPluginBridgeOpcodeMidiEvent:
{
uint8_t data[4] = { 0 };
const long time(rdwr_readLong(&fShmControl.data->ringBuffer));
const int dataSize(rdwr_readInt(&fShmControl.data->ringBuffer));
const long time(fShmControl.readLong());
const int dataSize(fShmControl.readInt());

CARLA_ASSERT_INT(dataSize >= 1 && dataSize <= 4, dataSize);

for (int i=0; i < dataSize && i < 4; ++i)
data[i] = rdwr_readChar(&fShmControl.data->ringBuffer);
data[i] = fShmControl.readChar();

CARLA_ASSERT(kData->bufEvents.in != nullptr);

@@ -311,52 +413,12 @@ public:
}

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

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

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

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

} fShmControl;
BridgeAudioPool fShmAudioPool;
BridgeControl fShmControl;

bool fIsRunning;
bool fQuitNow;

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

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

fShmAudioPool.data = nullptr;
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)
};



+ 1
- 0
source/backend/engine/CarlaEngineJack.cpp View File

@@ -2231,6 +2231,7 @@ private:

CarlaEngine* CarlaEngine::newJack()
{
carla_debug("CarlaEngine::newJack()");
return new CarlaEngineJack();
}



+ 1
- 0
source/backend/engine/distrho/DistrhoPluginInfo.h View File

@@ -29,6 +29,7 @@
#define DISTRHO_PLUGIN_WANT_LATENCY 0
#define DISTRHO_PLUGIN_WANT_PROGRAMS 1
#define DISTRHO_PLUGIN_WANT_STATE 1
#define DISTRHO_PLUGIN_WANT_TIMEPOS 1

#define DISTRHO_PLUGIN_URI "http://kxstudio.sf.net/carla"



+ 239
- 144
source/backend/plugin/BridgePlugin.cpp View File

@@ -71,26 +71,26 @@ shm_t shm_mkstemp(char* const fileBase)
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";

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

shm_t shm;
carla_shm_init(shm);
shm_t fakeShm;
carla_shm_init(fakeShm);

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

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

while (true)
for (;;)
{
for (int c = size - 6; c < size; ++c)
for (size_t c = fileBaseLen - 6; c < fileBaseLen; ++c)
{
// Note the -1 to avoid the trailing '\0' in charSet.
fileBase[c] = charSet[std::rand() % (sizeof(charSet) - 1)];
@@ -105,6 +105,139 @@ shm_t shm_mkstemp(char* const fileBase)

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

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

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

~BridgeAudioPool()
{
// should be cleared by now
CARLA_ASSERT(data == nullptr);

clear();
}

void clear()
{
filename.clear();

if (! carla_is_shm_valid(shm))
return;

if (data != nullptr)
{
carla_shm_unmap(shm, data, size);
data = nullptr;
}

size = 0;

carla_shm_close(shm);
}

void resize(const uint32_t bufferSize, const uint32_t portCount)
{
if (data != nullptr)
carla_shm_unmap(shm, data, size);

size = portCount*bufferSize*sizeof(float);

if (size == 0)
size = sizeof(float);

data = (float*)carla_shm_map(shm, size);
}
};

struct BridgeControl : public RingBufferControl {
CarlaString filename;
BridgeShmControl* data;
shm_t shm;

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

~BridgeControl()
{
// should be cleared by now
CARLA_ASSERT(data == nullptr);

clear();
}

void clear()
{
filename.clear();

if (! carla_is_shm_valid(shm))
return;

if (data != nullptr)
{
carla_shm_unmap(shm, data, sizeof(BridgeShmControl));
data = nullptr;
}

carla_shm_close(shm);
}

bool mapData()
{
CARLA_ASSERT(data == nullptr);

if (carla_shm_map<BridgeShmControl>(shm, data))
{
setRingBuffer(&data->ringBuffer, true);
return true;
}

return false;
}

void unmapData()
{
CARLA_ASSERT(data != nullptr);

if (data == nullptr)
return;

carla_shm_unmap(shm, data, sizeof(BridgeShmControl));
data = nullptr;

setRingBuffer(nullptr, false);
}

bool waitForServer()
{
CARLA_ASSERT(data != nullptr);

if (data == nullptr)
return false;

jackbridge_sem_post(&data->runServer);

return jackbridge_sem_timedwait(&data->runClient, 5);
}

void writeOpcode(const PluginBridgeOpcode opcode)
{
writeInt(static_cast<int>(opcode));
}
};

struct BridgeParamInfo {
float value;
CarlaString name;
@@ -116,6 +249,8 @@ struct BridgeParamInfo {
CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(BridgeParamInfo)
};

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

class BridgePlugin : public CarlaPlugin
{
public:
@@ -126,6 +261,7 @@ public:
fInitiated(false),
fInitError(false),
fSaved(false),
fNeedsSemDestroy(false),
fParams(nullptr)
{
carla_debug("BridgePlugin::BridgePlugin(%p, %i, %s, %s)", engine, id, BinaryType2Str(btype), PluginType2Str(ptype));
@@ -153,9 +289,9 @@ public:

if (kData->osc.thread.isRunning())
{
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeQuit);
rdwr_commitWrite(&fShmControl.data->ringBuffer);
waitForServer();
fShmControl.writeOpcode(kPluginBridgeOpcodeQuit);
fShmControl.commitWrite();
fShmControl.waitForServer();
}

if (kData->osc.data.target != nullptr)
@@ -173,7 +309,15 @@ public:
kData->osc.thread.terminate();
}

cleanup();
if (fNeedsSemDestroy)
{
jackbridge_sem_destroy(&fShmControl.data->runServer);
jackbridge_sem_destroy(&fShmControl.data->runClient);
}

fShmAudioPool.clear();
fShmControl.clear();

clearBuffers();

//info.chunk.clear();
@@ -336,13 +480,13 @@ public:
if (doLock)
kData->singleMutex.lock();

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetParameter);
rdwr_writeInt(&fShmControl.data->ringBuffer, parameterId);
rdwr_writeFloat(&fShmControl.data->ringBuffer, value);
fShmControl.writeOpcode(kPluginBridgeOpcodeSetParameter);
fShmControl.writeInt(parameterId);
fShmControl.writeFloat(value);

if (doLock)
{
rdwr_commitWrite(&fShmControl.data->ringBuffer);
fShmControl.commitWrite();
kData->singleMutex.unlock();
}

@@ -363,12 +507,12 @@ public:
if (doLock)
kData->singleMutex.lock();

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetProgram);
rdwr_writeInt(&fShmControl.data->ringBuffer, index);
fShmControl.writeOpcode(kPluginBridgeOpcodeSetProgram);
fShmControl.writeInt(index);

if (doLock)
{
rdwr_commitWrite(&fShmControl.data->ringBuffer);
fShmControl.commitWrite();
kData->singleMutex.unlock();
}

@@ -389,12 +533,12 @@ public:
if (doLock)
kData->singleMutex.lock();

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetMidiProgram);
rdwr_writeInt(&fShmControl.data->ringBuffer, index);
fShmControl.writeOpcode(kPluginBridgeOpcodeSetMidiProgram);
fShmControl.writeInt(index);

if (doLock)
{
rdwr_commitWrite(&fShmControl.data->ringBuffer);
fShmControl.commitWrite();
kData->singleMutex.unlock();
}

@@ -597,20 +741,20 @@ public:
void activate() override
{
// already locked before
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetParameter);
rdwr_writeInt(&fShmControl.data->ringBuffer, PARAMETER_ACTIVE);
rdwr_writeFloat(&fShmControl.data->ringBuffer, 1.0f);
rdwr_commitWrite(&fShmControl.data->ringBuffer);
fShmControl.writeOpcode(kPluginBridgeOpcodeSetParameter);
fShmControl.writeInt(PARAMETER_ACTIVE);
fShmControl.writeFloat(1.0f);
fShmControl.commitWrite();
waitForServer();
}

void deactivate() override
{
// already locked before
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetParameter);
rdwr_writeInt(&fShmControl.data->ringBuffer, PARAMETER_ACTIVE);
rdwr_writeFloat(&fShmControl.data->ringBuffer, 0.0f);
rdwr_commitWrite(&fShmControl.data->ringBuffer);
fShmControl.writeOpcode(kPluginBridgeOpcodeSetParameter);
fShmControl.writeInt(PARAMETER_ACTIVE);
fShmControl.writeFloat(0.0f);
fShmControl.commitWrite();
waitForServer();
}

@@ -662,12 +806,12 @@ public:
data2 = note.note;
data3 = note.velo;

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeMidiEvent);
rdwr_writeLong(&fShmControl.data->ringBuffer, 0);
rdwr_writeInt(&fShmControl.data->ringBuffer, 3);
rdwr_writeChar(&fShmControl.data->ringBuffer, data1);
rdwr_writeChar(&fShmControl.data->ringBuffer, data2);
rdwr_writeChar(&fShmControl.data->ringBuffer, data3);
fShmControl.writeOpcode(kPluginBridgeOpcodeMidiEvent);
fShmControl.writeLong(0);
fShmControl.writeInt(3);
fShmControl.writeChar(data1);
fShmControl.writeChar(data2);
fShmControl.writeChar(data3);
}

kData->extNotes.mutex.unlock();
@@ -785,12 +929,12 @@ public:

if ((fOptions & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param <= 0x5F)
{
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeMidiEvent);
rdwr_writeLong(&fShmControl.data->ringBuffer, event.time);
rdwr_writeInt(&fShmControl.data->ringBuffer, 3);
rdwr_writeChar(&fShmControl.data->ringBuffer, MIDI_STATUS_CONTROL_CHANGE + event.channel);
rdwr_writeChar(&fShmControl.data->ringBuffer, ctrlEvent.param);
rdwr_writeChar(&fShmControl.data->ringBuffer, ctrlEvent.value*127.0f);
fShmControl.writeOpcode(kPluginBridgeOpcodeMidiEvent);
fShmControl.writeLong(event.time);
fShmControl.writeInt(3);
fShmControl.writeChar(MIDI_STATUS_CONTROL_CHANGE + event.channel);
fShmControl.writeChar(ctrlEvent.param);
fShmControl.writeChar(ctrlEvent.value*127.0f);
}

break;
@@ -874,12 +1018,12 @@ public:
data[2] = midiEvent.data[2];
data[3] = midiEvent.data[3];

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeMidiEvent);
rdwr_writeLong(&fShmControl.data->ringBuffer, event.time);
rdwr_writeInt(&fShmControl.data->ringBuffer, midiEvent.size);
fShmControl.writeOpcode(kPluginBridgeOpcodeMidiEvent);
fShmControl.writeLong(event.time);
fShmControl.writeInt(midiEvent.size);

for (uint8_t j=0; j < midiEvent.size && j < 4; ++j)
rdwr_writeChar(&fShmControl.data->ringBuffer, data[j]);
fShmControl.writeChar(data[j]);

if (status == MIDI_STATUS_NOTE_ON)
postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]);
@@ -944,8 +1088,8 @@ public:
// --------------------------------------------------------------------------------------------------------
// Run plugin

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeProcess);
rdwr_commitWrite(&fShmControl.data->ringBuffer);
fShmControl.writeOpcode(kPluginBridgeOpcodeProcess);
fShmControl.commitWrite();

if (! waitForServer())
{
@@ -1030,17 +1174,17 @@ public:
{
resizeAudioPool(newBufferSize);

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetBufferSize);
rdwr_writeInt(&fShmControl.data->ringBuffer, newBufferSize);
rdwr_commitWrite(&fShmControl.data->ringBuffer);
fShmControl.writeOpcode(kPluginBridgeOpcodeSetBufferSize);
fShmControl.writeInt(newBufferSize);
fShmControl.commitWrite();

}

void sampleRateChanged(const double newSampleRate) override
{
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetSampleRate);
rdwr_writeFloat(&fShmControl.data->ringBuffer, newSampleRate);
rdwr_commitWrite(&fShmControl.data->ringBuffer);
fShmControl.writeOpcode(kPluginBridgeOpcodeSetSampleRate);
fShmControl.writeFloat(newSampleRate);
fShmControl.commitWrite();
}

// -------------------------------------------------------------------
@@ -1569,7 +1713,6 @@ public:

if (! carla_is_shm_valid(fShmAudioPool.shm))
{
//_cleanup();
carla_stdout("Failed to open or create shared memory file #1");
return false;
}
@@ -1588,48 +1731,57 @@ public:

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

fShmControl.filename = tmpFileBase;

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

CARLA_ASSERT(fShmControl.data != nullptr);

std::memset(fShmControl.data, 0, sizeof(BridgeShmControl));
std::strcpy(fShmControl.data->ringBuffer.buf, "This thing is actually working!!!!");

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

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

fNeedsSemDestroy = true;
}

// initial values
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetBufferSize);
rdwr_writeInt(&fShmControl.data->ringBuffer, kData->engine->getBufferSize());
fShmControl.writeOpcode(kPluginBridgeOpcodeSetBufferSize);
fShmControl.writeInt(kData->engine->getBufferSize());

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetSampleRate);
rdwr_writeFloat(&fShmControl.data->ringBuffer, kData->engine->getSampleRate());
fShmControl.writeOpcode(kPluginBridgeOpcodeSetSampleRate);
fShmControl.writeFloat(kData->engine->getSampleRate());

rdwr_commitWrite(&fShmControl.data->ringBuffer);
fShmControl.commitWrite();

// register plugin now so we can receive OSC (and wait for it)
fHints |= PLUGIN_IS_BRIDGE;
@@ -1689,35 +1841,12 @@ private:
bool fInitiated;
bool fInitError;
bool fSaved;
bool fNeedsSemDestroy;

CarlaString fBridgeBinary;

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;
BridgeAudioPool fShmAudioPool;
BridgeControl fShmControl;

struct Info {
uint32_t aIns, aOuts;
@@ -1741,59 +1870,20 @@ private:

BridgeParamInfo* fParams;

void cleanup()
void resizeAudioPool(const uint32_t bufferSize)
{
if (fShmAudioPool.filename.isNotEmpty())
fShmAudioPool.filename.clear();
fShmAudioPool.resize(bufferSize, fInfo.aIns+fInfo.aOuts);

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

if (fShmAudioPool.data != nullptr)
{
carla_shm_unmap(fShmAudioPool.shm, fShmAudioPool.data, fShmAudioPool.size);
fShmAudioPool.data = nullptr;
}

fShmAudioPool.size = 0;

if (fShmControl.data != nullptr)
{
carla_shm_unmap(fShmControl.shm, fShmControl.data, sizeof(BridgeShmControl));
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);
}

void resizeAudioPool(uint32_t bufferSize)
{
if (fShmAudioPool.data != nullptr)
carla_shm_unmap(fShmAudioPool.shm, fShmAudioPool.data, fShmAudioPool.size);

fShmAudioPool.size = (fInfo.aIns+fInfo.aOuts)*bufferSize*sizeof(float);

if (fShmAudioPool.size == 0)
fShmAudioPool.size = sizeof(float);

fShmAudioPool.data = (float*)carla_shm_map(fShmAudioPool.shm, fShmAudioPool.size);

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetAudioPool);
rdwr_writeInt(&fShmControl.data->ringBuffer, fShmAudioPool.size);
rdwr_commitWrite(&fShmControl.data->ringBuffer);
fShmControl.writeOpcode(kPluginBridgeOpcodeSetAudioPool);
fShmControl.writeLong(fShmAudioPool.size);
fShmControl.commitWrite();

waitForServer();
}

bool waitForServer()
{
sem_post(&fShmControl.data->runServer);

if (! jackbridge_sem_timedwait(&fShmControl.data->runClient, 5))
if (! fShmControl.waitForServer())
{
carla_stderr("waitForServer() timeout");
kData->active = false; // TODO
@@ -1854,18 +1944,23 @@ CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, P
// -------------------------------------------------------------------
// Bridge Helper

#define bridgePlugin ((BridgePlugin*)plugin)

int CarlaPluginSetOscBridgeInfo(CarlaPlugin* const plugin, const PluginBridgeInfoType type,
const int argc, const lo_arg* const* const argv, const char* const types)
{
CARLA_ASSERT(plugin != nullptr && (plugin->hints() & PLUGIN_IS_BRIDGE) != 0);
return ((BridgePlugin*)plugin)->setOscPluginBridgeInfo(type, argc, argv, types);
return bridgePlugin->setOscPluginBridgeInfo(type, argc, argv, types);
}

BinaryType CarlaPluginGetBridgeBinaryType(CarlaPlugin* const plugin)
{
CARLA_ASSERT(plugin != nullptr && (plugin->hints() & PLUGIN_IS_BRIDGE) != 0);
return ((BridgePlugin*)plugin)->binaryType();
return bridgePlugin->binaryType();
}

#undef bridgePlugin

#endif

CARLA_BACKEND_END_NAMESPACE

+ 2
- 0
source/backend/plugin/CarlaPlugin.pro View File

@@ -68,11 +68,13 @@ HEADERS += \

HEADERS += \
../../utils/CarlaUtils.hpp \
../../utils/CarlaBridgeUtils.hpp \
../../utils/CarlaJuceUtils.hpp \
../../utils/CarlaLibUtils.hpp \
../../utils/CarlaOscUtils.hpp \
../../utils/CarlaStateUtils.hpp \
../../utils/CarlaMutex.hpp \
../../utils/CarlaRingBuffer.hpp \
../../utils/CarlaString.hpp

INCLUDEPATH = . .. \


+ 1
- 1
source/libs/distrho/DistrhoUIExternal.hpp View File

@@ -33,7 +33,7 @@ public:
virtual ~ExternalUI() override;

protected:
const char* d_externalFilename() const = 0;
virtual const char* d_externalFilename() const = 0;

private:
friend class UIInternal;


+ 3
- 3
source/libs/distrho/src/DistrhoPluginVST.cpp View File

@@ -211,7 +211,7 @@ protected:
void setParameterValue(uint32_t index, float realValue)
{
const ParameterRanges& ranges(kPlugin->parameterRanges(index));
const float perValue(ranges.normalizeValue(realValue));
const float perValue(ranges.normalizedValue(realValue));

kPlugin->setParameterValue(index, realValue);
hostCallback(audioMasterAutomate, index, 0, nullptr, perValue);
@@ -472,13 +472,13 @@ public:
float vst_getParameter(int32_t index)
{
const ParameterRanges& ranges(fPlugin.parameterRanges(index));
return ranges.normalizeValue(fPlugin.parameterValue(index));
return ranges.normalizedValue(fPlugin.parameterValue(index));
}

void vst_setParameter(int32_t index, float value)
{
const ParameterRanges& ranges(fPlugin.parameterRanges(index));
const float realValue(ranges.unnormalizeValue(value));
const float realValue(ranges.unnormalizedValue(value));
fPlugin.setParameterValue(index, realValue);

#if DISTRHO_PLUGIN_HAS_UI


+ 2
- 0
source/libs/jackbridge/JackBridge.hpp View File

@@ -335,6 +335,8 @@ CARLA_EXPORT bool jackbridge_custom_unpublish_data(jack_client_t* client, const
CARLA_EXPORT bool jackbridge_custom_set_data_appearance_callback(jack_client_t* client, JackCustomDataAppearanceCallback callback, void* arg);
CARLA_EXPORT const char** jackbridge_custom_get_keys(jack_client_t* client, const char* client_name);

CARLA_EXPORT bool jackbridge_sem_init(void* sem);
CARLA_EXPORT bool jackbridge_sem_destroy(void* sem);
CARLA_EXPORT bool jackbridge_sem_post(void* sem);
CARLA_EXPORT bool jackbridge_sem_timedwait(void* sem, int secs);



+ 31
- 9
source/libs/jackbridge/JackBridge2.cpp View File

@@ -18,6 +18,8 @@

#ifndef __JACKBRIDGE_HPP__
// don't include the whole JACK API in this file
CARLA_EXPORT bool jackbridge_sem_init(void* sem);
CARLA_EXPORT bool jackbridge_sem_destroy(void* sem);
CARLA_EXPORT bool jackbridge_sem_post(void* sem);
CARLA_EXPORT bool jackbridge_sem_timedwait(void* sem, int secs);
#endif
@@ -25,6 +27,16 @@ CARLA_EXPORT bool jackbridge_sem_timedwait(void* sem, int secs);
// -----------------------------------------------------------------------------

#if JACKBRIDGE_DUMMY
bool jackbridge_sem_init(void*)
{
return false;
}

bool jackbridge_sem_destroy(void*)
{
return false;
}

bool jackbridge_sem_post(void*)
{
return false;
@@ -38,15 +50,15 @@ bool jackbridge_sem_timedwait(void*, int)

#include <semaphore.h>

#ifdef __WINE__
# define _STRUCT_TIMEVAL 1
# define _SYS_SELECT_H 1
# include <bits/types.h>
struct timespec {
__time_t tv_sec; /* Seconds. */
long int tv_nsec; /* Nanoseconds. */
};
#endif
//#ifdef __WINE__
//# define _STRUCT_TIMEVAL 1
//# define _SYS_SELECT_H 1
//# include <bits/types.h>
//struct timespec {
// __time_t tv_sec; /* Seconds. */
// long int tv_nsec; /* Nanoseconds. */
//};
//#endif

#ifdef CARLA_OS_WIN
# include <sys/time.h>
@@ -54,6 +66,16 @@ struct timespec {
# include <time.h>
#endif

bool jackbridge_sem_init(void* sem)
{
return (sem_init((sem_t*)sem, 1, 0) == 0);
}

bool jackbridge_sem_destroy(void* sem)
{
return (sem_destroy((sem_t*)sem) == 0);
}

bool jackbridge_sem_post(void* sem)
{
return (sem_post((sem_t*)sem) == 0);


+ 15
- 8
source/libs/jackbridge/Makefile View File

@@ -29,11 +29,13 @@ WINE_32BIT_FLAGS = $(32BIT_FLAGS) -L/usr/lib32/wine -L/usr/lib/i386-linux-gnu/wi
WINE_64BIT_FLAGS = $(64BIT_FLAGS) -L/usr/lib64/wine -L/usr/lib/x86_64-linux-gnu/wine
WINE_LINK_FLAGS = $(LINK_FLAGS) -ldl -lrt -lpthread -ljack

OBJS = JackBridge1.cpp JackBridge2.cpp
OBJS = JackBridge1.cpp JackBridge2.cpp
OBJSw32 = JackBridge1.w32.o JackBridge2.w32.o
OBJSw64 = JackBridge1.w64.o JackBridge2.w64.o

# --------------------------------------------------------------

all: test
all:

win32: ../jackbridge-win32.dll
win64: ../jackbridge-win64.dll
@@ -42,8 +44,13 @@ wine64: ../jackbridge-win64.dll.so

# --------------------------------------------------------------

test: $(OBJS)
$(CXX) $^ $(WINE_BUILD_FLAGS) $(WINE_LINK_FLAGS) -o $@
JackBridge%.w32.o: JackBridge%.cpp
$(CXX) $^ $(WINE_BUILD_FLAGS) $(WINE_32BIT_FLAGS) -c -o $@

JackBridge%.w64.o: JackBridge%.cpp
$(CXX) $^ $(WINE_BUILD_FLAGS) $(WINE_64BIT_FLAGS) -c -o $@

# --------------------------------------------------------------

../jackbridge-win32.dll: $(OBJS)
$(CXX) $^ $(WIN_BUILD_FLAGS) $(WIN_32BIT_FLAGS) $(WIN_LINK_FLAGS) -Wl,--output-def,$@.def,--out-implib,$@.a -o $@ $(CMD_STRIP) $@
@@ -51,10 +58,10 @@ test: $(OBJS)
../jackbridge-win64.dll: $(OBJS)
$(CXX) $^ $(WIN_BUILD_FLAGS) $(WIN_64BIT_FLAGS) $(WIN_LINK_FLAGS) -Wl,--output-def,$@.def,--out-implib,$@.a -o $@ $(CMD_STRIP) $@

../jackbridge-win32.dll.so: $(OBJS) ../jackbridge-win32.dll.def
$(WINECXX) $^ $(WINE_BUILD_FLAGS) $(WINE_32BIT_FLAGS) $(WINE_LINK_FLAGS) -mno-cygwin -o $@ $(CMD_STRIP) $@
../jackbridge-win32.dll.so: JackBridge1.cpp JackBridge2.cpp ../jackbridge-win32.dll.def
$(WINECXX) $^ $(WIN_BUILD_FLAGS) $(WINE_32BIT_FLAGS) $(WINE_LINK_FLAGS) -mno-cygwin -o $@ $(CMD_STRIP) $@

../jackbridge-win64.dll.so: $(OBJS) ../jackbridge-win64.dll.def
$(WINECXX) $^ $(WINE_BUILD_FLAGS) $(WINE_64BIT_FLAGS) $(WINE_LINK_FLAGS) -mno-cygwin -o $@ $(CMD_STRIP) $@
../jackbridge-win64.dll.so: JackBridge1.cpp JackBridge2.cpp ../jackbridge-win64.dll.def
$(WINECXX) $^ $(WIN_BUILD_FLAGS) $(WINE_64BIT_FLAGS) $(WINE_LINK_FLAGS) -mno-cygwin -o $@ $(CMD_STRIP) $@

# --------------------------------------------------------------

+ 36
- 190
source/utils/CarlaBridgeUtils.hpp View File

@@ -19,16 +19,12 @@
#ifndef __CARLA_BRIDGE_UTILS_HPP__
#define __CARLA_BRIDGE_UTILS_HPP__

#include "CarlaUtils.hpp"
#include "CarlaRingBuffer.hpp"

#include <semaphore.h>

#define BRIDGE_SHM_RING_BUFFER_SIZE 2048

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

enum PluginBridgeInfoType {
kPluginBridgeAudioCount,
kPluginBridgeAudioCount = 0,
kPluginBridgeMidiCount,
kPluginBridgeParameterCount,
kPluginBridgeProgramCount,
@@ -52,7 +48,7 @@ enum PluginBridgeInfoType {

enum PluginBridgeOpcode {
kPluginBridgeOpcodeNull = 0,
kPluginBridgeOpcodeSetAudioPool = 1, // int
kPluginBridgeOpcodeSetAudioPool = 1, // long
kPluginBridgeOpcodeSetBufferSize = 2, // int
kPluginBridgeOpcodeSetSampleRate = 3, // float
kPluginBridgeOpcodeSetParameter = 4, // int, float
@@ -72,29 +68,25 @@ const char* const CARLA_BRIDGE_MSG_SET_CUSTOM = "CarlaBridgeSetCustom"; //!< Hos
//If \a type is 'chunk' or 'binary' \a rvalue refers to chunk file.
#endif

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

struct BridgeRingBuffer {
int head, tail, written;
bool invalidateCommit;
char buf[BRIDGE_SHM_RING_BUFFER_SIZE];
};
// -------------------------------------------------

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;
void* runServer;
char _alignServer[128];
};
union {
sem_t runClient;
void* runClient;
char _alignClient[128];
};
BridgeRingBuffer ringBuffer;
RingBuffer ringBuffer;

CARLA_DECLARE_NON_COPY_STRUCT(BridgeShmControl)
};

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

static inline
const char* PluginBridgeInfoType2str(const PluginBridgeInfoType type)
@@ -147,183 +139,37 @@ const char* PluginBridgeInfoType2str(const PluginBridgeInfoType type)
return nullptr;
}

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

static inline
void rdwr_tryRead(BridgeRingBuffer* const ringbuf, void* const buf, const size_t size)
const char* PluginBridgeOpcode2str(const PluginBridgeOpcode opcode)
{
CARLA_ASSERT(buf != nullptr);

if (buf == nullptr)
return;

char* const charbuf(static_cast<char*>(buf));

size_t tail = ringbuf->tail;
size_t head = ringbuf->head;
size_t wrap = 0;

if (head <= tail) {
wrap = BRIDGE_SHM_RING_BUFFER_SIZE;
}
if (head - tail + wrap < size) {
return;
}

size_t readto = tail + size;

if (readto >= BRIDGE_SHM_RING_BUFFER_SIZE)
{
readto -= BRIDGE_SHM_RING_BUFFER_SIZE;
size_t firstpart = BRIDGE_SHM_RING_BUFFER_SIZE - tail;
std::memcpy(charbuf, ringbuf->buf + tail, firstpart);
std::memcpy(charbuf + firstpart, ringbuf->buf, readto);
}
else
switch (opcode)
{
std::memcpy(charbuf, ringbuf->buf + tail, size);
case kPluginBridgeOpcodeNull:
return "kPluginBridgeOpcodeNull";
case kPluginBridgeOpcodeSetAudioPool:
return "kPluginBridgeOpcodeSetAudioPool";
case kPluginBridgeOpcodeSetBufferSize:
return "kPluginBridgeOpcodeSetBufferSize";
case kPluginBridgeOpcodeSetSampleRate:
return "kPluginBridgeOpcodeSetSampleRate";
case kPluginBridgeOpcodeSetParameter:
return "kPluginBridgeOpcodeSetParameter";
case kPluginBridgeOpcodeSetProgram:
return "kPluginBridgeOpcodeSetProgram";
case kPluginBridgeOpcodeSetMidiProgram:
return "kPluginBridgeOpcodeSetMidiProgram";
case kPluginBridgeOpcodeMidiEvent:
return "kPluginBridgeOpcodeMidiEvent";
case kPluginBridgeOpcodeProcess:
return "kPluginBridgeOpcodeProcess";
case kPluginBridgeOpcodeQuit:
return "kPluginBridgeOpcodeQuit";
}

ringbuf->tail = readto;
}

static inline
void rdwr_tryWrite(BridgeRingBuffer* const ringbuf, const void* const buf, const size_t size)
{
CARLA_ASSERT(buf != nullptr);

if (buf == nullptr)
return;

const char* const charbuf(static_cast<const char*>(buf));

size_t written = ringbuf->written;
size_t tail = ringbuf->tail;
size_t wrap = 0;

if (tail <= written)
{
wrap = BRIDGE_SHM_RING_BUFFER_SIZE;
}
if (tail - written + wrap < size)
{
carla_stderr2("Ring buffer full! Dropping events.");
ringbuf->invalidateCommit = true;
return;
}

size_t writeto = written + size;

if (writeto >= BRIDGE_SHM_RING_BUFFER_SIZE)
{
writeto -= BRIDGE_SHM_RING_BUFFER_SIZE;
size_t firstpart = BRIDGE_SHM_RING_BUFFER_SIZE - written;
std::memcpy(ringbuf->buf + written, charbuf, firstpart);
std::memcpy(ringbuf->buf, charbuf + firstpart, writeto);
}
else
{
std::memcpy(ringbuf->buf + written, charbuf, size);
}

ringbuf->written = writeto;
}

static inline
void rdwr_commitWrite(BridgeRingBuffer* const ringbuf)
{
if (ringbuf->invalidateCommit)
{
ringbuf->written = ringbuf->head;
ringbuf->invalidateCommit = false;
}
else
{
ringbuf->head = ringbuf->written;
}
}

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

static inline
bool rdwr_dataAvailable(BridgeRingBuffer* const ringbuf)
{
return (ringbuf->tail != ringbuf->head);
}

static inline
PluginBridgeOpcode rdwr_readOpcode(BridgeRingBuffer* const ringbuf)
{
int i = static_cast<int>(kPluginBridgeOpcodeNull);
rdwr_tryRead(ringbuf, &i, sizeof(int));
return static_cast<PluginBridgeOpcode>(i);
}

static inline
char rdwr_readChar(BridgeRingBuffer* const ringbuf)
{
char c = 0;
rdwr_tryRead(ringbuf, &c, sizeof(char));
return c;
}

static inline
int rdwr_readInt(BridgeRingBuffer* const ringbuf)
{
int i = 0;
rdwr_tryRead(ringbuf, &i, sizeof(int));
return i;
}

static inline
long rdwr_readLong(BridgeRingBuffer* const ringbuf)
{
long l = 0;
rdwr_tryRead(ringbuf, &l, sizeof(long));
return l;
}

static inline
float rdwr_readFloat(BridgeRingBuffer* const ringbuf)
{
float f = 0.0f;
rdwr_tryRead(ringbuf, &f, sizeof(float));
return f;
}

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

static inline
void rdwr_writeOpcode(BridgeRingBuffer* const ringbuf, const PluginBridgeOpcode opcode)
{
const int intcode(static_cast<int>(opcode));
rdwr_tryWrite(ringbuf, &intcode, sizeof(int));
}

static inline
void rdwr_writeChar(BridgeRingBuffer* const ringbuf, const char value)
{
rdwr_tryWrite(ringbuf, &value, sizeof(char));
}

static inline
void rdwr_writeInt(BridgeRingBuffer* const ringbuf, const int value)
{
rdwr_tryWrite(ringbuf, &value, sizeof(int));
}

static inline
void rdwr_writeLong(BridgeRingBuffer* const ringbuf, const long value)
{
rdwr_tryWrite(ringbuf, &value, sizeof(long));
}

static inline
void rdwr_writeFloat(BridgeRingBuffer* const ringbuf, const float value)
{
rdwr_tryWrite(ringbuf, &value, sizeof(float));
carla_stderr("CarlaBackend::PluginBridgeOpcode2str(%i) - invalid opcode", opcode);
return nullptr;
}

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

#endif // __CARLA_BRIDGE_UTILS_HPP__

Loading…
Cancel
Save