| @@ -78,6 +78,7 @@ HEADERS += \ | |||
| ../../includes/CarlaDefines.hpp \ | |||
| ../../includes/CarlaMIDI.h \ | |||
| ../../utils/CarlaMutex.hpp \ | |||
| ../../utils/CarlaRingBuffer.hpp \ | |||
| ../../utils/CarlaString.hpp \ | |||
| ../../utils/CarlaThread.hpp \ | |||
| ../../utils/CarlaUtils.hpp \ | |||
| @@ -37,6 +37,111 @@ CARLA_BACKEND_START_NAMESPACE | |||
| // ------------------------------------------------------------------- | |||
| struct BridgeAudioPool { | |||
| CarlaString filename; | |||
| float* data; | |||
| shm_t shm; | |||
| BridgeAudioPool() | |||
| : data(nullptr) | |||
| { | |||
| carla_shm_init(shm); | |||
| } | |||
| ~BridgeAudioPool() | |||
| { | |||
| // should be cleared by now | |||
| CARLA_ASSERT(data == nullptr); | |||
| clear(); | |||
| } | |||
| bool attach() | |||
| { | |||
| #ifdef CARLA_OS_WIN | |||
| // TESTING! | |||
| shm = carla_shm_attach_linux((const char*)filename); | |||
| #else | |||
| shm = carla_shm_attach((const char*)filename); | |||
| #endif | |||
| return carla_is_shm_valid(shm); | |||
| } | |||
| void clear() | |||
| { | |||
| filename.clear(); | |||
| data = nullptr; | |||
| if (carla_is_shm_valid(shm)) | |||
| carla_shm_close(shm); | |||
| } | |||
| }; | |||
| struct BridgeControl : public RingBufferControl { | |||
| CarlaString filename; | |||
| BridgeShmControl* data; | |||
| shm_t shm; | |||
| BridgeControl() | |||
| : RingBufferControl(nullptr), | |||
| data(nullptr) | |||
| { | |||
| carla_shm_init(shm); | |||
| } | |||
| ~BridgeControl() | |||
| { | |||
| // should be cleared by now | |||
| CARLA_ASSERT(data == nullptr); | |||
| clear(); | |||
| } | |||
| bool attach() | |||
| { | |||
| #ifdef CARLA_OS_WIN | |||
| // TESTING! | |||
| shm = carla_shm_attach_linux((const char*)filename); | |||
| #else | |||
| shm = carla_shm_attach((const char*)filename); | |||
| #endif | |||
| return carla_is_shm_valid(shm); | |||
| } | |||
| void clear() | |||
| { | |||
| filename.clear(); | |||
| data = nullptr; | |||
| if (carla_is_shm_valid(shm)) | |||
| carla_shm_close(shm); | |||
| } | |||
| bool mapData() | |||
| { | |||
| CARLA_ASSERT(data == nullptr); | |||
| if (carla_shm_map<BridgeShmControl>(shm, data)) | |||
| { | |||
| setRingBuffer(&data->ringBuffer, false); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| PluginBridgeOpcode readOpcode() | |||
| { | |||
| return static_cast<PluginBridgeOpcode>(readInt()); | |||
| } | |||
| }; | |||
| // ------------------------------------------------------------------- | |||
| class CarlaEngineBridge : public CarlaEngine, | |||
| public QThread | |||
| { | |||
| @@ -69,16 +174,8 @@ public: | |||
| // SHM Audio Pool | |||
| { | |||
| #ifdef CARLA_OS_WIN | |||
| // TESTING! | |||
| fShmAudioPool.shm = carla_shm_attach_linux((const char*)fShmAudioPool.filename); | |||
| #else | |||
| fShmAudioPool.shm = carla_shm_attach((const char*)fShmAudioPool.filename); | |||
| #endif | |||
| if (! carla_is_shm_valid(fShmAudioPool.shm)) | |||
| if (! fShmAudioPool.attach()) | |||
| { | |||
| _cleanup(); | |||
| carla_stdout("Failed to open or create shared memory file #1"); | |||
| return false; | |||
| } | |||
| @@ -86,24 +183,20 @@ public: | |||
| // SHM Control | |||
| { | |||
| #ifdef CARLA_OS_WIN | |||
| // TESTING! | |||
| fShmControl.shm = carla_shm_attach_linux((const char*)fShmControl.filename); | |||
| #else | |||
| fShmControl.shm = carla_shm_attach((const char*)fShmControl.filename); | |||
| #endif | |||
| if (! carla_is_shm_valid(fShmControl.shm)) | |||
| if (! fShmControl.attach()) | |||
| { | |||
| _cleanup(); | |||
| carla_stdout("Failed to open or create shared memory file #2"); | |||
| // clear | |||
| fShmAudioPool.clear(); | |||
| return false; | |||
| } | |||
| if (! carla_shm_map<BridgeShmControl>(fShmControl.shm, fShmControl.data)) | |||
| if (! fShmControl.mapData()) | |||
| { | |||
| _cleanup(); | |||
| carla_stdout("Failed to mmap shared memory file"); | |||
| // clear | |||
| fShmControl.clear(); | |||
| fShmAudioPool.clear(); | |||
| return false; | |||
| } | |||
| } | |||
| @@ -111,14 +204,14 @@ public: | |||
| // Read values from memory | |||
| PluginBridgeOpcode opcode; | |||
| opcode = rdwr_readOpcode(&fShmControl.data->ringBuffer); | |||
| CARLA_ASSERT(opcode == kPluginBridgeOpcodeSetBufferSize); | |||
| fBufferSize = rdwr_readInt(&fShmControl.data->ringBuffer); | |||
| opcode = fShmControl.readOpcode(); | |||
| CARLA_ASSERT_INT(opcode == kPluginBridgeOpcodeSetBufferSize, opcode); | |||
| fBufferSize = fShmControl.readInt(); | |||
| carla_stderr("BufferSize: %i", fBufferSize); | |||
| opcode = rdwr_readOpcode(&fShmControl.data->ringBuffer); | |||
| CARLA_ASSERT(opcode == kPluginBridgeOpcodeSetSampleRate); | |||
| fSampleRate = rdwr_readFloat(&fShmControl.data->ringBuffer); | |||
| opcode = fShmControl.readOpcode(); | |||
| CARLA_ASSERT_INT(opcode == kPluginBridgeOpcodeSetSampleRate, opcode); | |||
| fSampleRate = fShmControl.readFloat(); | |||
| carla_stderr("SampleRate: %f", fSampleRate); | |||
| fQuitNow = false; | |||
| @@ -137,7 +230,8 @@ public: | |||
| fQuitNow = true; | |||
| QThread::wait(); | |||
| _cleanup(); | |||
| fShmControl.clear(); | |||
| fShmAudioPool.clear(); | |||
| return true; | |||
| } | |||
| @@ -163,21 +257,29 @@ public: | |||
| void run() | |||
| { | |||
| // TODO - set RT permissions | |||
| carla_debug("CarlaEngineBridge::run()"); | |||
| while (! fQuitNow) | |||
| { | |||
| carla_debug("CarlaEngineBridge::run() - try wait"); | |||
| if (! jackbridge_sem_timedwait(&fShmControl.data->runServer, 5)) | |||
| { | |||
| if (errno != ETIMEDOUT) | |||
| continue; | |||
| fQuitNow = true; | |||
| return; | |||
| if (errno == ETIMEDOUT) | |||
| { | |||
| fIsRunning = false; | |||
| fQuitNow = true; | |||
| return; | |||
| } | |||
| } | |||
| while (rdwr_dataAvailable(&fShmControl.data->ringBuffer)) | |||
| carla_debug("CarlaEngineBridge::run() - connected"); | |||
| while (fShmControl.dataAvailable()) | |||
| { | |||
| const PluginBridgeOpcode opcode(rdwr_readOpcode(&fShmControl.data->ringBuffer)); | |||
| const PluginBridgeOpcode opcode(fShmControl.readOpcode()); | |||
| carla_debug("CarlaEngineBridge::run() - got opcode: %s", PluginBridgeOpcode2str(opcode)); | |||
| switch (opcode) | |||
| { | |||
| @@ -186,29 +288,29 @@ public: | |||
| case kPluginBridgeOpcodeSetAudioPool: | |||
| { | |||
| const int poolSize(rdwr_readInt(&fShmControl.data->ringBuffer)); | |||
| const long poolSize(fShmControl.readLong()); | |||
| fShmAudioPool.data = (float*)carla_shm_map(fShmAudioPool.shm, poolSize); | |||
| break; | |||
| } | |||
| case kPluginBridgeOpcodeSetBufferSize: | |||
| { | |||
| const int bufferSize(rdwr_readInt(&fShmControl.data->ringBuffer)); | |||
| const int bufferSize(fShmControl.readInt()); | |||
| bufferSizeChanged(bufferSize); | |||
| break; | |||
| } | |||
| case kPluginBridgeOpcodeSetSampleRate: | |||
| { | |||
| const float sampleRate(rdwr_readFloat(&fShmControl.data->ringBuffer)); | |||
| const float sampleRate(fShmControl.readFloat()); | |||
| sampleRateChanged(sampleRate); | |||
| break; | |||
| } | |||
| case kPluginBridgeOpcodeSetParameter: | |||
| { | |||
| const int index(rdwr_readInt(&fShmControl.data->ringBuffer)); | |||
| const float value(rdwr_readFloat(&fShmControl.data->ringBuffer)); | |||
| const int index(fShmControl.readInt()); | |||
| const float value(fShmControl.readFloat()); | |||
| CarlaPlugin* const plugin(getPluginUnchecked(0)); | |||
| @@ -223,7 +325,7 @@ public: | |||
| case kPluginBridgeOpcodeSetProgram: | |||
| { | |||
| const int index(rdwr_readInt(&fShmControl.data->ringBuffer)); | |||
| const int index(fShmControl.readInt()); | |||
| CarlaPlugin* const plugin(getPluginUnchecked(0)); | |||
| @@ -238,7 +340,7 @@ public: | |||
| case kPluginBridgeOpcodeSetMidiProgram: | |||
| { | |||
| const int index(rdwr_readInt(&fShmControl.data->ringBuffer)); | |||
| const int index(fShmControl.readInt()); | |||
| CarlaPlugin* const plugin(getPluginUnchecked(0)); | |||
| @@ -254,13 +356,13 @@ public: | |||
| case kPluginBridgeOpcodeMidiEvent: | |||
| { | |||
| uint8_t data[4] = { 0 }; | |||
| const long time(rdwr_readLong(&fShmControl.data->ringBuffer)); | |||
| const int dataSize(rdwr_readInt(&fShmControl.data->ringBuffer)); | |||
| const long time(fShmControl.readLong()); | |||
| const int dataSize(fShmControl.readInt()); | |||
| CARLA_ASSERT_INT(dataSize >= 1 && dataSize <= 4, dataSize); | |||
| for (int i=0; i < dataSize && i < 4; ++i) | |||
| data[i] = rdwr_readChar(&fShmControl.data->ringBuffer); | |||
| data[i] = fShmControl.readChar(); | |||
| CARLA_ASSERT(kData->bufEvents.in != nullptr); | |||
| @@ -311,52 +413,12 @@ public: | |||
| } | |||
| private: | |||
| struct BridgeAudioPool { | |||
| CarlaString filename; | |||
| float* data; | |||
| shm_t shm; | |||
| BridgeAudioPool() | |||
| : data(nullptr) | |||
| { | |||
| carla_shm_init(shm); | |||
| } | |||
| } fShmAudioPool; | |||
| struct BridgeControl { | |||
| CarlaString filename; | |||
| BridgeShmControl* data; | |||
| shm_t shm; | |||
| BridgeControl() | |||
| : data(nullptr) | |||
| { | |||
| carla_shm_init(shm); | |||
| } | |||
| } fShmControl; | |||
| BridgeAudioPool fShmAudioPool; | |||
| BridgeControl fShmControl; | |||
| bool fIsRunning; | |||
| bool fQuitNow; | |||
| void _cleanup() | |||
| { | |||
| if (fShmAudioPool.filename.isNotEmpty()) | |||
| fShmAudioPool.filename.clear(); | |||
| if (fShmControl.filename.isNotEmpty()) | |||
| fShmControl.filename.clear(); | |||
| fShmAudioPool.data = nullptr; | |||
| fShmControl.data = nullptr; | |||
| if (carla_is_shm_valid(fShmAudioPool.shm)) | |||
| carla_shm_close(fShmAudioPool.shm); | |||
| if (carla_is_shm_valid(fShmControl.shm)) | |||
| carla_shm_close(fShmControl.shm); | |||
| } | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineBridge) | |||
| }; | |||
| @@ -2231,6 +2231,7 @@ private: | |||
| CarlaEngine* CarlaEngine::newJack() | |||
| { | |||
| carla_debug("CarlaEngine::newJack()"); | |||
| return new CarlaEngineJack(); | |||
| } | |||
| @@ -29,6 +29,7 @@ | |||
| #define DISTRHO_PLUGIN_WANT_LATENCY 0 | |||
| #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | |||
| #define DISTRHO_PLUGIN_WANT_STATE 1 | |||
| #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | |||
| #define DISTRHO_PLUGIN_URI "http://kxstudio.sf.net/carla" | |||
| @@ -71,26 +71,26 @@ shm_t shm_mkstemp(char* const fileBase) | |||
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |||
| "0123456789"; | |||
| const int size = (fileBase != nullptr) ? std::strlen(fileBase) : 0; | |||
| const size_t fileBaseLen((fileBase != nullptr) ? std::strlen(fileBase) : 0); | |||
| shm_t shm; | |||
| carla_shm_init(shm); | |||
| shm_t fakeShm; | |||
| carla_shm_init(fakeShm); | |||
| if (size < 6) | |||
| if (fileBaseLen < 6) | |||
| { | |||
| errno = EINVAL; | |||
| return shm; | |||
| return fakeShm; | |||
| } | |||
| if (std::strcmp(fileBase + size - 6, "XXXXXX") != 0) | |||
| if (std::strcmp(fileBase + fileBaseLen - 6, "XXXXXX") != 0) | |||
| { | |||
| errno = EINVAL; | |||
| return shm; | |||
| return fakeShm; | |||
| } | |||
| while (true) | |||
| for (;;) | |||
| { | |||
| for (int c = size - 6; c < size; ++c) | |||
| for (size_t c = fileBaseLen - 6; c < fileBaseLen; ++c) | |||
| { | |||
| // Note the -1 to avoid the trailing '\0' in charSet. | |||
| fileBase[c] = charSet[std::rand() % (sizeof(charSet) - 1)]; | |||
| @@ -105,6 +105,139 @@ shm_t shm_mkstemp(char* const fileBase) | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| struct BridgeAudioPool { | |||
| CarlaString filename; | |||
| float* data; | |||
| size_t size; | |||
| shm_t shm; | |||
| BridgeAudioPool() | |||
| : data(nullptr), | |||
| size(0) | |||
| { | |||
| carla_shm_init(shm); | |||
| } | |||
| ~BridgeAudioPool() | |||
| { | |||
| // should be cleared by now | |||
| CARLA_ASSERT(data == nullptr); | |||
| clear(); | |||
| } | |||
| void clear() | |||
| { | |||
| filename.clear(); | |||
| if (! carla_is_shm_valid(shm)) | |||
| return; | |||
| if (data != nullptr) | |||
| { | |||
| carla_shm_unmap(shm, data, size); | |||
| data = nullptr; | |||
| } | |||
| size = 0; | |||
| carla_shm_close(shm); | |||
| } | |||
| void resize(const uint32_t bufferSize, const uint32_t portCount) | |||
| { | |||
| if (data != nullptr) | |||
| carla_shm_unmap(shm, data, size); | |||
| size = portCount*bufferSize*sizeof(float); | |||
| if (size == 0) | |||
| size = sizeof(float); | |||
| data = (float*)carla_shm_map(shm, size); | |||
| } | |||
| }; | |||
| struct BridgeControl : public RingBufferControl { | |||
| CarlaString filename; | |||
| BridgeShmControl* data; | |||
| shm_t shm; | |||
| BridgeControl() | |||
| : RingBufferControl(nullptr), | |||
| data(nullptr) | |||
| { | |||
| carla_shm_init(shm); | |||
| } | |||
| ~BridgeControl() | |||
| { | |||
| // should be cleared by now | |||
| CARLA_ASSERT(data == nullptr); | |||
| clear(); | |||
| } | |||
| void clear() | |||
| { | |||
| filename.clear(); | |||
| if (! carla_is_shm_valid(shm)) | |||
| return; | |||
| if (data != nullptr) | |||
| { | |||
| carla_shm_unmap(shm, data, sizeof(BridgeShmControl)); | |||
| data = nullptr; | |||
| } | |||
| carla_shm_close(shm); | |||
| } | |||
| bool mapData() | |||
| { | |||
| CARLA_ASSERT(data == nullptr); | |||
| if (carla_shm_map<BridgeShmControl>(shm, data)) | |||
| { | |||
| setRingBuffer(&data->ringBuffer, true); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| void unmapData() | |||
| { | |||
| CARLA_ASSERT(data != nullptr); | |||
| if (data == nullptr) | |||
| return; | |||
| carla_shm_unmap(shm, data, sizeof(BridgeShmControl)); | |||
| data = nullptr; | |||
| setRingBuffer(nullptr, false); | |||
| } | |||
| bool waitForServer() | |||
| { | |||
| CARLA_ASSERT(data != nullptr); | |||
| if (data == nullptr) | |||
| return false; | |||
| jackbridge_sem_post(&data->runServer); | |||
| return jackbridge_sem_timedwait(&data->runClient, 5); | |||
| } | |||
| void writeOpcode(const PluginBridgeOpcode opcode) | |||
| { | |||
| writeInt(static_cast<int>(opcode)); | |||
| } | |||
| }; | |||
| struct BridgeParamInfo { | |||
| float value; | |||
| CarlaString name; | |||
| @@ -116,6 +249,8 @@ struct BridgeParamInfo { | |||
| CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(BridgeParamInfo) | |||
| }; | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| class BridgePlugin : public CarlaPlugin | |||
| { | |||
| public: | |||
| @@ -126,6 +261,7 @@ public: | |||
| fInitiated(false), | |||
| fInitError(false), | |||
| fSaved(false), | |||
| fNeedsSemDestroy(false), | |||
| fParams(nullptr) | |||
| { | |||
| carla_debug("BridgePlugin::BridgePlugin(%p, %i, %s, %s)", engine, id, BinaryType2Str(btype), PluginType2Str(ptype)); | |||
| @@ -153,9 +289,9 @@ public: | |||
| if (kData->osc.thread.isRunning()) | |||
| { | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeQuit); | |||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
| waitForServer(); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeQuit); | |||
| fShmControl.commitWrite(); | |||
| fShmControl.waitForServer(); | |||
| } | |||
| if (kData->osc.data.target != nullptr) | |||
| @@ -173,7 +309,15 @@ public: | |||
| kData->osc.thread.terminate(); | |||
| } | |||
| cleanup(); | |||
| if (fNeedsSemDestroy) | |||
| { | |||
| jackbridge_sem_destroy(&fShmControl.data->runServer); | |||
| jackbridge_sem_destroy(&fShmControl.data->runClient); | |||
| } | |||
| fShmAudioPool.clear(); | |||
| fShmControl.clear(); | |||
| clearBuffers(); | |||
| //info.chunk.clear(); | |||
| @@ -336,13 +480,13 @@ public: | |||
| if (doLock) | |||
| kData->singleMutex.lock(); | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetParameter); | |||
| rdwr_writeInt(&fShmControl.data->ringBuffer, parameterId); | |||
| rdwr_writeFloat(&fShmControl.data->ringBuffer, value); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeSetParameter); | |||
| fShmControl.writeInt(parameterId); | |||
| fShmControl.writeFloat(value); | |||
| if (doLock) | |||
| { | |||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
| fShmControl.commitWrite(); | |||
| kData->singleMutex.unlock(); | |||
| } | |||
| @@ -363,12 +507,12 @@ public: | |||
| if (doLock) | |||
| kData->singleMutex.lock(); | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetProgram); | |||
| rdwr_writeInt(&fShmControl.data->ringBuffer, index); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeSetProgram); | |||
| fShmControl.writeInt(index); | |||
| if (doLock) | |||
| { | |||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
| fShmControl.commitWrite(); | |||
| kData->singleMutex.unlock(); | |||
| } | |||
| @@ -389,12 +533,12 @@ public: | |||
| if (doLock) | |||
| kData->singleMutex.lock(); | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetMidiProgram); | |||
| rdwr_writeInt(&fShmControl.data->ringBuffer, index); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeSetMidiProgram); | |||
| fShmControl.writeInt(index); | |||
| if (doLock) | |||
| { | |||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
| fShmControl.commitWrite(); | |||
| kData->singleMutex.unlock(); | |||
| } | |||
| @@ -597,20 +741,20 @@ public: | |||
| void activate() override | |||
| { | |||
| // already locked before | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetParameter); | |||
| rdwr_writeInt(&fShmControl.data->ringBuffer, PARAMETER_ACTIVE); | |||
| rdwr_writeFloat(&fShmControl.data->ringBuffer, 1.0f); | |||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeSetParameter); | |||
| fShmControl.writeInt(PARAMETER_ACTIVE); | |||
| fShmControl.writeFloat(1.0f); | |||
| fShmControl.commitWrite(); | |||
| waitForServer(); | |||
| } | |||
| void deactivate() override | |||
| { | |||
| // already locked before | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetParameter); | |||
| rdwr_writeInt(&fShmControl.data->ringBuffer, PARAMETER_ACTIVE); | |||
| rdwr_writeFloat(&fShmControl.data->ringBuffer, 0.0f); | |||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeSetParameter); | |||
| fShmControl.writeInt(PARAMETER_ACTIVE); | |||
| fShmControl.writeFloat(0.0f); | |||
| fShmControl.commitWrite(); | |||
| waitForServer(); | |||
| } | |||
| @@ -662,12 +806,12 @@ public: | |||
| data2 = note.note; | |||
| data3 = note.velo; | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeMidiEvent); | |||
| rdwr_writeLong(&fShmControl.data->ringBuffer, 0); | |||
| rdwr_writeInt(&fShmControl.data->ringBuffer, 3); | |||
| rdwr_writeChar(&fShmControl.data->ringBuffer, data1); | |||
| rdwr_writeChar(&fShmControl.data->ringBuffer, data2); | |||
| rdwr_writeChar(&fShmControl.data->ringBuffer, data3); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeMidiEvent); | |||
| fShmControl.writeLong(0); | |||
| fShmControl.writeInt(3); | |||
| fShmControl.writeChar(data1); | |||
| fShmControl.writeChar(data2); | |||
| fShmControl.writeChar(data3); | |||
| } | |||
| kData->extNotes.mutex.unlock(); | |||
| @@ -785,12 +929,12 @@ public: | |||
| if ((fOptions & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param <= 0x5F) | |||
| { | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeMidiEvent); | |||
| rdwr_writeLong(&fShmControl.data->ringBuffer, event.time); | |||
| rdwr_writeInt(&fShmControl.data->ringBuffer, 3); | |||
| rdwr_writeChar(&fShmControl.data->ringBuffer, MIDI_STATUS_CONTROL_CHANGE + event.channel); | |||
| rdwr_writeChar(&fShmControl.data->ringBuffer, ctrlEvent.param); | |||
| rdwr_writeChar(&fShmControl.data->ringBuffer, ctrlEvent.value*127.0f); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeMidiEvent); | |||
| fShmControl.writeLong(event.time); | |||
| fShmControl.writeInt(3); | |||
| fShmControl.writeChar(MIDI_STATUS_CONTROL_CHANGE + event.channel); | |||
| fShmControl.writeChar(ctrlEvent.param); | |||
| fShmControl.writeChar(ctrlEvent.value*127.0f); | |||
| } | |||
| break; | |||
| @@ -874,12 +1018,12 @@ public: | |||
| data[2] = midiEvent.data[2]; | |||
| data[3] = midiEvent.data[3]; | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeMidiEvent); | |||
| rdwr_writeLong(&fShmControl.data->ringBuffer, event.time); | |||
| rdwr_writeInt(&fShmControl.data->ringBuffer, midiEvent.size); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeMidiEvent); | |||
| fShmControl.writeLong(event.time); | |||
| fShmControl.writeInt(midiEvent.size); | |||
| for (uint8_t j=0; j < midiEvent.size && j < 4; ++j) | |||
| rdwr_writeChar(&fShmControl.data->ringBuffer, data[j]); | |||
| fShmControl.writeChar(data[j]); | |||
| if (status == MIDI_STATUS_NOTE_ON) | |||
| postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]); | |||
| @@ -944,8 +1088,8 @@ public: | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Run plugin | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeProcess); | |||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeProcess); | |||
| fShmControl.commitWrite(); | |||
| if (! waitForServer()) | |||
| { | |||
| @@ -1030,17 +1174,17 @@ public: | |||
| { | |||
| resizeAudioPool(newBufferSize); | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetBufferSize); | |||
| rdwr_writeInt(&fShmControl.data->ringBuffer, newBufferSize); | |||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeSetBufferSize); | |||
| fShmControl.writeInt(newBufferSize); | |||
| fShmControl.commitWrite(); | |||
| } | |||
| void sampleRateChanged(const double newSampleRate) override | |||
| { | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetSampleRate); | |||
| rdwr_writeFloat(&fShmControl.data->ringBuffer, newSampleRate); | |||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeSetSampleRate); | |||
| fShmControl.writeFloat(newSampleRate); | |||
| fShmControl.commitWrite(); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| @@ -1569,7 +1713,6 @@ public: | |||
| if (! carla_is_shm_valid(fShmAudioPool.shm)) | |||
| { | |||
| //_cleanup(); | |||
| carla_stdout("Failed to open or create shared memory file #1"); | |||
| return false; | |||
| } | |||
| @@ -1588,48 +1731,57 @@ public: | |||
| if (! carla_is_shm_valid(fShmControl.shm)) | |||
| { | |||
| //_cleanup(); | |||
| carla_stdout("Failed to open or create shared memory file #2"); | |||
| // clear | |||
| carla_shm_close(fShmAudioPool.shm); | |||
| return false; | |||
| } | |||
| fShmControl.filename = tmpFileBase; | |||
| if (! carla_shm_map<BridgeShmControl>(fShmControl.shm, fShmControl.data)) | |||
| if (! fShmControl.mapData()) | |||
| { | |||
| //_cleanup(); | |||
| carla_stdout("Failed to mmap shared memory file"); | |||
| // clear | |||
| carla_shm_close(fShmControl.shm); | |||
| carla_shm_close(fShmAudioPool.shm); | |||
| return false; | |||
| } | |||
| CARLA_ASSERT(fShmControl.data != nullptr); | |||
| std::memset(fShmControl.data, 0, sizeof(BridgeShmControl)); | |||
| std::strcpy(fShmControl.data->ringBuffer.buf, "This thing is actually working!!!!"); | |||
| if (sem_init(&fShmControl.data->runServer, 1, 0) != 0) | |||
| if (! jackbridge_sem_init(&fShmControl.data->runServer)) | |||
| { | |||
| //_cleanup(); | |||
| carla_stdout("Failed to initialize shared memory semaphore #1"); | |||
| // clear | |||
| fShmControl.unmapData(); | |||
| carla_shm_close(fShmControl.shm); | |||
| carla_shm_close(fShmAudioPool.shm); | |||
| return false; | |||
| } | |||
| if (sem_init(&fShmControl.data->runClient, 1, 0) != 0) | |||
| if (! jackbridge_sem_init(&fShmControl.data->runClient)) | |||
| { | |||
| //_cleanup(); | |||
| carla_stdout("Failed to initialize shared memory semaphore #2"); | |||
| // clear | |||
| jackbridge_sem_destroy(&fShmControl.data->runServer); | |||
| fShmControl.unmapData(); | |||
| carla_shm_close(fShmControl.shm); | |||
| carla_shm_close(fShmAudioPool.shm); | |||
| return false; | |||
| } | |||
| fNeedsSemDestroy = true; | |||
| } | |||
| // initial values | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetBufferSize); | |||
| rdwr_writeInt(&fShmControl.data->ringBuffer, kData->engine->getBufferSize()); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeSetBufferSize); | |||
| fShmControl.writeInt(kData->engine->getBufferSize()); | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetSampleRate); | |||
| rdwr_writeFloat(&fShmControl.data->ringBuffer, kData->engine->getSampleRate()); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeSetSampleRate); | |||
| fShmControl.writeFloat(kData->engine->getSampleRate()); | |||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
| fShmControl.commitWrite(); | |||
| // register plugin now so we can receive OSC (and wait for it) | |||
| fHints |= PLUGIN_IS_BRIDGE; | |||
| @@ -1689,35 +1841,12 @@ private: | |||
| bool fInitiated; | |||
| bool fInitError; | |||
| bool fSaved; | |||
| bool fNeedsSemDestroy; | |||
| CarlaString fBridgeBinary; | |||
| struct BridgeAudioPool { | |||
| CarlaString filename; | |||
| float* data; | |||
| size_t size; | |||
| shm_t shm; | |||
| BridgeAudioPool() | |||
| : data(nullptr), | |||
| size(0) | |||
| { | |||
| carla_shm_init(shm); | |||
| } | |||
| } fShmAudioPool; | |||
| struct BridgeControl { | |||
| CarlaString filename; | |||
| BridgeShmControl* data; | |||
| shm_t shm; | |||
| BridgeControl() | |||
| : data(nullptr) | |||
| { | |||
| carla_shm_init(shm); | |||
| } | |||
| } fShmControl; | |||
| BridgeAudioPool fShmAudioPool; | |||
| BridgeControl fShmControl; | |||
| struct Info { | |||
| uint32_t aIns, aOuts; | |||
| @@ -1741,59 +1870,20 @@ private: | |||
| BridgeParamInfo* fParams; | |||
| void cleanup() | |||
| void resizeAudioPool(const uint32_t bufferSize) | |||
| { | |||
| if (fShmAudioPool.filename.isNotEmpty()) | |||
| fShmAudioPool.filename.clear(); | |||
| fShmAudioPool.resize(bufferSize, fInfo.aIns+fInfo.aOuts); | |||
| if (fShmControl.filename.isNotEmpty()) | |||
| fShmControl.filename.clear(); | |||
| if (fShmAudioPool.data != nullptr) | |||
| { | |||
| carla_shm_unmap(fShmAudioPool.shm, fShmAudioPool.data, fShmAudioPool.size); | |||
| fShmAudioPool.data = nullptr; | |||
| } | |||
| fShmAudioPool.size = 0; | |||
| if (fShmControl.data != nullptr) | |||
| { | |||
| carla_shm_unmap(fShmControl.shm, fShmControl.data, sizeof(BridgeShmControl)); | |||
| fShmControl.data = nullptr; | |||
| } | |||
| if (carla_is_shm_valid(fShmAudioPool.shm)) | |||
| carla_shm_close(fShmAudioPool.shm); | |||
| if (carla_is_shm_valid(fShmControl.shm)) | |||
| carla_shm_close(fShmControl.shm); | |||
| } | |||
| void resizeAudioPool(uint32_t bufferSize) | |||
| { | |||
| if (fShmAudioPool.data != nullptr) | |||
| carla_shm_unmap(fShmAudioPool.shm, fShmAudioPool.data, fShmAudioPool.size); | |||
| fShmAudioPool.size = (fInfo.aIns+fInfo.aOuts)*bufferSize*sizeof(float); | |||
| if (fShmAudioPool.size == 0) | |||
| fShmAudioPool.size = sizeof(float); | |||
| fShmAudioPool.data = (float*)carla_shm_map(fShmAudioPool.shm, fShmAudioPool.size); | |||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetAudioPool); | |||
| rdwr_writeInt(&fShmControl.data->ringBuffer, fShmAudioPool.size); | |||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||
| fShmControl.writeOpcode(kPluginBridgeOpcodeSetAudioPool); | |||
| fShmControl.writeLong(fShmAudioPool.size); | |||
| fShmControl.commitWrite(); | |||
| waitForServer(); | |||
| } | |||
| bool waitForServer() | |||
| { | |||
| sem_post(&fShmControl.data->runServer); | |||
| if (! jackbridge_sem_timedwait(&fShmControl.data->runClient, 5)) | |||
| if (! fShmControl.waitForServer()) | |||
| { | |||
| carla_stderr("waitForServer() timeout"); | |||
| kData->active = false; // TODO | |||
| @@ -1854,18 +1944,23 @@ CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, P | |||
| // ------------------------------------------------------------------- | |||
| // Bridge Helper | |||
| #define bridgePlugin ((BridgePlugin*)plugin) | |||
| int CarlaPluginSetOscBridgeInfo(CarlaPlugin* const plugin, const PluginBridgeInfoType type, | |||
| const int argc, const lo_arg* const* const argv, const char* const types) | |||
| { | |||
| CARLA_ASSERT(plugin != nullptr && (plugin->hints() & PLUGIN_IS_BRIDGE) != 0); | |||
| return ((BridgePlugin*)plugin)->setOscPluginBridgeInfo(type, argc, argv, types); | |||
| return bridgePlugin->setOscPluginBridgeInfo(type, argc, argv, types); | |||
| } | |||
| BinaryType CarlaPluginGetBridgeBinaryType(CarlaPlugin* const plugin) | |||
| { | |||
| CARLA_ASSERT(plugin != nullptr && (plugin->hints() & PLUGIN_IS_BRIDGE) != 0); | |||
| return ((BridgePlugin*)plugin)->binaryType(); | |||
| return bridgePlugin->binaryType(); | |||
| } | |||
| #undef bridgePlugin | |||
| #endif | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| @@ -68,11 +68,13 @@ HEADERS += \ | |||
| HEADERS += \ | |||
| ../../utils/CarlaUtils.hpp \ | |||
| ../../utils/CarlaBridgeUtils.hpp \ | |||
| ../../utils/CarlaJuceUtils.hpp \ | |||
| ../../utils/CarlaLibUtils.hpp \ | |||
| ../../utils/CarlaOscUtils.hpp \ | |||
| ../../utils/CarlaStateUtils.hpp \ | |||
| ../../utils/CarlaMutex.hpp \ | |||
| ../../utils/CarlaRingBuffer.hpp \ | |||
| ../../utils/CarlaString.hpp | |||
| INCLUDEPATH = . .. \ | |||
| @@ -33,7 +33,7 @@ public: | |||
| virtual ~ExternalUI() override; | |||
| protected: | |||
| const char* d_externalFilename() const = 0; | |||
| virtual const char* d_externalFilename() const = 0; | |||
| private: | |||
| friend class UIInternal; | |||
| @@ -211,7 +211,7 @@ protected: | |||
| void setParameterValue(uint32_t index, float realValue) | |||
| { | |||
| const ParameterRanges& ranges(kPlugin->parameterRanges(index)); | |||
| const float perValue(ranges.normalizeValue(realValue)); | |||
| const float perValue(ranges.normalizedValue(realValue)); | |||
| kPlugin->setParameterValue(index, realValue); | |||
| hostCallback(audioMasterAutomate, index, 0, nullptr, perValue); | |||
| @@ -472,13 +472,13 @@ public: | |||
| float vst_getParameter(int32_t index) | |||
| { | |||
| const ParameterRanges& ranges(fPlugin.parameterRanges(index)); | |||
| return ranges.normalizeValue(fPlugin.parameterValue(index)); | |||
| return ranges.normalizedValue(fPlugin.parameterValue(index)); | |||
| } | |||
| void vst_setParameter(int32_t index, float value) | |||
| { | |||
| const ParameterRanges& ranges(fPlugin.parameterRanges(index)); | |||
| const float realValue(ranges.unnormalizeValue(value)); | |||
| const float realValue(ranges.unnormalizedValue(value)); | |||
| fPlugin.setParameterValue(index, realValue); | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| @@ -335,6 +335,8 @@ CARLA_EXPORT bool jackbridge_custom_unpublish_data(jack_client_t* client, const | |||
| CARLA_EXPORT bool jackbridge_custom_set_data_appearance_callback(jack_client_t* client, JackCustomDataAppearanceCallback callback, void* arg); | |||
| CARLA_EXPORT const char** jackbridge_custom_get_keys(jack_client_t* client, const char* client_name); | |||
| CARLA_EXPORT bool jackbridge_sem_init(void* sem); | |||
| CARLA_EXPORT bool jackbridge_sem_destroy(void* sem); | |||
| CARLA_EXPORT bool jackbridge_sem_post(void* sem); | |||
| CARLA_EXPORT bool jackbridge_sem_timedwait(void* sem, int secs); | |||
| @@ -18,6 +18,8 @@ | |||
| #ifndef __JACKBRIDGE_HPP__ | |||
| // don't include the whole JACK API in this file | |||
| CARLA_EXPORT bool jackbridge_sem_init(void* sem); | |||
| CARLA_EXPORT bool jackbridge_sem_destroy(void* sem); | |||
| CARLA_EXPORT bool jackbridge_sem_post(void* sem); | |||
| CARLA_EXPORT bool jackbridge_sem_timedwait(void* sem, int secs); | |||
| #endif | |||
| @@ -25,6 +27,16 @@ CARLA_EXPORT bool jackbridge_sem_timedwait(void* sem, int secs); | |||
| // ----------------------------------------------------------------------------- | |||
| #if JACKBRIDGE_DUMMY | |||
| bool jackbridge_sem_init(void*) | |||
| { | |||
| return false; | |||
| } | |||
| bool jackbridge_sem_destroy(void*) | |||
| { | |||
| return false; | |||
| } | |||
| bool jackbridge_sem_post(void*) | |||
| { | |||
| return false; | |||
| @@ -38,15 +50,15 @@ bool jackbridge_sem_timedwait(void*, int) | |||
| #include <semaphore.h> | |||
| #ifdef __WINE__ | |||
| # define _STRUCT_TIMEVAL 1 | |||
| # define _SYS_SELECT_H 1 | |||
| # include <bits/types.h> | |||
| struct timespec { | |||
| __time_t tv_sec; /* Seconds. */ | |||
| long int tv_nsec; /* Nanoseconds. */ | |||
| }; | |||
| #endif | |||
| //#ifdef __WINE__ | |||
| //# define _STRUCT_TIMEVAL 1 | |||
| //# define _SYS_SELECT_H 1 | |||
| //# include <bits/types.h> | |||
| //struct timespec { | |||
| // __time_t tv_sec; /* Seconds. */ | |||
| // long int tv_nsec; /* Nanoseconds. */ | |||
| //}; | |||
| //#endif | |||
| #ifdef CARLA_OS_WIN | |||
| # include <sys/time.h> | |||
| @@ -54,6 +66,16 @@ struct timespec { | |||
| # include <time.h> | |||
| #endif | |||
| bool jackbridge_sem_init(void* sem) | |||
| { | |||
| return (sem_init((sem_t*)sem, 1, 0) == 0); | |||
| } | |||
| bool jackbridge_sem_destroy(void* sem) | |||
| { | |||
| return (sem_destroy((sem_t*)sem) == 0); | |||
| } | |||
| bool jackbridge_sem_post(void* sem) | |||
| { | |||
| return (sem_post((sem_t*)sem) == 0); | |||
| @@ -29,11 +29,13 @@ WINE_32BIT_FLAGS = $(32BIT_FLAGS) -L/usr/lib32/wine -L/usr/lib/i386-linux-gnu/wi | |||
| WINE_64BIT_FLAGS = $(64BIT_FLAGS) -L/usr/lib64/wine -L/usr/lib/x86_64-linux-gnu/wine | |||
| WINE_LINK_FLAGS = $(LINK_FLAGS) -ldl -lrt -lpthread -ljack | |||
| OBJS = JackBridge1.cpp JackBridge2.cpp | |||
| OBJS = JackBridge1.cpp JackBridge2.cpp | |||
| OBJSw32 = JackBridge1.w32.o JackBridge2.w32.o | |||
| OBJSw64 = JackBridge1.w64.o JackBridge2.w64.o | |||
| # -------------------------------------------------------------- | |||
| all: test | |||
| all: | |||
| win32: ../jackbridge-win32.dll | |||
| win64: ../jackbridge-win64.dll | |||
| @@ -42,8 +44,13 @@ wine64: ../jackbridge-win64.dll.so | |||
| # -------------------------------------------------------------- | |||
| test: $(OBJS) | |||
| $(CXX) $^ $(WINE_BUILD_FLAGS) $(WINE_LINK_FLAGS) -o $@ | |||
| JackBridge%.w32.o: JackBridge%.cpp | |||
| $(CXX) $^ $(WINE_BUILD_FLAGS) $(WINE_32BIT_FLAGS) -c -o $@ | |||
| JackBridge%.w64.o: JackBridge%.cpp | |||
| $(CXX) $^ $(WINE_BUILD_FLAGS) $(WINE_64BIT_FLAGS) -c -o $@ | |||
| # -------------------------------------------------------------- | |||
| ../jackbridge-win32.dll: $(OBJS) | |||
| $(CXX) $^ $(WIN_BUILD_FLAGS) $(WIN_32BIT_FLAGS) $(WIN_LINK_FLAGS) -Wl,--output-def,$@.def,--out-implib,$@.a -o $@ $(CMD_STRIP) $@ | |||
| @@ -51,10 +58,10 @@ test: $(OBJS) | |||
| ../jackbridge-win64.dll: $(OBJS) | |||
| $(CXX) $^ $(WIN_BUILD_FLAGS) $(WIN_64BIT_FLAGS) $(WIN_LINK_FLAGS) -Wl,--output-def,$@.def,--out-implib,$@.a -o $@ $(CMD_STRIP) $@ | |||
| ../jackbridge-win32.dll.so: $(OBJS) ../jackbridge-win32.dll.def | |||
| $(WINECXX) $^ $(WINE_BUILD_FLAGS) $(WINE_32BIT_FLAGS) $(WINE_LINK_FLAGS) -mno-cygwin -o $@ $(CMD_STRIP) $@ | |||
| ../jackbridge-win32.dll.so: JackBridge1.cpp JackBridge2.cpp ../jackbridge-win32.dll.def | |||
| $(WINECXX) $^ $(WIN_BUILD_FLAGS) $(WINE_32BIT_FLAGS) $(WINE_LINK_FLAGS) -mno-cygwin -o $@ $(CMD_STRIP) $@ | |||
| ../jackbridge-win64.dll.so: $(OBJS) ../jackbridge-win64.dll.def | |||
| $(WINECXX) $^ $(WINE_BUILD_FLAGS) $(WINE_64BIT_FLAGS) $(WINE_LINK_FLAGS) -mno-cygwin -o $@ $(CMD_STRIP) $@ | |||
| ../jackbridge-win64.dll.so: JackBridge1.cpp JackBridge2.cpp ../jackbridge-win64.dll.def | |||
| $(WINECXX) $^ $(WIN_BUILD_FLAGS) $(WINE_64BIT_FLAGS) $(WINE_LINK_FLAGS) -mno-cygwin -o $@ $(CMD_STRIP) $@ | |||
| # -------------------------------------------------------------- | |||
| @@ -19,16 +19,12 @@ | |||
| #ifndef __CARLA_BRIDGE_UTILS_HPP__ | |||
| #define __CARLA_BRIDGE_UTILS_HPP__ | |||
| #include "CarlaUtils.hpp" | |||
| #include "CarlaRingBuffer.hpp" | |||
| #include <semaphore.h> | |||
| #define BRIDGE_SHM_RING_BUFFER_SIZE 2048 | |||
| // --------------------------------------------------------------------------------------------- | |||
| // ------------------------------------------------- | |||
| enum PluginBridgeInfoType { | |||
| kPluginBridgeAudioCount, | |||
| kPluginBridgeAudioCount = 0, | |||
| kPluginBridgeMidiCount, | |||
| kPluginBridgeParameterCount, | |||
| kPluginBridgeProgramCount, | |||
| @@ -52,7 +48,7 @@ enum PluginBridgeInfoType { | |||
| enum PluginBridgeOpcode { | |||
| kPluginBridgeOpcodeNull = 0, | |||
| kPluginBridgeOpcodeSetAudioPool = 1, // int | |||
| kPluginBridgeOpcodeSetAudioPool = 1, // long | |||
| kPluginBridgeOpcodeSetBufferSize = 2, // int | |||
| kPluginBridgeOpcodeSetSampleRate = 3, // float | |||
| kPluginBridgeOpcodeSetParameter = 4, // int, float | |||
| @@ -72,29 +68,25 @@ const char* const CARLA_BRIDGE_MSG_SET_CUSTOM = "CarlaBridgeSetCustom"; //!< Hos | |||
| //If \a type is 'chunk' or 'binary' \a rvalue refers to chunk file. | |||
| #endif | |||
| // --------------------------------------------------------------------------------------------- | |||
| struct BridgeRingBuffer { | |||
| int head, tail, written; | |||
| bool invalidateCommit; | |||
| char buf[BRIDGE_SHM_RING_BUFFER_SIZE]; | |||
| }; | |||
| // ------------------------------------------------- | |||
| struct BridgeShmControl { | |||
| // 32 and 64-bit binaries align semaphores differently. | |||
| // Let's make sure there's plenty of room for either one. | |||
| union { | |||
| sem_t runServer; | |||
| void* runServer; | |||
| char _alignServer[128]; | |||
| }; | |||
| union { | |||
| sem_t runClient; | |||
| void* runClient; | |||
| char _alignClient[128]; | |||
| }; | |||
| BridgeRingBuffer ringBuffer; | |||
| RingBuffer ringBuffer; | |||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeShmControl) | |||
| }; | |||
| // --------------------------------------------------------------------------------------------- | |||
| // ------------------------------------------------- | |||
| static inline | |||
| const char* PluginBridgeInfoType2str(const PluginBridgeInfoType type) | |||
| @@ -147,183 +139,37 @@ const char* PluginBridgeInfoType2str(const PluginBridgeInfoType type) | |||
| return nullptr; | |||
| } | |||
| // --------------------------------------------------------------------------------------------- | |||
| static inline | |||
| void rdwr_tryRead(BridgeRingBuffer* const ringbuf, void* const buf, const size_t size) | |||
| const char* PluginBridgeOpcode2str(const PluginBridgeOpcode opcode) | |||
| { | |||
| CARLA_ASSERT(buf != nullptr); | |||
| if (buf == nullptr) | |||
| return; | |||
| char* const charbuf(static_cast<char*>(buf)); | |||
| size_t tail = ringbuf->tail; | |||
| size_t head = ringbuf->head; | |||
| size_t wrap = 0; | |||
| if (head <= tail) { | |||
| wrap = BRIDGE_SHM_RING_BUFFER_SIZE; | |||
| } | |||
| if (head - tail + wrap < size) { | |||
| return; | |||
| } | |||
| size_t readto = tail + size; | |||
| if (readto >= BRIDGE_SHM_RING_BUFFER_SIZE) | |||
| { | |||
| readto -= BRIDGE_SHM_RING_BUFFER_SIZE; | |||
| size_t firstpart = BRIDGE_SHM_RING_BUFFER_SIZE - tail; | |||
| std::memcpy(charbuf, ringbuf->buf + tail, firstpart); | |||
| std::memcpy(charbuf + firstpart, ringbuf->buf, readto); | |||
| } | |||
| else | |||
| switch (opcode) | |||
| { | |||
| std::memcpy(charbuf, ringbuf->buf + tail, size); | |||
| case kPluginBridgeOpcodeNull: | |||
| return "kPluginBridgeOpcodeNull"; | |||
| case kPluginBridgeOpcodeSetAudioPool: | |||
| return "kPluginBridgeOpcodeSetAudioPool"; | |||
| case kPluginBridgeOpcodeSetBufferSize: | |||
| return "kPluginBridgeOpcodeSetBufferSize"; | |||
| case kPluginBridgeOpcodeSetSampleRate: | |||
| return "kPluginBridgeOpcodeSetSampleRate"; | |||
| case kPluginBridgeOpcodeSetParameter: | |||
| return "kPluginBridgeOpcodeSetParameter"; | |||
| case kPluginBridgeOpcodeSetProgram: | |||
| return "kPluginBridgeOpcodeSetProgram"; | |||
| case kPluginBridgeOpcodeSetMidiProgram: | |||
| return "kPluginBridgeOpcodeSetMidiProgram"; | |||
| case kPluginBridgeOpcodeMidiEvent: | |||
| return "kPluginBridgeOpcodeMidiEvent"; | |||
| case kPluginBridgeOpcodeProcess: | |||
| return "kPluginBridgeOpcodeProcess"; | |||
| case kPluginBridgeOpcodeQuit: | |||
| return "kPluginBridgeOpcodeQuit"; | |||
| } | |||
| ringbuf->tail = readto; | |||
| } | |||
| static inline | |||
| void rdwr_tryWrite(BridgeRingBuffer* const ringbuf, const void* const buf, const size_t size) | |||
| { | |||
| CARLA_ASSERT(buf != nullptr); | |||
| if (buf == nullptr) | |||
| return; | |||
| const char* const charbuf(static_cast<const char*>(buf)); | |||
| size_t written = ringbuf->written; | |||
| size_t tail = ringbuf->tail; | |||
| size_t wrap = 0; | |||
| if (tail <= written) | |||
| { | |||
| wrap = BRIDGE_SHM_RING_BUFFER_SIZE; | |||
| } | |||
| if (tail - written + wrap < size) | |||
| { | |||
| carla_stderr2("Ring buffer full! Dropping events."); | |||
| ringbuf->invalidateCommit = true; | |||
| return; | |||
| } | |||
| size_t writeto = written + size; | |||
| if (writeto >= BRIDGE_SHM_RING_BUFFER_SIZE) | |||
| { | |||
| writeto -= BRIDGE_SHM_RING_BUFFER_SIZE; | |||
| size_t firstpart = BRIDGE_SHM_RING_BUFFER_SIZE - written; | |||
| std::memcpy(ringbuf->buf + written, charbuf, firstpart); | |||
| std::memcpy(ringbuf->buf, charbuf + firstpart, writeto); | |||
| } | |||
| else | |||
| { | |||
| std::memcpy(ringbuf->buf + written, charbuf, size); | |||
| } | |||
| ringbuf->written = writeto; | |||
| } | |||
| static inline | |||
| void rdwr_commitWrite(BridgeRingBuffer* const ringbuf) | |||
| { | |||
| if (ringbuf->invalidateCommit) | |||
| { | |||
| ringbuf->written = ringbuf->head; | |||
| ringbuf->invalidateCommit = false; | |||
| } | |||
| else | |||
| { | |||
| ringbuf->head = ringbuf->written; | |||
| } | |||
| } | |||
| // --------------------------------------------------------------------------------------------- | |||
| static inline | |||
| bool rdwr_dataAvailable(BridgeRingBuffer* const ringbuf) | |||
| { | |||
| return (ringbuf->tail != ringbuf->head); | |||
| } | |||
| static inline | |||
| PluginBridgeOpcode rdwr_readOpcode(BridgeRingBuffer* const ringbuf) | |||
| { | |||
| int i = static_cast<int>(kPluginBridgeOpcodeNull); | |||
| rdwr_tryRead(ringbuf, &i, sizeof(int)); | |||
| return static_cast<PluginBridgeOpcode>(i); | |||
| } | |||
| static inline | |||
| char rdwr_readChar(BridgeRingBuffer* const ringbuf) | |||
| { | |||
| char c = 0; | |||
| rdwr_tryRead(ringbuf, &c, sizeof(char)); | |||
| return c; | |||
| } | |||
| static inline | |||
| int rdwr_readInt(BridgeRingBuffer* const ringbuf) | |||
| { | |||
| int i = 0; | |||
| rdwr_tryRead(ringbuf, &i, sizeof(int)); | |||
| return i; | |||
| } | |||
| static inline | |||
| long rdwr_readLong(BridgeRingBuffer* const ringbuf) | |||
| { | |||
| long l = 0; | |||
| rdwr_tryRead(ringbuf, &l, sizeof(long)); | |||
| return l; | |||
| } | |||
| static inline | |||
| float rdwr_readFloat(BridgeRingBuffer* const ringbuf) | |||
| { | |||
| float f = 0.0f; | |||
| rdwr_tryRead(ringbuf, &f, sizeof(float)); | |||
| return f; | |||
| } | |||
| // --------------------------------------------------------------------------------------------- | |||
| static inline | |||
| void rdwr_writeOpcode(BridgeRingBuffer* const ringbuf, const PluginBridgeOpcode opcode) | |||
| { | |||
| const int intcode(static_cast<int>(opcode)); | |||
| rdwr_tryWrite(ringbuf, &intcode, sizeof(int)); | |||
| } | |||
| static inline | |||
| void rdwr_writeChar(BridgeRingBuffer* const ringbuf, const char value) | |||
| { | |||
| rdwr_tryWrite(ringbuf, &value, sizeof(char)); | |||
| } | |||
| static inline | |||
| void rdwr_writeInt(BridgeRingBuffer* const ringbuf, const int value) | |||
| { | |||
| rdwr_tryWrite(ringbuf, &value, sizeof(int)); | |||
| } | |||
| static inline | |||
| void rdwr_writeLong(BridgeRingBuffer* const ringbuf, const long value) | |||
| { | |||
| rdwr_tryWrite(ringbuf, &value, sizeof(long)); | |||
| } | |||
| static inline | |||
| void rdwr_writeFloat(BridgeRingBuffer* const ringbuf, const float value) | |||
| { | |||
| rdwr_tryWrite(ringbuf, &value, sizeof(float)); | |||
| carla_stderr("CarlaBackend::PluginBridgeOpcode2str(%i) - invalid opcode", opcode); | |||
| return nullptr; | |||
| } | |||
| // --------------------------------------------------------------------------------------------- | |||
| // ------------------------------------------------- | |||
| #endif // __CARLA_BRIDGE_UTILS_HPP__ | |||