@@ -619,7 +619,7 @@ enum ProcessMode { | |||
PROCESS_MODE_MULTIPLE_CLIENTS = 1, //!< Multiple client mode (1 master client + 1 client per plugin) | |||
PROCESS_MODE_CONTINUOUS_RACK = 2, //!< Single client, 'rack' mode. Processes plugins in order of id, with forced stereo. | |||
PROCESS_MODE_PATCHBAY = 3, //!< Single client, 'patchbay' mode. | |||
PROCESS_MODE_BRIDGE = 4 //!< Special mode, used in plugin-bridges only. RT buffers come from shared memory in a separate host app. | |||
PROCESS_MODE_BRIDGE = 4 //!< Special mode, used in plugin-bridges only. | |||
}; | |||
/*! | |||
@@ -627,7 +627,8 @@ enum ProcessMode { | |||
*/ | |||
enum TransportMode { | |||
TRANSPORT_MODE_INTERNAL = 0, //!< Internal transport mode. | |||
TRANSPORT_MODE_JACK = 1 //!< JACK transport, only available if driver name is "JACK" | |||
TRANSPORT_MODE_JACK = 1, //!< JACK transport, only available if driver name is "JACK" | |||
TRANSPORT_MODE_BRIDGE = 2 //!< Special mode, used in plugin-bridges only. | |||
}; | |||
/*! | |||
@@ -18,6 +18,8 @@ | |||
#ifndef __CARLA_BRIDGE_HPP__ | |||
#define __CARLA_BRIDGE_HPP__ | |||
#include "CarlaUtils.hpp" | |||
#include <semaphore.h> | |||
#define BRIDGE_SHM_RING_BUFFER_SIZE 2048 | |||
@@ -50,6 +52,14 @@ enum PluginBridgeInfoType { | |||
}; | |||
#endif | |||
enum PluginBridgeOpcode { | |||
kPluginBridgeOpcodeNull = 0, | |||
kPluginBridgeOpcodeReadyWait = 1, | |||
kPluginBridgeOpcodeBufferSize = 2, | |||
kPluginBridgeOpcodeSampleRate = 3, | |||
kPluginBridgeOpcodeProcess = 4 | |||
}; | |||
/*! | |||
* TODO. | |||
*/ | |||
@@ -69,14 +79,154 @@ struct BridgeShmControl { | |||
// Let's make sure there's plenty of room for either one. | |||
union { | |||
sem_t runServer; | |||
char _alignServer[32]; | |||
char _alignServer[64]; | |||
}; | |||
union { | |||
sem_t runClient; | |||
char _alignClient[32]; | |||
char _alignClient[64]; | |||
}; | |||
BridgeRingBuffer ringBuffer; | |||
}; | |||
// --------------------------------------------------------------------------------------------- | |||
static inline | |||
void rdwr_tryRead(BridgeRingBuffer* const ringbuf, void* const buf, const size_t size) | |||
{ | |||
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 | |||
{ | |||
std::memcpy(charbuf, ringbuf->buf + tail, size); | |||
} | |||
ringbuf->tail = readto; | |||
} | |||
static inline | |||
void rdwr_tryWrite(BridgeRingBuffer* const ringbuf, const void* const buf, const size_t size) | |||
{ | |||
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("Operation 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) | |||
{ | |||
PluginBridgeOpcode code = kPluginBridgeOpcodeNull; | |||
rdwr_tryRead(ringbuf, &code, sizeof(PluginBridgeOpcode)); | |||
return code; | |||
} | |||
static inline | |||
int rdwr_readInt(BridgeRingBuffer* const ringbuf) | |||
{ | |||
int i = 0; | |||
rdwr_tryRead(ringbuf, &i, sizeof(int)); | |||
return i; | |||
} | |||
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) | |||
{ | |||
rdwr_tryWrite(ringbuf, &opcode, sizeof(PluginBridgeOpcode)); | |||
} | |||
static inline | |||
void rdwr_writeInt(BridgeRingBuffer* const ringbuf, const int value) | |||
{ | |||
rdwr_tryWrite(ringbuf, &value, sizeof(int)); | |||
} | |||
static inline | |||
void rdwr_writeFloat(BridgeRingBuffer* const ringbuf, const float value) | |||
{ | |||
rdwr_tryWrite(ringbuf, &value, sizeof(float)); | |||
} | |||
// --------------------------------------------------------------------------------------------- | |||
#endif // __CARLA_BRIDGE_HPP__ |
@@ -23,8 +23,6 @@ | |||
#ifdef BUILD_BRIDGE | |||
struct CarlaOscData; | |||
#else | |||
class QProcessEnvironment; | |||
#endif | |||
CARLA_BACKEND_START_NAMESPACE | |||
@@ -913,20 +911,13 @@ public: | |||
*/ | |||
void setAboutToClose(); | |||
#ifndef BUILD_BRIDGE | |||
// ------------------------------------------------------------------- | |||
// Options | |||
/*! | |||
* Get the engine options as process environment. | |||
*/ | |||
const QProcessEnvironment& getOptionsAsProcessEnvironment() const; | |||
/*! | |||
* Set the engine option \a option. | |||
*/ | |||
void setOption(const OptionsType option, const int value, const char* const valueStr); | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// OSC Stuff | |||
@@ -1013,9 +1004,6 @@ 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 | |||
@@ -1038,6 +1026,8 @@ private: | |||
public: | |||
#ifdef BUILD_BRIDGE | |||
static CarlaEngine* newBridge(const char* const audioBaseName, const char* const controlBaseName); | |||
void osc_send_bridge_audio_count(const int32_t ins, const int32_t outs, const int32_t total); | |||
void osc_send_bridge_midi_count(const int32_t ins, const int32_t outs, const int32_t total); | |||
void osc_send_bridge_parameter_count(const int32_t ins, const int32_t outs, const int32_t total); | |||
@@ -804,7 +804,7 @@ public: | |||
static const PluginDescriptor* getNativePluginDescriptor(const size_t index); | |||
static CarlaPlugin* newNative(const Initializer& init); | |||
static CarlaPlugin* newBridge(const Initializer& init, const BinaryType btype, const PluginType ptype, const char* const bridgeFilename); | |||
static CarlaPlugin* newBridge(const Initializer& init, const BinaryType btype, const PluginType ptype, const char* const bridgeBinary); | |||
static CarlaPlugin* newLADSPA(const Initializer& init, const LADSPA_RDF_Descriptor* const rdfDescriptor); | |||
static CarlaPlugin* newDSSI(const Initializer& init, const char* const guiFilename); | |||
@@ -250,6 +250,11 @@ CARLA_EXPORT void carla_nsm_reply_open(); | |||
CARLA_EXPORT void carla_nsm_reply_save(); | |||
#endif | |||
#ifdef BUILD_BRIDGE | |||
CARLA_EXPORT bool carla_engine_init_bridge(const char* audioBaseName, const char* controlBaseName, const char* clientName); | |||
CARLA_EXPORT CarlaBackend::CarlaEngine* carla_get_standalone_engine(); | |||
#endif | |||
/**@}*/ | |||
#endif // __CARLA_STANDALONE_HPP__ |
@@ -101,7 +101,7 @@ CarlaEngineEventPort::CarlaEngineEventPort(const bool isInput, const ProcessMode | |||
{ | |||
carla_debug("CarlaEngineEventPort::CarlaEngineEventPort(%s, %s)", bool2str(isInput), ProcessMode2Str(processMode)); | |||
if (kProcessMode == PROCESS_MODE_PATCHBAY) | |||
if (kProcessMode == PROCESS_MODE_PATCHBAY || kProcessMode == PROCESS_MODE_BRIDGE) | |||
fBuffer = new EngineEvent[PATCHBAY_EVENT_COUNT]; | |||
} | |||
@@ -109,7 +109,7 @@ CarlaEngineEventPort::~CarlaEngineEventPort() | |||
{ | |||
carla_debug("CarlaEngineEventPort::~CarlaEngineEventPort()"); | |||
if (kProcessMode == PROCESS_MODE_PATCHBAY) | |||
if (kProcessMode == PROCESS_MODE_PATCHBAY || kProcessMode == PROCESS_MODE_BRIDGE) | |||
{ | |||
CARLA_ASSERT(fBuffer != nullptr); | |||
@@ -128,22 +128,23 @@ void CarlaEngineEventPort::initBuffer(CarlaEngine* const engine) | |||
#ifndef BUILD_BRIDGE | |||
if (kProcessMode == PROCESS_MODE_CONTINUOUS_RACK) | |||
fBuffer = engine->getRackEventBuffer(kIsInput); | |||
else if (kProcessMode == PROCESS_MODE_PATCHBAY && ! kIsInput) | |||
carla_zeroMem(fBuffer, sizeof(EngineEvent)*PATCHBAY_EVENT_COUNT); | |||
else | |||
#endif | |||
if ((kProcessMode == PROCESS_MODE_PATCHBAY || kProcessMode == PROCESS_MODE_BRIDGE) && ! kIsInput) | |||
carla_zeroMem(fBuffer, sizeof(EngineEvent)*PATCHBAY_EVENT_COUNT); | |||
} | |||
uint32_t CarlaEngineEventPort::getEventCount() | |||
{ | |||
CARLA_ASSERT(kIsInput); | |||
CARLA_ASSERT(fBuffer != nullptr); | |||
CARLA_ASSERT(kProcessMode == PROCESS_MODE_CONTINUOUS_RACK || kProcessMode == PROCESS_MODE_PATCHBAY); | |||
CARLA_ASSERT(kProcessMode == PROCESS_MODE_CONTINUOUS_RACK || kProcessMode == PROCESS_MODE_PATCHBAY || kProcessMode == PROCESS_MODE_BRIDGE); | |||
if (! kIsInput) | |||
return 0; | |||
if (fBuffer == nullptr) | |||
return 0; | |||
if (kProcessMode != PROCESS_MODE_CONTINUOUS_RACK && kProcessMode != PROCESS_MODE_PATCHBAY) | |||
if (kProcessMode != PROCESS_MODE_CONTINUOUS_RACK && kProcessMode != PROCESS_MODE_PATCHBAY && kProcessMode != PROCESS_MODE_BRIDGE) | |||
return 0; | |||
uint32_t count = 0; | |||
@@ -162,14 +163,14 @@ const EngineEvent& CarlaEngineEventPort::getEvent(const uint32_t index) | |||
{ | |||
CARLA_ASSERT(kIsInput); | |||
CARLA_ASSERT(fBuffer != nullptr); | |||
CARLA_ASSERT(kProcessMode == PROCESS_MODE_CONTINUOUS_RACK || kProcessMode == PROCESS_MODE_PATCHBAY); | |||
CARLA_ASSERT(kProcessMode == PROCESS_MODE_CONTINUOUS_RACK || kProcessMode == PROCESS_MODE_PATCHBAY || kProcessMode == PROCESS_MODE_BRIDGE); | |||
CARLA_ASSERT(index < kMaxEventCount); | |||
if (! kIsInput) | |||
return kFallbackEngineEvent; | |||
if (fBuffer == nullptr) | |||
return kFallbackEngineEvent; | |||
if (kProcessMode != PROCESS_MODE_CONTINUOUS_RACK && kProcessMode != PROCESS_MODE_PATCHBAY) | |||
if (kProcessMode != PROCESS_MODE_CONTINUOUS_RACK && kProcessMode != PROCESS_MODE_PATCHBAY && kProcessMode != PROCESS_MODE_BRIDGE) | |||
return kFallbackEngineEvent; | |||
if (index >= kMaxEventCount) | |||
return kFallbackEngineEvent; | |||
@@ -181,7 +182,7 @@ void CarlaEngineEventPort::writeControlEvent(const uint32_t time, const uint8_t | |||
{ | |||
CARLA_ASSERT(! kIsInput); | |||
CARLA_ASSERT(fBuffer != nullptr); | |||
CARLA_ASSERT(kProcessMode == PROCESS_MODE_CONTINUOUS_RACK || kProcessMode == PROCESS_MODE_PATCHBAY); | |||
CARLA_ASSERT(kProcessMode == PROCESS_MODE_CONTINUOUS_RACK || kProcessMode == PROCESS_MODE_PATCHBAY || kProcessMode == PROCESS_MODE_BRIDGE); | |||
CARLA_ASSERT(type != kEngineControlEventTypeNull); | |||
CARLA_ASSERT(channel < MAX_MIDI_CHANNELS); | |||
CARLA_SAFE_ASSERT(value >= 0.0 && value <= 1.0); | |||
@@ -190,7 +191,7 @@ void CarlaEngineEventPort::writeControlEvent(const uint32_t time, const uint8_t | |||
return; | |||
if (fBuffer == nullptr) | |||
return; | |||
if (kProcessMode != PROCESS_MODE_CONTINUOUS_RACK && kProcessMode != PROCESS_MODE_PATCHBAY) | |||
if (kProcessMode != PROCESS_MODE_CONTINUOUS_RACK && kProcessMode != PROCESS_MODE_PATCHBAY && kProcessMode != PROCESS_MODE_BRIDGE) | |||
return; | |||
if (type == kEngineControlEventTypeNull) | |||
return; | |||
@@ -224,7 +225,7 @@ void CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t cha | |||
{ | |||
CARLA_ASSERT(! kIsInput); | |||
CARLA_ASSERT(fBuffer != nullptr); | |||
CARLA_ASSERT(kProcessMode == PROCESS_MODE_CONTINUOUS_RACK || kProcessMode == PROCESS_MODE_PATCHBAY); | |||
CARLA_ASSERT(kProcessMode == PROCESS_MODE_CONTINUOUS_RACK || kProcessMode == PROCESS_MODE_PATCHBAY || kProcessMode == PROCESS_MODE_BRIDGE); | |||
CARLA_ASSERT(channel < MAX_MIDI_CHANNELS); | |||
CARLA_ASSERT(data != nullptr); | |||
CARLA_ASSERT(size > 0); | |||
@@ -233,7 +234,7 @@ void CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t cha | |||
return; | |||
if (fBuffer == nullptr) | |||
return; | |||
if (kProcessMode != PROCESS_MODE_CONTINUOUS_RACK && kProcessMode != PROCESS_MODE_PATCHBAY) | |||
if (kProcessMode != PROCESS_MODE_CONTINUOUS_RACK && kProcessMode != PROCESS_MODE_PATCHBAY && kProcessMode != PROCESS_MODE_BRIDGE) | |||
return; | |||
if (channel >= MAX_MIDI_CHANNELS) | |||
return; | |||
@@ -641,7 +642,7 @@ bool CarlaEngine::close() | |||
void CarlaEngine::idle() | |||
{ | |||
CARLA_ASSERT(kData->plugins != nullptr); | |||
CARLA_ASSERT(isRunning()); | |||
//CARLA_ASSERT(isRunning()); | |||
for (unsigned int i=0; i < kData->curPluginCount; i++) | |||
{ | |||
@@ -714,26 +715,10 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, cons | |||
bridgeBinary = (const char*)fOptions.bridge_native; | |||
#endif | |||
if (fOptions.preferPluginBridges && bridgeBinary != nullptr) | |||
if (true) | |||
//if (fOptions.preferPluginBridges && bridgeBinary != nullptr) | |||
{ | |||
// TODO | |||
if (fOptions.processMode != PROCESS_MODE_MULTIPLE_CLIENTS) | |||
{ | |||
setLastError("Can only use bridged plugins in JACK Multi-Client mode"); | |||
return -1; | |||
} | |||
// TODO | |||
if (type() != kEngineTypeJack) | |||
{ | |||
setLastError("Can only use bridged plugins with JACK backend"); | |||
return -1; | |||
} | |||
#if 0 | |||
plugin = CarlaPlugin::newBridge(init, btype, ptype, bridgeBinary); | |||
#endif | |||
setLastError("Bridged plugins are not implemented yet"); | |||
} | |||
else | |||
#endif // BUILD_BRIDGE | |||
@@ -1207,13 +1192,6 @@ void CarlaEngine::setAboutToClose() | |||
// ----------------------------------------------------------------------- | |||
// Global options | |||
#ifndef BUILD_BRIDGE | |||
const QProcessEnvironment& CarlaEngine::getOptionsAsProcessEnvironment() const | |||
{ | |||
return kData->procEnv; | |||
} | |||
#define CARLA_ENGINE_SET_OPTION_RUNNING_CHECK \ | |||
if (isRunning()) \ | |||
return carla_stderr("CarlaEngine::setOption(%s, %i, \"%s\") - Cannot set this option while engine is running!", OptionsType2Str(option), value, valueStr); | |||
@@ -1231,7 +1209,7 @@ void CarlaEngine::setOption(const OptionsType option, const int value, const cha | |||
case OPTION_PROCESS_MODE: | |||
CARLA_ENGINE_SET_OPTION_RUNNING_CHECK | |||
if (value < PROCESS_MODE_SINGLE_CLIENT || value > PROCESS_MODE_PATCHBAY) | |||
if (value < PROCESS_MODE_SINGLE_CLIENT || value > PROCESS_MODE_BRIDGE) | |||
return carla_stderr("CarlaEngine::setOption(%s, %i, \"%s\") - invalid value", OptionsType2Str(option), value, valueStr); | |||
fOptions.processMode = static_cast<ProcessMode>(value); | |||
@@ -1240,7 +1218,7 @@ void CarlaEngine::setOption(const OptionsType option, const int value, const cha | |||
case OPTION_TRANSPORT_MODE: | |||
// FIXME: Always enable JACK transport for now | |||
#if 0 | |||
if (value < CarlaBackend::TRANSPORT_MODE_INTERNAL || value > CarlaBackend::TRANSPORT_MODE_JACK) | |||
if (value < CarlaBackend::TRANSPORT_MODE_INTERNAL || value > CarlaBackend::TRANSPORT_MODE_BRIDGE) | |||
return carla_stderr2("carla_set_engine_option(OPTION_TRANSPORT_MODE, %i, \"%s\") - invalid value", value, valueStr); | |||
fOptions.transportMode = static_cast<CarlaBackend::TransportMode>(value); | |||
@@ -1293,6 +1271,7 @@ void CarlaEngine::setOption(const OptionsType option, const int value, const cha | |||
fOptions.oscUiTimeout = static_cast<uint>(value); | |||
break; | |||
#ifndef BUILD_BRIDGE | |||
case OPTION_PATH_BRIDGE_NATIVE: | |||
fOptions.bridge_native = valueStr; | |||
break; | |||
@@ -1308,6 +1287,7 @@ void CarlaEngine::setOption(const OptionsType option, const int value, const cha | |||
case OPTION_PATH_BRIDGE_WIN64: | |||
fOptions.bridge_win64 = valueStr; | |||
break; | |||
#endif | |||
#ifdef WANT_LV2 | |||
case OPTION_PATH_BRIDGE_LV2_GTK2: | |||
@@ -1346,7 +1326,6 @@ void CarlaEngine::setOption(const OptionsType option, const int value, const cha | |||
#endif | |||
} | |||
} | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
// OSC Stuff | |||
@@ -2167,21 +2146,6 @@ void CarlaEngine::osc_send_bridge_set_chunk_data(const char* const chunkFile) | |||
lo_send(kData->oscData->target, targetPath, "s", chunkFile); | |||
} | |||
} | |||
void CarlaEngine::osc_send_bridge_set_peaks() | |||
{ | |||
CARLA_ASSERT(kData->oscData != nullptr); | |||
const EnginePluginData& pData = kData->plugins[0]; | |||
if (kData->oscData != nullptr && kData->oscData->target != nullptr) | |||
{ | |||
char targetPath[std::strlen(kData->oscData->path)+22]; | |||
std::strcpy(targetPath, kData->oscData->path); | |||
std::strcat(targetPath, "/bridge_set_peaks"); | |||
lo_send(kData->oscData->target, targetPath, "ffff", pData.insPeak[0], pData.insPeak[1], pData.outsPeak[0], pData.outsPeak[1]); | |||
} | |||
} | |||
#endif | |||
CARLA_BACKEND_END_NAMESPACE |
@@ -21,9 +21,17 @@ | |||
#include "CarlaBackendUtils.hpp" | |||
#include "CarlaMIDI.h" | |||
#include "CarlaBridge.hpp" | |||
#include "../CarlaBridge.hpp" | |||
#include "CarlaShmUtils.hpp" | |||
#include "jackbridge/jackbridge.h" | |||
#include <ctime> | |||
//#ifdef CARLA_OS_WIN | |||
//# include <sys/time.h> | |||
//#endif | |||
CARLA_BACKEND_START_NAMESPACE | |||
#if 0 | |||
@@ -32,16 +40,22 @@ CARLA_BACKEND_START_NAMESPACE | |||
// ----------------------------------------- | |||
class CarlaEngineBridge : public CarlaEngine | |||
class CarlaEngineBridge : public CarlaEngine, | |||
public CarlaThread | |||
{ | |||
public: | |||
CarlaEngineBridge(const char* const audioBaseName, const char* const controlBaseName) | |||
: CarlaEngine() | |||
: CarlaEngine(), | |||
fIsRunning(false), | |||
fQuitNow(false) | |||
{ | |||
carla_debug("CarlaEngineBridge::CarlaEngineBridge()"); | |||
fShmAudioPool.filename = "/carla-bridge_shm_" + audioBaseName; | |||
fShmControl.filename = "/carla-bridge_shc_" + controlBaseName; | |||
fShmAudioPool.filename = "/carla-bridge_shm_"; | |||
fShmAudioPool.filename += audioBaseName; | |||
fShmControl.filename = "/carla-bridge_shc_"; | |||
fShmControl.filename += controlBaseName; | |||
} | |||
~CarlaEngineBridge() | |||
@@ -56,11 +70,14 @@ public: | |||
{ | |||
carla_debug("CarlaEngineBridge::init(\"%s\")", clientName); | |||
char tmpFileBase[60]; | |||
// 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)) | |||
{ | |||
@@ -72,7 +89,12 @@ 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)) | |||
{ | |||
@@ -81,7 +103,7 @@ public: | |||
return false; | |||
} | |||
if (! carla_shm_map<ShmControl>(fShmControl.shm, fShmControl.data)) | |||
if (! carla_shm_map<BridgeShmControl>(fShmControl.shm, fShmControl.data)) | |||
{ | |||
_cleanup(); | |||
carla_stdout("Failed to mmap shared memory file"); | |||
@@ -89,7 +111,20 @@ public: | |||
} | |||
} | |||
CarlaEngine::init(fName); | |||
// Read values from memory | |||
CARLA_ASSERT(rdwr_readOpcode(&fShmControl.data->ringBuffer) == kPluginBridgeOpcodeBufferSize); | |||
fBufferSize = rdwr_readInt(&fShmControl.data->ringBuffer); | |||
carla_stderr("BufferSize: %i", fBufferSize); | |||
CARLA_ASSERT(rdwr_readOpcode(&fShmControl.data->ringBuffer) == kPluginBridgeOpcodeSampleRate); | |||
fSampleRate = rdwr_readFloat(&fShmControl.data->ringBuffer); | |||
carla_stderr("SampleRate: %f", fSampleRate); | |||
fQuitNow = false; | |||
fIsRunning = true; | |||
CarlaThread::start(); | |||
CarlaEngine::init(clientName); | |||
return true; | |||
} | |||
@@ -98,6 +133,9 @@ public: | |||
carla_debug("CarlaEnginePlugin::close()"); | |||
CarlaEngine::close(); | |||
fQuitNow = true; | |||
CarlaThread::stop(); | |||
_cleanup(); | |||
return true; | |||
@@ -105,7 +143,7 @@ public: | |||
bool isRunning() const | |||
{ | |||
return true; | |||
return fIsRunning; | |||
} | |||
bool isOffline() const | |||
@@ -118,16 +156,113 @@ public: | |||
return kEngineTypeBridge; | |||
} | |||
// ------------------------------------- | |||
// CarlaThread virtual calls | |||
void run() | |||
{ | |||
// TODO - set RT permissions | |||
const int timeout = 50; | |||
while (! fQuitNow) | |||
{ | |||
carla_debug("RUN 001"); | |||
timespec ts_timeout; | |||
#if 0//def CARLA_OS_WIN | |||
timeval now; | |||
gettimeofday(&now, nullptr); | |||
ts_timeout.tv_sec = now.tv_sec; | |||
ts_timeout.tv_nsec = now.tv_usec * 1000; | |||
#else | |||
linux_clock_gettime_rt(&ts_timeout); | |||
#endif | |||
time_t seconds = timeout / 1000; | |||
ts_timeout.tv_sec += seconds; | |||
ts_timeout.tv_nsec += (timeout - seconds * 1000) * 1000000; | |||
if (ts_timeout.tv_nsec >= 1000000000) { | |||
ts_timeout.tv_nsec -= 1000000000; | |||
ts_timeout.tv_sec++; | |||
} | |||
if (linux_sem_timedwait(&fShmControl.data->runServer, &ts_timeout)) | |||
{ | |||
if (errno == ETIMEDOUT) | |||
{ | |||
continue; | |||
} | |||
else | |||
{ | |||
fQuitNow = true; | |||
break; | |||
} | |||
} | |||
carla_debug("RUN 004"); | |||
while (rdwr_dataAvailable(&fShmControl.data->ringBuffer)) | |||
{ | |||
carla_debug("RUN 005"); | |||
const PluginBridgeOpcode opcode = rdwr_readOpcode(&fShmControl.data->ringBuffer); | |||
switch (opcode) | |||
{ | |||
case kPluginBridgeOpcodeNull: | |||
break; | |||
case kPluginBridgeOpcodeReadyWait: | |||
fShmAudioPool.data = (float*)carla_shm_map(fShmAudioPool.shm, rdwr_readInt(&fShmControl.data->ringBuffer)); | |||
break; | |||
case kPluginBridgeOpcodeBufferSize: | |||
bufferSizeChanged(rdwr_readInt(&fShmControl.data->ringBuffer)); | |||
break; | |||
case kPluginBridgeOpcodeSampleRate: | |||
sampleRateChanged(rdwr_readFloat(&fShmControl.data->ringBuffer)); | |||
break; | |||
case kPluginBridgeOpcodeProcess: | |||
{ | |||
CARLA_ASSERT(fShmAudioPool.data != nullptr); | |||
CarlaPlugin* const plugin(getPluginUnchecked(0)); | |||
carla_debug("RUN 006"); | |||
if (plugin != nullptr && plugin->enabled() && plugin->tryLock()) | |||
{ | |||
const uint32_t inCount = plugin->audioInCount(); | |||
const uint32_t outCount = plugin->audioOutCount(); | |||
float* inBuffer[inCount]; | |||
float* outBuffer[outCount]; | |||
for (uint32_t i=0; i < inCount; i++) | |||
inBuffer[i] = fShmAudioPool.data + i*fBufferSize; | |||
for (uint32_t i=0; i < outCount; i++) | |||
outBuffer[i] = fShmAudioPool.data + (i+inCount)*fBufferSize; | |||
plugin->initBuffers(); | |||
plugin->setActive(true, false, false); | |||
plugin->process(inBuffer, outBuffer, fBufferSize); | |||
plugin->unlock(); | |||
} | |||
break; | |||
} | |||
} | |||
} | |||
if (linux_sem_post(&fShmControl.data->runClient) != 0) | |||
carla_stderr2("Could not post to semaphore"); | |||
} | |||
fIsRunning = false; | |||
} | |||
private: | |||
struct BridgeAudioPool { | |||
CarlaString filename; | |||
float* data; | |||
size_t size; | |||
shm_t shm; | |||
BridgeAudioPool() | |||
: data(nullptr), | |||
size(0) | |||
: data(nullptr) | |||
{ | |||
carla_shm_init(shm); | |||
} | |||
@@ -135,7 +270,7 @@ private: | |||
struct BridgeControl { | |||
CarlaString filename; | |||
ShmControl* data; | |||
BridgeShmControl* data; | |||
shm_t shm; | |||
BridgeControl() | |||
@@ -146,6 +281,9 @@ private: | |||
} fShmControl; | |||
bool fIsRunning; | |||
bool fQuitNow; | |||
void _cleanup() | |||
{ | |||
if (fShmAudioPool.filename.isNotEmpty()) | |||
@@ -154,11 +292,7 @@ private: | |||
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)) | |||
@@ -210,9 +210,9 @@ struct CarlaEngineProtectedData { | |||
#ifndef BUILD_BRIDGE | |||
static void registerEnginePlugin(CarlaEngine* const engine, const unsigned int id, CarlaPlugin* const plugin) | |||
{ | |||
CARLA_ASSERT(id < engine->kData->curPluginCount); | |||
CARLA_ASSERT(id == engine->kData->curPluginCount); | |||
if (id < engine->kData->curPluginCount) | |||
if (id == engine->kData->curPluginCount) | |||
engine->kData->plugins[id].plugin = plugin; | |||
} | |||
#endif | |||
@@ -99,10 +99,7 @@ public: | |||
fBufferSize = d_bufferSize(); | |||
fSampleRate = d_sampleRate(); | |||
fName = clientName; | |||
fName.toBasic(); | |||
CarlaEngine::init(fName); | |||
CarlaEngine::init(clientName); | |||
return true; | |||
} | |||
@@ -129,17 +129,13 @@ void CarlaEngineThread::run() | |||
} | |||
} | |||
#ifndef BUILD_BRIDGE | |||
// --------------------------------------------------- | |||
// Update OSC control client peaks | |||
if (oscRegisted) | |||
{ | |||
#ifdef BUILD_BRIDGE | |||
kEngine->osc_send_bridge_set_peaks(); | |||
#else | |||
kEngine->osc_send_control_set_peaks(i); | |||
#endif | |||
} | |||
} | |||
} | |||
@@ -84,8 +84,6 @@ shm_t shm_mkstemp(char* const fileBase) | |||
return shm; | |||
} | |||
std::srand(std::time(NULL)); | |||
while (true) | |||
{ | |||
for (int c = size - 6; c < size; c++) | |||
@@ -136,28 +134,24 @@ public: | |||
kData->singleMutex.lock(); | |||
kData->masterMutex.lock(); | |||
#if 0 | |||
if (osc.data.target) | |||
_cleanup(); | |||
if (kData->osc.data.target != nullptr) | |||
{ | |||
osc_send_hide(&osc.data); | |||
osc_send_quit(&osc.data); | |||
osc.data.free(); | |||
osc_send_hide(&kData->osc.data); | |||
osc_send_quit(&kData->osc.data); | |||
} | |||
if (osc.thread) | |||
{ | |||
// Wait a bit first, try safe quit, then force kill | |||
if (osc.thread->isRunning() && ! osc.thread->wait(3000)) | |||
{ | |||
carla_stderr("Failed to properly stop Plugin Bridge thread"); | |||
osc.thread->terminate(); | |||
} | |||
kData->osc.data.free(); | |||
delete osc.thread; | |||
// Wait a bit first, then force kill | |||
if (kData->osc.thread.isRunning() && ! kData->osc.thread.stop(1000)) // kData->engine->getOptions().oscUiTimeout | |||
{ | |||
carla_stderr("Failed to properly stop Plugin Bridge thread"); | |||
kData->osc.thread.terminate(); | |||
} | |||
info.chunk.clear(); | |||
#endif | |||
//info.chunk.clear(); | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -227,39 +221,29 @@ public: | |||
return params[parameterId].value; | |||
} | |||
#endif | |||
void getLabel(char* const strBuf) | |||
{ | |||
if (info.label) | |||
strncpy(strBuf, info.label, STR_MAX); | |||
else | |||
CarlaPlugin::getLabel(strBuf); | |||
std::strncpy(strBuf, (const char*)fInfo.label, STR_MAX); | |||
} | |||
void getMaker(char* const strBuf) | |||
{ | |||
if (info.maker) | |||
strncpy(strBuf, info.maker, STR_MAX); | |||
else | |||
CarlaPlugin::getMaker(strBuf); | |||
std::strncpy(strBuf, (const char*)fInfo.maker, STR_MAX); | |||
} | |||
void getCopyright(char* const strBuf) | |||
{ | |||
if (info.copyright) | |||
strncpy(strBuf, info.copyright, STR_MAX); | |||
else | |||
CarlaPlugin::getCopyright(strBuf); | |||
std::strncpy(strBuf, (const char*)fInfo.copyright, STR_MAX); | |||
} | |||
void getRealName(char* const strBuf) | |||
{ | |||
if (info.name) | |||
strncpy(strBuf, info.name, STR_MAX); | |||
else | |||
CarlaPlugin::getRealName(strBuf); | |||
std::strncpy(strBuf, (const char*)fInfo.name, STR_MAX); | |||
} | |||
#if 0 | |||
void getParameterName(const uint32_t parameterId, char* const strBuf) | |||
{ | |||
CARLA_ASSERT(parameterId < param.count); | |||
@@ -273,15 +257,6 @@ public: | |||
strncpy(strBuf, params[parameterId].unit.toUtf8().constData(), STR_MAX); | |||
} | |||
void getGuiInfo(GuiType* const type, bool* const resizable) | |||
{ | |||
if (m_hints & PLUGIN_HAS_GUI) | |||
*type = GUI_EXTERNAL_OSC; | |||
else | |||
*type = GUI_NONE; | |||
*resizable = false; | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
@@ -289,12 +264,11 @@ public: | |||
int setOscPluginBridgeInfo(const PluginBridgeInfoType type, const int argc, const lo_arg* const* const argv, const char* const types) | |||
{ | |||
carla_debug("setOscPluginBridgeInfo(%i, %i, %p, \"%s\")", type, argc, argv, types); | |||
carla_stdout("setOscPluginBridgeInfo(%i, %i, %p, \"%s\")", type, argc, argv, types); | |||
#if 0 | |||
switch (type) | |||
{ | |||
case PluginBridgeAudioCount: | |||
case kPluginBridgeAudioCount: | |||
{ | |||
CARLA_BRIDGE_CHECK_OSC_TYPES(3, "iii"); | |||
@@ -306,14 +280,16 @@ public: | |||
CARLA_ASSERT(aOuts >= 0); | |||
CARLA_ASSERT(aIns + aOuts == aTotal); | |||
info.aIns = aIns; | |||
info.aOuts = aOuts; | |||
fInfo.aIns = aIns; | |||
fInfo.aOuts = aOuts; | |||
break; | |||
Q_UNUSED(aTotal); | |||
// unused | |||
(void)aTotal; | |||
} | |||
case PluginBridgeMidiCount: | |||
case kPluginBridgeMidiCount: | |||
{ | |||
CARLA_BRIDGE_CHECK_OSC_TYPES(3, "iii"); | |||
@@ -325,13 +301,16 @@ public: | |||
CARLA_ASSERT(mOuts >= 0); | |||
CARLA_ASSERT(mIns + mOuts == mTotal); | |||
info.mIns = mIns; | |||
info.mOuts = mOuts; | |||
fInfo.mIns = mIns; | |||
fInfo.mOuts = mOuts; | |||
break; | |||
Q_UNUSED(mTotal); | |||
// unused | |||
(void)mTotal; | |||
} | |||
#if 0 | |||
case PluginBridgeParameterCount: | |||
{ | |||
CARLA_BRIDGE_CHECK_OSC_TYPES(3, "iii"); | |||
@@ -438,8 +417,9 @@ public: | |||
break; | |||
} | |||
#endif | |||
case PluginBridgePluginInfo: | |||
case kPluginBridgePluginInfo: | |||
{ | |||
CARLA_BRIDGE_CHECK_OSC_TYPES(7, "iissssh"); | |||
@@ -458,21 +438,23 @@ public: | |||
CARLA_ASSERT(maker); | |||
CARLA_ASSERT(copyright); | |||
m_hints = hints | PLUGIN_IS_BRIDGE; | |||
info.category = (PluginCategory)category; | |||
info.uniqueId = uniqueId; | |||
fHints = hints | PLUGIN_IS_BRIDGE; | |||
info.name = strdup(name); | |||
info.label = strdup(label); | |||
info.maker = strdup(maker); | |||
info.copyright = strdup(copyright); | |||
fInfo.category = static_cast<PluginCategory>(category); | |||
fInfo.uniqueId = uniqueId; | |||
if (! m_name) | |||
m_name = x_engine->getUniquePluginName(name); | |||
fInfo.name = name; | |||
fInfo.label = label; | |||
fInfo.maker = maker; | |||
fInfo.copyright = copyright; | |||
if (fName.isEmpty()) | |||
fName = kData->engine->getNewUniquePluginName(name); | |||
break; | |||
} | |||
#if 0 | |||
case PluginBridgeParameterInfo: | |||
{ | |||
CARLA_BRIDGE_CHECK_OSC_TYPES(3, "iss"); | |||
@@ -753,30 +735,29 @@ public: | |||
break; | |||
} | |||
#endif | |||
case PluginBridgeUpdateNow: | |||
case kPluginBridgeUpdateNow: | |||
{ | |||
m_initiated = true; | |||
fInitiated = true; | |||
break; | |||
} | |||
case PluginBridgeError: | |||
case kPluginBridgeError: | |||
{ | |||
CARLA_BRIDGE_CHECK_OSC_TYPES(1, "s"); | |||
const char* const error = (const char*)&argv[0]->s; | |||
CARLA_ASSERT(error); | |||
CARLA_ASSERT(error != nullptr); | |||
m_initiated = true; | |||
m_initError = true; | |||
x_engine->setLastError(error); | |||
kData->engine->setLastError(error); | |||
fInitError = true; | |||
fInitiated = true; | |||
break; | |||
} | |||
} | |||
#endif | |||
return 0; | |||
} | |||
@@ -837,6 +818,7 @@ public: | |||
osc_send_configure(&osc.data, CARLA_BRIDGE_MSG_SET_CHUNK, filePath.toUtf8().constData()); | |||
} | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// Set gui stuff | |||
@@ -844,15 +826,15 @@ public: | |||
void showGui(const bool yesNo) | |||
{ | |||
if (yesNo) | |||
osc_send_show(&osc.data); | |||
osc_send_show(&kData->osc.data); | |||
else | |||
osc_send_hide(&osc.data); | |||
osc_send_hide(&kData->osc.data); | |||
} | |||
void idleGui() | |||
{ | |||
if (! osc.thread->isRunning()) | |||
carla_stderr("TESTING: Bridge has closed!"); | |||
if (! kData->osc.thread.isRunning()) | |||
carla_stderr2("TESTING: Bridge has closed!"); | |||
CarlaPlugin::idleGui(); | |||
} | |||
@@ -860,6 +842,131 @@ public: | |||
// ------------------------------------------------------------------- | |||
// Plugin state | |||
void reload() | |||
{ | |||
carla_debug("BridgePlugin::reload() - start"); | |||
CARLA_ASSERT(kData->engine != nullptr); | |||
if (kData->engine == nullptr) | |||
return; | |||
const ProcessMode processMode(kData->engine->getProccessMode()); | |||
// Safely disable plugin for reload | |||
const ScopedDisabler sd(this); | |||
deleteBuffers(); | |||
bool needsCtrlIn, needsCtrlOut; | |||
needsCtrlIn = needsCtrlOut = false; | |||
if (fInfo.aIns > 0) | |||
{ | |||
kData->audioIn.createNew(fInfo.aIns); | |||
} | |||
if (fInfo.aOuts > 0) | |||
{ | |||
kData->audioOut.createNew(fInfo.aOuts); | |||
needsCtrlIn = true; | |||
} | |||
if (fInfo.mIns > 0) | |||
needsCtrlIn = true; | |||
if (fInfo.mOuts > 0) | |||
needsCtrlOut = true; | |||
const uint portNameSize = kData->engine->maxPortNameSize(); | |||
CarlaString portName; | |||
// Audio Ins | |||
for (uint32_t j=0; j < fInfo.aIns; j++) | |||
{ | |||
portName.clear(); | |||
if (processMode == PROCESS_MODE_SINGLE_CLIENT) | |||
{ | |||
portName = fName; | |||
portName += ":"; | |||
} | |||
if (fInfo.aIns > 1) | |||
{ | |||
portName += "input_"; | |||
portName += CarlaString(j+1); | |||
} | |||
else | |||
portName += "input"; | |||
portName.truncate(portNameSize); | |||
kData->audioIn.ports[j].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, true); | |||
kData->audioIn.ports[j].rindex = j; | |||
} | |||
// Audio Outs | |||
for (uint32_t j=0; j < fInfo.aOuts; j++) | |||
{ | |||
portName.clear(); | |||
if (processMode == PROCESS_MODE_SINGLE_CLIENT) | |||
{ | |||
portName = fName; | |||
portName += ":"; | |||
} | |||
if (fInfo.aOuts > 1) | |||
{ | |||
portName += "output_"; | |||
portName += CarlaString(j+1); | |||
} | |||
else | |||
portName += "output"; | |||
portName.truncate(portNameSize); | |||
kData->audioOut.ports[j].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false); | |||
kData->audioOut.ports[j].rindex = j; | |||
} | |||
if (needsCtrlIn) | |||
{ | |||
portName.clear(); | |||
if (processMode == PROCESS_MODE_SINGLE_CLIENT) | |||
{ | |||
portName = fName; | |||
portName += ":"; | |||
} | |||
portName += "event-in"; | |||
portName.truncate(portNameSize); | |||
kData->event.portIn = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, true); | |||
} | |||
if (needsCtrlOut) | |||
{ | |||
portName.clear(); | |||
if (processMode == PROCESS_MODE_SINGLE_CLIENT) | |||
{ | |||
portName = fName; | |||
portName += ":"; | |||
} | |||
portName += "event-out"; | |||
portName.truncate(portNameSize); | |||
kData->event.portOut = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, false); | |||
} | |||
//bufferSizeChanged(kData->engine->getBufferSize()); | |||
//reloadPrograms(true); | |||
carla_debug("BridgePlugin::reload() - end"); | |||
} | |||
#if 0 | |||
void prepareForSave() | |||
{ | |||
m_saved = false; | |||
@@ -877,93 +984,125 @@ public: | |||
else | |||
carla_debug("BridgePlugin::prepareForSave() - success!"); | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// Plugin processing | |||
void process(float** const inBuffer, float** const outBuffer, const uint32_t frames) | |||
{ | |||
uint32_t i, k; | |||
// -------------------------------------------------------------------------------------------------------- | |||
// Check if active | |||
if (! kData->active) | |||
{ | |||
// disable any output sound | |||
for (i=0; i < kData->audioOut.count; i++) | |||
carla_zeroFloat(outBuffer[i], frames); | |||
kData->activeBefore = kData->active; | |||
return; | |||
} | |||
for (i=0; i < fInfo.aIns; ++i) | |||
carla_copyFloat(fShmAudioPool.data + i * frames, inBuffer[i], frames); | |||
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeProcess); | |||
rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
waitForServer(); | |||
for (i=0; i < fInfo.aOuts; ++i) | |||
carla_copyFloat(outBuffer[i], fShmAudioPool.data + (i+fInfo.aIns) * frames, frames); | |||
} | |||
// ------------------------------------------------------------------- | |||
// Post-poned events | |||
void uiParameterChange(const uint32_t index, const double value) | |||
void uiParameterChange(const uint32_t index, const float value) | |||
{ | |||
CARLA_ASSERT(index < param.count); | |||
CARLA_ASSERT(index < kData->param.count); | |||
if (index >= param.count) | |||
if (index >= kData->param.count) | |||
return; | |||
if (! osc.data.target) | |||
if (kData->osc.data.target == nullptr) | |||
return; | |||
osc_send_control(&osc.data, param.data[index].rindex, value); | |||
osc_send_control(&kData->osc.data, kData->param.data[index].rindex, value); | |||
} | |||
void uiProgramChange(const uint32_t index) | |||
{ | |||
CARLA_ASSERT(index < prog.count); | |||
CARLA_ASSERT(index < kData->prog.count); | |||
if (index >= prog.count) | |||
if (index >= kData->prog.count) | |||
return; | |||
if (! osc.data.target) | |||
if (kData->osc.data.target == nullptr) | |||
return; | |||
osc_send_program(&osc.data, index); | |||
osc_send_program(&kData->osc.data, index); | |||
} | |||
void uiMidiProgramChange(const uint32_t index) | |||
{ | |||
CARLA_ASSERT(index < midiprog.count); | |||
CARLA_ASSERT(index < kData->midiprog.count); | |||
if (index >= midiprog.count) | |||
if (index >= kData->midiprog.count) | |||
return; | |||
if (! osc.data.target) | |||
if (kData->osc.data.target == nullptr) | |||
return; | |||
osc_send_midi_program(&osc.data, index); | |||
osc_send_midi_program(&kData->osc.data, index); | |||
} | |||
void uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) | |||
{ | |||
CARLA_ASSERT(channel < 16); | |||
CARLA_ASSERT(note < 128); | |||
CARLA_ASSERT(velo > 0 && velo < 128); | |||
CARLA_ASSERT(channel < MAX_MIDI_CHANNELS); | |||
CARLA_ASSERT(note < MAX_MIDI_NOTE); | |||
CARLA_ASSERT(velo > 0 && velo < MAX_MIDI_VALUE); | |||
if (! osc.data.target) | |||
if (channel >= MAX_MIDI_CHANNELS) | |||
return; | |||
if (note >= MAX_MIDI_NOTE) | |||
return; | |||
if (velo >= MAX_MIDI_VALUE) | |||
return; | |||
if (kData->osc.data.target == nullptr) | |||
return; | |||
uint8_t midiData[4] = { 0 }; | |||
midiData[1] = MIDI_STATUS_NOTE_ON + channel; | |||
midiData[2] = note; | |||
midiData[3] = velo; | |||
osc_send_midi(&osc.data, midiData); | |||
osc_send_midi(&kData->osc.data, midiData); | |||
} | |||
void uiNoteOff(const uint8_t channel, const uint8_t note) | |||
{ | |||
CARLA_ASSERT(channel < 16); | |||
CARLA_ASSERT(note < 128); | |||
CARLA_ASSERT(channel < MAX_MIDI_CHANNELS); | |||
CARLA_ASSERT(note < MAX_MIDI_NOTE); | |||
if (! osc.data.target) | |||
if (channel >= MAX_MIDI_CHANNELS) | |||
return; | |||
if (note >= MAX_MIDI_NOTE) | |||
return; | |||
if (kData->osc.data.target == nullptr) | |||
return; | |||
uint8_t midiData[4] = { 0 }; | |||
midiData[1] = MIDI_STATUS_NOTE_OFF + channel; | |||
midiData[2] = note; | |||
osc_send_midi(&osc.data, midiData); | |||
} | |||
// ------------------------------------------------------------------- | |||
// Cleanup | |||
osc_send_midi(&kData->osc.data, midiData); | |||
} | |||
void deleteBuffers() | |||
void bufferSizeChanged(const uint32_t newBufferSize) | |||
{ | |||
carla_debug("BridgePlugin::delete_buffers() - start"); | |||
if (param.count > 0) | |||
delete[] params; | |||
params = nullptr; | |||
CarlaPlugin::deleteBuffers(); | |||
carla_debug("BridgePlugin::delete_buffers() - end"); | |||
resizeAudioPool(newBufferSize); | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
@@ -1001,11 +1140,23 @@ public: | |||
fFilename = filename; | |||
// --------------------------------------------------------------- | |||
// register client | |||
kData->client = kData->engine->addClient(this); | |||
if (kData->client == nullptr || ! kData->client->isOk()) | |||
{ | |||
kData->engine->setLastError("Failed to register plugin client"); | |||
return false; | |||
} | |||
// --------------------------------------------------------------- | |||
// SHM Audio Pool | |||
{ | |||
char tmpFileBase[60]; | |||
std::srand(std::time(NULL)); | |||
std::sprintf(tmpFileBase, "/carla-bridge_shm_XXXXXX"); | |||
fShmAudioPool.shm = shm_mkstemp(tmpFileBase); | |||
@@ -1024,6 +1175,7 @@ public: | |||
// SHM Control | |||
{ | |||
char tmpFileBase[60]; | |||
std::sprintf(tmpFileBase, "/carla-bridge_shc_XXXXXX"); | |||
fShmControl.shm = shm_mkstemp(tmpFileBase); | |||
@@ -1044,7 +1196,10 @@ public: | |||
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) | |||
{ | |||
@@ -1061,11 +1216,29 @@ public: | |||
} | |||
} | |||
// initial values | |||
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeBufferSize); | |||
rdwr_writeInt(&fShmControl.data->ringBuffer, kData->engine->getBufferSize()); | |||
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSampleRate); | |||
rdwr_writeFloat(&fShmControl.data->ringBuffer, kData->engine->getSampleRate()); | |||
rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
// register plugin now so we can receive OSC (and wait for it) | |||
fHints |= PLUGIN_IS_BRIDGE; | |||
registerEnginePlugin(kData->engine, fId, this); | |||
kData->osc.thread.setOscData(bridgeBinary, label, getPluginTypeAsString(fPluginType)); | |||
kData->osc.thread.start(); | |||
// init OSC | |||
{ | |||
char shmIdStr[12+1] = { 0 }; | |||
std::strncpy(shmIdStr, &fShmAudioPool.filename[fShmAudioPool.filename.length()-6], 6); | |||
std::strncat(shmIdStr, &fShmControl.filename[fShmControl.filename.length()-6], 6); | |||
kData->osc.thread.setOscData(bridgeBinary, label, getPluginTypeAsString(fPluginType), shmIdStr); | |||
kData->osc.thread.start(); | |||
kData->osc.thread.waitForStarted(); | |||
} | |||
for (int i=0; i < 200; i++) | |||
{ | |||
@@ -1079,7 +1252,9 @@ public: | |||
// unregister so it gets handled properly | |||
registerEnginePlugin(kData->engine, fId, nullptr); | |||
kData->osc.thread.terminate(); | |||
if (kData->osc.thread.isRunning()) | |||
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; | |||
} | |||
@@ -1093,10 +1268,16 @@ public: | |||
return false; | |||
} | |||
resizeAudioPool(kData->engine->getBufferSize()); | |||
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeReadyWait); | |||
rdwr_writeInt(&fShmControl.data->ringBuffer, fShmAudioPool.size); | |||
rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
waitForServer(); | |||
return true; | |||
} | |||
private: | |||
const BinaryType fBinaryType; | |||
const PluginType fPluginType; | |||
@@ -1154,6 +1335,61 @@ private: | |||
BridgeParamInfo* fParams; | |||
void _cleanup() | |||
{ | |||
if (fShmAudioPool.filename.isNotEmpty()) | |||
fShmAudioPool.filename.clear(); | |||
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; | |||
// and again | |||
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(const 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.data = (float*)carla_shm_map(fShmAudioPool.shm, fShmAudioPool.size); | |||
else | |||
fShmAudioPool.data = nullptr; | |||
} | |||
void waitForServer() | |||
{ | |||
sem_post(&fShmControl.data->runServer); | |||
timespec ts_timeout; | |||
clock_gettime(CLOCK_REALTIME, &ts_timeout); | |||
ts_timeout.tv_sec += 5; | |||
if (sem_timedwait(&fShmControl.data->runClient, &ts_timeout) != 0) | |||
kData->active = false; // TODO | |||
} | |||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(BridgePlugin) | |||
}; | |||
@@ -1163,12 +1399,12 @@ CARLA_BACKEND_END_NAMESPACE | |||
CARLA_BACKEND_START_NAMESPACE | |||
CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, PluginType ptype, const char* const extra) | |||
CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, PluginType ptype, const char* const bridgeBinary) | |||
{ | |||
carla_debug("CarlaPlugin::newBridge({%p, \"%s\", \"%s\", \"%s\"}, %s, %s)", init.engine, init.filename, init.name, init.label, BinaryType2Str(btype), PluginType2Str(ptype)); | |||
carla_debug("CarlaPlugin::newBridge({%p, \"%s\", \"%s\", \"%s\"}, %s, %s, \"%s\")", init.engine, init.filename, init.name, init.label, BinaryType2Str(btype), PluginType2Str(ptype), bridgeBinary); | |||
#if 1//ndef BUILD_BRIDGE | |||
if (extra == nullptr) | |||
#ifndef BUILD_BRIDGE | |||
if (bridgeBinary == nullptr) | |||
{ | |||
init.engine->setLastError("Bridge not possible, bridge-binary not found"); | |||
return nullptr; | |||
@@ -1176,7 +1412,7 @@ CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, P | |||
BridgePlugin* const plugin = new BridgePlugin(init.engine, init.id, btype, ptype); | |||
//if (! plugin->init(init.filename, init.name, init.label, (const char*)extra)) | |||
if (! plugin->init(init.filename, init.name, init.label, bridgeBinary)) | |||
{ | |||
delete plugin; | |||
return nullptr; | |||
@@ -1188,10 +1424,13 @@ CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, P | |||
#else | |||
init.engine->setLastError("Plugin bridge support not available"); | |||
return nullptr; | |||
// unused | |||
(void)bridgeBinary; | |||
#endif | |||
} | |||
#if 1//ndef BUILD_BRIDGE | |||
#ifndef BUILD_BRIDGE | |||
// ------------------------------------------------------------------- | |||
// Bridge Helper | |||
@@ -64,11 +64,12 @@ void CarlaPluginThread::setMode(const CarlaPluginThread::Mode mode) | |||
fMode = mode; | |||
} | |||
void CarlaPluginThread::setOscData(const char* const binary, const char* const label, const char* const extra) | |||
void CarlaPluginThread::setOscData(const char* const binary, const char* const label, const char* const extra1, const char* const extra2) | |||
{ | |||
fBinary = binary; | |||
fLabel = label; | |||
fExtra = extra; | |||
fExtra1 = extra1; | |||
fExtra2 = extra2; | |||
} | |||
void CarlaPluginThread::run() | |||
@@ -84,40 +85,44 @@ void CarlaPluginThread::run() | |||
#endif | |||
} | |||
QString name(kPlugin->name() ? kPlugin->name() : "(none)"); | |||
QString name(kPlugin->name()); | |||
QStringList arguments; | |||
if (name.isEmpty()) | |||
name = "(none)"; | |||
switch (fMode) | |||
{ | |||
case PLUGIN_THREAD_NULL: | |||
break; | |||
case PLUGIN_THREAD_DSSI_GUI: | |||
/* osc_url */ arguments << QString("%1/%2").arg(kEngine->getOscServerPathUDP()).arg(kPlugin->id()); | |||
/* osc-url */ arguments << QString("%1/%2").arg(kEngine->getOscServerPathUDP()).arg(kPlugin->id()); | |||
/* filename */ arguments << kPlugin->filename(); | |||
/* label */ arguments << (const char*)fLabel; | |||
/* ui-title */ arguments << QString("%1 (GUI)").arg(kPlugin->name()); | |||
break; | |||
case PLUGIN_THREAD_LV2_GUI: | |||
/* osc_url */ arguments << QString("%1/%2").arg(kEngine->getOscServerPathTCP()).arg(kPlugin->id()); | |||
/* osc-url */ arguments << QString("%1/%2").arg(kEngine->getOscServerPathTCP()).arg(kPlugin->id()); | |||
/* URI */ arguments << (const char*)fLabel; | |||
/* ui-URI */ arguments << (const char*)fExtra; | |||
/* ui-URI */ arguments << (const char*)fExtra1; | |||
/* ui-title */ arguments << QString("%1 (GUI)").arg(kPlugin->name()); | |||
break; | |||
case PLUGIN_THREAD_VST_GUI: | |||
/* osc_url */ arguments << QString("%1/%2").arg(kEngine->getOscServerPathTCP()).arg(kPlugin->id()); | |||
/* osc-url */ arguments << QString("%1/%2").arg(kEngine->getOscServerPathTCP()).arg(kPlugin->id()); | |||
/* filename */ arguments << kPlugin->filename(); | |||
/* ui-title */ arguments << QString("%1 (GUI)").arg(kPlugin->name()); | |||
break; | |||
case PLUGIN_THREAD_BRIDGE: | |||
/* osc_url */ arguments << QString("%1/%2").arg(kEngine->getOscServerPathTCP()).arg(kPlugin->id()); | |||
/* stype */ arguments << (const char*)fExtra; | |||
/* osc-url */ arguments << QString("%1/%2").arg(kEngine->getOscServerPathTCP()).arg(kPlugin->id()); | |||
/* stype */ arguments << (const char*)fExtra1; | |||
/* filename */ arguments << kPlugin->filename(); | |||
/* name */ arguments << name; | |||
/* label */ arguments << (const char*)fLabel; | |||
/* SHM ids */ arguments << (const char*)fExtra2; | |||
break; | |||
} | |||
@@ -41,7 +41,7 @@ public: | |||
~CarlaPluginThread(); | |||
void setMode(const CarlaPluginThread::Mode mode); | |||
void setOscData(const char* const binary, const char* const label, const char* const extra=""); | |||
void setOscData(const char* const binary, const char* const label, const char* const extra1="", const char* const extra2=""); | |||
protected: | |||
void run(); | |||
@@ -53,7 +53,8 @@ private: | |||
Mode fMode; | |||
CarlaString fBinary; | |||
CarlaString fLabel; | |||
CarlaString fExtra; | |||
CarlaString fExtra1; | |||
CarlaString fExtra2; | |||
QProcess* fProcess; | |||
}; | |||
@@ -46,7 +46,9 @@ struct CarlaBackendStandalone { | |||
CarlaEngine* engine; | |||
CarlaString lastError; | |||
CarlaString procName; | |||
#ifndef BUILD_BRIDGE | |||
EngineOptions options; | |||
#endif | |||
QApplication* app; | |||
bool needsInit; | |||
@@ -85,14 +87,6 @@ struct CarlaBackendStandalone { | |||
} standalone; | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
// Helpers | |||
CarlaEngine* carla_get_standalone_engine() | |||
{ | |||
return standalone.engine; | |||
} | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
// API | |||
@@ -232,16 +226,6 @@ bool carla_engine_init(const char* driverName, const char* clientName) | |||
CARLA_ASSERT(driverName != nullptr); | |||
CARLA_ASSERT(clientName != nullptr); | |||
#if 0 | |||
static bool sigInfoInitiated = false; | |||
if (! sigInfoInitiated) | |||
{ | |||
setup_siginfo(); | |||
sigInfoInitiated = true; | |||
} | |||
#endif | |||
standalone.engine = CarlaEngine::newDriverByName(driverName); | |||
if (standalone.engine == nullptr) | |||
@@ -377,14 +361,13 @@ void carla_set_engine_callback(CarlaBackend::CallbackFunc func, void* ptr) | |||
standalone.engine->setCallback(func, ptr); | |||
} | |||
#ifndef BUILD_BRIDGE | |||
void carla_set_engine_option(CarlaBackend::OptionsType option, int value, const char* valueStr) | |||
{ | |||
carla_debug("carla_set_engine_option(%s, %i, \"%s\")", CarlaBackend::OptionsType2Str(option), value, valueStr); | |||
#ifndef BUILD_BRIDGE | |||
if (standalone.engine != nullptr) | |||
standalone.engine->setOption(option, value, valueStr); | |||
#endif | |||
switch (option) | |||
{ | |||
@@ -493,6 +476,7 @@ void carla_set_engine_option(CarlaBackend::OptionsType option, int value, const | |||
#endif | |||
} | |||
} | |||
#endif | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
@@ -1853,6 +1837,65 @@ void carla_nsm_reply_save() | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
#ifdef BUILD_BRIDGE | |||
bool carla_engine_init_bridge(const char* audioBaseName, const char* controlBaseName, const char* clientName) | |||
{ | |||
carla_debug("carla_engine_init_bridge(\"%s\", \"%s\", \"%s\")", audioBaseName, controlBaseName, clientName); | |||
CARLA_ASSERT(standalone.engine == nullptr); | |||
CARLA_ASSERT(audioBaseName != nullptr); | |||
CARLA_ASSERT(controlBaseName != nullptr); | |||
CARLA_ASSERT(clientName != nullptr); | |||
standalone.engine = CarlaEngine::newBridge(audioBaseName, controlBaseName); | |||
if (standalone.engine == nullptr) | |||
{ | |||
standalone.lastError = "The seleted audio driver is not available!"; | |||
return false; | |||
} | |||
if (standalone.callback != nullptr) | |||
standalone.engine->setCallback(standalone.callback, nullptr); | |||
standalone.engine->setOption(CarlaBackend::OPTION_PROCESS_MODE, CarlaBackend::PROCESS_MODE_BRIDGE, nullptr); | |||
standalone.engine->setOption(CarlaBackend::OPTION_TRANSPORT_MODE, CarlaBackend::TRANSPORT_MODE_BRIDGE, nullptr); | |||
standalone.engine->setOption(CarlaBackend::OPTION_PREFER_PLUGIN_BRIDGES, false, nullptr); | |||
standalone.engine->setOption(CarlaBackend::OPTION_PREFER_UI_BRIDGES, false, nullptr); | |||
// TODO - read from environment | |||
#ifndef BUILD_BRIDGE | |||
standalone.engine->setOption(CarlaBackend::OPTION_FORCE_STEREO, standalone.options.forceStereo ? 1 : 0, nullptr); | |||
# ifdef WANT_DSSI | |||
standalone.engine->setOption(CarlaBackend::OPTION_USE_DSSI_VST_CHUNKS, standalone.options.useDssiVstChunks ? 1 : 0, nullptr); | |||
# endif | |||
standalone.engine->setOption(CarlaBackend::OPTION_MAX_PARAMETERS, static_cast<int>(standalone.options.maxParameters), nullptr); | |||
#endif | |||
const bool initiated = standalone.engine->init(clientName); | |||
if (initiated) | |||
{ | |||
standalone.lastError = "no error"; | |||
standalone.init(); | |||
} | |||
else | |||
{ | |||
standalone.lastError = standalone.engine->getLastError(); | |||
delete standalone.engine; | |||
standalone.engine = nullptr; | |||
} | |||
return initiated; | |||
} | |||
CarlaEngine* carla_get_standalone_engine() | |||
{ | |||
return standalone.engine; | |||
} | |||
#endif | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
#if 0 | |||
//def QTCREATOR_TEST | |||
@@ -140,6 +140,8 @@ private: | |||
const char* fUiFilename; | |||
void* fUiLib; | |||
bool fUiQuit; | |||
#else | |||
friend class CarlaPluginClient; | |||
#endif | |||
const CarlaOscData* fOscData; | |||
@@ -115,17 +115,21 @@ class CarlaPluginClient : public CarlaBridgeClient, | |||
public QObject | |||
{ | |||
public: | |||
CarlaPluginClient(const char* const name) | |||
CarlaPluginClient(const bool useBridge, const char* const driverName, const char* audioBaseName, const char* controlBaseName) | |||
: CarlaBridgeClient(nullptr), | |||
QObject(nullptr), | |||
fEngine(nullptr), | |||
fPlugin(nullptr), | |||
fTimerId(0) | |||
{ | |||
CARLA_ASSERT(name != nullptr); | |||
carla_debug("CarlaPluginClient::CarlaPluginClient()"); | |||
CARLA_ASSERT(driverName != nullptr); | |||
carla_debug("CarlaPluginClient::CarlaPluginClient(%s, \"%s\", %s, %s)", bool2str(useBridge), driverName, audioBaseName, controlBaseName); | |||
if (useBridge) | |||
carla_engine_init_bridge(audioBaseName, controlBaseName, driverName); | |||
else | |||
carla_engine_init("JACK", driverName); | |||
carla_engine_init("JACK", name); | |||
carla_set_engine_callback(callback, this); | |||
} | |||
@@ -138,6 +142,14 @@ public: | |||
carla_engine_close(); | |||
} | |||
void oscInit(const char* const url) | |||
{ | |||
CarlaBridgeClient::oscInit(url); | |||
fEngine = carla_get_standalone_engine(); | |||
fEngine->setOscBridgeData(fOscData); | |||
} | |||
void ready() | |||
{ | |||
CARLA_ASSERT(fTimerId == 0); | |||
@@ -405,9 +417,6 @@ int CarlaBridgeOsc::handleMsgQuit() | |||
carla_debug("CarlaBridgeOsc::handleMsgQuit()"); | |||
CARLA_ASSERT(kClient != nullptr); | |||
if (kClient == nullptr) | |||
return 1; | |||
gCloseNow = true; | |||
return 0; | |||
@@ -473,7 +482,7 @@ int main(int argc, char* argv[]) | |||
{ | |||
CARLA_BRIDGE_USE_NAMESPACE | |||
if (argc != 6) | |||
if (argc != 6 && argc != 7) | |||
{ | |||
carla_stdout("usage: %s <osc-url|\"null\"> <type> <filename> <name|\"(none)\"> <label>", argv[0]); | |||
return 1; | |||
@@ -485,11 +494,21 @@ int main(int argc, char* argv[]) | |||
const char* name = argv[4]; | |||
const char* const label = argv[5]; | |||
const bool useOsc = std::strcmp(oscUrl, "null"); | |||
const bool useBridge = (argc == 7); | |||
const bool useOsc = std::strcmp(oscUrl, "null"); | |||
if (std::strcmp(name, "(none)") == 0) | |||
name = nullptr; | |||
char bridgeBaseAudioName[6+1] = { 0 }; | |||
char bridgeBaseControlName[6+1] = { 0 }; | |||
if (useBridge) | |||
{ | |||
std::strncpy(bridgeBaseAudioName, argv[6], 6); | |||
std::strncpy(bridgeBaseControlName, argv[6]+6, 6); | |||
} | |||
CarlaBackend::PluginType itype; | |||
if (std::strcmp(stype, "LADSPA") == 0) | |||
@@ -512,7 +531,7 @@ int main(int argc, char* argv[]) | |||
app.setQuitOnLastWindowClosed(false); | |||
// Init Plugin client | |||
CarlaPluginClient client(name ? name : label); | |||
CarlaPluginClient client(useBridge, (name != nullptr) ? name : label, bridgeBaseAudioName, bridgeBaseControlName); | |||
// Init OSC | |||
if (useOsc) | |||
@@ -535,6 +554,10 @@ int main(int argc, char* argv[]) | |||
{ | |||
client.sendOscUpdate(); | |||
client.sendOscBridgeUpdate(); | |||
// TESTING!! | |||
carla_set_active(0, true); | |||
carla_show_gui(0, true); | |||
} | |||
else | |||
{ | |||
@@ -31,7 +31,7 @@ LINK_FLAGS += $(shell pkg-config --libs liblo QtCore) | |||
BUILD_PLUGIN_FLAGS = $(BUILD_CXX_FLAGS) | |||
BUILD_PLUGIN_FLAGS += -DBUILD_BRIDGE_PLUGIN -DBRIDGE_PLUGIN | |||
BUILD_PLUGIN_FLAGS += -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 -DWANT_VST -DWANT_JACK | |||
BUILD_PLUGIN_FLAGS += -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 -DWANT_VST | |||
BUILD_PLUGIN_FLAGS += -I../backend/engine -I../backend/plugin -I../libs | |||
BUILD_PLUGIN_FLAGS += $(QT_UI_FLAGS) $(shell pkg-config --cflags QtXml) | |||
@@ -57,7 +57,7 @@ WIN_LINK_FLAGS = $(LINK_PLUGIN_FLAGS) -mwindows -lwinspool -lole32 -luuid - | |||
# -------------------------------------------------------------- | |||
# Plugin bridges (Native) | |||
NATIVE_BUILD_FLAGS = $(POSIX_BUILD_FLAGS) | |||
NATIVE_BUILD_FLAGS = $(POSIX_BUILD_FLAGS) -DWANT_JACK | |||
NATIVE_LINK_FLAGS = $(POSIX_LINK_FLAGS) | |||
NATIVE_BUILD_FLAGS += -DWANT_NATIVE | |||
@@ -288,7 +288,8 @@ OBJS_NATIVE += \ | |||
../backend/engine/CarlaEngine__native.o \ | |||
../backend/engine/CarlaEngineOsc__native.o \ | |||
../backend/engine/CarlaEngineThread__native.o \ | |||
../backend/engine/CarlaEngineJack__native.o | |||
../backend/engine/CarlaEngineJack__native.o \ | |||
../backend/engine/CarlaEngineBridge__native.o | |||
# carla-plugin | |||
OBJS_NATIVE += \ | |||
@@ -332,7 +333,8 @@ OBJS_POSIX32 += \ | |||
../backend/engine/CarlaEngine__posix32.o \ | |||
../backend/engine/CarlaEngineOsc__posix32.o \ | |||
../backend/engine/CarlaEngineThread__posix32.o \ | |||
../backend/engine/CarlaEngineJack__posix32.o | |||
../backend/engine/CarlaEngineJack__posix32.o \ | |||
../backend/engine/CarlaEngineBridge__posix32.o | |||
# carla-plugin | |||
OBJS_POSIX32 += \ | |||
@@ -374,7 +376,8 @@ OBJS_POSIX64 += \ | |||
../backend/engine/CarlaEngine__posix64.o \ | |||
../backend/engine/CarlaEngineOsc__posix64.o \ | |||
../backend/engine/CarlaEngineThread__posix64.o \ | |||
../backend/engine/CarlaEngineJack__posix64.o | |||
../backend/engine/CarlaEngineJack__posix64.o \ | |||
../backend/engine/CarlaEngineBridge__posix64.o | |||
# carla-plugin | |||
OBJS_POSIX64 += \ | |||
@@ -416,7 +419,7 @@ OBJS_WIN32 += \ | |||
../backend/engine/CarlaEngine__win32.o \ | |||
../backend/engine/CarlaEngineOsc__win32.o \ | |||
../backend/engine/CarlaEngineThread__win32.o \ | |||
../backend/engine/CarlaEngineJack__win32.o | |||
../backend/engine/CarlaEngineBridge__win32.o | |||
# carla-plugin | |||
OBJS_WIN32 += \ | |||
@@ -458,7 +461,7 @@ OBJS_WIN64 += \ | |||
../backend/engine/CarlaEngine__win64.o \ | |||
../backend/engine/CarlaEngineOsc__win64.o \ | |||
../backend/engine/CarlaEngineThread__win64.o \ | |||
../backend/engine/CarlaEngineJack__win64.o | |||
../backend/engine/CarlaEngineBridge__win64.o | |||
# carla-plugin | |||
OBJS_WIN64 += \ | |||
@@ -28,6 +28,7 @@ SOURCES += \ | |||
../../backend/engine/CarlaEngine.cpp \ | |||
../../backend/engine/CarlaEngineOsc.cpp \ | |||
../../backend/engine/CarlaEngineThread.cpp \ | |||
../../backend/engine/CarlaEngineBridge.cpp \ | |||
../../backend/engine/CarlaEngineJack.cpp \ | |||
../../backend/engine/CarlaEnginePlugin.cpp \ | |||
../../backend/engine/CarlaEngineRtAudio.cpp | |||
@@ -88,6 +89,7 @@ HEADERS += \ | |||
../../utils/CarlaLibUtils.hpp \ | |||
../../utils/CarlaLv2Utils.hpp \ | |||
../../utils/CarlaOscUtils.hpp \ | |||
../../utils/CarlaShmUtils.hpp \ | |||
../../utils/CarlaStateUtils.hpp \ | |||
../../utils/CarlaVstUtils.hpp \ | |||
../../utils/CarlaUtils.hpp \ | |||
@@ -114,7 +116,7 @@ DEFINES += DEBUG | |||
DEFINES += BUILD_BRIDGE BUILD_BRIDGE_PLUGIN BRIDGE_PLUGIN | |||
DEFINES += WANT_JACK | |||
DEFINES += WANT_NATIVE WANT_LADSPA WANT_DSSI WANT_LV2 WANT_VST WANT_VST3 | |||
DEFINES += WANT_LADSPA WANT_DSSI WANT_LV2 WANT_VST WANT_VST3 | |||
DEFINES += WANT_FLUIDSYNTH WANT_LINUXSAMPLER | |||
LIBS = -ldl \ | |||
@@ -322,6 +322,7 @@ PROCESS_MODE_BRIDGE = 4 | |||
# Transport Mode | |||
TRANSPORT_MODE_INTERNAL = 0 | |||
TRANSPORT_MODE_JACK = 1 | |||
TRANSPORT_MODE_BRIDGE = 2 | |||
# Set BINARY_NATIVE | |||
if HAIKU or LINUX or MACOS: | |||
@@ -21,7 +21,7 @@ WIN_LINK_FLAGS = $(LINK_FLAGS) | |||
WINE_BUILD_FLAGS = $(BUILD_C_FLAGS) -fPIC | |||
WINE_32BIT_FLAGS = $(32BIT_FLAGS) -L/usr/lib32/wine -L/usr/lib/i386-linux-gnu/wine | |||
WINE_64BIT_FLAGS = $(64BIT_FLAGS) -L/usr/lib64/wine -L/usr/lib/x86_64-linux-gnu/wine | |||
WINE_LINK_FLAGS = $(LINK_FLAGS) $(shell pkg-config --libs jack) -ldl | |||
WINE_LINK_FLAGS = $(LINK_FLAGS) $(shell pkg-config --libs jack) -lrt -lpthread | |||
OBJS = jackbridge.c | |||
@@ -16,6 +16,11 @@ | |||
#include "jackbridge.h" | |||
#ifndef JACKBRIDGE_DUMMY | |||
# include <time.h> | |||
# include <semaphore.h> | |||
#endif | |||
// ----------------------------------------------------------------------------- | |||
jack_client_t* jackbridge_client_open(const char* client_name, jack_options_t options, jack_status_t* status, ...) | |||
@@ -279,3 +284,30 @@ void jackbridge_transport_stop(jack_client_t* client) | |||
jack_transport_stop(client); | |||
#endif | |||
} | |||
// ----------------------------------------------------------------------------- | |||
void linux_clock_gettime_rt(struct timespec* ts) | |||
{ | |||
#ifndef JACKBRIDGE_DUMMY | |||
clock_gettime(CLOCK_REALTIME, ts); | |||
#endif | |||
} | |||
int linux_sem_post(void* sem) | |||
{ | |||
#ifndef JACKBRIDGE_DUMMY | |||
return sem_post(sem); | |||
#else | |||
return 1; | |||
#endif | |||
} | |||
int linux_sem_timedwait(void* sem, struct timespec* ts) | |||
{ | |||
#ifndef JACKBRIDGE_DUMMY | |||
return sem_timedwait(sem, ts); | |||
#else | |||
return 1; | |||
#endif | |||
} |
@@ -27,6 +27,7 @@ | |||
#ifdef JACKBRIDGE_EXPORT | |||
# define GNU_WIN32 // fix jack threads, always use pthread | |||
# include <sys/time.h> | |||
#endif | |||
#include <jack/jack.h> | |||
@@ -72,6 +73,10 @@ BRIDGE_EXPORT jack_transport_state_t jackbridge_transport_query(const jack_clien | |||
BRIDGE_EXPORT void jackbridge_transport_start(jack_client_t* client); | |||
BRIDGE_EXPORT void jackbridge_transport_stop(jack_client_t* client); | |||
BRIDGE_EXPORT void linux_clock_gettime_rt(struct timespec*); | |||
BRIDGE_EXPORT int linux_sem_post(void*); | |||
BRIDGE_EXPORT int linux_sem_timedwait(void*, struct timespec*); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
@@ -111,6 +116,10 @@ BRIDGE_EXPORT void jackbridge_transport_stop(jack_client_t* client); | |||
#define jackbridge_transport_start jack_transport_start | |||
#define jackbridge_transport_stop jack_transport_stop | |||
#define linux_clock_gettime_rt(ts) clock_gettime(CLOCK_REALTIME, ts) | |||
#define linux_sem_post sem_post | |||
#define linux_sem_timedwait sem_timedwait | |||
#endif // JACKBRIDGE_EXPORT | |||
#endif // __JACKBRIDGE_H__ |
@@ -21,10 +21,8 @@ | |||
#include "CarlaUtils.hpp" | |||
#ifdef CARLA_OS_WIN | |||
# include <vector> | |||
# include <windows.h> | |||
struct map_t { HANDLE map; void* ptr; }; | |||
struct shm_t { HANDLE shm; std::vector<map_t> maps; }; | |||
struct shm_t { HANDLE shm; HANDLE map; }; | |||
#else | |||
# include <fcntl.h> | |||
# include <sys/mman.h> | |||
@@ -49,7 +47,7 @@ void carla_shm_init(shm_t& shm) | |||
{ | |||
#ifdef CARLA_OS_WIN | |||
shm.shm = nullptr; | |||
shm.maps.clear(); | |||
shm.map = nullptr; | |||
#else | |||
shm = -1; | |||
#endif | |||
@@ -67,6 +65,7 @@ shm_t carla_shm_attach_linux(const char* const name) | |||
shm_t ret; | |||
ret.shm = CreateFileA(shmName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); | |||
ret.map = nullptr; | |||
return ret; | |||
} | |||
@@ -94,7 +93,7 @@ void carla_shm_close(shm_t& shm) | |||
CARLA_ASSERT(carla_is_shm_valid(shm)); | |||
#ifdef CARLA_OS_WIN | |||
CARLA_ASSERT(shm.maps.empty()); | |||
CARLA_ASSERT(shm.map == nullptr); | |||
CloseHandle(shm.shm); | |||
shm.shm = nullptr; | |||
@@ -111,6 +110,8 @@ void* carla_shm_map(shm_t& shm, const size_t size) | |||
CARLA_ASSERT(size > 0); | |||
#ifdef CARLA_OS_WIN | |||
CARLA_ASSERT(shm.map == nullptr); | |||
HANDLE map = CreateFileMapping(shm.shm, NULL, PAGE_READWRITE, size, size, NULL); | |||
if (map == nullptr) | |||
@@ -119,13 +120,12 @@ void* carla_shm_map(shm_t& shm, const size_t size) | |||
HANDLE ptr = MapViewOfFile(map, FILE_MAP_COPY, 0, 0, size); | |||
if (ptr == nullptr) | |||
{ | |||
CloseHandle(map); | |||
return nullptr; | |||
} | |||
map_t newMap; | |||
newMap.map = map; | |||
newMap.ptr = ptr; | |||
shm.maps.push_back(newMap); | |||
shm.map = map; | |||
return ptr; | |||
#else | |||
@@ -135,31 +135,18 @@ void* carla_shm_map(shm_t& shm, const size_t size) | |||
} | |||
static inline | |||
void carla_shm_unmap(const shm_t& shm, void* const ptr, const size_t size) | |||
void carla_shm_unmap(shm_t& shm, void* const ptr, const size_t size) | |||
{ | |||
CARLA_ASSERT(carla_is_shm_valid(shm)); | |||
CARLA_ASSERT(ptr != nullptr); | |||
CARLA_ASSERT(size > 0); | |||
#ifdef CARLA_OS_WIN | |||
CARLA_ASSERT(! shm.maps.empty()); | |||
for (auto it = shm.maps.begin(); it != shm.maps.end(); ++it) | |||
{ | |||
map_t map(*it); | |||
if (map.ptr == ptr) | |||
{ | |||
UnmapViewOfFile(ptr); | |||
CloseHandle(map.map); | |||
shm.maps.erase(it); | |||
break; | |||
} | |||
} | |||
CARLA_ASSERT(false); | |||
CARLA_ASSERT(shm.map != nullptr); | |||
UnmapViewOfFile(ptr); | |||
CloseHandle(shm.map); | |||
shm.map = nullptr; | |||
return; | |||
// unused | |||
@@ -178,17 +165,17 @@ void carla_shm_unmap(const shm_t& shm, void* const ptr, const size_t size) | |||
template<typename T> | |||
static inline | |||
bool carla_shm_map(shm_t& shm, T* value) | |||
bool carla_shm_map(shm_t& shm, T*& value) | |||
{ | |||
value = (T*)carla_shm_map(shm, sizeof(value)); | |||
value = (T*)carla_shm_map(shm, sizeof(T)); | |||
return (value != nullptr); | |||
} | |||
template<typename T> | |||
static inline | |||
void carla_shm_unmap(const shm_t& shm, T* value) | |||
void carla_shm_unmap(shm_t& shm, T*& value) | |||
{ | |||
carla_shm_unmap(shm, value, sizeof(value)); | |||
carla_shm_unmap(shm, value, sizeof(T)); | |||
value = nullptr; | |||
} | |||
@@ -263,7 +263,7 @@ private: | |||
} | |||
#endif | |||
CARLA_PREVENT_HEAP_ALLOCATION | |||
//CARLA_PREVENT_HEAP_ALLOCATION | |||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaThread) | |||
}; | |||