| @@ -78,6 +78,7 @@ HEADERS += \ | |||||
| ../../includes/CarlaDefines.hpp \ | ../../includes/CarlaDefines.hpp \ | ||||
| ../../includes/CarlaMIDI.h \ | ../../includes/CarlaMIDI.h \ | ||||
| ../../utils/CarlaMutex.hpp \ | ../../utils/CarlaMutex.hpp \ | ||||
| ../../utils/CarlaRingBuffer.hpp \ | |||||
| ../../utils/CarlaString.hpp \ | ../../utils/CarlaString.hpp \ | ||||
| ../../utils/CarlaThread.hpp \ | ../../utils/CarlaThread.hpp \ | ||||
| ../../utils/CarlaUtils.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, | class CarlaEngineBridge : public CarlaEngine, | ||||
| public QThread | public QThread | ||||
| { | { | ||||
| @@ -69,16 +174,8 @@ public: | |||||
| // SHM Audio Pool | // SHM Audio Pool | ||||
| { | { | ||||
| #ifdef CARLA_OS_WIN | |||||
| // TESTING! | |||||
| fShmAudioPool.shm = carla_shm_attach_linux((const char*)fShmAudioPool.filename); | |||||
| #else | |||||
| fShmAudioPool.shm = carla_shm_attach((const char*)fShmAudioPool.filename); | |||||
| #endif | |||||
| if (! carla_is_shm_valid(fShmAudioPool.shm)) | |||||
| if (! fShmAudioPool.attach()) | |||||
| { | { | ||||
| _cleanup(); | |||||
| carla_stdout("Failed to open or create shared memory file #1"); | carla_stdout("Failed to open or create shared memory file #1"); | ||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -86,24 +183,20 @@ public: | |||||
| // SHM Control | // SHM Control | ||||
| { | { | ||||
| #ifdef CARLA_OS_WIN | |||||
| // TESTING! | |||||
| fShmControl.shm = carla_shm_attach_linux((const char*)fShmControl.filename); | |||||
| #else | |||||
| fShmControl.shm = carla_shm_attach((const char*)fShmControl.filename); | |||||
| #endif | |||||
| if (! carla_is_shm_valid(fShmControl.shm)) | |||||
| if (! fShmControl.attach()) | |||||
| { | { | ||||
| _cleanup(); | |||||
| carla_stdout("Failed to open or create shared memory file #2"); | carla_stdout("Failed to open or create shared memory file #2"); | ||||
| // clear | |||||
| fShmAudioPool.clear(); | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (! carla_shm_map<BridgeShmControl>(fShmControl.shm, fShmControl.data)) | |||||
| if (! fShmControl.mapData()) | |||||
| { | { | ||||
| _cleanup(); | |||||
| carla_stdout("Failed to mmap shared memory file"); | carla_stdout("Failed to mmap shared memory file"); | ||||
| // clear | |||||
| fShmControl.clear(); | |||||
| fShmAudioPool.clear(); | |||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| @@ -111,14 +204,14 @@ public: | |||||
| // Read values from memory | // Read values from memory | ||||
| PluginBridgeOpcode opcode; | 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); | 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); | carla_stderr("SampleRate: %f", fSampleRate); | ||||
| fQuitNow = false; | fQuitNow = false; | ||||
| @@ -137,7 +230,8 @@ public: | |||||
| fQuitNow = true; | fQuitNow = true; | ||||
| QThread::wait(); | QThread::wait(); | ||||
| _cleanup(); | |||||
| fShmControl.clear(); | |||||
| fShmAudioPool.clear(); | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -163,21 +257,29 @@ public: | |||||
| void run() | void run() | ||||
| { | { | ||||
| // TODO - set RT permissions | // TODO - set RT permissions | ||||
| carla_debug("CarlaEngineBridge::run()"); | |||||
| while (! fQuitNow) | while (! fQuitNow) | ||||
| { | { | ||||
| carla_debug("CarlaEngineBridge::run() - try wait"); | |||||
| if (! jackbridge_sem_timedwait(&fShmControl.data->runServer, 5)) | 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) | switch (opcode) | ||||
| { | { | ||||
| @@ -186,29 +288,29 @@ public: | |||||
| case kPluginBridgeOpcodeSetAudioPool: | case kPluginBridgeOpcodeSetAudioPool: | ||||
| { | { | ||||
| const int poolSize(rdwr_readInt(&fShmControl.data->ringBuffer)); | |||||
| const long poolSize(fShmControl.readLong()); | |||||
| fShmAudioPool.data = (float*)carla_shm_map(fShmAudioPool.shm, poolSize); | fShmAudioPool.data = (float*)carla_shm_map(fShmAudioPool.shm, poolSize); | ||||
| break; | break; | ||||
| } | } | ||||
| case kPluginBridgeOpcodeSetBufferSize: | case kPluginBridgeOpcodeSetBufferSize: | ||||
| { | { | ||||
| const int bufferSize(rdwr_readInt(&fShmControl.data->ringBuffer)); | |||||
| const int bufferSize(fShmControl.readInt()); | |||||
| bufferSizeChanged(bufferSize); | bufferSizeChanged(bufferSize); | ||||
| break; | break; | ||||
| } | } | ||||
| case kPluginBridgeOpcodeSetSampleRate: | case kPluginBridgeOpcodeSetSampleRate: | ||||
| { | { | ||||
| const float sampleRate(rdwr_readFloat(&fShmControl.data->ringBuffer)); | |||||
| const float sampleRate(fShmControl.readFloat()); | |||||
| sampleRateChanged(sampleRate); | sampleRateChanged(sampleRate); | ||||
| break; | break; | ||||
| } | } | ||||
| case kPluginBridgeOpcodeSetParameter: | 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)); | CarlaPlugin* const plugin(getPluginUnchecked(0)); | ||||
| @@ -223,7 +325,7 @@ public: | |||||
| case kPluginBridgeOpcodeSetProgram: | case kPluginBridgeOpcodeSetProgram: | ||||
| { | { | ||||
| const int index(rdwr_readInt(&fShmControl.data->ringBuffer)); | |||||
| const int index(fShmControl.readInt()); | |||||
| CarlaPlugin* const plugin(getPluginUnchecked(0)); | CarlaPlugin* const plugin(getPluginUnchecked(0)); | ||||
| @@ -238,7 +340,7 @@ public: | |||||
| case kPluginBridgeOpcodeSetMidiProgram: | case kPluginBridgeOpcodeSetMidiProgram: | ||||
| { | { | ||||
| const int index(rdwr_readInt(&fShmControl.data->ringBuffer)); | |||||
| const int index(fShmControl.readInt()); | |||||
| CarlaPlugin* const plugin(getPluginUnchecked(0)); | CarlaPlugin* const plugin(getPluginUnchecked(0)); | ||||
| @@ -254,13 +356,13 @@ public: | |||||
| case kPluginBridgeOpcodeMidiEvent: | case kPluginBridgeOpcodeMidiEvent: | ||||
| { | { | ||||
| uint8_t data[4] = { 0 }; | 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); | CARLA_ASSERT_INT(dataSize >= 1 && dataSize <= 4, dataSize); | ||||
| for (int i=0; i < dataSize && i < 4; ++i) | 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); | CARLA_ASSERT(kData->bufEvents.in != nullptr); | ||||
| @@ -311,52 +413,12 @@ public: | |||||
| } | } | ||||
| private: | 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 fIsRunning; | ||||
| bool fQuitNow; | 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) | CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineBridge) | ||||
| }; | }; | ||||
| @@ -2231,6 +2231,7 @@ private: | |||||
| CarlaEngine* CarlaEngine::newJack() | CarlaEngine* CarlaEngine::newJack() | ||||
| { | { | ||||
| carla_debug("CarlaEngine::newJack()"); | |||||
| return new CarlaEngineJack(); | return new CarlaEngineJack(); | ||||
| } | } | ||||
| @@ -29,6 +29,7 @@ | |||||
| #define DISTRHO_PLUGIN_WANT_LATENCY 0 | #define DISTRHO_PLUGIN_WANT_LATENCY 0 | ||||
| #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | ||||
| #define DISTRHO_PLUGIN_WANT_STATE 1 | #define DISTRHO_PLUGIN_WANT_STATE 1 | ||||
| #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | |||||
| #define DISTRHO_PLUGIN_URI "http://kxstudio.sf.net/carla" | #define DISTRHO_PLUGIN_URI "http://kxstudio.sf.net/carla" | ||||
| @@ -71,26 +71,26 @@ shm_t shm_mkstemp(char* const fileBase) | |||||
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | ||||
| "0123456789"; | "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; | errno = EINVAL; | ||||
| return shm; | |||||
| return fakeShm; | |||||
| } | } | ||||
| if (std::strcmp(fileBase + size - 6, "XXXXXX") != 0) | |||||
| if (std::strcmp(fileBase + fileBaseLen - 6, "XXXXXX") != 0) | |||||
| { | { | ||||
| errno = EINVAL; | 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. | // Note the -1 to avoid the trailing '\0' in charSet. | ||||
| fileBase[c] = charSet[std::rand() % (sizeof(charSet) - 1)]; | 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 { | struct BridgeParamInfo { | ||||
| float value; | float value; | ||||
| CarlaString name; | CarlaString name; | ||||
| @@ -116,6 +249,8 @@ struct BridgeParamInfo { | |||||
| CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(BridgeParamInfo) | CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(BridgeParamInfo) | ||||
| }; | }; | ||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| class BridgePlugin : public CarlaPlugin | class BridgePlugin : public CarlaPlugin | ||||
| { | { | ||||
| public: | public: | ||||
| @@ -126,6 +261,7 @@ public: | |||||
| fInitiated(false), | fInitiated(false), | ||||
| fInitError(false), | fInitError(false), | ||||
| fSaved(false), | fSaved(false), | ||||
| fNeedsSemDestroy(false), | |||||
| fParams(nullptr) | fParams(nullptr) | ||||
| { | { | ||||
| carla_debug("BridgePlugin::BridgePlugin(%p, %i, %s, %s)", engine, id, BinaryType2Str(btype), PluginType2Str(ptype)); | carla_debug("BridgePlugin::BridgePlugin(%p, %i, %s, %s)", engine, id, BinaryType2Str(btype), PluginType2Str(ptype)); | ||||
| @@ -153,9 +289,9 @@ public: | |||||
| if (kData->osc.thread.isRunning()) | 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) | if (kData->osc.data.target != nullptr) | ||||
| @@ -173,7 +309,15 @@ public: | |||||
| kData->osc.thread.terminate(); | kData->osc.thread.terminate(); | ||||
| } | } | ||||
| cleanup(); | |||||
| if (fNeedsSemDestroy) | |||||
| { | |||||
| jackbridge_sem_destroy(&fShmControl.data->runServer); | |||||
| jackbridge_sem_destroy(&fShmControl.data->runClient); | |||||
| } | |||||
| fShmAudioPool.clear(); | |||||
| fShmControl.clear(); | |||||
| clearBuffers(); | clearBuffers(); | ||||
| //info.chunk.clear(); | //info.chunk.clear(); | ||||
| @@ -336,13 +480,13 @@ public: | |||||
| if (doLock) | if (doLock) | ||||
| kData->singleMutex.lock(); | 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) | if (doLock) | ||||
| { | { | ||||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||||
| fShmControl.commitWrite(); | |||||
| kData->singleMutex.unlock(); | kData->singleMutex.unlock(); | ||||
| } | } | ||||
| @@ -363,12 +507,12 @@ public: | |||||
| if (doLock) | if (doLock) | ||||
| kData->singleMutex.lock(); | kData->singleMutex.lock(); | ||||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetProgram); | |||||
| rdwr_writeInt(&fShmControl.data->ringBuffer, index); | |||||
| fShmControl.writeOpcode(kPluginBridgeOpcodeSetProgram); | |||||
| fShmControl.writeInt(index); | |||||
| if (doLock) | if (doLock) | ||||
| { | { | ||||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||||
| fShmControl.commitWrite(); | |||||
| kData->singleMutex.unlock(); | kData->singleMutex.unlock(); | ||||
| } | } | ||||
| @@ -389,12 +533,12 @@ public: | |||||
| if (doLock) | if (doLock) | ||||
| kData->singleMutex.lock(); | kData->singleMutex.lock(); | ||||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetMidiProgram); | |||||
| rdwr_writeInt(&fShmControl.data->ringBuffer, index); | |||||
| fShmControl.writeOpcode(kPluginBridgeOpcodeSetMidiProgram); | |||||
| fShmControl.writeInt(index); | |||||
| if (doLock) | if (doLock) | ||||
| { | { | ||||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||||
| fShmControl.commitWrite(); | |||||
| kData->singleMutex.unlock(); | kData->singleMutex.unlock(); | ||||
| } | } | ||||
| @@ -597,20 +741,20 @@ public: | |||||
| void activate() override | void activate() override | ||||
| { | { | ||||
| // already locked before | // 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(); | waitForServer(); | ||||
| } | } | ||||
| void deactivate() override | void deactivate() override | ||||
| { | { | ||||
| // already locked before | // 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(); | waitForServer(); | ||||
| } | } | ||||
| @@ -662,12 +806,12 @@ public: | |||||
| data2 = note.note; | data2 = note.note; | ||||
| data3 = note.velo; | 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(); | kData->extNotes.mutex.unlock(); | ||||
| @@ -785,12 +929,12 @@ public: | |||||
| if ((fOptions & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param <= 0x5F) | 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; | break; | ||||
| @@ -874,12 +1018,12 @@ public: | |||||
| data[2] = midiEvent.data[2]; | data[2] = midiEvent.data[2]; | ||||
| data[3] = midiEvent.data[3]; | 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) | 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) | if (status == MIDI_STATUS_NOTE_ON) | ||||
| postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]); | postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]); | ||||
| @@ -944,8 +1088,8 @@ public: | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Run plugin | // Run plugin | ||||
| rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeProcess); | |||||
| rdwr_commitWrite(&fShmControl.data->ringBuffer); | |||||
| fShmControl.writeOpcode(kPluginBridgeOpcodeProcess); | |||||
| fShmControl.commitWrite(); | |||||
| if (! waitForServer()) | if (! waitForServer()) | ||||
| { | { | ||||
| @@ -1030,17 +1174,17 @@ public: | |||||
| { | { | ||||
| resizeAudioPool(newBufferSize); | 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 | 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)) | if (! carla_is_shm_valid(fShmAudioPool.shm)) | ||||
| { | { | ||||
| //_cleanup(); | |||||
| carla_stdout("Failed to open or create shared memory file #1"); | carla_stdout("Failed to open or create shared memory file #1"); | ||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -1588,48 +1731,57 @@ public: | |||||
| if (! carla_is_shm_valid(fShmControl.shm)) | if (! carla_is_shm_valid(fShmControl.shm)) | ||||
| { | { | ||||
| //_cleanup(); | |||||
| carla_stdout("Failed to open or create shared memory file #2"); | carla_stdout("Failed to open or create shared memory file #2"); | ||||
| // clear | |||||
| carla_shm_close(fShmAudioPool.shm); | |||||
| return false; | return false; | ||||
| } | } | ||||
| fShmControl.filename = tmpFileBase; | fShmControl.filename = tmpFileBase; | ||||
| if (! carla_shm_map<BridgeShmControl>(fShmControl.shm, fShmControl.data)) | |||||
| if (! fShmControl.mapData()) | |||||
| { | { | ||||
| //_cleanup(); | |||||
| carla_stdout("Failed to mmap shared memory file"); | carla_stdout("Failed to mmap shared memory file"); | ||||
| // clear | |||||
| carla_shm_close(fShmControl.shm); | |||||
| carla_shm_close(fShmAudioPool.shm); | |||||
| return false; | return false; | ||||
| } | } | ||||
| CARLA_ASSERT(fShmControl.data != nullptr); | 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"); | carla_stdout("Failed to initialize shared memory semaphore #1"); | ||||
| // clear | |||||
| fShmControl.unmapData(); | |||||
| carla_shm_close(fShmControl.shm); | |||||
| carla_shm_close(fShmAudioPool.shm); | |||||
| return false; | 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"); | 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; | return false; | ||||
| } | } | ||||
| fNeedsSemDestroy = true; | |||||
| } | } | ||||
| // initial values | // 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) | // register plugin now so we can receive OSC (and wait for it) | ||||
| fHints |= PLUGIN_IS_BRIDGE; | fHints |= PLUGIN_IS_BRIDGE; | ||||
| @@ -1689,35 +1841,12 @@ private: | |||||
| bool fInitiated; | bool fInitiated; | ||||
| bool fInitError; | bool fInitError; | ||||
| bool fSaved; | bool fSaved; | ||||
| bool fNeedsSemDestroy; | |||||
| CarlaString fBridgeBinary; | 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 { | struct Info { | ||||
| uint32_t aIns, aOuts; | uint32_t aIns, aOuts; | ||||
| @@ -1741,59 +1870,20 @@ private: | |||||
| BridgeParamInfo* fParams; | 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(); | waitForServer(); | ||||
| } | } | ||||
| bool waitForServer() | bool waitForServer() | ||||
| { | { | ||||
| sem_post(&fShmControl.data->runServer); | |||||
| if (! jackbridge_sem_timedwait(&fShmControl.data->runClient, 5)) | |||||
| if (! fShmControl.waitForServer()) | |||||
| { | { | ||||
| carla_stderr("waitForServer() timeout"); | carla_stderr("waitForServer() timeout"); | ||||
| kData->active = false; // TODO | kData->active = false; // TODO | ||||
| @@ -1854,18 +1944,23 @@ CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, P | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Bridge Helper | // Bridge Helper | ||||
| #define bridgePlugin ((BridgePlugin*)plugin) | |||||
| int CarlaPluginSetOscBridgeInfo(CarlaPlugin* const plugin, const PluginBridgeInfoType type, | int CarlaPluginSetOscBridgeInfo(CarlaPlugin* const plugin, const PluginBridgeInfoType type, | ||||
| const int argc, const lo_arg* const* const argv, const char* const types) | const int argc, const lo_arg* const* const argv, const char* const types) | ||||
| { | { | ||||
| CARLA_ASSERT(plugin != nullptr && (plugin->hints() & PLUGIN_IS_BRIDGE) != 0); | 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) | BinaryType CarlaPluginGetBridgeBinaryType(CarlaPlugin* const plugin) | ||||
| { | { | ||||
| CARLA_ASSERT(plugin != nullptr && (plugin->hints() & PLUGIN_IS_BRIDGE) != 0); | CARLA_ASSERT(plugin != nullptr && (plugin->hints() & PLUGIN_IS_BRIDGE) != 0); | ||||
| return ((BridgePlugin*)plugin)->binaryType(); | |||||
| return bridgePlugin->binaryType(); | |||||
| } | } | ||||
| #undef bridgePlugin | |||||
| #endif | #endif | ||||
| CARLA_BACKEND_END_NAMESPACE | CARLA_BACKEND_END_NAMESPACE | ||||
| @@ -68,11 +68,13 @@ HEADERS += \ | |||||
| HEADERS += \ | HEADERS += \ | ||||
| ../../utils/CarlaUtils.hpp \ | ../../utils/CarlaUtils.hpp \ | ||||
| ../../utils/CarlaBridgeUtils.hpp \ | |||||
| ../../utils/CarlaJuceUtils.hpp \ | ../../utils/CarlaJuceUtils.hpp \ | ||||
| ../../utils/CarlaLibUtils.hpp \ | ../../utils/CarlaLibUtils.hpp \ | ||||
| ../../utils/CarlaOscUtils.hpp \ | ../../utils/CarlaOscUtils.hpp \ | ||||
| ../../utils/CarlaStateUtils.hpp \ | ../../utils/CarlaStateUtils.hpp \ | ||||
| ../../utils/CarlaMutex.hpp \ | ../../utils/CarlaMutex.hpp \ | ||||
| ../../utils/CarlaRingBuffer.hpp \ | |||||
| ../../utils/CarlaString.hpp | ../../utils/CarlaString.hpp | ||||
| INCLUDEPATH = . .. \ | INCLUDEPATH = . .. \ | ||||
| @@ -33,7 +33,7 @@ public: | |||||
| virtual ~ExternalUI() override; | virtual ~ExternalUI() override; | ||||
| protected: | protected: | ||||
| const char* d_externalFilename() const = 0; | |||||
| virtual const char* d_externalFilename() const = 0; | |||||
| private: | private: | ||||
| friend class UIInternal; | friend class UIInternal; | ||||
| @@ -211,7 +211,7 @@ protected: | |||||
| void setParameterValue(uint32_t index, float realValue) | void setParameterValue(uint32_t index, float realValue) | ||||
| { | { | ||||
| const ParameterRanges& ranges(kPlugin->parameterRanges(index)); | const ParameterRanges& ranges(kPlugin->parameterRanges(index)); | ||||
| const float perValue(ranges.normalizeValue(realValue)); | |||||
| const float perValue(ranges.normalizedValue(realValue)); | |||||
| kPlugin->setParameterValue(index, realValue); | kPlugin->setParameterValue(index, realValue); | ||||
| hostCallback(audioMasterAutomate, index, 0, nullptr, perValue); | hostCallback(audioMasterAutomate, index, 0, nullptr, perValue); | ||||
| @@ -472,13 +472,13 @@ public: | |||||
| float vst_getParameter(int32_t index) | float vst_getParameter(int32_t index) | ||||
| { | { | ||||
| const ParameterRanges& ranges(fPlugin.parameterRanges(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) | void vst_setParameter(int32_t index, float value) | ||||
| { | { | ||||
| const ParameterRanges& ranges(fPlugin.parameterRanges(index)); | const ParameterRanges& ranges(fPlugin.parameterRanges(index)); | ||||
| const float realValue(ranges.unnormalizeValue(value)); | |||||
| const float realValue(ranges.unnormalizedValue(value)); | |||||
| fPlugin.setParameterValue(index, realValue); | fPlugin.setParameterValue(index, realValue); | ||||
| #if DISTRHO_PLUGIN_HAS_UI | #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 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 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_post(void* sem); | ||||
| CARLA_EXPORT bool jackbridge_sem_timedwait(void* sem, int secs); | CARLA_EXPORT bool jackbridge_sem_timedwait(void* sem, int secs); | ||||
| @@ -18,6 +18,8 @@ | |||||
| #ifndef __JACKBRIDGE_HPP__ | #ifndef __JACKBRIDGE_HPP__ | ||||
| // don't include the whole JACK API in this file | // 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_post(void* sem); | ||||
| CARLA_EXPORT bool jackbridge_sem_timedwait(void* sem, int secs); | CARLA_EXPORT bool jackbridge_sem_timedwait(void* sem, int secs); | ||||
| #endif | #endif | ||||
| @@ -25,6 +27,16 @@ CARLA_EXPORT bool jackbridge_sem_timedwait(void* sem, int secs); | |||||
| // ----------------------------------------------------------------------------- | // ----------------------------------------------------------------------------- | ||||
| #if JACKBRIDGE_DUMMY | #if JACKBRIDGE_DUMMY | ||||
| bool jackbridge_sem_init(void*) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| bool jackbridge_sem_destroy(void*) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| bool jackbridge_sem_post(void*) | bool jackbridge_sem_post(void*) | ||||
| { | { | ||||
| return false; | return false; | ||||
| @@ -38,15 +50,15 @@ bool jackbridge_sem_timedwait(void*, int) | |||||
| #include <semaphore.h> | #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 | #ifdef CARLA_OS_WIN | ||||
| # include <sys/time.h> | # include <sys/time.h> | ||||
| @@ -54,6 +66,16 @@ struct timespec { | |||||
| # include <time.h> | # include <time.h> | ||||
| #endif | #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) | bool jackbridge_sem_post(void* sem) | ||||
| { | { | ||||
| return (sem_post((sem_t*)sem) == 0); | 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_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 | 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 | win32: ../jackbridge-win32.dll | ||||
| win64: ../jackbridge-win64.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) | ../jackbridge-win32.dll: $(OBJS) | ||||
| $(CXX) $^ $(WIN_BUILD_FLAGS) $(WIN_32BIT_FLAGS) $(WIN_LINK_FLAGS) -Wl,--output-def,$@.def,--out-implib,$@.a -o $@ $(CMD_STRIP) $@ | $(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) | ../jackbridge-win64.dll: $(OBJS) | ||||
| $(CXX) $^ $(WIN_BUILD_FLAGS) $(WIN_64BIT_FLAGS) $(WIN_LINK_FLAGS) -Wl,--output-def,$@.def,--out-implib,$@.a -o $@ $(CMD_STRIP) $@ | $(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__ | #ifndef __CARLA_BRIDGE_UTILS_HPP__ | ||||
| #define __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 { | enum PluginBridgeInfoType { | ||||
| kPluginBridgeAudioCount, | |||||
| kPluginBridgeAudioCount = 0, | |||||
| kPluginBridgeMidiCount, | kPluginBridgeMidiCount, | ||||
| kPluginBridgeParameterCount, | kPluginBridgeParameterCount, | ||||
| kPluginBridgeProgramCount, | kPluginBridgeProgramCount, | ||||
| @@ -52,7 +48,7 @@ enum PluginBridgeInfoType { | |||||
| enum PluginBridgeOpcode { | enum PluginBridgeOpcode { | ||||
| kPluginBridgeOpcodeNull = 0, | kPluginBridgeOpcodeNull = 0, | ||||
| kPluginBridgeOpcodeSetAudioPool = 1, // int | |||||
| kPluginBridgeOpcodeSetAudioPool = 1, // long | |||||
| kPluginBridgeOpcodeSetBufferSize = 2, // int | kPluginBridgeOpcodeSetBufferSize = 2, // int | ||||
| kPluginBridgeOpcodeSetSampleRate = 3, // float | kPluginBridgeOpcodeSetSampleRate = 3, // float | ||||
| kPluginBridgeOpcodeSetParameter = 4, // int, 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. | //If \a type is 'chunk' or 'binary' \a rvalue refers to chunk file. | ||||
| #endif | #endif | ||||
| // --------------------------------------------------------------------------------------------- | |||||
| struct BridgeRingBuffer { | |||||
| int head, tail, written; | |||||
| bool invalidateCommit; | |||||
| char buf[BRIDGE_SHM_RING_BUFFER_SIZE]; | |||||
| }; | |||||
| // ------------------------------------------------- | |||||
| struct BridgeShmControl { | struct BridgeShmControl { | ||||
| // 32 and 64-bit binaries align semaphores differently. | // 32 and 64-bit binaries align semaphores differently. | ||||
| // Let's make sure there's plenty of room for either one. | // Let's make sure there's plenty of room for either one. | ||||
| union { | union { | ||||
| sem_t runServer; | |||||
| void* runServer; | |||||
| char _alignServer[128]; | char _alignServer[128]; | ||||
| }; | }; | ||||
| union { | union { | ||||
| sem_t runClient; | |||||
| void* runClient; | |||||
| char _alignClient[128]; | char _alignClient[128]; | ||||
| }; | }; | ||||
| BridgeRingBuffer ringBuffer; | |||||
| RingBuffer ringBuffer; | |||||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeShmControl) | |||||
| }; | }; | ||||
| // --------------------------------------------------------------------------------------------- | |||||
| // ------------------------------------------------- | |||||
| static inline | static inline | ||||
| const char* PluginBridgeInfoType2str(const PluginBridgeInfoType type) | const char* PluginBridgeInfoType2str(const PluginBridgeInfoType type) | ||||
| @@ -147,183 +139,37 @@ const char* PluginBridgeInfoType2str(const PluginBridgeInfoType type) | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| // --------------------------------------------------------------------------------------------- | |||||
| static inline | 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__ | #endif // __CARLA_BRIDGE_UTILS_HPP__ | ||||