| @@ -1167,7 +1167,7 @@ public: | |||
| #ifdef BUILD_BRIDGE | |||
| // Bridge | |||
| static CarlaEngine* newBridge(const char* const audioPoolBaseName, const char* const rtBaseName, const char* const nonRtBaseName); | |||
| static CarlaEngine* newBridge(const char* const audioPoolBaseName, const char* const rtClientBaseName, const char* const nonRtClientBaseName, const char* const nonRtServerBaseName); | |||
| #else | |||
| # if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||
| // Juce | |||
| @@ -423,7 +423,8 @@ CARLA_EXPORT bool carla_engine_init(const char* driverName, const char* clientNa | |||
| /*! | |||
| * Initialize the engine in bridged mode. | |||
| */ | |||
| CARLA_EXPORT bool carla_engine_init_bridge(const char audioBaseName[6+1], const char rtBaseName[6+1], const char nonRtBaseName[6+1], const char* clientName); | |||
| CARLA_EXPORT bool carla_engine_init_bridge(const char audioBaseName[6+1], const char rtClientBaseName[6+1], const char nonRtClientBaseName[6+1], | |||
| const char nonRtServerBaseName[6+1], const char* clientName); | |||
| #endif | |||
| /*! | |||
| @@ -532,13 +532,15 @@ bool carla_engine_init(const char* driverName, const char* clientName) | |||
| } | |||
| #ifdef BUILD_BRIDGE | |||
| bool carla_engine_init_bridge(const char audioBaseName[6+1], const char rtBaseName[6+1], const char nonRtBaseName[6+1], const char* clientName) | |||
| bool carla_engine_init_bridge(const char audioBaseName[6+1], const char rtClientBaseName[6+1], const char nonRtClientBaseName[6+1], | |||
| const char nonRtServerBaseName[6+1], const char* clientName) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(audioBaseName != nullptr && audioBaseName[0] != '\0', false); | |||
| CARLA_SAFE_ASSERT_RETURN(rtBaseName != nullptr && rtBaseName[0] != '\0', false); | |||
| CARLA_SAFE_ASSERT_RETURN(nonRtBaseName != nullptr && nonRtBaseName[0] != '\0', false); | |||
| CARLA_SAFE_ASSERT_RETURN(rtClientBaseName != nullptr && rtClientBaseName[0] != '\0', false); | |||
| CARLA_SAFE_ASSERT_RETURN(nonRtClientBaseName != nullptr && nonRtClientBaseName[0] != '\0', false); | |||
| CARLA_SAFE_ASSERT_RETURN(nonRtServerBaseName != nullptr && nonRtServerBaseName[0] != '\0', false); | |||
| CARLA_SAFE_ASSERT_RETURN(clientName != nullptr && clientName[0] != '\0', false); | |||
| carla_debug("carla_engine_init_bridge(\"%s\", \"%s\", \"%s\", \"%s\")", audioBaseName, rtBaseName, nonRtBaseName, clientName); | |||
| carla_debug("carla_engine_init_bridge(\"%s\", \"%s\", \"%s\", \"%s\", \"%s\")", audioBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName, clientName); | |||
| if (gStandalone.engine != nullptr) | |||
| { | |||
| @@ -547,7 +549,7 @@ bool carla_engine_init_bridge(const char audioBaseName[6+1], const char rtBaseNa | |||
| return false; | |||
| } | |||
| gStandalone.engine = CarlaEngine::newBridge(audioBaseName, rtBaseName, nonRtBaseName); | |||
| gStandalone.engine = CarlaEngine::newBridge(audioBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName); | |||
| if (gStandalone.engine == nullptr) | |||
| { | |||
| @@ -29,15 +29,10 @@ | |||
| #include "jackbridge/JackBridge.hpp" | |||
| #include <cerrno> | |||
| #include <ctime> | |||
| using juce::File; | |||
| using juce::MemoryBlock; | |||
| using juce::String; | |||
| // ------------------------------------------------------------------- | |||
| template<typename T> | |||
| bool jackbridge_shm_map2(char* shm, T*& value) noexcept | |||
| { | |||
| @@ -45,8 +40,6 @@ bool jackbridge_shm_map2(char* shm, T*& value) noexcept | |||
| return (value != nullptr); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| // ------------------------------------------------------------------- | |||
| @@ -72,34 +65,128 @@ struct BridgeAudioPool { | |||
| clear(); | |||
| } | |||
| void clear() noexcept | |||
| { | |||
| filename.clear(); | |||
| if (! jackbridge_shm_is_valid(shm)) | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| return; | |||
| } | |||
| data = nullptr; | |||
| jackbridge_shm_close(shm); | |||
| jackbridge_shm_init(shm); | |||
| } | |||
| bool attach() noexcept | |||
| { | |||
| // must be invalid right now | |||
| CARLA_SAFE_ASSERT_RETURN(! jackbridge_shm_is_valid(shm), false); | |||
| jackbridge_shm_attach(shm, filename); | |||
| return jackbridge_shm_is_valid(shm); | |||
| } | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeAudioPool) | |||
| }; | |||
| // ------------------------------------------------------------------- | |||
| struct BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||
| CarlaString filename; | |||
| BridgeRtClientData* data; | |||
| char shm[64]; | |||
| BridgeRtClientControl() noexcept | |||
| : filename(), | |||
| data(nullptr) | |||
| { | |||
| carla_zeroChar(shm, 64); | |||
| jackbridge_shm_init(shm); | |||
| } | |||
| ~BridgeRtClientControl() noexcept override | |||
| { | |||
| // should be cleared by now | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| clear(); | |||
| } | |||
| void clear() noexcept | |||
| { | |||
| filename.clear(); | |||
| if (! jackbridge_shm_is_valid(shm)) | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| return; | |||
| } | |||
| data = nullptr; | |||
| if (jackbridge_shm_is_valid(shm)) | |||
| jackbridge_shm_close(shm); | |||
| jackbridge_shm_close(shm); | |||
| jackbridge_shm_init(shm); | |||
| } | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeAudioPool) | |||
| bool attach() noexcept | |||
| { | |||
| // must be invalid right now | |||
| CARLA_SAFE_ASSERT_RETURN(! jackbridge_shm_is_valid(shm), false); | |||
| jackbridge_shm_attach(shm, filename); | |||
| return jackbridge_shm_is_valid(shm); | |||
| } | |||
| bool mapData() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| if (jackbridge_shm_map2<BridgeRtClientData>(shm, data)) | |||
| { | |||
| CARLA_SAFE_ASSERT(data->midiOut[0] == 0); | |||
| setRingBuffer(&data->ringBuffer, false); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| bool postClient() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(data != nullptr, false); | |||
| return jackbridge_sem_post(&data->sem.client); | |||
| } | |||
| bool waitForServer(const uint secs) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(data != nullptr, false); | |||
| return jackbridge_sem_timedwait(&data->sem.server, secs); | |||
| } | |||
| PluginBridgeRtClientOpcode readOpcode() noexcept | |||
| { | |||
| return static_cast<PluginBridgeRtClientOpcode>(readUInt()); | |||
| } | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeRtClientControl) | |||
| }; | |||
| // ------------------------------------------------------------------- | |||
| struct BridgeRtControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||
| struct BridgeNonRtClientControl : public CarlaRingBufferControl<BigStackBuffer> { | |||
| CarlaString filename; | |||
| BridgeRtClientData* data; | |||
| BridgeNonRtClientData* data; | |||
| char shm[64]; | |||
| BridgeRtControl() noexcept | |||
| BridgeNonRtClientControl() noexcept | |||
| : filename(), | |||
| data(nullptr) | |||
| { | |||
| @@ -107,7 +194,7 @@ struct BridgeRtControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||
| jackbridge_shm_init(shm); | |||
| } | |||
| ~BridgeRtControl() noexcept override | |||
| ~BridgeNonRtClientControl() noexcept override | |||
| { | |||
| // should be cleared by now | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| @@ -126,19 +213,24 @@ struct BridgeRtControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||
| { | |||
| filename.clear(); | |||
| if (! jackbridge_shm_is_valid(shm)) | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| return; | |||
| } | |||
| data = nullptr; | |||
| if (jackbridge_shm_is_valid(shm)) | |||
| jackbridge_shm_close(shm); | |||
| jackbridge_shm_close(shm); | |||
| jackbridge_shm_init(shm); | |||
| } | |||
| bool mapData() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| if (jackbridge_shm_map2<BridgeRtClientData>(shm, data)) | |||
| if (jackbridge_shm_map2<BridgeNonRtClientData>(shm, data)) | |||
| { | |||
| CARLA_SAFE_ASSERT(data->midiOut[0] == 0); | |||
| setRingBuffer(&data->ringBuffer, false); | |||
| return true; | |||
| } | |||
| @@ -146,22 +238,22 @@ struct BridgeRtControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||
| return false; | |||
| } | |||
| PluginBridgeRtClientOpcode readOpcode() noexcept | |||
| PluginBridgeNonRtClientOpcode readOpcode() noexcept | |||
| { | |||
| return static_cast<PluginBridgeRtClientOpcode>(readInt()); | |||
| return static_cast<PluginBridgeNonRtClientOpcode>(readUInt()); | |||
| } | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeRtControl) | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeNonRtClientControl) | |||
| }; | |||
| // ------------------------------------------------------------------- | |||
| struct BridgeNonRtControl : public CarlaRingBufferControl<BigStackBuffer> { | |||
| struct BridgeNonRtServerControl : public CarlaRingBufferControl<HugeStackBuffer> { | |||
| CarlaString filename; | |||
| BridgeNonRtClientData* data; | |||
| BridgeNonRtServerData* data; | |||
| char shm[64]; | |||
| BridgeNonRtControl() noexcept | |||
| BridgeNonRtServerControl() noexcept | |||
| : filename(), | |||
| data(nullptr) | |||
| { | |||
| @@ -169,7 +261,7 @@ struct BridgeNonRtControl : public CarlaRingBufferControl<BigStackBuffer> { | |||
| jackbridge_shm_init(shm); | |||
| } | |||
| ~BridgeNonRtControl() noexcept override | |||
| ~BridgeNonRtServerControl() noexcept override | |||
| { | |||
| // should be cleared by now | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| @@ -188,17 +280,23 @@ struct BridgeNonRtControl : public CarlaRingBufferControl<BigStackBuffer> { | |||
| { | |||
| filename.clear(); | |||
| if (! jackbridge_shm_is_valid(shm)) | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| return; | |||
| } | |||
| data = nullptr; | |||
| if (jackbridge_shm_is_valid(shm)) | |||
| jackbridge_shm_close(shm); | |||
| jackbridge_shm_close(shm); | |||
| jackbridge_shm_init(shm); | |||
| } | |||
| bool mapData() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| if (jackbridge_shm_map2<BridgeNonRtClientData>(shm, data)) | |||
| if (jackbridge_shm_map2<BridgeNonRtServerData>(shm, data)) | |||
| { | |||
| setRingBuffer(&data->ringBuffer, false); | |||
| return true; | |||
| @@ -207,12 +305,12 @@ struct BridgeNonRtControl : public CarlaRingBufferControl<BigStackBuffer> { | |||
| return false; | |||
| } | |||
| PluginBridgeNonRtClientOpcode readOpcode() noexcept | |||
| void writeOpcode(const PluginBridgeNonRtServerOpcode opcode) noexcept | |||
| { | |||
| return static_cast<PluginBridgeNonRtClientOpcode>(readInt()); | |||
| writeUInt(static_cast<uint32_t>(opcode)); | |||
| } | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeNonRtControl) | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeNonRtServerControl) | |||
| }; | |||
| // ------------------------------------------------------------------- | |||
| @@ -221,30 +319,30 @@ class CarlaEngineBridge : public CarlaEngine, | |||
| public CarlaThread | |||
| { | |||
| public: | |||
| CarlaEngineBridge(const char* const audioPoolBaseName, const char* const rtBaseName, const char* const nonRtBaseName) | |||
| CarlaEngineBridge(const char* const audioPoolBaseName, const char* const rtClientBaseName, const char* const nonRtClientBaseName, const char* const nonRtServerBaseName) | |||
| : CarlaEngine(), | |||
| CarlaThread("CarlaEngineBridge"), | |||
| fShmAudioPool(), | |||
| fShmCVPool(), | |||
| fShmRtControl(), | |||
| fShmNonRtControl(), | |||
| fShmRtClientControl(), | |||
| fShmNonRtClientControl(), | |||
| fShmNonRtServerControl(), | |||
| fIsRunning(false), | |||
| fIsOffline(false), | |||
| leakDetector_CarlaEngineBridge() | |||
| { | |||
| carla_stdout("CarlaEngineBridge::CarlaEngineBridge(\"%s\", \"%s\", \"%s\")", audioPoolBaseName, rtBaseName, nonRtBaseName); | |||
| carla_stdout("CarlaEngineBridge::CarlaEngineBridge(\"%s\", \"%s\", \"%s\", \"%s\")", audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName); | |||
| fShmAudioPool.filename = "/carla-bridge_shm_ap_"; | |||
| fShmAudioPool.filename += audioPoolBaseName; | |||
| //fShmCVPool.filename = "/carla-bridge_shm_cvp_"; | |||
| //fShmCVPool.filename += cvPoolBaseName; | |||
| fShmRtClientControl.filename = "/carla-bridge_shm_rtC_"; | |||
| fShmRtClientControl.filename += rtClientBaseName; | |||
| fShmRtControl.filename = "/carla-bridge_shm_rt_"; | |||
| fShmRtControl.filename += rtBaseName; | |||
| fShmNonRtClientControl.filename = "/carla-bridge_shm_nonrtC_"; | |||
| fShmNonRtClientControl.filename += nonRtClientBaseName; | |||
| fShmNonRtControl.filename = "/carla-bridge_shm_nonrt_"; | |||
| fShmNonRtControl.filename += nonRtBaseName; | |||
| fShmNonRtServerControl.filename = "/carla-bridge_shm_nonrtS_"; | |||
| fShmNonRtServerControl.filename += nonRtServerBaseName; | |||
| } | |||
| ~CarlaEngineBridge() noexcept override | |||
| @@ -271,28 +369,28 @@ public: | |||
| return false; | |||
| } | |||
| if (! fShmRtControl.attach()) | |||
| if (! fShmRtClientControl.attach()) | |||
| { | |||
| clear(); | |||
| carla_stdout("Failed to attach to rt control shared memory"); | |||
| return false; | |||
| } | |||
| if (! fShmRtControl.mapData()) | |||
| if (! fShmRtClientControl.mapData()) | |||
| { | |||
| clear(); | |||
| carla_stdout("Failed to map rt control shared memory"); | |||
| return false; | |||
| } | |||
| if (! fShmNonRtControl.attach()) | |||
| if (! fShmNonRtClientControl.attach()) | |||
| { | |||
| clear(); | |||
| carla_stdout("Failed to attach to non-rt control shared memory"); | |||
| return false; | |||
| } | |||
| if (! fShmNonRtControl.mapData()) | |||
| if (! fShmNonRtClientControl.mapData()) | |||
| { | |||
| clear(); | |||
| carla_stdout("Failed to map non-rt control shared memory"); | |||
| @@ -301,22 +399,22 @@ public: | |||
| PluginBridgeNonRtClientOpcode opcode; | |||
| opcode = fShmNonRtControl.readOpcode(); | |||
| opcode = fShmNonRtClientControl.readOpcode(); | |||
| CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientNull, opcode); | |||
| const uint32_t shmRtDataSize = fShmNonRtControl.readUInt(); | |||
| const uint32_t shmRtDataSize = fShmNonRtClientControl.readUInt(); | |||
| CARLA_SAFE_ASSERT_INT2(shmRtDataSize == sizeof(BridgeRtClientData), shmRtDataSize, sizeof(BridgeRtClientData)); | |||
| const uint32_t shmNonRtDataSize = fShmNonRtControl.readUInt(); | |||
| const uint32_t shmNonRtDataSize = fShmNonRtClientControl.readUInt(); | |||
| CARLA_SAFE_ASSERT_INT2(shmNonRtDataSize == sizeof(BridgeNonRtClientData), shmNonRtDataSize, sizeof(BridgeNonRtClientData)); | |||
| opcode = fShmNonRtControl.readOpcode(); | |||
| opcode = fShmNonRtClientControl.readOpcode(); | |||
| CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetBufferSize, opcode); | |||
| pData->bufferSize = fShmNonRtControl.readUInt(); | |||
| pData->bufferSize = fShmNonRtClientControl.readUInt(); | |||
| opcode = fShmNonRtControl.readOpcode(); | |||
| opcode = fShmNonRtClientControl.readOpcode(); | |||
| CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetSampleRate, opcode); | |||
| pData->sampleRate = fShmNonRtControl.readDouble(); | |||
| pData->sampleRate = fShmNonRtClientControl.readDouble(); | |||
| carla_stdout("Carla Client Info:"); | |||
| carla_stdout(" BufferSize: %i", pData->bufferSize); | |||
| @@ -377,15 +475,15 @@ public: | |||
| void clear() noexcept | |||
| { | |||
| fShmAudioPool.clear(); | |||
| fShmRtControl.clear(); | |||
| fShmNonRtControl.clear(); | |||
| fShmRtClientControl.clear(); | |||
| fShmNonRtClientControl.clear(); | |||
| } | |||
| void handleNonRtData() | |||
| { | |||
| for (; fShmNonRtControl.isDataAvailableForReading();) | |||
| for (; fShmNonRtClientControl.isDataAvailableForReading();) | |||
| { | |||
| const PluginBridgeNonRtClientOpcode opcode(fShmNonRtControl.readOpcode()); | |||
| const PluginBridgeNonRtClientOpcode opcode(fShmNonRtClientControl.readOpcode()); | |||
| CarlaPlugin* const plugin(pData->plugins[0].plugin); | |||
| #ifdef DEBUG | |||
| @@ -414,14 +512,14 @@ public: | |||
| break; | |||
| case kPluginBridgeNonRtClientSetBufferSize: { | |||
| const uint32_t bufferSize(fShmNonRtControl.readUInt()); | |||
| const uint32_t bufferSize(fShmNonRtClientControl.readUInt()); | |||
| pData->bufferSize = bufferSize; | |||
| bufferSizeChanged(bufferSize); | |||
| break; | |||
| } | |||
| case kPluginBridgeNonRtClientSetSampleRate: { | |||
| const double sampleRate(fShmNonRtControl.readDouble()); | |||
| const double sampleRate(fShmNonRtClientControl.readDouble()); | |||
| pData->sampleRate = sampleRate; | |||
| sampleRateChanged(sampleRate); | |||
| break; | |||
| @@ -438,8 +536,8 @@ public: | |||
| break; | |||
| case kPluginBridgeNonRtClientSetParameterValue: { | |||
| const uint32_t index(fShmNonRtControl.readUInt()); | |||
| const float value(fShmNonRtControl.readFloat()); | |||
| const uint32_t index(fShmNonRtClientControl.readUInt()); | |||
| const float value(fShmNonRtClientControl.readFloat()); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| plugin->setParameterValue(index, value, false, false, false); | |||
| @@ -447,8 +545,8 @@ public: | |||
| } | |||
| case kPluginBridgeNonRtClientSetParameterMidiChannel: { | |||
| const uint32_t index(fShmNonRtControl.readUInt()); | |||
| const uint8_t channel(fShmNonRtControl.readByte()); | |||
| const uint32_t index(fShmNonRtClientControl.readUInt()); | |||
| const uint8_t channel(fShmNonRtClientControl.readByte()); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| plugin->setParameterMidiChannel(index, channel, false, false); | |||
| @@ -456,8 +554,8 @@ public: | |||
| } | |||
| case kPluginBridgeNonRtClientSetParameterMidiCC: { | |||
| const uint32_t index(fShmNonRtControl.readUInt()); | |||
| const int16_t cc(fShmNonRtControl.readShort()); | |||
| const uint32_t index(fShmNonRtClientControl.readUInt()); | |||
| const int16_t cc(fShmNonRtClientControl.readShort()); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| plugin->setParameterMidiCC(index, cc, false, false); | |||
| @@ -465,7 +563,7 @@ public: | |||
| } | |||
| case kPluginBridgeNonRtClientSetProgram: { | |||
| const int32_t index(fShmNonRtControl.readInt()); | |||
| const int32_t index(fShmNonRtClientControl.readInt()); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| plugin->setProgram(index, false, false, false); | |||
| @@ -473,7 +571,7 @@ public: | |||
| } | |||
| case kPluginBridgeNonRtClientSetMidiProgram: { | |||
| const int32_t index(fShmNonRtControl.readInt()); | |||
| const int32_t index(fShmNonRtClientControl.readInt()); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| plugin->setMidiProgram(index, false, false, false); | |||
| @@ -482,22 +580,22 @@ public: | |||
| case kPluginBridgeNonRtClientSetCustomData: { | |||
| // type | |||
| const uint32_t typeSize(fShmNonRtControl.readUInt()); | |||
| const uint32_t typeSize(fShmNonRtClientControl.readUInt()); | |||
| char typeStr[typeSize+1]; | |||
| carla_zeroChar(typeStr, typeSize+1); | |||
| fShmNonRtControl.readCustomData(typeStr, typeSize); | |||
| fShmNonRtClientControl.readCustomData(typeStr, typeSize); | |||
| // key | |||
| const uint32_t keySize(fShmNonRtControl.readUInt()); | |||
| const uint32_t keySize(fShmNonRtClientControl.readUInt()); | |||
| char keyStr[keySize+1]; | |||
| carla_zeroChar(keyStr, keySize+1); | |||
| fShmNonRtControl.readCustomData(keyStr, keySize); | |||
| fShmNonRtClientControl.readCustomData(keyStr, keySize); | |||
| // value | |||
| const uint32_t valueSize(fShmNonRtControl.readUInt()); | |||
| const uint32_t valueSize(fShmNonRtClientControl.readUInt()); | |||
| char valueStr[valueSize+1]; | |||
| carla_zeroChar(valueStr, valueSize+1); | |||
| fShmNonRtControl.readCustomData(valueStr, valueSize); | |||
| fShmNonRtClientControl.readCustomData(valueStr, valueSize); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| plugin->setCustomData(typeStr, keyStr, valueStr, true); | |||
| @@ -505,12 +603,12 @@ public: | |||
| } | |||
| case kPluginBridgeNonRtClientSetChunkDataFile: { | |||
| const uint32_t size(fShmNonRtControl.readUInt()); | |||
| const uint32_t size(fShmNonRtClientControl.readUInt()); | |||
| CARLA_SAFE_ASSERT_BREAK(size > 0); | |||
| char chunkFilePathTry[size+1]; | |||
| carla_zeroChar(chunkFilePathTry, size+1); | |||
| fShmNonRtControl.readCustomData(chunkFilePathTry, size); | |||
| fShmNonRtClientControl.readCustomData(chunkFilePathTry, size); | |||
| CARLA_SAFE_ASSERT_BREAK(chunkFilePathTry[0] != '\0'); | |||
| if (plugin == nullptr || ! plugin->isEnabled()) break; | |||
| @@ -536,7 +634,7 @@ public: | |||
| } | |||
| case kPluginBridgeNonRtClientSetCtrlChannel: { | |||
| const int16_t channel(fShmNonRtControl.readShort()); | |||
| const int16_t channel(fShmNonRtClientControl.readShort()); | |||
| CARLA_SAFE_ASSERT_BREAK(channel >= -1 && channel < MAX_MIDI_CHANNELS); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| @@ -545,8 +643,8 @@ public: | |||
| } | |||
| case kPluginBridgeNonRtClientSetOption: { | |||
| const uint32_t option(fShmNonRtControl.readUInt()); | |||
| const bool yesNo(fShmNonRtControl.readBool()); | |||
| const uint32_t option(fShmNonRtClientControl.readUInt()); | |||
| const bool yesNo(fShmNonRtClientControl.readBool()); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| plugin->setOption(option, yesNo, false); | |||
| @@ -578,7 +676,7 @@ public: | |||
| filePath += CARLA_OS_SEP_STR; | |||
| filePath += ".CarlaChunk_"; | |||
| filePath += fShmNonRtControl.filename.buffer() + 24; | |||
| filePath += fShmNonRtClientControl.filename.buffer() + 24; | |||
| if (File(filePath).replaceWithText(dataBase64.buffer())) | |||
| oscSend_bridge_set_chunk_data_file(filePath.toRawUTF8()); | |||
| @@ -600,8 +698,8 @@ public: | |||
| break; | |||
| case kPluginBridgeNonRtClientUiParameterChange: { | |||
| const uint32_t index(fShmNonRtControl.readUInt()); | |||
| const float value(fShmNonRtControl.readFloat()); | |||
| const uint32_t index(fShmNonRtClientControl.readUInt()); | |||
| const float value(fShmNonRtClientControl.readFloat()); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| plugin->uiParameterChange(index, value); | |||
| @@ -609,7 +707,7 @@ public: | |||
| } | |||
| case kPluginBridgeNonRtClientUiProgramChange: { | |||
| const uint32_t index(fShmNonRtControl.readUInt()); | |||
| const uint32_t index(fShmNonRtClientControl.readUInt()); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| plugin->uiProgramChange(index); | |||
| @@ -617,7 +715,7 @@ public: | |||
| } | |||
| case kPluginBridgeNonRtClientUiMidiProgramChange: { | |||
| const uint32_t index(fShmNonRtControl.readUInt()); | |||
| const uint32_t index(fShmNonRtClientControl.readUInt()); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| plugin->uiMidiProgramChange(index); | |||
| @@ -625,9 +723,9 @@ public: | |||
| } | |||
| case kPluginBridgeNonRtClientUiNoteOn: { | |||
| const uint8_t chnl(fShmNonRtControl.readByte()); | |||
| const uint8_t note(fShmNonRtControl.readByte()); | |||
| const uint8_t velo(fShmNonRtControl.readByte()); | |||
| const uint8_t chnl(fShmNonRtClientControl.readByte()); | |||
| const uint8_t note(fShmNonRtClientControl.readByte()); | |||
| const uint8_t velo(fShmNonRtClientControl.readByte()); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| plugin->uiNoteOn(chnl, note, velo); | |||
| @@ -635,8 +733,8 @@ public: | |||
| } | |||
| case kPluginBridgeNonRtClientUiNoteOff: { | |||
| const uint8_t chnl(fShmNonRtControl.readByte()); | |||
| const uint8_t note(fShmNonRtControl.readByte()); | |||
| const uint8_t chnl(fShmNonRtClientControl.readByte()); | |||
| const uint8_t note(fShmNonRtClientControl.readByte()); | |||
| if (plugin != nullptr && plugin->isEnabled()) | |||
| plugin->uiNoteOff(chnl, note); | |||
| @@ -658,18 +756,18 @@ protected: | |||
| { | |||
| for (; ! shouldThreadExit();) | |||
| { | |||
| if (! jackbridge_sem_timedwait(&fShmRtControl.data->sem.server, 5)) | |||
| if (! fShmRtClientControl.waitForServer(5)) | |||
| { | |||
| if (errno == ETIMEDOUT) | |||
| { | |||
| signalThreadShouldExit(); | |||
| break; | |||
| } | |||
| carla_stderr2("Bridge timed-out, final post..."); | |||
| fShmRtClientControl.postClient(); | |||
| carla_stderr2("Bridge timed-out, done."); | |||
| signalThreadShouldExit(); | |||
| break; | |||
| } | |||
| for (; fShmRtControl.isDataAvailableForReading();) | |||
| for (; fShmRtClientControl.isDataAvailableForReading();) | |||
| { | |||
| const PluginBridgeRtClientOpcode opcode(fShmRtControl.readOpcode()); | |||
| const PluginBridgeRtClientOpcode opcode(fShmRtClientControl.readOpcode()); | |||
| CarlaPlugin* const plugin(pData->plugins[0].plugin); | |||
| #ifdef DEBUG | |||
| @@ -684,24 +782,24 @@ protected: | |||
| break; | |||
| case kPluginBridgeRtClientSetAudioPool: { | |||
| const uint64_t poolSize(fShmRtControl.readULong()); | |||
| const uint64_t poolSize(fShmRtClientControl.readULong()); | |||
| CARLA_SAFE_ASSERT_BREAK(poolSize > 0); | |||
| fShmAudioPool.data = (float*)jackbridge_shm_map(fShmAudioPool.shm, static_cast<size_t>(poolSize)); | |||
| break; | |||
| } | |||
| case kPluginBridgeRtClientSetCVPool: { | |||
| const uint64_t poolSize(fShmRtControl.readULong()); | |||
| const uint64_t poolSize(fShmRtClientControl.readULong()); | |||
| CARLA_SAFE_ASSERT_BREAK(poolSize > 0); | |||
| //fShmCVPool.data = (float*)jackbridge_shm_map(fShmCVPool.shm, static_cast<size_t>(poolSize)); | |||
| break; | |||
| } | |||
| case kPluginBridgeRtClientControlEventParameter: { | |||
| const uint32_t time(fShmRtControl.readUInt()); | |||
| const uint8_t channel(fShmRtControl.readByte()); | |||
| const uint16_t param(fShmRtControl.readUShort()); | |||
| const float value(fShmRtControl.readFloat()); | |||
| const uint32_t time(fShmRtClientControl.readUInt()); | |||
| const uint8_t channel(fShmRtClientControl.readByte()); | |||
| const uint16_t param(fShmRtClientControl.readUShort()); | |||
| const float value(fShmRtClientControl.readFloat()); | |||
| if (EngineEvent* const event = getNextFreeInputEvent()) | |||
| { | |||
| @@ -716,9 +814,9 @@ protected: | |||
| } | |||
| case kPluginBridgeRtClientControlEventMidiBank: { | |||
| const uint32_t time(fShmRtControl.readUInt()); | |||
| const uint8_t channel(fShmRtControl.readByte()); | |||
| const uint16_t index(fShmRtControl.readUShort()); | |||
| const uint32_t time(fShmRtClientControl.readUInt()); | |||
| const uint8_t channel(fShmRtClientControl.readByte()); | |||
| const uint16_t index(fShmRtClientControl.readUShort()); | |||
| if (EngineEvent* const event = getNextFreeInputEvent()) | |||
| { | |||
| @@ -733,9 +831,9 @@ protected: | |||
| } | |||
| case kPluginBridgeRtClientControlEventMidiProgram: { | |||
| const uint32_t time(fShmRtControl.readUInt()); | |||
| const uint8_t channel(fShmRtControl.readByte()); | |||
| const uint16_t index(fShmRtControl.readUShort()); | |||
| const uint32_t time(fShmRtClientControl.readUInt()); | |||
| const uint8_t channel(fShmRtClientControl.readByte()); | |||
| const uint16_t index(fShmRtClientControl.readUShort()); | |||
| if (EngineEvent* const event = getNextFreeInputEvent()) | |||
| { | |||
| @@ -750,8 +848,8 @@ protected: | |||
| } | |||
| case kPluginBridgeRtClientControlEventAllSoundOff: { | |||
| const uint32_t time(fShmRtControl.readUInt()); | |||
| const uint8_t channel(fShmRtControl.readByte()); | |||
| const uint32_t time(fShmRtClientControl.readUInt()); | |||
| const uint8_t channel(fShmRtClientControl.readByte()); | |||
| if (EngineEvent* const event = getNextFreeInputEvent()) | |||
| { | |||
| @@ -765,8 +863,8 @@ protected: | |||
| } | |||
| case kPluginBridgeRtClientControlEventAllNotesOff: { | |||
| const uint32_t time(fShmRtControl.readUInt()); | |||
| const uint8_t channel(fShmRtControl.readByte()); | |||
| const uint32_t time(fShmRtClientControl.readUInt()); | |||
| const uint8_t channel(fShmRtClientControl.readByte()); | |||
| if (EngineEvent* const event = getNextFreeInputEvent()) | |||
| { | |||
| @@ -780,15 +878,15 @@ protected: | |||
| } | |||
| case kPluginBridgeRtClientMidiEvent: { | |||
| const uint32_t time(fShmRtControl.readUInt()); | |||
| const uint8_t port(fShmRtControl.readByte()); | |||
| const uint8_t size(fShmRtControl.readByte()); | |||
| const uint32_t time(fShmRtClientControl.readUInt()); | |||
| const uint8_t port(fShmRtClientControl.readByte()); | |||
| const uint8_t size(fShmRtClientControl.readByte()); | |||
| CARLA_SAFE_ASSERT_BREAK(size > 0); | |||
| uint8_t data[size]; | |||
| for (uint8_t i=0; i<size; ++i) | |||
| data[i] = fShmRtControl.readByte(); | |||
| data[i] = fShmRtClientControl.readByte(); | |||
| if (EngineEvent* const event = getNextFreeInputEvent()) | |||
| { | |||
| @@ -825,7 +923,7 @@ protected: | |||
| if (plugin != nullptr && plugin->isEnabled() && plugin->tryLock(false)) | |||
| { | |||
| const BridgeTimeInfo& bridgeTimeInfo(fShmRtControl.data->timeInfo); | |||
| const BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo); | |||
| const uint32_t audioInCount(plugin->getAudioInCount()); | |||
| const uint32_t audioOutCount(plugin->getAudioOutCount()); | |||
| @@ -888,8 +986,8 @@ protected: | |||
| } | |||
| } | |||
| if (! jackbridge_sem_post(&fShmRtControl.data->sem.client)) | |||
| carla_stderr2("Could not post to rt semaphore"); | |||
| if (! fShmRtClientControl.postClient()) | |||
| carla_stderr2("Could not post to client rt semaphore"); | |||
| } | |||
| fIsRunning = false; | |||
| @@ -912,10 +1010,10 @@ protected: | |||
| // ------------------------------------------------------------------- | |||
| private: | |||
| BridgeAudioPool fShmAudioPool; | |||
| BridgeAudioPool fShmCVPool; | |||
| BridgeRtControl fShmRtControl; | |||
| BridgeNonRtControl fShmNonRtControl; | |||
| BridgeAudioPool fShmAudioPool; | |||
| BridgeRtClientControl fShmRtClientControl; | |||
| BridgeNonRtClientControl fShmNonRtClientControl; | |||
| BridgeNonRtServerControl fShmNonRtServerControl; | |||
| bool fIsRunning; | |||
| bool fIsOffline; | |||
| @@ -925,9 +1023,9 @@ private: | |||
| // ----------------------------------------------------------------------- | |||
| CarlaEngine* CarlaEngine::newBridge(const char* const audioPoolBaseName, const char* const rtBaseName, const char* const nonRtBaseName) | |||
| CarlaEngine* CarlaEngine::newBridge(const char* const audioPoolBaseName, const char* const rtClientBaseName, const char* const nonRtClientBaseName, const char* const nonRtServerBaseName) | |||
| { | |||
| return new CarlaEngineBridge(audioPoolBaseName, rtBaseName, nonRtBaseName); | |||
| return new CarlaEngineBridge(audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -18,11 +18,6 @@ | |||
| #include "CarlaEngine.hpp" | |||
| #include "CarlaEngineOsc.hpp" | |||
| #include "CarlaPlugin.hpp" | |||
| #ifndef BUILD_BRIDGE | |||
| # include "CarlaBridgeUtils.hpp" | |||
| #endif | |||
| #include "CarlaMIDI.h" | |||
| #include <cctype> | |||
| @@ -32,29 +32,6 @@ | |||
| #include <cmath> | |||
| #include <ctime> | |||
| #define CARLA_BRIDGE_CHECK_OSC_TYPES(/* argc, types, */ argcToCompare, typesToCompare) \ | |||
| /* check argument count */ \ | |||
| if (argc != argcToCompare) \ | |||
| { \ | |||
| carla_stderr("BridgePlugin::%s() - argument count mismatch: %i != %i", __FUNCTION__, argc, argcToCompare); \ | |||
| return 1; \ | |||
| } \ | |||
| if (argc > 0) \ | |||
| { \ | |||
| /* check for nullness */ \ | |||
| if (! (types && typesToCompare)) \ | |||
| { \ | |||
| carla_stderr("BridgePlugin::%s() - argument types are null", __FUNCTION__); \ | |||
| return 1; \ | |||
| } \ | |||
| /* check argument types */ \ | |||
| if (std::strcmp(types, typesToCompare) != 0) \ | |||
| { \ | |||
| carla_stderr("BridgePlugin::%s() - argument types mismatch: '%s' != '%s'", __FUNCTION__, types, typesToCompare); \ | |||
| return 1; \ | |||
| } \ | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| using juce::File; | |||
| @@ -63,56 +40,23 @@ using juce::StringArray; | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| #if 0 | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // call carla_shm_create with for a XXXXXX temp filename | |||
| static shm_t shm_mkstemp(char* const fileBase) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fileBase != nullptr, gNullCarlaShm); | |||
| const size_t fileBaseLen(std::strlen(fileBase)); | |||
| CARLA_SAFE_ASSERT_RETURN(fileBaseLen > 6, gNullCarlaShm); | |||
| CARLA_SAFE_ASSERT_RETURN(std::strcmp(fileBase + fileBaseLen - 6, "XXXXXX") == 0, gNullCarlaShm); | |||
| static const char charSet[] = "abcdefghijklmnopqrstuvwxyz" | |||
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |||
| "0123456789"; | |||
| static const int charSetLen = static_cast<int>(std::strlen(charSet) - 1); // -1 to avoid trailing '\0' | |||
| // try until getting a valid shm or an error occurs | |||
| for (;;) | |||
| { | |||
| for (size_t c = fileBaseLen - 6; c < fileBaseLen; ++c) | |||
| fileBase[c] = charSet[std::rand() % charSetLen]; | |||
| const shm_t shm = carla_shm_create(fileBase); | |||
| if (carla_is_shm_valid(shm)) | |||
| return shm; | |||
| if (errno != EEXIST) | |||
| return gNullCarlaShm; | |||
| } | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| struct BridgeAudioPool { | |||
| CarlaString filename; | |||
| std::size_t size; | |||
| float* data; | |||
| size_t size; | |||
| shm_t shm; | |||
| BridgeAudioPool() noexcept | |||
| : filename(), | |||
| data(nullptr), | |||
| size(0) | |||
| size(0), | |||
| data(nullptr) | |||
| #ifdef CARLA_PROPER_CPP11_SUPPORT | |||
| , shm(shm_t_INIT) {} | |||
| #else | |||
| { | |||
| carla_shm_init(shm); | |||
| shm = shm_t_INIT; | |||
| } | |||
| #endif | |||
| @@ -129,7 +73,10 @@ struct BridgeAudioPool { | |||
| filename.clear(); | |||
| if (! carla_is_shm_valid(shm)) | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| return; | |||
| } | |||
| if (data != nullptr) | |||
| { | |||
| @@ -139,14 +86,17 @@ struct BridgeAudioPool { | |||
| size = 0; | |||
| carla_shm_close(shm); | |||
| carla_shm_init(shm); | |||
| } | |||
| void resize(const uint32_t bufferSize, const uint32_t portCount) noexcept | |||
| void resize(const uint32_t bufferSize, const uint32_t audioPortCount, const uint32_t cvPortCount) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm),); | |||
| if (data != nullptr) | |||
| carla_shm_unmap(shm, data); | |||
| size = portCount*bufferSize*sizeof(float); | |||
| size = (audioPortCount+cvPortCount)*bufferSize*sizeof(float); | |||
| if (size == 0) | |||
| size = sizeof(float); | |||
| @@ -159,23 +109,23 @@ struct BridgeAudioPool { | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| struct BridgeRtControl : public CarlaRingBuffer<StackBuffer> { | |||
| struct BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||
| CarlaString filename; | |||
| BridgeRtData* data; | |||
| BridgeRtClientData* data; | |||
| shm_t shm; | |||
| BridgeRtControl() | |||
| BridgeRtClientControl() | |||
| : filename(), | |||
| data(nullptr) | |||
| #ifdef CARLA_PROPER_CPP11_SUPPORT | |||
| , shm(shm_t_INIT) {} | |||
| #else | |||
| { | |||
| carla_shm_init(shm); | |||
| shm = shm_t_INIT; | |||
| } | |||
| #endif | |||
| ~BridgeRtControl() noexcept override | |||
| ~BridgeRtClientControl() noexcept override | |||
| { | |||
| // should be cleared by now | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| @@ -188,7 +138,10 @@ struct BridgeRtControl : public CarlaRingBuffer<StackBuffer> { | |||
| filename.clear(); | |||
| if (! carla_is_shm_valid(shm)) | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| return; | |||
| } | |||
| if (data != nullptr) | |||
| { | |||
| @@ -197,17 +150,18 @@ struct BridgeRtControl : public CarlaRingBuffer<StackBuffer> { | |||
| } | |||
| carla_shm_close(shm); | |||
| carla_shm_init(shm); | |||
| } | |||
| bool mapData() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| if (carla_shm_map<BridgeRtData>(shm, data)) | |||
| if (carla_shm_map<BridgeRtClientData>(shm, data)) | |||
| { | |||
| carla_zeroStruct(data->sem); | |||
| carla_zeroStruct(data->timeInfo); | |||
| carla_zeroBytes(data->midiOut, kBridgeRtDataMidiOutSize); | |||
| carla_zeroBytes(data->midiOut, kBridgeRtClientDataMidiOutSize); | |||
| setRingBuffer(&data->ringBuffer, true); | |||
| return true; | |||
| } | |||
| @@ -225,7 +179,7 @@ struct BridgeRtControl : public CarlaRingBuffer<StackBuffer> { | |||
| setRingBuffer(nullptr, false); | |||
| } | |||
| bool waitForServer(const uint secs) noexcept | |||
| bool waitForClient(const uint secs) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(data != nullptr, false); | |||
| @@ -234,23 +188,23 @@ struct BridgeRtControl : public CarlaRingBuffer<StackBuffer> { | |||
| return jackbridge_sem_timedwait(&data->sem.client, secs); | |||
| } | |||
| void writeOpcode(const PluginBridgeRtOpcode opcode) noexcept | |||
| void writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept | |||
| { | |||
| writeInt(static_cast<int32_t>(opcode)); | |||
| writeUInt(static_cast<uint32_t>(opcode)); | |||
| } | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeRtControl) | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeRtClientControl) | |||
| }; | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| struct BridgeNonRtControl : public CarlaRingBuffer<BigStackBuffer> { | |||
| struct BridgeNonRtClientControl : public CarlaRingBufferControl<BigStackBuffer> { | |||
| CarlaMutex mutex; | |||
| CarlaString filename; | |||
| BridgeNonRtData* data; | |||
| BridgeNonRtClientData* data; | |||
| shm_t shm; | |||
| BridgeNonRtControl() noexcept | |||
| BridgeNonRtClientControl() noexcept | |||
| : mutex(), | |||
| filename(), | |||
| data(nullptr) | |||
| @@ -258,11 +212,88 @@ struct BridgeNonRtControl : public CarlaRingBuffer<BigStackBuffer> { | |||
| , shm(shm_t_INIT) {} | |||
| #else | |||
| { | |||
| shm = shm_t_INIT; | |||
| } | |||
| #endif | |||
| ~BridgeNonRtClientControl() noexcept override | |||
| { | |||
| // should be cleared by now | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| clear(); | |||
| } | |||
| void clear() noexcept | |||
| { | |||
| filename.clear(); | |||
| if (! carla_is_shm_valid(shm)) | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| return; | |||
| } | |||
| if (data != nullptr) | |||
| { | |||
| carla_shm_unmap(shm, data); | |||
| data = nullptr; | |||
| } | |||
| carla_shm_close(shm); | |||
| carla_shm_init(shm); | |||
| } | |||
| bool mapData() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| if (carla_shm_map<BridgeNonRtClientData>(shm, data)) | |||
| { | |||
| setRingBuffer(&data->ringBuffer, true); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| void unmapData() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(data != nullptr,); | |||
| carla_shm_unmap(shm, data); | |||
| data = nullptr; | |||
| setRingBuffer(nullptr, false); | |||
| } | |||
| void writeOpcode(const PluginBridgeNonRtClientOpcode opcode) noexcept | |||
| { | |||
| writeUInt(static_cast<uint32_t>(opcode)); | |||
| } | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeNonRtClientControl) | |||
| }; | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| struct BridgeNonRtServerControl : public CarlaRingBufferControl<HugeStackBuffer> { | |||
| CarlaString filename; | |||
| BridgeNonRtServerData* data; | |||
| shm_t shm; | |||
| BridgeNonRtServerControl() noexcept | |||
| : filename(), | |||
| data(nullptr) | |||
| #ifdef CARLA_PROPER_CPP11_SUPPORT | |||
| , shm(shm_t_INIT) {} | |||
| #else | |||
| { | |||
| shm = shm_t_INIT; | |||
| } | |||
| #endif | |||
| ~BridgeNonRtControl() noexcept override | |||
| ~BridgeNonRtServerControl() noexcept override | |||
| { | |||
| // should be cleared by now | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| @@ -275,7 +306,10 @@ struct BridgeNonRtControl : public CarlaRingBuffer<BigStackBuffer> { | |||
| filename.clear(); | |||
| if (! carla_is_shm_valid(shm)) | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| return; | |||
| } | |||
| if (data != nullptr) | |||
| { | |||
| @@ -284,13 +318,14 @@ struct BridgeNonRtControl : public CarlaRingBuffer<BigStackBuffer> { | |||
| } | |||
| carla_shm_close(shm); | |||
| carla_shm_init(shm); | |||
| } | |||
| bool mapData() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT(data == nullptr); | |||
| if (carla_shm_map<BridgeNonRtData>(shm, data)) | |||
| if (carla_shm_map<BridgeNonRtServerData>(shm, data)) | |||
| { | |||
| setRingBuffer(&data->ringBuffer, true); | |||
| return true; | |||
| @@ -309,12 +344,12 @@ struct BridgeNonRtControl : public CarlaRingBuffer<BigStackBuffer> { | |||
| setRingBuffer(nullptr, false); | |||
| } | |||
| void writeOpcode(const PluginBridgeNonRtOpcode opcode) noexcept | |||
| PluginBridgeNonRtClientOpcode readOpcode() noexcept | |||
| { | |||
| writeInt(static_cast<int32_t>(opcode)); | |||
| return static_cast<PluginBridgeNonRtClientOpcode>(readUInt()); | |||
| } | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeNonRtControl) | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeNonRtServerControl) | |||
| }; | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| @@ -349,9 +384,9 @@ public: | |||
| fLastPongCounter(-1), | |||
| fBridgeBinary(), | |||
| fShmAudioPool(), | |||
| fShmCVPool(), | |||
| fShmRtControl(), | |||
| fShmNonRtControl(), | |||
| fShmRtClientControl(), | |||
| fShmNonRtClientControl(), | |||
| fShmNonRtServerControl(), | |||
| fInfo(), | |||
| fParams(nullptr), | |||
| leakDetector_BridgePlugin() | |||
| @@ -361,6 +396,7 @@ public: | |||
| pData->hints |= PLUGIN_IS_BRIDGE; | |||
| } | |||
| #if 0 | |||
| ~BridgePlugin() override | |||
| { | |||
| carla_debug("BridgePlugin::~BridgePlugin()"); | |||
| @@ -410,6 +446,7 @@ public: | |||
| fInfo.chunk.clear(); | |||
| } | |||
| #endif | |||
| // ------------------------------------------------------------------- | |||
| // Information (base) | |||
| @@ -509,6 +546,7 @@ public: | |||
| std::strncpy(strBuf, fParams[parameterId].unit.buffer(), STR_MAX); | |||
| } | |||
| #if 0 | |||
| // ------------------------------------------------------------------- | |||
| // Set data (state) | |||
| @@ -750,6 +788,7 @@ public: | |||
| CarlaPlugin::idle(); | |||
| } | |||
| #endif | |||
| // ------------------------------------------------------------------- | |||
| // Plugin state | |||
| @@ -759,6 +798,7 @@ public: | |||
| CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr,); | |||
| carla_debug("BridgePlugin::reload() - start"); | |||
| #if 0 | |||
| const EngineProcessMode processMode(pData->engine->getProccessMode()); | |||
| // Safely disable plugin for reload | |||
| @@ -881,6 +921,7 @@ public: | |||
| bufferSizeChanged(pData->engine->getBufferSize()); | |||
| reloadPrograms(true); | |||
| #endif | |||
| carla_debug("BridgePlugin::reload() - end"); | |||
| } | |||
| @@ -891,16 +932,16 @@ public: | |||
| void activate() noexcept override | |||
| { | |||
| { | |||
| const CarlaMutexLocker _cml(fShmNonRtControl.mutex); | |||
| const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex); | |||
| fShmNonRtControl.writeOpcode(kPluginBridgeNonRtActivate); | |||
| fShmNonRtControl.commitWrite(); | |||
| fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientActivate); | |||
| fShmNonRtClientControl.commitWrite(); | |||
| } | |||
| bool timedOut = true; | |||
| try { | |||
| timedOut = waitForServer(1); | |||
| timedOut = waitForClient(1); | |||
| } catch(...) {} | |||
| if (! timedOut) | |||
| @@ -910,16 +951,16 @@ public: | |||
| void deactivate() noexcept override | |||
| { | |||
| { | |||
| const CarlaMutexLocker _cml(fShmNonRtControl.mutex); | |||
| const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex); | |||
| fShmNonRtControl.writeOpcode(kPluginBridgeNonRtDeactivate); | |||
| fShmNonRtControl.commitWrite(); | |||
| fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientDeactivate); | |||
| fShmNonRtClientControl.commitWrite(); | |||
| } | |||
| bool timedOut = true; | |||
| try { | |||
| timedOut = waitForServer(1); | |||
| timedOut = waitForClient(1); | |||
| } catch(...) {} | |||
| if (! timedOut) | |||
| @@ -951,6 +992,8 @@ public: | |||
| pData->needsReset = false; | |||
| } | |||
| (void)audioIn; (void)cvIn; | |||
| #if 0 | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Event Input | |||
| @@ -1168,8 +1211,10 @@ public: | |||
| } // End of Event Input | |||
| processSingle(audioIn, audioOut, cvIn, cvOut, frames); | |||
| #endif | |||
| } | |||
| #if 0 | |||
| bool processSingle(const float** const audioIn, float** const audioOut, const float** const cvIn, float** const cvOut, const uint32_t frames) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(frames > 0, false); | |||
| @@ -1977,7 +2022,7 @@ public: | |||
| { | |||
| char tmpFileBase[64]; | |||
| std::sprintf(tmpFileBase, "/carla-bridge_shm_rt_XXXXXX"); | |||
| std::sprintf(tmpFileBase, "/carla-bridge_shm_rtC_XXXXXX"); | |||
| fShmRtControl.shm = shm_mkstemp(tmpFileBase); | |||
| @@ -2031,7 +2076,7 @@ public: | |||
| { | |||
| char tmpFileBase[64]; | |||
| std::sprintf(tmpFileBase, "/carla-bridge_shm_nonrt_XXXXXX"); | |||
| std::sprintf(tmpFileBase, "/carla-bridge_shm_nonrtC_XXXXXX"); | |||
| fShmNonRtControl.shm = shm_mkstemp(tmpFileBase); | |||
| @@ -2134,6 +2179,7 @@ public: | |||
| return true; | |||
| } | |||
| #endif | |||
| private: | |||
| const BinaryType fBinaryType; | |||
| @@ -2149,10 +2195,10 @@ private: | |||
| CarlaString fBridgeBinary; | |||
| BridgeAudioPool fShmAudioPool; | |||
| BridgeAudioPool fShmCVPool; | |||
| BridgeRtControl fShmRtControl; | |||
| BridgeNonRtControl fShmNonRtControl; | |||
| BridgeAudioPool fShmAudioPool; | |||
| BridgeRtClientControl fShmRtClientControl; | |||
| BridgeNonRtClientControl fShmNonRtClientControl; | |||
| BridgeNonRtServerControl fShmNonRtServerControl; | |||
| struct Info { | |||
| uint32_t aIns, aOuts; | |||
| @@ -2188,27 +2234,23 @@ private: | |||
| void resizeAudioAndCVPool(const uint32_t bufferSize) | |||
| { | |||
| fShmAudioPool.resize(bufferSize, fInfo.aIns+fInfo.aOuts); | |||
| fShmCVPool.resize(bufferSize, fInfo.cvIns+fInfo.cvOuts); | |||
| fShmAudioPool.resize(bufferSize, fInfo.aIns+fInfo.aOuts, fInfo.cvIns+fInfo.cvOuts); | |||
| fShmRtControl.writeOpcode(kPluginBridgeRtSetAudioPool); | |||
| fShmRtControl.writeLong(static_cast<int64_t>(fShmAudioPool.size)); | |||
| fShmRtClientControl.writeOpcode(kPluginBridgeRtClientSetAudioPool); | |||
| fShmRtClientControl.writeULong(static_cast<uint64_t>(fShmAudioPool.size)); | |||
| fShmRtControl.writeOpcode(kPluginBridgeRtSetCVPool); | |||
| fShmRtControl.writeLong(static_cast<int64_t>(fShmCVPool.size)); | |||
| fShmRtClientControl.commitWrite(); | |||
| fShmRtControl.commitWrite(); | |||
| waitForServer(); | |||
| waitForClient(); | |||
| } | |||
| bool waitForServer(const uint secs = 5) | |||
| bool waitForClient(const uint secs = 5) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(! fTimedOut, false); | |||
| if (! fShmRtControl.waitForServer(secs)) | |||
| if (! fShmRtClientControl.waitForClient(secs)) | |||
| { | |||
| carla_stderr("waitForServer() timeout here"); | |||
| carla_stderr("waitForClient() timeout here"); | |||
| fTimedOut = true; | |||
| return false; | |||
| } | |||
| @@ -2218,7 +2260,6 @@ private: | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(BridgePlugin) | |||
| }; | |||
| #endif | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| @@ -2233,7 +2274,6 @@ CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, P | |||
| carla_debug("CarlaPlugin::newBridge({%p, \"%s\", \"%s\", \"%s\"}, %s, %s, \"%s\")", init.engine, init.filename, init.name, init.label, BinaryType2Str(btype), PluginType2Str(ptype), bridgeBinary); | |||
| #ifndef BUILD_BRIDGE | |||
| # if 0 | |||
| if (bridgeBinary == nullptr || bridgeBinary[0] == '\0') | |||
| { | |||
| init.engine->setLastError("Bridge not possible, bridge-binary not found"); | |||
| @@ -2242,6 +2282,7 @@ CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, P | |||
| BridgePlugin* const plugin(new BridgePlugin(init.engine, init.id, btype, ptype)); | |||
| # if 0 | |||
| if (! plugin->init(init.filename, init.name, init.label, bridgeBinary)) | |||
| { | |||
| init.engine->registerEnginePlugin(init.id, nullptr); | |||
| @@ -2252,6 +2293,9 @@ CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, P | |||
| plugin->reload(); | |||
| bool canRun = true; | |||
| # else | |||
| bool canRun = false; | |||
| # endif | |||
| if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) | |||
| { | |||
| @@ -2279,12 +2323,6 @@ CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, P | |||
| } | |||
| return plugin; | |||
| # else | |||
| init.engine->setLastError("Bridged plugins not working due to pending code rewrite."); | |||
| return nullptr; | |||
| // unused | |||
| (void)bridgeBinary; (void)btype; (void)ptype; | |||
| # endif | |||
| #else | |||
| init.engine->setLastError("Plugin bridge support not available"); | |||
| return nullptr; | |||
| @@ -169,7 +169,8 @@ static JUCEApplicationBase* juce_CreateApplication() { return new CarlaJuceApp() | |||
| class CarlaBridgePlugin | |||
| { | |||
| public: | |||
| CarlaBridgePlugin(const bool useBridge, const char* const clientName, const char* const audioPoolBaseName, const char* const rtBaseName, const char* const nonRtBaseName) | |||
| CarlaBridgePlugin(const bool useBridge, const char* const clientName, const char* const audioPoolBaseName, | |||
| const char* const rtClientBaseName, const char* const nonRtClientBaseName, const char* const nonRtServerBaseName) | |||
| : fEngine(nullptr), | |||
| fProjFilename(), | |||
| fOscControlData(), | |||
| @@ -178,12 +179,12 @@ public: | |||
| leakDetector_CarlaBridgePlugin() | |||
| { | |||
| CARLA_ASSERT(clientName != nullptr && clientName[0] != '\0'); | |||
| carla_debug("CarlaBridgePlugin::CarlaBridgePlugin(%s, \"%s\", %s, %s, %s)", bool2str(useBridge), clientName, audioPoolBaseName, rtBaseName, nonRtBaseName); | |||
| carla_debug("CarlaBridgePlugin::CarlaBridgePlugin(%s, \"%s\", %s, %s, %s, %s)", bool2str(useBridge), clientName, audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName); | |||
| carla_set_engine_callback(callback, this); | |||
| if (useBridge) | |||
| carla_engine_init_bridge(audioPoolBaseName, rtBaseName, nonRtBaseName, clientName); | |||
| carla_engine_init_bridge(audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName, clientName); | |||
| else | |||
| carla_engine_init("JACK", clientName); | |||
| @@ -420,25 +421,29 @@ int main(int argc, char* argv[]) | |||
| // --------------------------------------------------------------------- | |||
| // Setup bridge ids | |||
| char bridgeBaseAudioName[6+1]; | |||
| char bridgeBaseControlName[6+1]; | |||
| char bridgeBaseTimeName[6+1]; | |||
| char audioPoolBaseName[6+1]; | |||
| char rtClientBaseName[6+1]; | |||
| char nonRtClientBaseName[6+1]; | |||
| char nonRtServerBaseName[6+1]; | |||
| if (useBridge) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(std::strlen(shmIds) == 6*3, 1); | |||
| std::strncpy(bridgeBaseAudioName, shmIds, 6); | |||
| std::strncpy(bridgeBaseControlName, shmIds+6, 6); | |||
| std::strncpy(bridgeBaseTimeName, shmIds+12, 6); | |||
| bridgeBaseAudioName[6] = '\0'; | |||
| bridgeBaseControlName[6] = '\0'; | |||
| bridgeBaseTimeName[6] = '\0'; | |||
| CARLA_SAFE_ASSERT_RETURN(std::strlen(shmIds) == 6*4, 1); | |||
| std::strncpy(audioPoolBaseName, shmIds+6*0, 6); | |||
| std::strncpy(rtClientBaseName, shmIds+6*1, 6); | |||
| std::strncpy(nonRtClientBaseName, shmIds+6*2, 6); | |||
| std::strncpy(nonRtServerBaseName, shmIds+6*3, 6); | |||
| audioPoolBaseName[6] = '\0'; | |||
| rtClientBaseName[6] = '\0'; | |||
| nonRtClientBaseName[6] = '\0'; | |||
| nonRtServerBaseName[6] = '\0'; | |||
| } | |||
| else | |||
| { | |||
| bridgeBaseAudioName[0] = '\0'; | |||
| bridgeBaseControlName[0] = '\0'; | |||
| bridgeBaseTimeName[0] = '\0'; | |||
| audioPoolBaseName[0] = '\0'; | |||
| rtClientBaseName[0] = '\0'; | |||
| nonRtClientBaseName[0] = '\0'; | |||
| nonRtServerBaseName[0] = '\0'; | |||
| } | |||
| // --------------------------------------------------------------------- | |||
| @@ -466,7 +471,7 @@ int main(int argc, char* argv[]) | |||
| // --------------------------------------------------------------------- | |||
| // Init plugin bridge | |||
| CarlaBridgePlugin bridge(useBridge, clientName, bridgeBaseAudioName, bridgeBaseControlName, bridgeBaseTimeName); | |||
| CarlaBridgePlugin bridge(useBridge, clientName, audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName); | |||
| if (! bridge.isOk()) | |||
| { | |||
| @@ -125,14 +125,14 @@ struct BridgeTimeInfo { | |||
| // ----------------------------------------------------------------------- | |||
| static const std::size_t kBridgeRtDataMidiOutSize = 512*4; | |||
| static const std::size_t kBridgeRtClientDataMidiOutSize = 512*4; | |||
| // Server => Client RT | |||
| struct BridgeRtClientData { | |||
| BridgeSemaphore sem; | |||
| BridgeTimeInfo timeInfo; | |||
| SmallStackBuffer ringBuffer; | |||
| uint8_t midiOut[kBridgeRtDataMidiOutSize]; | |||
| uint8_t midiOut[kBridgeRtClientDataMidiOutSize]; | |||
| }; | |||
| // Server => Client Non-RT | |||
| @@ -22,12 +22,13 @@ | |||
| #ifdef CARLA_OS_WIN | |||
| struct shm_t { HANDLE shm; HANDLE map; }; | |||
| # define shm_t_INIT {nullptr, nullptr} | |||
| # define shm_t_INIT { nullptr, nullptr } | |||
| #else | |||
| # include <cerrno> | |||
| # include <fcntl.h> | |||
| # include <sys/mman.h> | |||
| struct shm_t { int fd; const char* filename; std::size_t size; }; | |||
| # define shm_t_INIT {-1, nullptr} | |||
| # define shm_t_INIT { -1, nullptr, 0 } | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| @@ -36,11 +37,7 @@ struct shm_t { int fd; const char* filename; std::size_t size; }; | |||
| /* | |||
| * Null object returned when a shared memory operation fails. | |||
| */ | |||
| #ifdef CARLA_OS_WIN | |||
| static const shm_t gNullCarlaShm = { nullptr, nullptr }; | |||
| #else | |||
| static const shm_t gNullCarlaShm = { -1, nullptr, 0 }; | |||
| #endif | |||
| static const shm_t gNullCarlaShm = shm_t_INIT; | |||
| /* | |||
| * Check if a shared memory object is valid. | |||
| @@ -61,14 +58,7 @@ bool carla_is_shm_valid(const shm_t& shm) noexcept | |||
| static inline | |||
| void carla_shm_init(shm_t& shm) noexcept | |||
| { | |||
| #ifdef CARLA_OS_WIN | |||
| shm.shm = nullptr; | |||
| shm.map = nullptr; | |||
| #else | |||
| shm.fd = -1; | |||
| shm.filename = nullptr; | |||
| shm.size = 0; | |||
| #endif | |||
| shm = gNullCarlaShm; | |||
| } | |||
| /* | |||
| @@ -246,6 +236,57 @@ void carla_shm_unmap(shm_t& shm, void* const ptr) noexcept | |||
| } CARLA_SAFE_EXCEPTION("carla_shm_unmap"); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // advanced calls | |||
| /* | |||
| * Create and open a new shared memory object for a XXXXXX temp filename. | |||
| * Will keep trying until a free random filename is obtained. | |||
| */ | |||
| static inline | |||
| shm_t carla_shm_create_temp(char* const fileBase) | |||
| { | |||
| // check if the fileBase name is valid | |||
| CARLA_SAFE_ASSERT_RETURN(fileBase != nullptr, gNullCarlaShm); | |||
| const std::size_t fileBaseLen(std::strlen(fileBase)); | |||
| CARLA_SAFE_ASSERT_RETURN(fileBaseLen > 6, gNullCarlaShm); | |||
| CARLA_SAFE_ASSERT_RETURN(std::strcmp(fileBase + fileBaseLen - 6, "XXXXXX") == 0, gNullCarlaShm); | |||
| // character set to use randomly | |||
| static const char charSet[] = "abcdefghijklmnopqrstuvwxyz" | |||
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |||
| "0123456789"; | |||
| static const int charSetLen = static_cast<int>(std::strlen(charSet) - 1); // -1 to avoid trailing '\0' | |||
| // try until getting a valid shm is obtained or an error occurs | |||
| for (;;) | |||
| { | |||
| // fill the XXXXXX characters randomly | |||
| for (std::size_t c = fileBaseLen - 6; c < fileBaseLen; ++c) | |||
| fileBase[c] = charSet[std::rand() % charSetLen]; | |||
| // (try to) create new shm for this filename | |||
| const shm_t shm = carla_shm_create(fileBase); | |||
| // all ok! | |||
| if (carla_is_shm_valid(shm)) | |||
| return shm; | |||
| // file already exists, keep trying | |||
| #ifdef CARLA_OS_WIN | |||
| // TODO | |||
| #else | |||
| if (errno == EEXIST) | |||
| continue; | |||
| #endif | |||
| // some unknown error occurred, return null | |||
| return gNullCarlaShm; | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // shared memory, templated calls | |||