@@ -619,7 +619,7 @@ enum ProcessMode { | |||||
PROCESS_MODE_MULTIPLE_CLIENTS = 1, //!< Multiple client mode (1 master client + 1 client per plugin) | 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_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_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 { | enum TransportMode { | ||||
TRANSPORT_MODE_INTERNAL = 0, //!< Internal transport mode. | 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__ | #ifndef __CARLA_BRIDGE_HPP__ | ||||
#define __CARLA_BRIDGE_HPP__ | #define __CARLA_BRIDGE_HPP__ | ||||
#include "CarlaUtils.hpp" | |||||
#include <semaphore.h> | #include <semaphore.h> | ||||
#define BRIDGE_SHM_RING_BUFFER_SIZE 2048 | #define BRIDGE_SHM_RING_BUFFER_SIZE 2048 | ||||
@@ -50,6 +52,14 @@ enum PluginBridgeInfoType { | |||||
}; | }; | ||||
#endif | #endif | ||||
enum PluginBridgeOpcode { | |||||
kPluginBridgeOpcodeNull = 0, | |||||
kPluginBridgeOpcodeReadyWait = 1, | |||||
kPluginBridgeOpcodeBufferSize = 2, | |||||
kPluginBridgeOpcodeSampleRate = 3, | |||||
kPluginBridgeOpcodeProcess = 4 | |||||
}; | |||||
/*! | /*! | ||||
* TODO. | * TODO. | ||||
*/ | */ | ||||
@@ -69,14 +79,154 @@ struct BridgeShmControl { | |||||
// Let's make sure there's plenty of room for either one. | // Let's make sure there's plenty of room for either one. | ||||
union { | union { | ||||
sem_t runServer; | sem_t runServer; | ||||
char _alignServer[32]; | |||||
char _alignServer[64]; | |||||
}; | }; | ||||
union { | union { | ||||
sem_t runClient; | sem_t runClient; | ||||
char _alignClient[32]; | |||||
char _alignClient[64]; | |||||
}; | }; | ||||
BridgeRingBuffer ringBuffer; | 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__ | #endif // __CARLA_BRIDGE_HPP__ |
@@ -23,8 +23,6 @@ | |||||
#ifdef BUILD_BRIDGE | #ifdef BUILD_BRIDGE | ||||
struct CarlaOscData; | struct CarlaOscData; | ||||
#else | |||||
class QProcessEnvironment; | |||||
#endif | #endif | ||||
CARLA_BACKEND_START_NAMESPACE | CARLA_BACKEND_START_NAMESPACE | ||||
@@ -913,20 +911,13 @@ public: | |||||
*/ | */ | ||||
void setAboutToClose(); | void setAboutToClose(); | ||||
#ifndef BUILD_BRIDGE | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Options | // Options | ||||
/*! | |||||
* Get the engine options as process environment. | |||||
*/ | |||||
const QProcessEnvironment& getOptionsAsProcessEnvironment() const; | |||||
/*! | /*! | ||||
* Set the engine option \a option. | * Set the engine option \a option. | ||||
*/ | */ | ||||
void setOption(const OptionsType option, const int value, const char* const valueStr); | void setOption(const OptionsType option, const int value, const char* const valueStr); | ||||
#endif | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// OSC Stuff | // OSC Stuff | ||||
@@ -1013,9 +1004,6 @@ protected: | |||||
#endif | #endif | ||||
private: | private: | ||||
#ifdef BUILD_BRIDGE | |||||
static CarlaEngine* newBridge(const char* const audioBaseName, const char* const controlBaseName); | |||||
#endif | |||||
#ifdef WANT_JACK | #ifdef WANT_JACK | ||||
static CarlaEngine* newJack(); | static CarlaEngine* newJack(); | ||||
#endif | #endif | ||||
@@ -1038,6 +1026,8 @@ private: | |||||
public: | public: | ||||
#ifdef BUILD_BRIDGE | #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_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_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); | 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 const PluginDescriptor* getNativePluginDescriptor(const size_t index); | ||||
static CarlaPlugin* newNative(const Initializer& init); | 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* newLADSPA(const Initializer& init, const LADSPA_RDF_Descriptor* const rdfDescriptor); | ||||
static CarlaPlugin* newDSSI(const Initializer& init, const char* const guiFilename); | 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(); | CARLA_EXPORT void carla_nsm_reply_save(); | ||||
#endif | #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__ | #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)); | 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]; | fBuffer = new EngineEvent[PATCHBAY_EVENT_COUNT]; | ||||
} | } | ||||
@@ -109,7 +109,7 @@ CarlaEngineEventPort::~CarlaEngineEventPort() | |||||
{ | { | ||||
carla_debug("CarlaEngineEventPort::~CarlaEngineEventPort()"); | carla_debug("CarlaEngineEventPort::~CarlaEngineEventPort()"); | ||||
if (kProcessMode == PROCESS_MODE_PATCHBAY) | |||||
if (kProcessMode == PROCESS_MODE_PATCHBAY || kProcessMode == PROCESS_MODE_BRIDGE) | |||||
{ | { | ||||
CARLA_ASSERT(fBuffer != nullptr); | CARLA_ASSERT(fBuffer != nullptr); | ||||
@@ -128,22 +128,23 @@ void CarlaEngineEventPort::initBuffer(CarlaEngine* const engine) | |||||
#ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
if (kProcessMode == PROCESS_MODE_CONTINUOUS_RACK) | if (kProcessMode == PROCESS_MODE_CONTINUOUS_RACK) | ||||
fBuffer = engine->getRackEventBuffer(kIsInput); | fBuffer = engine->getRackEventBuffer(kIsInput); | ||||
else if (kProcessMode == PROCESS_MODE_PATCHBAY && ! kIsInput) | |||||
carla_zeroMem(fBuffer, sizeof(EngineEvent)*PATCHBAY_EVENT_COUNT); | |||||
else | |||||
#endif | #endif | ||||
if ((kProcessMode == PROCESS_MODE_PATCHBAY || kProcessMode == PROCESS_MODE_BRIDGE) && ! kIsInput) | |||||
carla_zeroMem(fBuffer, sizeof(EngineEvent)*PATCHBAY_EVENT_COUNT); | |||||
} | } | ||||
uint32_t CarlaEngineEventPort::getEventCount() | uint32_t CarlaEngineEventPort::getEventCount() | ||||
{ | { | ||||
CARLA_ASSERT(kIsInput); | CARLA_ASSERT(kIsInput); | ||||
CARLA_ASSERT(fBuffer != nullptr); | 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) | if (! kIsInput) | ||||
return 0; | return 0; | ||||
if (fBuffer == nullptr) | if (fBuffer == nullptr) | ||||
return 0; | 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; | return 0; | ||||
uint32_t count = 0; | uint32_t count = 0; | ||||
@@ -162,14 +163,14 @@ const EngineEvent& CarlaEngineEventPort::getEvent(const uint32_t index) | |||||
{ | { | ||||
CARLA_ASSERT(kIsInput); | CARLA_ASSERT(kIsInput); | ||||
CARLA_ASSERT(fBuffer != nullptr); | 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); | CARLA_ASSERT(index < kMaxEventCount); | ||||
if (! kIsInput) | if (! kIsInput) | ||||
return kFallbackEngineEvent; | return kFallbackEngineEvent; | ||||
if (fBuffer == nullptr) | if (fBuffer == nullptr) | ||||
return kFallbackEngineEvent; | 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; | return kFallbackEngineEvent; | ||||
if (index >= kMaxEventCount) | if (index >= kMaxEventCount) | ||||
return kFallbackEngineEvent; | return kFallbackEngineEvent; | ||||
@@ -181,7 +182,7 @@ void CarlaEngineEventPort::writeControlEvent(const uint32_t time, const uint8_t | |||||
{ | { | ||||
CARLA_ASSERT(! kIsInput); | CARLA_ASSERT(! kIsInput); | ||||
CARLA_ASSERT(fBuffer != nullptr); | 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(type != kEngineControlEventTypeNull); | ||||
CARLA_ASSERT(channel < MAX_MIDI_CHANNELS); | CARLA_ASSERT(channel < MAX_MIDI_CHANNELS); | ||||
CARLA_SAFE_ASSERT(value >= 0.0 && value <= 1.0); | CARLA_SAFE_ASSERT(value >= 0.0 && value <= 1.0); | ||||
@@ -190,7 +191,7 @@ void CarlaEngineEventPort::writeControlEvent(const uint32_t time, const uint8_t | |||||
return; | return; | ||||
if (fBuffer == nullptr) | if (fBuffer == nullptr) | ||||
return; | 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; | return; | ||||
if (type == kEngineControlEventTypeNull) | if (type == kEngineControlEventTypeNull) | ||||
return; | return; | ||||
@@ -224,7 +225,7 @@ void CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t cha | |||||
{ | { | ||||
CARLA_ASSERT(! kIsInput); | CARLA_ASSERT(! kIsInput); | ||||
CARLA_ASSERT(fBuffer != nullptr); | 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(channel < MAX_MIDI_CHANNELS); | ||||
CARLA_ASSERT(data != nullptr); | CARLA_ASSERT(data != nullptr); | ||||
CARLA_ASSERT(size > 0); | CARLA_ASSERT(size > 0); | ||||
@@ -233,7 +234,7 @@ void CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t cha | |||||
return; | return; | ||||
if (fBuffer == nullptr) | if (fBuffer == nullptr) | ||||
return; | 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; | return; | ||||
if (channel >= MAX_MIDI_CHANNELS) | if (channel >= MAX_MIDI_CHANNELS) | ||||
return; | return; | ||||
@@ -641,7 +642,7 @@ bool CarlaEngine::close() | |||||
void CarlaEngine::idle() | void CarlaEngine::idle() | ||||
{ | { | ||||
CARLA_ASSERT(kData->plugins != nullptr); | CARLA_ASSERT(kData->plugins != nullptr); | ||||
CARLA_ASSERT(isRunning()); | |||||
//CARLA_ASSERT(isRunning()); | |||||
for (unsigned int i=0; i < kData->curPluginCount; i++) | 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; | bridgeBinary = (const char*)fOptions.bridge_native; | ||||
#endif | #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); | plugin = CarlaPlugin::newBridge(init, btype, ptype, bridgeBinary); | ||||
#endif | |||||
setLastError("Bridged plugins are not implemented yet"); | |||||
} | } | ||||
else | else | ||||
#endif // BUILD_BRIDGE | #endif // BUILD_BRIDGE | ||||
@@ -1207,13 +1192,6 @@ void CarlaEngine::setAboutToClose() | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Global options | // Global options | ||||
#ifndef BUILD_BRIDGE | |||||
const QProcessEnvironment& CarlaEngine::getOptionsAsProcessEnvironment() const | |||||
{ | |||||
return kData->procEnv; | |||||
} | |||||
#define CARLA_ENGINE_SET_OPTION_RUNNING_CHECK \ | #define CARLA_ENGINE_SET_OPTION_RUNNING_CHECK \ | ||||
if (isRunning()) \ | if (isRunning()) \ | ||||
return carla_stderr("CarlaEngine::setOption(%s, %i, \"%s\") - Cannot set this option while engine is running!", OptionsType2Str(option), value, valueStr); | 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: | case OPTION_PROCESS_MODE: | ||||
CARLA_ENGINE_SET_OPTION_RUNNING_CHECK | 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); | return carla_stderr("CarlaEngine::setOption(%s, %i, \"%s\") - invalid value", OptionsType2Str(option), value, valueStr); | ||||
fOptions.processMode = static_cast<ProcessMode>(value); | 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: | case OPTION_TRANSPORT_MODE: | ||||
// FIXME: Always enable JACK transport for now | // FIXME: Always enable JACK transport for now | ||||
#if 0 | #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); | return carla_stderr2("carla_set_engine_option(OPTION_TRANSPORT_MODE, %i, \"%s\") - invalid value", value, valueStr); | ||||
fOptions.transportMode = static_cast<CarlaBackend::TransportMode>(value); | 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); | fOptions.oscUiTimeout = static_cast<uint>(value); | ||||
break; | break; | ||||
#ifndef BUILD_BRIDGE | |||||
case OPTION_PATH_BRIDGE_NATIVE: | case OPTION_PATH_BRIDGE_NATIVE: | ||||
fOptions.bridge_native = valueStr; | fOptions.bridge_native = valueStr; | ||||
break; | break; | ||||
@@ -1308,6 +1287,7 @@ void CarlaEngine::setOption(const OptionsType option, const int value, const cha | |||||
case OPTION_PATH_BRIDGE_WIN64: | case OPTION_PATH_BRIDGE_WIN64: | ||||
fOptions.bridge_win64 = valueStr; | fOptions.bridge_win64 = valueStr; | ||||
break; | break; | ||||
#endif | |||||
#ifdef WANT_LV2 | #ifdef WANT_LV2 | ||||
case OPTION_PATH_BRIDGE_LV2_GTK2: | case OPTION_PATH_BRIDGE_LV2_GTK2: | ||||
@@ -1346,7 +1326,6 @@ void CarlaEngine::setOption(const OptionsType option, const int value, const cha | |||||
#endif | #endif | ||||
} | } | ||||
} | } | ||||
#endif | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// OSC Stuff | // 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); | 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 | #endif | ||||
CARLA_BACKEND_END_NAMESPACE | CARLA_BACKEND_END_NAMESPACE |
@@ -21,9 +21,17 @@ | |||||
#include "CarlaBackendUtils.hpp" | #include "CarlaBackendUtils.hpp" | ||||
#include "CarlaMIDI.h" | #include "CarlaMIDI.h" | ||||
#include "CarlaBridge.hpp" | |||||
#include "../CarlaBridge.hpp" | |||||
#include "CarlaShmUtils.hpp" | #include "CarlaShmUtils.hpp" | ||||
#include "jackbridge/jackbridge.h" | |||||
#include <ctime> | |||||
//#ifdef CARLA_OS_WIN | |||||
//# include <sys/time.h> | |||||
//#endif | |||||
CARLA_BACKEND_START_NAMESPACE | CARLA_BACKEND_START_NAMESPACE | ||||
#if 0 | #if 0 | ||||
@@ -32,16 +40,22 @@ CARLA_BACKEND_START_NAMESPACE | |||||
// ----------------------------------------- | // ----------------------------------------- | ||||
class CarlaEngineBridge : public CarlaEngine | |||||
class CarlaEngineBridge : public CarlaEngine, | |||||
public CarlaThread | |||||
{ | { | ||||
public: | public: | ||||
CarlaEngineBridge(const char* const audioBaseName, const char* const controlBaseName) | CarlaEngineBridge(const char* const audioBaseName, const char* const controlBaseName) | ||||
: CarlaEngine() | |||||
: CarlaEngine(), | |||||
fIsRunning(false), | |||||
fQuitNow(false) | |||||
{ | { | ||||
carla_debug("CarlaEngineBridge::CarlaEngineBridge()"); | 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() | ~CarlaEngineBridge() | ||||
@@ -56,11 +70,14 @@ public: | |||||
{ | { | ||||
carla_debug("CarlaEngineBridge::init(\"%s\")", clientName); | carla_debug("CarlaEngineBridge::init(\"%s\")", clientName); | ||||
char tmpFileBase[60]; | |||||
// SHM Audio Pool | // 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); | fShmAudioPool.shm = carla_shm_attach((const char*)fShmAudioPool.filename); | ||||
#endif | |||||
if (! carla_is_shm_valid(fShmAudioPool.shm)) | if (! carla_is_shm_valid(fShmAudioPool.shm)) | ||||
{ | { | ||||
@@ -72,7 +89,12 @@ public: | |||||
// SHM Control | // 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); | fShmControl.shm = carla_shm_attach((const char*)fShmControl.filename); | ||||
#endif | |||||
if (! carla_is_shm_valid(fShmControl.shm)) | if (! carla_is_shm_valid(fShmControl.shm)) | ||||
{ | { | ||||
@@ -81,7 +103,7 @@ public: | |||||
return false; | return false; | ||||
} | } | ||||
if (! carla_shm_map<ShmControl>(fShmControl.shm, fShmControl.data)) | |||||
if (! carla_shm_map<BridgeShmControl>(fShmControl.shm, fShmControl.data)) | |||||
{ | { | ||||
_cleanup(); | _cleanup(); | ||||
carla_stdout("Failed to mmap shared memory file"); | 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; | return true; | ||||
} | } | ||||
@@ -98,6 +133,9 @@ public: | |||||
carla_debug("CarlaEnginePlugin::close()"); | carla_debug("CarlaEnginePlugin::close()"); | ||||
CarlaEngine::close(); | CarlaEngine::close(); | ||||
fQuitNow = true; | |||||
CarlaThread::stop(); | |||||
_cleanup(); | _cleanup(); | ||||
return true; | return true; | ||||
@@ -105,7 +143,7 @@ public: | |||||
bool isRunning() const | bool isRunning() const | ||||
{ | { | ||||
return true; | |||||
return fIsRunning; | |||||
} | } | ||||
bool isOffline() const | bool isOffline() const | ||||
@@ -118,16 +156,113 @@ public: | |||||
return kEngineTypeBridge; | 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: | private: | ||||
struct BridgeAudioPool { | struct BridgeAudioPool { | ||||
CarlaString filename; | CarlaString filename; | ||||
float* data; | float* data; | ||||
size_t size; | |||||
shm_t shm; | shm_t shm; | ||||
BridgeAudioPool() | BridgeAudioPool() | ||||
: data(nullptr), | |||||
size(0) | |||||
: data(nullptr) | |||||
{ | { | ||||
carla_shm_init(shm); | carla_shm_init(shm); | ||||
} | } | ||||
@@ -135,7 +270,7 @@ private: | |||||
struct BridgeControl { | struct BridgeControl { | ||||
CarlaString filename; | CarlaString filename; | ||||
ShmControl* data; | |||||
BridgeShmControl* data; | |||||
shm_t shm; | shm_t shm; | ||||
BridgeControl() | BridgeControl() | ||||
@@ -146,6 +281,9 @@ private: | |||||
} fShmControl; | } fShmControl; | ||||
bool fIsRunning; | |||||
bool fQuitNow; | |||||
void _cleanup() | void _cleanup() | ||||
{ | { | ||||
if (fShmAudioPool.filename.isNotEmpty()) | if (fShmAudioPool.filename.isNotEmpty()) | ||||
@@ -154,11 +292,7 @@ private: | |||||
if (fShmControl.filename.isNotEmpty()) | if (fShmControl.filename.isNotEmpty()) | ||||
fShmControl.filename.clear(); | fShmControl.filename.clear(); | ||||
// delete data | |||||
fShmAudioPool.data = nullptr; | fShmAudioPool.data = nullptr; | ||||
fShmAudioPool.size = 0; | |||||
// and again | |||||
fShmControl.data = nullptr; | fShmControl.data = nullptr; | ||||
if (carla_is_shm_valid(fShmAudioPool.shm)) | if (carla_is_shm_valid(fShmAudioPool.shm)) | ||||
@@ -210,9 +210,9 @@ struct CarlaEngineProtectedData { | |||||
#ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
static void registerEnginePlugin(CarlaEngine* const engine, const unsigned int id, CarlaPlugin* const plugin) | 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; | engine->kData->plugins[id].plugin = plugin; | ||||
} | } | ||||
#endif | #endif | ||||
@@ -99,10 +99,7 @@ public: | |||||
fBufferSize = d_bufferSize(); | fBufferSize = d_bufferSize(); | ||||
fSampleRate = d_sampleRate(); | fSampleRate = d_sampleRate(); | ||||
fName = clientName; | |||||
fName.toBasic(); | |||||
CarlaEngine::init(fName); | |||||
CarlaEngine::init(clientName); | |||||
return true; | return true; | ||||
} | } | ||||
@@ -129,17 +129,13 @@ void CarlaEngineThread::run() | |||||
} | } | ||||
} | } | ||||
#ifndef BUILD_BRIDGE | |||||
// --------------------------------------------------- | // --------------------------------------------------- | ||||
// Update OSC control client peaks | // Update OSC control client peaks | ||||
if (oscRegisted) | if (oscRegisted) | ||||
{ | |||||
#ifdef BUILD_BRIDGE | |||||
kEngine->osc_send_bridge_set_peaks(); | |||||
#else | |||||
kEngine->osc_send_control_set_peaks(i); | kEngine->osc_send_control_set_peaks(i); | ||||
#endif | #endif | ||||
} | |||||
} | } | ||||
} | } | ||||
@@ -84,8 +84,6 @@ shm_t shm_mkstemp(char* const fileBase) | |||||
return shm; | return shm; | ||||
} | } | ||||
std::srand(std::time(NULL)); | |||||
while (true) | while (true) | ||||
{ | { | ||||
for (int c = size - 6; c < size; c++) | for (int c = size - 6; c < size; c++) | ||||
@@ -136,28 +134,24 @@ public: | |||||
kData->singleMutex.lock(); | kData->singleMutex.lock(); | ||||
kData->masterMutex.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; | return params[parameterId].value; | ||||
} | } | ||||
#endif | |||||
void getLabel(char* const strBuf) | 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) | 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) | 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) | 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) | void getParameterName(const uint32_t parameterId, char* const strBuf) | ||||
{ | { | ||||
CARLA_ASSERT(parameterId < param.count); | CARLA_ASSERT(parameterId < param.count); | ||||
@@ -273,15 +257,6 @@ public: | |||||
strncpy(strBuf, params[parameterId].unit.toUtf8().constData(), STR_MAX); | 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 | #endif | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -289,12 +264,11 @@ public: | |||||
int setOscPluginBridgeInfo(const PluginBridgeInfoType type, const int argc, const lo_arg* const* const argv, const char* const types) | 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) | switch (type) | ||||
{ | { | ||||
case PluginBridgeAudioCount: | |||||
case kPluginBridgeAudioCount: | |||||
{ | { | ||||
CARLA_BRIDGE_CHECK_OSC_TYPES(3, "iii"); | CARLA_BRIDGE_CHECK_OSC_TYPES(3, "iii"); | ||||
@@ -306,14 +280,16 @@ public: | |||||
CARLA_ASSERT(aOuts >= 0); | CARLA_ASSERT(aOuts >= 0); | ||||
CARLA_ASSERT(aIns + aOuts == aTotal); | CARLA_ASSERT(aIns + aOuts == aTotal); | ||||
info.aIns = aIns; | |||||
info.aOuts = aOuts; | |||||
fInfo.aIns = aIns; | |||||
fInfo.aOuts = aOuts; | |||||
break; | break; | ||||
Q_UNUSED(aTotal); | |||||
// unused | |||||
(void)aTotal; | |||||
} | } | ||||
case PluginBridgeMidiCount: | |||||
case kPluginBridgeMidiCount: | |||||
{ | { | ||||
CARLA_BRIDGE_CHECK_OSC_TYPES(3, "iii"); | CARLA_BRIDGE_CHECK_OSC_TYPES(3, "iii"); | ||||
@@ -325,13 +301,16 @@ public: | |||||
CARLA_ASSERT(mOuts >= 0); | CARLA_ASSERT(mOuts >= 0); | ||||
CARLA_ASSERT(mIns + mOuts == mTotal); | CARLA_ASSERT(mIns + mOuts == mTotal); | ||||
info.mIns = mIns; | |||||
info.mOuts = mOuts; | |||||
fInfo.mIns = mIns; | |||||
fInfo.mOuts = mOuts; | |||||
break; | break; | ||||
Q_UNUSED(mTotal); | |||||
// unused | |||||
(void)mTotal; | |||||
} | } | ||||
#if 0 | |||||
case PluginBridgeParameterCount: | case PluginBridgeParameterCount: | ||||
{ | { | ||||
CARLA_BRIDGE_CHECK_OSC_TYPES(3, "iii"); | CARLA_BRIDGE_CHECK_OSC_TYPES(3, "iii"); | ||||
@@ -438,8 +417,9 @@ public: | |||||
break; | break; | ||||
} | } | ||||
#endif | |||||
case PluginBridgePluginInfo: | |||||
case kPluginBridgePluginInfo: | |||||
{ | { | ||||
CARLA_BRIDGE_CHECK_OSC_TYPES(7, "iissssh"); | CARLA_BRIDGE_CHECK_OSC_TYPES(7, "iissssh"); | ||||
@@ -458,21 +438,23 @@ public: | |||||
CARLA_ASSERT(maker); | CARLA_ASSERT(maker); | ||||
CARLA_ASSERT(copyright); | 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; | break; | ||||
} | } | ||||
#if 0 | |||||
case PluginBridgeParameterInfo: | case PluginBridgeParameterInfo: | ||||
{ | { | ||||
CARLA_BRIDGE_CHECK_OSC_TYPES(3, "iss"); | CARLA_BRIDGE_CHECK_OSC_TYPES(3, "iss"); | ||||
@@ -753,30 +735,29 @@ public: | |||||
break; | break; | ||||
} | } | ||||
#endif | |||||
case PluginBridgeUpdateNow: | |||||
case kPluginBridgeUpdateNow: | |||||
{ | { | ||||
m_initiated = true; | |||||
fInitiated = true; | |||||
break; | break; | ||||
} | } | ||||
case PluginBridgeError: | |||||
case kPluginBridgeError: | |||||
{ | { | ||||
CARLA_BRIDGE_CHECK_OSC_TYPES(1, "s"); | CARLA_BRIDGE_CHECK_OSC_TYPES(1, "s"); | ||||
const char* const error = (const char*)&argv[0]->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; | break; | ||||
} | } | ||||
} | } | ||||
#endif | |||||
return 0; | return 0; | ||||
} | } | ||||
@@ -837,6 +818,7 @@ public: | |||||
osc_send_configure(&osc.data, CARLA_BRIDGE_MSG_SET_CHUNK, filePath.toUtf8().constData()); | osc_send_configure(&osc.data, CARLA_BRIDGE_MSG_SET_CHUNK, filePath.toUtf8().constData()); | ||||
} | } | ||||
} | } | ||||
#endif | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Set gui stuff | // Set gui stuff | ||||
@@ -844,15 +826,15 @@ public: | |||||
void showGui(const bool yesNo) | void showGui(const bool yesNo) | ||||
{ | { | ||||
if (yesNo) | if (yesNo) | ||||
osc_send_show(&osc.data); | |||||
osc_send_show(&kData->osc.data); | |||||
else | else | ||||
osc_send_hide(&osc.data); | |||||
osc_send_hide(&kData->osc.data); | |||||
} | } | ||||
void idleGui() | 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(); | CarlaPlugin::idleGui(); | ||||
} | } | ||||
@@ -860,6 +842,131 @@ public: | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Plugin state | // 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() | void prepareForSave() | ||||
{ | { | ||||
m_saved = false; | m_saved = false; | ||||
@@ -877,93 +984,125 @@ public: | |||||
else | else | ||||
carla_debug("BridgePlugin::prepareForSave() - success!"); | 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 | // 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; | return; | ||||
if (! osc.data.target) | |||||
if (kData->osc.data.target == nullptr) | |||||
return; | 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) | 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; | return; | ||||
if (! osc.data.target) | |||||
if (kData->osc.data.target == nullptr) | |||||
return; | return; | ||||
osc_send_program(&osc.data, index); | |||||
osc_send_program(&kData->osc.data, index); | |||||
} | } | ||||
void uiMidiProgramChange(const uint32_t 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; | return; | ||||
if (! osc.data.target) | |||||
if (kData->osc.data.target == nullptr) | |||||
return; | 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) | 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; | return; | ||||
uint8_t midiData[4] = { 0 }; | uint8_t midiData[4] = { 0 }; | ||||
midiData[1] = MIDI_STATUS_NOTE_ON + channel; | midiData[1] = MIDI_STATUS_NOTE_ON + channel; | ||||
midiData[2] = note; | midiData[2] = note; | ||||
midiData[3] = velo; | 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) | 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; | return; | ||||
uint8_t midiData[4] = { 0 }; | uint8_t midiData[4] = { 0 }; | ||||
midiData[1] = MIDI_STATUS_NOTE_OFF + channel; | midiData[1] = MIDI_STATUS_NOTE_OFF + channel; | ||||
midiData[2] = note; | 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; | 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 | // SHM Audio Pool | ||||
{ | { | ||||
char tmpFileBase[60]; | char tmpFileBase[60]; | ||||
std::srand(std::time(NULL)); | |||||
std::sprintf(tmpFileBase, "/carla-bridge_shm_XXXXXX"); | std::sprintf(tmpFileBase, "/carla-bridge_shm_XXXXXX"); | ||||
fShmAudioPool.shm = shm_mkstemp(tmpFileBase); | fShmAudioPool.shm = shm_mkstemp(tmpFileBase); | ||||
@@ -1024,6 +1175,7 @@ public: | |||||
// SHM Control | // SHM Control | ||||
{ | { | ||||
char tmpFileBase[60]; | char tmpFileBase[60]; | ||||
std::sprintf(tmpFileBase, "/carla-bridge_shc_XXXXXX"); | std::sprintf(tmpFileBase, "/carla-bridge_shc_XXXXXX"); | ||||
fShmControl.shm = shm_mkstemp(tmpFileBase); | fShmControl.shm = shm_mkstemp(tmpFileBase); | ||||
@@ -1044,7 +1196,10 @@ public: | |||||
return false; | return false; | ||||
} | } | ||||
CARLA_ASSERT(fShmControl.data != nullptr); | |||||
std::memset(fShmControl.data, 0, sizeof(BridgeShmControl)); | 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 (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) | // register plugin now so we can receive OSC (and wait for it) | ||||
fHints |= PLUGIN_IS_BRIDGE; | |||||
registerEnginePlugin(kData->engine, fId, this); | 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++) | for (int i=0; i < 200; i++) | ||||
{ | { | ||||
@@ -1079,7 +1252,9 @@ public: | |||||
// unregister so it gets handled properly | // unregister so it gets handled properly | ||||
registerEnginePlugin(kData->engine, fId, nullptr); | 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?)"); | kData->engine->setLastError("Timeout while waiting for a response from plugin-bridge\n(or the plugin crashed on initialization?)"); | ||||
return false; | return false; | ||||
} | } | ||||
@@ -1093,10 +1268,16 @@ public: | |||||
return false; | 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; | return true; | ||||
} | } | ||||
private: | private: | ||||
const BinaryType fBinaryType; | const BinaryType fBinaryType; | ||||
const PluginType fPluginType; | const PluginType fPluginType; | ||||
@@ -1154,6 +1335,61 @@ private: | |||||
BridgeParamInfo* fParams; | 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) | CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(BridgePlugin) | ||||
}; | }; | ||||
@@ -1163,12 +1399,12 @@ CARLA_BACKEND_END_NAMESPACE | |||||
CARLA_BACKEND_START_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"); | init.engine->setLastError("Bridge not possible, bridge-binary not found"); | ||||
return nullptr; | 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); | 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; | delete plugin; | ||||
return nullptr; | return nullptr; | ||||
@@ -1188,10 +1424,13 @@ CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, P | |||||
#else | #else | ||||
init.engine->setLastError("Plugin bridge support not available"); | init.engine->setLastError("Plugin bridge support not available"); | ||||
return nullptr; | return nullptr; | ||||
// unused | |||||
(void)bridgeBinary; | |||||
#endif | #endif | ||||
} | } | ||||
#if 1//ndef BUILD_BRIDGE | |||||
#ifndef BUILD_BRIDGE | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Bridge Helper | // Bridge Helper | ||||
@@ -64,11 +64,12 @@ void CarlaPluginThread::setMode(const CarlaPluginThread::Mode mode) | |||||
fMode = 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; | fBinary = binary; | ||||
fLabel = label; | fLabel = label; | ||||
fExtra = extra; | |||||
fExtra1 = extra1; | |||||
fExtra2 = extra2; | |||||
} | } | ||||
void CarlaPluginThread::run() | void CarlaPluginThread::run() | ||||
@@ -84,40 +85,44 @@ void CarlaPluginThread::run() | |||||
#endif | #endif | ||||
} | } | ||||
QString name(kPlugin->name() ? kPlugin->name() : "(none)"); | |||||
QString name(kPlugin->name()); | |||||
QStringList arguments; | QStringList arguments; | ||||
if (name.isEmpty()) | |||||
name = "(none)"; | |||||
switch (fMode) | switch (fMode) | ||||
{ | { | ||||
case PLUGIN_THREAD_NULL: | case PLUGIN_THREAD_NULL: | ||||
break; | break; | ||||
case PLUGIN_THREAD_DSSI_GUI: | 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(); | /* filename */ arguments << kPlugin->filename(); | ||||
/* label */ arguments << (const char*)fLabel; | /* label */ arguments << (const char*)fLabel; | ||||
/* ui-title */ arguments << QString("%1 (GUI)").arg(kPlugin->name()); | /* ui-title */ arguments << QString("%1 (GUI)").arg(kPlugin->name()); | ||||
break; | break; | ||||
case PLUGIN_THREAD_LV2_GUI: | 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; | /* 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()); | /* ui-title */ arguments << QString("%1 (GUI)").arg(kPlugin->name()); | ||||
break; | break; | ||||
case PLUGIN_THREAD_VST_GUI: | 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(); | /* filename */ arguments << kPlugin->filename(); | ||||
/* ui-title */ arguments << QString("%1 (GUI)").arg(kPlugin->name()); | /* ui-title */ arguments << QString("%1 (GUI)").arg(kPlugin->name()); | ||||
break; | break; | ||||
case PLUGIN_THREAD_BRIDGE: | 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(); | /* filename */ arguments << kPlugin->filename(); | ||||
/* name */ arguments << name; | /* name */ arguments << name; | ||||
/* label */ arguments << (const char*)fLabel; | /* label */ arguments << (const char*)fLabel; | ||||
/* SHM ids */ arguments << (const char*)fExtra2; | |||||
break; | break; | ||||
} | } | ||||
@@ -41,7 +41,7 @@ public: | |||||
~CarlaPluginThread(); | ~CarlaPluginThread(); | ||||
void setMode(const CarlaPluginThread::Mode mode); | 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: | protected: | ||||
void run(); | void run(); | ||||
@@ -53,7 +53,8 @@ private: | |||||
Mode fMode; | Mode fMode; | ||||
CarlaString fBinary; | CarlaString fBinary; | ||||
CarlaString fLabel; | CarlaString fLabel; | ||||
CarlaString fExtra; | |||||
CarlaString fExtra1; | |||||
CarlaString fExtra2; | |||||
QProcess* fProcess; | QProcess* fProcess; | ||||
}; | }; | ||||
@@ -46,7 +46,9 @@ struct CarlaBackendStandalone { | |||||
CarlaEngine* engine; | CarlaEngine* engine; | ||||
CarlaString lastError; | CarlaString lastError; | ||||
CarlaString procName; | CarlaString procName; | ||||
#ifndef BUILD_BRIDGE | |||||
EngineOptions options; | EngineOptions options; | ||||
#endif | |||||
QApplication* app; | QApplication* app; | ||||
bool needsInit; | bool needsInit; | ||||
@@ -85,14 +87,6 @@ struct CarlaBackendStandalone { | |||||
} standalone; | } standalone; | ||||
// ------------------------------------------------------------------------------------------------------------------- | |||||
// Helpers | |||||
CarlaEngine* carla_get_standalone_engine() | |||||
{ | |||||
return standalone.engine; | |||||
} | |||||
// ------------------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------------------- | ||||
// API | // API | ||||
@@ -232,16 +226,6 @@ bool carla_engine_init(const char* driverName, const char* clientName) | |||||
CARLA_ASSERT(driverName != nullptr); | CARLA_ASSERT(driverName != nullptr); | ||||
CARLA_ASSERT(clientName != nullptr); | CARLA_ASSERT(clientName != nullptr); | ||||
#if 0 | |||||
static bool sigInfoInitiated = false; | |||||
if (! sigInfoInitiated) | |||||
{ | |||||
setup_siginfo(); | |||||
sigInfoInitiated = true; | |||||
} | |||||
#endif | |||||
standalone.engine = CarlaEngine::newDriverByName(driverName); | standalone.engine = CarlaEngine::newDriverByName(driverName); | ||||
if (standalone.engine == nullptr) | if (standalone.engine == nullptr) | ||||
@@ -377,14 +361,13 @@ void carla_set_engine_callback(CarlaBackend::CallbackFunc func, void* ptr) | |||||
standalone.engine->setCallback(func, ptr); | standalone.engine->setCallback(func, ptr); | ||||
} | } | ||||
#ifndef BUILD_BRIDGE | |||||
void carla_set_engine_option(CarlaBackend::OptionsType option, int value, const char* valueStr) | 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); | carla_debug("carla_set_engine_option(%s, %i, \"%s\")", CarlaBackend::OptionsType2Str(option), value, valueStr); | ||||
#ifndef BUILD_BRIDGE | |||||
if (standalone.engine != nullptr) | if (standalone.engine != nullptr) | ||||
standalone.engine->setOption(option, value, valueStr); | standalone.engine->setOption(option, value, valueStr); | ||||
#endif | |||||
switch (option) | switch (option) | ||||
{ | { | ||||
@@ -493,6 +476,7 @@ void carla_set_engine_option(CarlaBackend::OptionsType option, int value, const | |||||
#endif | #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 | #if 0 | ||||
//def QTCREATOR_TEST | //def QTCREATOR_TEST | ||||
@@ -140,6 +140,8 @@ private: | |||||
const char* fUiFilename; | const char* fUiFilename; | ||||
void* fUiLib; | void* fUiLib; | ||||
bool fUiQuit; | bool fUiQuit; | ||||
#else | |||||
friend class CarlaPluginClient; | |||||
#endif | #endif | ||||
const CarlaOscData* fOscData; | const CarlaOscData* fOscData; | ||||
@@ -115,17 +115,21 @@ class CarlaPluginClient : public CarlaBridgeClient, | |||||
public QObject | public QObject | ||||
{ | { | ||||
public: | public: | ||||
CarlaPluginClient(const char* const name) | |||||
CarlaPluginClient(const bool useBridge, const char* const driverName, const char* audioBaseName, const char* controlBaseName) | |||||
: CarlaBridgeClient(nullptr), | : CarlaBridgeClient(nullptr), | ||||
QObject(nullptr), | QObject(nullptr), | ||||
fEngine(nullptr), | fEngine(nullptr), | ||||
fPlugin(nullptr), | fPlugin(nullptr), | ||||
fTimerId(0) | 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); | carla_set_engine_callback(callback, this); | ||||
} | } | ||||
@@ -138,6 +142,14 @@ public: | |||||
carla_engine_close(); | carla_engine_close(); | ||||
} | } | ||||
void oscInit(const char* const url) | |||||
{ | |||||
CarlaBridgeClient::oscInit(url); | |||||
fEngine = carla_get_standalone_engine(); | |||||
fEngine->setOscBridgeData(fOscData); | |||||
} | |||||
void ready() | void ready() | ||||
{ | { | ||||
CARLA_ASSERT(fTimerId == 0); | CARLA_ASSERT(fTimerId == 0); | ||||
@@ -405,9 +417,6 @@ int CarlaBridgeOsc::handleMsgQuit() | |||||
carla_debug("CarlaBridgeOsc::handleMsgQuit()"); | carla_debug("CarlaBridgeOsc::handleMsgQuit()"); | ||||
CARLA_ASSERT(kClient != nullptr); | CARLA_ASSERT(kClient != nullptr); | ||||
if (kClient == nullptr) | |||||
return 1; | |||||
gCloseNow = true; | gCloseNow = true; | ||||
return 0; | return 0; | ||||
@@ -473,7 +482,7 @@ int main(int argc, char* argv[]) | |||||
{ | { | ||||
CARLA_BRIDGE_USE_NAMESPACE | 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]); | carla_stdout("usage: %s <osc-url|\"null\"> <type> <filename> <name|\"(none)\"> <label>", argv[0]); | ||||
return 1; | return 1; | ||||
@@ -485,11 +494,21 @@ int main(int argc, char* argv[]) | |||||
const char* name = argv[4]; | const char* name = argv[4]; | ||||
const char* const label = argv[5]; | 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) | if (std::strcmp(name, "(none)") == 0) | ||||
name = nullptr; | 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; | CarlaBackend::PluginType itype; | ||||
if (std::strcmp(stype, "LADSPA") == 0) | if (std::strcmp(stype, "LADSPA") == 0) | ||||
@@ -512,7 +531,7 @@ int main(int argc, char* argv[]) | |||||
app.setQuitOnLastWindowClosed(false); | app.setQuitOnLastWindowClosed(false); | ||||
// Init Plugin client | // Init Plugin client | ||||
CarlaPluginClient client(name ? name : label); | |||||
CarlaPluginClient client(useBridge, (name != nullptr) ? name : label, bridgeBaseAudioName, bridgeBaseControlName); | |||||
// Init OSC | // Init OSC | ||||
if (useOsc) | if (useOsc) | ||||
@@ -535,6 +554,10 @@ int main(int argc, char* argv[]) | |||||
{ | { | ||||
client.sendOscUpdate(); | client.sendOscUpdate(); | ||||
client.sendOscBridgeUpdate(); | client.sendOscBridgeUpdate(); | ||||
// TESTING!! | |||||
carla_set_active(0, true); | |||||
carla_show_gui(0, true); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -31,7 +31,7 @@ LINK_FLAGS += $(shell pkg-config --libs liblo QtCore) | |||||
BUILD_PLUGIN_FLAGS = $(BUILD_CXX_FLAGS) | BUILD_PLUGIN_FLAGS = $(BUILD_CXX_FLAGS) | ||||
BUILD_PLUGIN_FLAGS += -DBUILD_BRIDGE_PLUGIN -DBRIDGE_PLUGIN | 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 += -I../backend/engine -I../backend/plugin -I../libs | ||||
BUILD_PLUGIN_FLAGS += $(QT_UI_FLAGS) $(shell pkg-config --cflags QtXml) | 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) | # Plugin bridges (Native) | ||||
NATIVE_BUILD_FLAGS = $(POSIX_BUILD_FLAGS) | |||||
NATIVE_BUILD_FLAGS = $(POSIX_BUILD_FLAGS) -DWANT_JACK | |||||
NATIVE_LINK_FLAGS = $(POSIX_LINK_FLAGS) | NATIVE_LINK_FLAGS = $(POSIX_LINK_FLAGS) | ||||
NATIVE_BUILD_FLAGS += -DWANT_NATIVE | NATIVE_BUILD_FLAGS += -DWANT_NATIVE | ||||
@@ -288,7 +288,8 @@ OBJS_NATIVE += \ | |||||
../backend/engine/CarlaEngine__native.o \ | ../backend/engine/CarlaEngine__native.o \ | ||||
../backend/engine/CarlaEngineOsc__native.o \ | ../backend/engine/CarlaEngineOsc__native.o \ | ||||
../backend/engine/CarlaEngineThread__native.o \ | ../backend/engine/CarlaEngineThread__native.o \ | ||||
../backend/engine/CarlaEngineJack__native.o | |||||
../backend/engine/CarlaEngineJack__native.o \ | |||||
../backend/engine/CarlaEngineBridge__native.o | |||||
# carla-plugin | # carla-plugin | ||||
OBJS_NATIVE += \ | OBJS_NATIVE += \ | ||||
@@ -332,7 +333,8 @@ OBJS_POSIX32 += \ | |||||
../backend/engine/CarlaEngine__posix32.o \ | ../backend/engine/CarlaEngine__posix32.o \ | ||||
../backend/engine/CarlaEngineOsc__posix32.o \ | ../backend/engine/CarlaEngineOsc__posix32.o \ | ||||
../backend/engine/CarlaEngineThread__posix32.o \ | ../backend/engine/CarlaEngineThread__posix32.o \ | ||||
../backend/engine/CarlaEngineJack__posix32.o | |||||
../backend/engine/CarlaEngineJack__posix32.o \ | |||||
../backend/engine/CarlaEngineBridge__posix32.o | |||||
# carla-plugin | # carla-plugin | ||||
OBJS_POSIX32 += \ | OBJS_POSIX32 += \ | ||||
@@ -374,7 +376,8 @@ OBJS_POSIX64 += \ | |||||
../backend/engine/CarlaEngine__posix64.o \ | ../backend/engine/CarlaEngine__posix64.o \ | ||||
../backend/engine/CarlaEngineOsc__posix64.o \ | ../backend/engine/CarlaEngineOsc__posix64.o \ | ||||
../backend/engine/CarlaEngineThread__posix64.o \ | ../backend/engine/CarlaEngineThread__posix64.o \ | ||||
../backend/engine/CarlaEngineJack__posix64.o | |||||
../backend/engine/CarlaEngineJack__posix64.o \ | |||||
../backend/engine/CarlaEngineBridge__posix64.o | |||||
# carla-plugin | # carla-plugin | ||||
OBJS_POSIX64 += \ | OBJS_POSIX64 += \ | ||||
@@ -416,7 +419,7 @@ OBJS_WIN32 += \ | |||||
../backend/engine/CarlaEngine__win32.o \ | ../backend/engine/CarlaEngine__win32.o \ | ||||
../backend/engine/CarlaEngineOsc__win32.o \ | ../backend/engine/CarlaEngineOsc__win32.o \ | ||||
../backend/engine/CarlaEngineThread__win32.o \ | ../backend/engine/CarlaEngineThread__win32.o \ | ||||
../backend/engine/CarlaEngineJack__win32.o | |||||
../backend/engine/CarlaEngineBridge__win32.o | |||||
# carla-plugin | # carla-plugin | ||||
OBJS_WIN32 += \ | OBJS_WIN32 += \ | ||||
@@ -458,7 +461,7 @@ OBJS_WIN64 += \ | |||||
../backend/engine/CarlaEngine__win64.o \ | ../backend/engine/CarlaEngine__win64.o \ | ||||
../backend/engine/CarlaEngineOsc__win64.o \ | ../backend/engine/CarlaEngineOsc__win64.o \ | ||||
../backend/engine/CarlaEngineThread__win64.o \ | ../backend/engine/CarlaEngineThread__win64.o \ | ||||
../backend/engine/CarlaEngineJack__win64.o | |||||
../backend/engine/CarlaEngineBridge__win64.o | |||||
# carla-plugin | # carla-plugin | ||||
OBJS_WIN64 += \ | OBJS_WIN64 += \ | ||||
@@ -28,6 +28,7 @@ SOURCES += \ | |||||
../../backend/engine/CarlaEngine.cpp \ | ../../backend/engine/CarlaEngine.cpp \ | ||||
../../backend/engine/CarlaEngineOsc.cpp \ | ../../backend/engine/CarlaEngineOsc.cpp \ | ||||
../../backend/engine/CarlaEngineThread.cpp \ | ../../backend/engine/CarlaEngineThread.cpp \ | ||||
../../backend/engine/CarlaEngineBridge.cpp \ | |||||
../../backend/engine/CarlaEngineJack.cpp \ | ../../backend/engine/CarlaEngineJack.cpp \ | ||||
../../backend/engine/CarlaEnginePlugin.cpp \ | ../../backend/engine/CarlaEnginePlugin.cpp \ | ||||
../../backend/engine/CarlaEngineRtAudio.cpp | ../../backend/engine/CarlaEngineRtAudio.cpp | ||||
@@ -88,6 +89,7 @@ HEADERS += \ | |||||
../../utils/CarlaLibUtils.hpp \ | ../../utils/CarlaLibUtils.hpp \ | ||||
../../utils/CarlaLv2Utils.hpp \ | ../../utils/CarlaLv2Utils.hpp \ | ||||
../../utils/CarlaOscUtils.hpp \ | ../../utils/CarlaOscUtils.hpp \ | ||||
../../utils/CarlaShmUtils.hpp \ | |||||
../../utils/CarlaStateUtils.hpp \ | ../../utils/CarlaStateUtils.hpp \ | ||||
../../utils/CarlaVstUtils.hpp \ | ../../utils/CarlaVstUtils.hpp \ | ||||
../../utils/CarlaUtils.hpp \ | ../../utils/CarlaUtils.hpp \ | ||||
@@ -114,7 +116,7 @@ DEFINES += DEBUG | |||||
DEFINES += BUILD_BRIDGE BUILD_BRIDGE_PLUGIN BRIDGE_PLUGIN | DEFINES += BUILD_BRIDGE BUILD_BRIDGE_PLUGIN BRIDGE_PLUGIN | ||||
DEFINES += WANT_JACK | 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 | DEFINES += WANT_FLUIDSYNTH WANT_LINUXSAMPLER | ||||
LIBS = -ldl \ | LIBS = -ldl \ | ||||
@@ -322,6 +322,7 @@ PROCESS_MODE_BRIDGE = 4 | |||||
# Transport Mode | # Transport Mode | ||||
TRANSPORT_MODE_INTERNAL = 0 | TRANSPORT_MODE_INTERNAL = 0 | ||||
TRANSPORT_MODE_JACK = 1 | TRANSPORT_MODE_JACK = 1 | ||||
TRANSPORT_MODE_BRIDGE = 2 | |||||
# Set BINARY_NATIVE | # Set BINARY_NATIVE | ||||
if HAIKU or LINUX or MACOS: | if HAIKU or LINUX or MACOS: | ||||
@@ -21,7 +21,7 @@ WIN_LINK_FLAGS = $(LINK_FLAGS) | |||||
WINE_BUILD_FLAGS = $(BUILD_C_FLAGS) -fPIC | WINE_BUILD_FLAGS = $(BUILD_C_FLAGS) -fPIC | ||||
WINE_32BIT_FLAGS = $(32BIT_FLAGS) -L/usr/lib32/wine -L/usr/lib/i386-linux-gnu/wine | 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_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 | OBJS = jackbridge.c | ||||
@@ -16,6 +16,11 @@ | |||||
#include "jackbridge.h" | #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, ...) | 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); | jack_transport_stop(client); | ||||
#endif | #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 | #ifdef JACKBRIDGE_EXPORT | ||||
# define GNU_WIN32 // fix jack threads, always use pthread | # define GNU_WIN32 // fix jack threads, always use pthread | ||||
# include <sys/time.h> | |||||
#endif | #endif | ||||
#include <jack/jack.h> | #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_start(jack_client_t* client); | ||||
BRIDGE_EXPORT void jackbridge_transport_stop(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 | #ifdef __cplusplus | ||||
} | } | ||||
#endif | #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_start jack_transport_start | ||||
#define jackbridge_transport_stop jack_transport_stop | #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_EXPORT | ||||
#endif // __JACKBRIDGE_H__ | #endif // __JACKBRIDGE_H__ |
@@ -21,10 +21,8 @@ | |||||
#include "CarlaUtils.hpp" | #include "CarlaUtils.hpp" | ||||
#ifdef CARLA_OS_WIN | #ifdef CARLA_OS_WIN | ||||
# include <vector> | |||||
# include <windows.h> | # 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 | #else | ||||
# include <fcntl.h> | # include <fcntl.h> | ||||
# include <sys/mman.h> | # include <sys/mman.h> | ||||
@@ -49,7 +47,7 @@ void carla_shm_init(shm_t& shm) | |||||
{ | { | ||||
#ifdef CARLA_OS_WIN | #ifdef CARLA_OS_WIN | ||||
shm.shm = nullptr; | shm.shm = nullptr; | ||||
shm.maps.clear(); | |||||
shm.map = nullptr; | |||||
#else | #else | ||||
shm = -1; | shm = -1; | ||||
#endif | #endif | ||||
@@ -67,6 +65,7 @@ shm_t carla_shm_attach_linux(const char* const name) | |||||
shm_t ret; | shm_t ret; | ||||
ret.shm = CreateFileA(shmName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); | ret.shm = CreateFileA(shmName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); | ||||
ret.map = nullptr; | |||||
return ret; | return ret; | ||||
} | } | ||||
@@ -94,7 +93,7 @@ void carla_shm_close(shm_t& shm) | |||||
CARLA_ASSERT(carla_is_shm_valid(shm)); | CARLA_ASSERT(carla_is_shm_valid(shm)); | ||||
#ifdef CARLA_OS_WIN | #ifdef CARLA_OS_WIN | ||||
CARLA_ASSERT(shm.maps.empty()); | |||||
CARLA_ASSERT(shm.map == nullptr); | |||||
CloseHandle(shm.shm); | CloseHandle(shm.shm); | ||||
shm.shm = nullptr; | shm.shm = nullptr; | ||||
@@ -111,6 +110,8 @@ void* carla_shm_map(shm_t& shm, const size_t size) | |||||
CARLA_ASSERT(size > 0); | CARLA_ASSERT(size > 0); | ||||
#ifdef CARLA_OS_WIN | #ifdef CARLA_OS_WIN | ||||
CARLA_ASSERT(shm.map == nullptr); | |||||
HANDLE map = CreateFileMapping(shm.shm, NULL, PAGE_READWRITE, size, size, NULL); | HANDLE map = CreateFileMapping(shm.shm, NULL, PAGE_READWRITE, size, size, NULL); | ||||
if (map == nullptr) | 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); | HANDLE ptr = MapViewOfFile(map, FILE_MAP_COPY, 0, 0, size); | ||||
if (ptr == nullptr) | if (ptr == nullptr) | ||||
{ | |||||
CloseHandle(map); | |||||
return nullptr; | return nullptr; | ||||
} | |||||
map_t newMap; | |||||
newMap.map = map; | |||||
newMap.ptr = ptr; | |||||
shm.maps.push_back(newMap); | |||||
shm.map = map; | |||||
return ptr; | return ptr; | ||||
#else | #else | ||||
@@ -135,31 +135,18 @@ void* carla_shm_map(shm_t& shm, const size_t size) | |||||
} | } | ||||
static inline | 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(carla_is_shm_valid(shm)); | ||||
CARLA_ASSERT(ptr != nullptr); | CARLA_ASSERT(ptr != nullptr); | ||||
CARLA_ASSERT(size > 0); | CARLA_ASSERT(size > 0); | ||||
#ifdef CARLA_OS_WIN | #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; | return; | ||||
// unused | // unused | ||||
@@ -178,17 +165,17 @@ void carla_shm_unmap(const shm_t& shm, void* const ptr, const size_t size) | |||||
template<typename T> | template<typename T> | ||||
static inline | 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); | return (value != nullptr); | ||||
} | } | ||||
template<typename T> | template<typename T> | ||||
static inline | 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; | value = nullptr; | ||||
} | } | ||||
@@ -263,7 +263,7 @@ private: | |||||
} | } | ||||
#endif | #endif | ||||
CARLA_PREVENT_HEAP_ALLOCATION | |||||
//CARLA_PREVENT_HEAP_ALLOCATION | |||||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaThread) | CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaThread) | ||||
}; | }; | ||||