|
- /*
- * Carla Plugin Host
- * Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * For a full copy of the GNU General Public License see the doc/GPL.txt file.
- */
-
- #ifndef BUILD_BRIDGE
- # error This file should not be compiled if not building bridge
- #endif
-
- #include "CarlaEngineInternal.hpp"
- #include "CarlaPlugin.hpp"
-
- #include "CarlaBackendUtils.hpp"
- #include "CarlaBase64Utils.hpp"
- #include "CarlaBridgeUtils.hpp"
- #include "CarlaMIDI.h"
-
- #include "jackbridge/JackBridge.hpp"
-
- #include <cerrno>
- #include <ctime>
-
- using juce::File;
- using juce::MemoryBlock;
- using juce::String;
-
- // -------------------------------------------------------------------
-
- template<typename T>
- bool jackbridge_shm_map2(char* shm, T*& value) noexcept
- {
- value = (T*)jackbridge_shm_map(shm, sizeof(T));
- return (value != nullptr);
- }
-
- // -------------------------------------------------------------------
-
- CARLA_BACKEND_START_NAMESPACE
-
- // -------------------------------------------------------------------
-
- struct BridgeAudioPool {
- CarlaString filename;
- float* data;
- char shm[64];
-
- BridgeAudioPool() noexcept
- : filename(),
- data(nullptr)
- {
- carla_zeroChar(shm, 64);
- jackbridge_shm_init(shm);
- }
-
- ~BridgeAudioPool() noexcept
- {
- // should be cleared by now
- CARLA_SAFE_ASSERT(data == nullptr);
-
- clear();
- }
-
- bool attach() noexcept
- {
- jackbridge_shm_attach(shm, filename);
-
- return jackbridge_shm_is_valid(shm);
- }
-
- void clear() noexcept
- {
- filename.clear();
-
- data = nullptr;
-
- if (jackbridge_shm_is_valid(shm))
- jackbridge_shm_close(shm);
- }
-
- CARLA_DECLARE_NON_COPY_STRUCT(BridgeAudioPool)
- };
-
- // -------------------------------------------------------------------
-
- struct BridgeRtControl : public CarlaRingBuffer<StackBuffer> {
- CarlaString filename;
- BridgeRtData* data;
- char shm[64];
-
- BridgeRtControl() noexcept
- : filename(),
- data(nullptr)
- {
- carla_zeroChar(shm, 64);
- jackbridge_shm_init(shm);
- }
-
- ~BridgeRtControl() noexcept override
- {
- // should be cleared by now
- CARLA_SAFE_ASSERT(data == nullptr);
-
- clear();
- }
-
- bool attach() noexcept
- {
- jackbridge_shm_attach(shm, filename);
-
- return jackbridge_shm_is_valid(shm);
- }
-
- void clear() noexcept
- {
- filename.clear();
-
- data = nullptr;
-
- if (jackbridge_shm_is_valid(shm))
- jackbridge_shm_close(shm);
- }
-
- bool mapData() noexcept
- {
- CARLA_SAFE_ASSERT(data == nullptr);
-
- if (jackbridge_shm_map2<BridgeRtData>(shm, data))
- {
- CARLA_SAFE_ASSERT(data->midiOut[0] == 0);
- setRingBuffer(&data->ringBuffer, false);
- return true;
- }
-
- return false;
- }
-
- PluginBridgeRtOpcode readOpcode() noexcept
- {
- return static_cast<PluginBridgeRtOpcode>(readInt());
- }
-
- CARLA_DECLARE_NON_COPY_STRUCT(BridgeRtControl)
- };
-
- // -------------------------------------------------------------------
-
- struct BridgeNonRtControl : public CarlaRingBuffer<BigStackBuffer> {
- CarlaString filename;
- BridgeNonRtData* data;
- char shm[64];
-
- BridgeNonRtControl() noexcept
- : filename(),
- data(nullptr)
- {
- carla_zeroChar(shm, 64);
- jackbridge_shm_init(shm);
- }
-
- ~BridgeNonRtControl() noexcept override
- {
- // should be cleared by now
- CARLA_SAFE_ASSERT(data == nullptr);
-
- clear();
- }
-
- bool attach() noexcept
- {
- jackbridge_shm_attach(shm, filename);
-
- return jackbridge_shm_is_valid(shm);
- }
-
- void clear() noexcept
- {
- filename.clear();
-
- data = nullptr;
-
- if (jackbridge_shm_is_valid(shm))
- jackbridge_shm_close(shm);
- }
-
- bool mapData() noexcept
- {
- CARLA_SAFE_ASSERT(data == nullptr);
-
- if (jackbridge_shm_map2<BridgeNonRtData>(shm, data))
- {
- setRingBuffer(&data->ringBuffer, false);
- return true;
- }
-
- return false;
- }
-
- PluginBridgeNonRtOpcode readOpcode() noexcept
- {
- return static_cast<PluginBridgeNonRtOpcode>(readInt());
- }
-
- CARLA_DECLARE_NON_COPY_STRUCT(BridgeNonRtControl)
- };
-
- // -------------------------------------------------------------------
-
- class CarlaEngineBridge : public CarlaEngine,
- public CarlaThread
- {
- public:
- CarlaEngineBridge(const char* const audioPoolBaseName, const char* const rtBaseName, const char* const nonRtBaseName)
- : CarlaEngine(),
- CarlaThread("CarlaEngineBridge"),
- fShmAudioPool(),
- fShmCVPool(),
- fShmRtControl(),
- fShmNonRtControl(),
- fIsRunning(false),
- fIsOffline(false),
- leakDetector_CarlaEngineBridge()
- {
- carla_stdout("CarlaEngineBridge::CarlaEngineBridge(\"%s\", \"%s\", \"%s\")", audioPoolBaseName, rtBaseName, nonRtBaseName);
-
- fShmAudioPool.filename = "/carla-bridge_shm_ap_";
- fShmAudioPool.filename += audioPoolBaseName;
-
- //fShmCVPool.filename = "/carla-bridge_shm_cvp_";
- //fShmCVPool.filename += cvPoolBaseName;
-
- fShmRtControl.filename = "/carla-bridge_shm_rt_";
- fShmRtControl.filename += rtBaseName;
-
- fShmNonRtControl.filename = "/carla-bridge_shm_nonrt_";
- fShmNonRtControl.filename += nonRtBaseName;
- }
-
- ~CarlaEngineBridge() noexcept override
- {
- carla_debug("CarlaEngineBridge::~CarlaEngineBridge()");
- }
-
- // -------------------------------------
- // CarlaEngine virtual calls
-
- bool init(const char* const clientName) override
- {
- carla_debug("CarlaEngineBridge::init(\"%s\")", clientName);
-
- if (! pData->init(clientName))
- {
- setLastError("Failed to init internal data");
- return false;
- }
-
- if (! fShmAudioPool.attach())
- {
- carla_stdout("Failed to attach to audio pool shared memory");
- return false;
- }
-
- if (! fShmRtControl.attach())
- {
- clear();
- carla_stdout("Failed to attach to rt control shared memory");
- return false;
- }
-
- if (! fShmRtControl.mapData())
- {
- clear();
- carla_stdout("Failed to map rt control shared memory");
- return false;
- }
-
- if (! fShmNonRtControl.attach())
- {
- clear();
- carla_stdout("Failed to attach to non-rt control shared memory");
- return false;
- }
-
- if (! fShmNonRtControl.mapData())
- {
- clear();
- carla_stdout("Failed to map non-rt control shared memory");
- return false;
- }
-
- PluginBridgeNonRtOpcode opcode;
-
- opcode = fShmNonRtControl.readOpcode();
- CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtNull, opcode);
-
- const uint32_t shmRtDataSize = fShmNonRtControl.readUInt();
- CARLA_SAFE_ASSERT_INT2(shmRtDataSize == sizeof(BridgeRtData), shmRtDataSize, sizeof(BridgeRtData));
-
- const uint32_t shmNonRtDataSize = fShmNonRtControl.readUInt();
- CARLA_SAFE_ASSERT_INT2(shmNonRtDataSize == sizeof(BridgeNonRtData), shmNonRtDataSize, sizeof(BridgeNonRtData));
-
- opcode = fShmNonRtControl.readOpcode();
- CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtSetBufferSize, opcode);
- pData->bufferSize = fShmNonRtControl.readUInt();
-
- opcode = fShmNonRtControl.readOpcode();
- CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtSetSampleRate, opcode);
- pData->sampleRate = fShmNonRtControl.readDouble();
-
- carla_stdout("Carla Client Info:");
- carla_stdout(" BufferSize: %i", pData->bufferSize);
- carla_stdout(" SampleRate: %g", pData->sampleRate);
- carla_stdout(" sizeof(BridgeRtData): %i/" P_SIZE, shmRtDataSize, sizeof(BridgeRtData));
- carla_stdout(" sizeof(BridgeNonRtData): %i/" P_SIZE, shmNonRtDataSize, sizeof(BridgeNonRtData));
-
- if (shmRtDataSize != sizeof(BridgeRtData) || shmNonRtDataSize != sizeof(BridgeNonRtData))
- return false;
-
- startThread();
-
- return true;
- }
-
- bool close() override
- {
- carla_debug("CarlaEnginePlugin::close()");
- CarlaEngine::close();
-
- stopThread(5000);
- clear();
-
- return true;
- }
-
- bool isRunning() const noexcept override
- {
- return isThreadRunning();
- }
-
- bool isOffline() const noexcept override
- {
- return fIsOffline;
- }
-
- EngineType getType() const noexcept override
- {
- return kEngineTypeBridge;
- }
-
- const char* getCurrentDriverName() const noexcept
- {
- return "Bridge";
- }
-
- void idle() noexcept override
- {
- CarlaEngine::idle();
-
- try {
- handleNonRtData();
- } CARLA_SAFE_EXCEPTION("handleNonRtData");
- }
-
- // -------------------------------------------------------------------
-
- void clear() noexcept
- {
- fShmAudioPool.clear();
- fShmRtControl.clear();
- fShmNonRtControl.clear();
- }
-
- void handleNonRtData()
- {
- for (; fShmNonRtControl.isDataAvailableForReading();)
- {
- const PluginBridgeNonRtOpcode opcode(fShmNonRtControl.readOpcode());
- CarlaPlugin* const plugin(pData->plugins[0].plugin);
-
- #ifdef DEBUG
- if (opcode != kPluginBridgeNonRtPing) {
- carla_debug("CarlaEngineBridge::handleNonRtData() - got opcode: %s", PluginBridgeNonRtOpcode2str(opcode));
- }
- #endif
-
- switch (opcode)
- {
- case kPluginBridgeNonRtNull:
- break;
-
- case kPluginBridgeNonRtPing:
- oscSend_bridge_pong();
- break;
-
- case kPluginBridgeNonRtActivate:
- if (plugin != nullptr && plugin->isEnabled())
- plugin->setActive(true, false, false);
- break;
-
- case kPluginBridgeNonRtDeactivate:
- if (plugin != nullptr && plugin->isEnabled())
- plugin->setActive(false, false, false);
- break;
-
- case kPluginBridgeNonRtSetBufferSize: {
- const uint32_t bufferSize(fShmNonRtControl.readUInt());
- pData->bufferSize = bufferSize;
- bufferSizeChanged(bufferSize);
- break;
- }
-
- case kPluginBridgeNonRtSetSampleRate: {
- const double sampleRate(fShmNonRtControl.readDouble());
- pData->sampleRate = sampleRate;
- sampleRateChanged(sampleRate);
- break;
- }
-
- case kPluginBridgeNonRtSetOffline:
- fIsOffline = true;
- offlineModeChanged(true);
- break;
-
- case kPluginBridgeNonRtSetOnline:
- fIsOffline = false;
- offlineModeChanged(false);
- break;
-
- case kPluginBridgeNonRtSetParameterValue: {
- const uint32_t index(fShmNonRtControl.readUInt());
- const float value(fShmNonRtControl.readFloat());
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->setParameterValue(index, value, false, false, false);
- break;
- }
-
- case kPluginBridgeNonRtSetParameterMidiChannel: {
- const uint32_t index(fShmNonRtControl.readUInt());
- const uint8_t channel(fShmNonRtControl.readByte());
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->setParameterMidiChannel(index, channel, false, false);
- break;
- }
-
- case kPluginBridgeNonRtSetParameterMidiCC: {
- const uint32_t index(fShmNonRtControl.readUInt());
- const int16_t cc(fShmNonRtControl.readShort());
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->setParameterMidiCC(index, cc, false, false);
- break;
- }
-
- case kPluginBridgeNonRtSetProgram: {
- const int32_t index(fShmNonRtControl.readInt());
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->setProgram(index, false, false, false);
- break;
- }
-
- case kPluginBridgeNonRtSetMidiProgram: {
- const int32_t index(fShmNonRtControl.readInt());
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->setMidiProgram(index, false, false, false);
- break;
- }
-
- case kPluginBridgeNonRtSetCustomData: {
- // type
- const uint32_t typeSize(fShmNonRtControl.readUInt());
- char typeStr[typeSize+1];
- carla_zeroChar(typeStr, typeSize+1);
- fShmNonRtControl.readCustomData(typeStr, typeSize);
-
- // key
- const uint32_t keySize(fShmNonRtControl.readUInt());
- char keyStr[keySize+1];
- carla_zeroChar(keyStr, keySize+1);
- fShmNonRtControl.readCustomData(keyStr, keySize);
-
- // value
- const uint32_t valueSize(fShmNonRtControl.readUInt());
- char valueStr[valueSize+1];
- carla_zeroChar(valueStr, valueSize+1);
- fShmNonRtControl.readCustomData(valueStr, valueSize);
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->setCustomData(typeStr, keyStr, valueStr, true);
- break;
- }
-
- case kPluginBridgeNonRtSetChunkDataFile: {
- const uint32_t size(fShmNonRtControl.readUInt());
- CARLA_SAFE_ASSERT_BREAK(size > 0);
-
- char chunkFilePathTry[size+1];
- carla_zeroChar(chunkFilePathTry, size+1);
- fShmNonRtControl.readCustomData(chunkFilePathTry, size);
-
- CARLA_SAFE_ASSERT_BREAK(chunkFilePathTry[0] != '\0');
- if (plugin == nullptr || ! plugin->isEnabled()) break;
-
- String chunkFilePath(chunkFilePathTry);
-
- #ifdef CARLA_OS_WIN
- // check if running under Wine
- if (chunkFilePath.startsWith("/"))
- chunkFilePath = chunkFilePath.replaceSection(0, 1, "Z:\\").replace("/", "\\");
- #endif
-
- File chunkFile(chunkFilePath);
- CARLA_SAFE_ASSERT_BREAK(chunkFile.existsAsFile());
-
- String chunkDataBase64(chunkFile.loadFileAsString());
- chunkFile.deleteFile();
- CARLA_SAFE_ASSERT_BREAK(chunkDataBase64.isNotEmpty());
-
- std::vector<uint8_t> chunk(carla_getChunkFromBase64String(chunkDataBase64.toRawUTF8()));
- plugin->setChunkData(chunk.data(), chunk.size());
- break;
- }
-
- case kPluginBridgeNonRtSetCtrlChannel: {
- const int16_t channel(fShmNonRtControl.readShort());
- CARLA_SAFE_ASSERT_BREAK(channel >= -1 && channel < MAX_MIDI_CHANNELS);
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->setCtrlChannel(static_cast<int8_t>(channel), false, false);
- break;
- }
-
- case kPluginBridgeNonRtSetOscURL: {
- const uint32_t size(fShmNonRtControl.readUInt());
-
- char url[size+1];
- carla_zeroChar(url, size+1);
- fShmNonRtControl.readCustomData(url, size);
-
- CARLA_SAFE_ASSERT_BREAK(url[0] != '\0');
- if (plugin == nullptr || ! plugin->isEnabled()) break;
-
- pData->oscData->setNewURL(url);
- break;
- }
-
- case kPluginBridgeNonRtSetOption: {
- const uint32_t option(fShmNonRtControl.readUInt());
- const bool yesNo(fShmNonRtControl.readBool());
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->setOption(option, yesNo, false);
- break;
- }
-
- case kPluginBridgeNonRtPrepareForSave: {
- if (plugin == nullptr || ! plugin->isEnabled()) break;
-
- plugin->prepareForSave();
-
- for (uint32_t i=0, count=plugin->getCustomDataCount(); i<count; ++i)
- {
- const CustomData& cdata(plugin->getCustomData(i));
- oscSend_bridge_set_custom_data(cdata.type, cdata.key, cdata.value);
- }
-
- if (plugin->getOptionsEnabled() & PLUGIN_OPTION_USE_CHUNKS)
- {
- void* data = nullptr;
- if (const std::size_t dataSize = plugin->getChunkData(&data))
- {
- CARLA_SAFE_ASSERT_BREAK(data != nullptr);
-
- CarlaString dataBase64 = CarlaString::asBase64(data, dataSize);
- CARLA_SAFE_ASSERT_BREAK(dataBase64.length() > 0);
-
- String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());
-
- filePath += CARLA_OS_SEP_STR;
- filePath += ".CarlaChunk_";
- filePath += fShmNonRtControl.filename.buffer() + 24;
-
- if (File(filePath).replaceWithText(dataBase64.buffer()))
- oscSend_bridge_set_chunk_data_file(filePath.toRawUTF8());
- }
- }
-
- oscSend_bridge_configure(CARLA_BRIDGE_MSG_SAVED, "");
- break;
- }
-
- case kPluginBridgeNonRtShowUI:
- if (plugin != nullptr && plugin->isEnabled())
- plugin->showCustomUI(true);
- break;
-
- case kPluginBridgeNonRtHideUI:
- if (plugin != nullptr && plugin->isEnabled())
- plugin->showCustomUI(false);
- break;
-
- case kPluginBridgeNonRtUiParameterChange: {
- const uint32_t index(fShmNonRtControl.readUInt());
- const float value(fShmNonRtControl.readFloat());
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->uiParameterChange(index, value);
- break;
- }
-
- case kPluginBridgeNonRtUiProgramChange: {
- const uint32_t index(fShmNonRtControl.readUInt());
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->uiProgramChange(index);
- break;
- }
-
- case kPluginBridgeNonRtUiMidiProgramChange: {
- const uint32_t index(fShmNonRtControl.readUInt());
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->uiMidiProgramChange(index);
- break;
- }
-
- case kPluginBridgeNonRtUiNoteOn: {
- const uint8_t chnl(fShmNonRtControl.readByte());
- const uint8_t note(fShmNonRtControl.readByte());
- const uint8_t velo(fShmNonRtControl.readByte());
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->uiNoteOn(chnl, note, velo);
- break;
- }
-
- case kPluginBridgeNonRtUiNoteOff: {
- const uint8_t chnl(fShmNonRtControl.readByte());
- const uint8_t note(fShmNonRtControl.readByte());
-
- if (plugin != nullptr && plugin->isEnabled())
- plugin->uiNoteOff(chnl, note);
- break;
- }
-
- case kPluginBridgeNonRtQuit:
- signalThreadShouldExit();
- callback(ENGINE_CALLBACK_QUIT, 0, 0, 0, 0.0f, nullptr);
- break;
- }
- }
- }
-
- // -------------------------------------------------------------------
-
- protected:
- void run() override
- {
- for (; ! shouldThreadExit();)
- {
- if (! jackbridge_sem_timedwait(&fShmRtControl.data->sem.server, 5))
- {
- if (errno == ETIMEDOUT)
- {
- signalThreadShouldExit();
- break;
- }
- }
-
- for (; fShmRtControl.isDataAvailableForReading();)
- {
- const PluginBridgeRtOpcode opcode(fShmRtControl.readOpcode());
- CarlaPlugin* const plugin(pData->plugins[0].plugin);
-
- #ifdef DEBUG
- if (opcode != kPluginBridgeRtProcess && opcode != kPluginBridgeRtMidiEvent) {
- carla_debug("CarlaEngineBridgeRtThread::run() - got opcode: %s", PluginBridgeRtOpcode2str(opcode));
- }
- #endif
-
- switch (opcode)
- {
- case kPluginBridgeRtNull:
- break;
-
- case kPluginBridgeRtSetAudioPool: {
- const uint64_t poolSize(fShmRtControl.readULong());
- CARLA_SAFE_ASSERT_BREAK(poolSize > 0);
- fShmAudioPool.data = (float*)jackbridge_shm_map(fShmAudioPool.shm, static_cast<size_t>(poolSize));
- break;
- }
-
- case kPluginBridgeRtSetCVPool: {
- const uint64_t poolSize(fShmRtControl.readULong());
- CARLA_SAFE_ASSERT_BREAK(poolSize > 0);
- //fShmCVPool.data = (float*)jackbridge_shm_map(fShmCVPool.shm, static_cast<size_t>(poolSize));
- break;
- }
-
- case kPluginBridgeRtControlEventParameter: {
- const uint32_t time(fShmRtControl.readUInt());
- const uint8_t channel(fShmRtControl.readByte());
- const uint16_t param(fShmRtControl.readUShort());
- const float value(fShmRtControl.readFloat());
-
- if (EngineEvent* const event = getNextFreeInputEvent())
- {
- event->type = kEngineEventTypeControl;
- event->time = time;
- event->channel = channel;
- event->ctrl.type = kEngineControlEventTypeParameter;
- event->ctrl.param = param;
- event->ctrl.value = value;
- }
- break;
- }
-
- case kPluginBridgeRtControlEventMidiBank: {
- const uint32_t time(fShmRtControl.readUInt());
- const uint8_t channel(fShmRtControl.readByte());
- const uint16_t index(fShmRtControl.readUShort());
-
- if (EngineEvent* const event = getNextFreeInputEvent())
- {
- event->type = kEngineEventTypeControl;
- event->time = time;
- event->channel = channel;
- event->ctrl.type = kEngineControlEventTypeMidiBank;
- event->ctrl.param = index;
- event->ctrl.value = 0.0f;
- }
- break;
- }
-
- case kPluginBridgeRtControlEventMidiProgram: {
- const uint32_t time(fShmRtControl.readUInt());
- const uint8_t channel(fShmRtControl.readByte());
- const uint16_t index(fShmRtControl.readUShort());
-
- if (EngineEvent* const event = getNextFreeInputEvent())
- {
- event->type = kEngineEventTypeControl;
- event->time = time;
- event->channel = channel;
- event->ctrl.type = kEngineControlEventTypeMidiProgram;
- event->ctrl.param = index;
- event->ctrl.value = 0.0f;
- }
- break;
- }
-
- case kPluginBridgeRtControlEventAllSoundOff: {
- const uint32_t time(fShmRtControl.readUInt());
- const uint8_t channel(fShmRtControl.readByte());
-
- if (EngineEvent* const event = getNextFreeInputEvent())
- {
- event->type = kEngineEventTypeControl;
- event->time = time;
- event->channel = channel;
- event->ctrl.type = kEngineControlEventTypeAllSoundOff;
- event->ctrl.param = 0;
- event->ctrl.value = 0.0f;
- }
- }
-
- case kPluginBridgeRtControlEventAllNotesOff: {
- const uint32_t time(fShmRtControl.readUInt());
- const uint8_t channel(fShmRtControl.readByte());
-
- if (EngineEvent* const event = getNextFreeInputEvent())
- {
- event->type = kEngineEventTypeControl;
- event->time = time;
- event->channel = channel;
- event->ctrl.type = kEngineControlEventTypeAllNotesOff;
- event->ctrl.param = 0;
- event->ctrl.value = 0.0f;
- }
- }
-
- case kPluginBridgeRtMidiEvent: {
- const uint32_t time(fShmRtControl.readUInt());
- const uint8_t port(fShmRtControl.readByte());
- const uint8_t size(fShmRtControl.readByte());
- CARLA_SAFE_ASSERT_BREAK(size > 0);
-
- uint8_t data[size];
-
- for (uint8_t i=0; i<size; ++i)
- data[i] = fShmRtControl.readByte();
-
- if (EngineEvent* const event = getNextFreeInputEvent())
- {
- event->type = kEngineEventTypeMidi;
- event->time = time;
- event->channel = MIDI_GET_CHANNEL_FROM_DATA(data);
-
- event->midi.port = port;
- event->midi.size = size;
-
- if (size > EngineMidiEvent::kDataSize)
- {
- event->midi.dataExt = data;
- std::memset(event->midi.data, 0, sizeof(uint8_t)*EngineMidiEvent::kDataSize);
- }
- else
- {
- event->midi.data[0] = MIDI_GET_STATUS_FROM_DATA(data);
-
- uint8_t i=1;
- for (; i < size; ++i)
- event->midi.data[i] = data[i];
- for (; i < EngineMidiEvent::kDataSize; ++i)
- event->midi.data[i] = 0;
-
- event->midi.dataExt = nullptr;
- }
- }
- break;
- }
-
- case kPluginBridgeRtProcess: {
- CARLA_SAFE_ASSERT_BREAK(fShmAudioPool.data != nullptr);
-
- if (plugin != nullptr && plugin->isEnabled() && plugin->tryLock(false))
- {
- const BridgeTimeInfo& bridgeTimeInfo(fShmRtControl.data->timeInfo);
-
- const uint32_t audioInCount(plugin->getAudioInCount());
- const uint32_t audioOutCount(plugin->getAudioOutCount());
- const uint32_t cvInCount(plugin->getCVInCount());
- const uint32_t cvOutCount(plugin->getCVOutCount());
-
- const float* audioIn[audioInCount];
- /* */ float* audioOut[audioOutCount];
- const float* cvIn[cvInCount];
- /* */ float* cvOut[cvOutCount];
-
- for (uint32_t i=0; i < audioInCount; ++i)
- audioIn[i] = fShmAudioPool.data + i*pData->bufferSize;
- for (uint32_t i=0; i < audioOutCount; ++i)
- audioOut[i] = fShmAudioPool.data + (i+audioInCount)*pData->bufferSize;
-
- for (uint32_t i=0; i < cvInCount; ++i)
- cvIn[i] = fShmAudioPool.data + i*pData->bufferSize;
- for (uint32_t i=0; i < cvOutCount; ++i)
- cvOut[i] = fShmAudioPool.data + (i+cvInCount)*pData->bufferSize;
-
- EngineTimeInfo& timeInfo(pData->timeInfo);
-
- timeInfo.playing = bridgeTimeInfo.playing;
- timeInfo.frame = bridgeTimeInfo.frame;
- timeInfo.usecs = bridgeTimeInfo.usecs;
- timeInfo.valid = bridgeTimeInfo.valid;
-
- if (timeInfo.valid & EngineTimeInfo::kValidBBT)
- {
- timeInfo.bbt.bar = bridgeTimeInfo.bar;
- timeInfo.bbt.beat = bridgeTimeInfo.beat;
- timeInfo.bbt.tick = bridgeTimeInfo.tick;
-
- timeInfo.bbt.beatsPerBar = bridgeTimeInfo.beatsPerBar;
- timeInfo.bbt.beatType = bridgeTimeInfo.beatType;
-
- timeInfo.bbt.ticksPerBeat = bridgeTimeInfo.ticksPerBeat;
- timeInfo.bbt.beatsPerMinute = bridgeTimeInfo.beatsPerMinute;
- timeInfo.bbt.barStartTick = bridgeTimeInfo.barStartTick;
- }
-
- plugin->initBuffers();
- plugin->process(audioIn, audioOut, cvIn, cvOut, pData->bufferSize);
- plugin->unlock();
- }
-
- // clear buffer
- CARLA_SAFE_ASSERT_BREAK(pData->events.in != nullptr);
-
- if (pData->events.in[0].type != kEngineEventTypeNull)
- carla_zeroStruct<EngineEvent>(pData->events.in, kMaxEngineEventInternalCount);
-
- break;
- }
-
- case kPluginBridgeRtQuit:
- signalThreadShouldExit();
- break;
- }
- }
-
- if (! jackbridge_sem_post(&fShmRtControl.data->sem.client))
- carla_stderr2("Could not post to rt semaphore");
- }
-
- fIsRunning = false;
- callback(ENGINE_CALLBACK_ENGINE_STOPPED, 0, 0, 0, 0.0f, nullptr);
- }
-
- // called from process thread above
- EngineEvent* getNextFreeInputEvent() const noexcept
- {
- for (ushort i=0; i < kMaxEngineEventInternalCount; ++i)
- {
- EngineEvent& event(pData->events.in[i]);
-
- if (event.type == kEngineEventTypeNull)
- return &event;
- }
- return nullptr;
- }
-
- // -------------------------------------------------------------------
-
- private:
- BridgeAudioPool fShmAudioPool;
- BridgeAudioPool fShmCVPool;
- BridgeRtControl fShmRtControl;
- BridgeNonRtControl fShmNonRtControl;
-
- bool fIsRunning;
- bool fIsOffline;
-
- CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineBridge)
- };
-
- // -----------------------------------------------------------------------
-
- CarlaEngine* CarlaEngine::newBridge(const char* const audioPoolBaseName, const char* const rtBaseName, const char* const nonRtBaseName)
- {
- return new CarlaEngineBridge(audioPoolBaseName, rtBaseName, nonRtBaseName);
- }
-
- // -----------------------------------------------------------------------
-
- #ifdef BRIDGE_PLUGIN
- CarlaPlugin* CarlaPlugin::newNative(const CarlaPlugin::Initializer&) { return nullptr; }
- CarlaPlugin* CarlaPlugin::newFileGIG(const CarlaPlugin::Initializer&, const bool) { return nullptr; }
- CarlaPlugin* CarlaPlugin::newFileSF2(const CarlaPlugin::Initializer&, const bool) { return nullptr; }
- CarlaPlugin* CarlaPlugin::newFileSFZ(const CarlaPlugin::Initializer&) { return nullptr; }
- #endif
-
- CARLA_BACKEND_END_NAMESPACE
-
- // -----------------------------------------------------------------------
-
- #if defined(CARLA_OS_WIN) && ! defined(__WINE__)
- extern "C" __declspec (dllexport)
- #else
- extern "C" __attribute__ ((visibility("default")))
- #endif
- void carla_register_native_plugin_carla();
- void carla_register_native_plugin_carla(){}
-
- // -----------------------------------------------------------------------
|