| 
							- /*
 -  * 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 "CarlaBridgeUtils.hpp"
 - #include "CarlaMIDI.h"
 - 
 - #include "jackbridge/JackBridge.hpp"
 - 
 - #include <cerrno>
 - #include <ctime>
 - 
 - #ifdef JACKBRIDGE_EXPORT
 - // -------------------------------------------------------------------
 - 
 - bool jackbridge_is_ok() noexcept
 - {
 -     return true;
 - }
 - #endif
 - 
 - // -------------------------------------------------------------------
 - 
 - CARLA_BACKEND_START_NAMESPACE
 - 
 - #if 0
 - } // Fix editor indentation
 - #endif
 - 
 - // -------------------------------------------------------------------
 - 
 - template<typename T>
 - bool jackbridge_shm_map2(char* shm, T*& value)
 - {
 -     value = (T*)jackbridge_shm_map(shm, sizeof(T));
 -     return (value != nullptr);
 - }
 - 
 - struct BridgeAudioPool {
 -     CarlaString filename;
 -     float* data;
 -     char shm[32];
 - 
 -     BridgeAudioPool()
 -         : data(nullptr)
 -     {
 -         carla_zeroChar(shm, 32);
 -         jackbridge_shm_init(shm);
 -     }
 - 
 -     ~BridgeAudioPool()
 -     {
 -         // should be cleared by now
 -         CARLA_ASSERT(data == nullptr);
 - 
 -         clear();
 -     }
 - 
 -     bool attach()
 -     {
 -         jackbridge_shm_attach(shm, filename);
 - 
 -         return jackbridge_shm_is_valid(shm);
 -     }
 - 
 -     void clear()
 -     {
 -         filename.clear();
 - 
 -         data = nullptr;
 - 
 -         if (jackbridge_shm_is_valid(shm))
 -             jackbridge_shm_close(shm);
 -     }
 - 
 -     CARLA_DECLARE_NON_COPY_STRUCT(BridgeAudioPool)
 - };
 - 
 - struct BridgeControl : public RingBufferControl<StackBuffer> {
 -     CarlaString filename;
 -     BridgeShmControl* data;
 -     char shm[32];
 - 
 -     BridgeControl()
 -         : RingBufferControl<StackBuffer>(nullptr),
 -           data(nullptr)
 -     {
 -         carla_zeroChar(shm, 32);
 -         jackbridge_shm_init(shm);
 -     }
 - 
 -     ~BridgeControl()
 -     {
 -         // should be cleared by now
 -         CARLA_ASSERT(data == nullptr);
 - 
 -         clear();
 -     }
 - 
 -     bool attach()
 -     {
 -         jackbridge_shm_attach(shm, filename);
 - 
 -         return jackbridge_shm_is_valid(shm);
 -     }
 - 
 -     void clear()
 -     {
 -         filename.clear();
 - 
 -         data = nullptr;
 - 
 -         if (jackbridge_shm_is_valid(shm))
 -             jackbridge_shm_close(shm);
 -     }
 - 
 -     bool mapData()
 -     {
 -         CARLA_ASSERT(data == nullptr);
 - 
 -         if (jackbridge_shm_map2<BridgeShmControl>(shm, data))
 -         {
 -             setRingBuffer(&data->buffer, false);
 -             return true;
 -         }
 - 
 -         return false;
 -     }
 - 
 -     PluginBridgeOpcode readOpcode()
 -     {
 -         return static_cast<PluginBridgeOpcode>(readInt());
 -     }
 - 
 -     CARLA_DECLARE_NON_COPY_STRUCT(BridgeControl)
 - };
 - 
 - struct BridgeTime {
 -     CarlaString filename;
 -     BridgeTimeInfo* info;
 -     char shm[32];
 - 
 -     BridgeTime()
 -         : info(nullptr)
 -     {
 -         carla_zeroChar(shm, 32);
 -         jackbridge_shm_init(shm);
 -     }
 - 
 -     ~BridgeTime()
 -     {
 -         // should be cleared by now
 -         CARLA_ASSERT(info == nullptr);
 - 
 -         clear();
 -     }
 - 
 -     bool attach()
 -     {
 -         jackbridge_shm_attach(shm, filename);
 - 
 -         return jackbridge_shm_is_valid(shm);
 -     }
 - 
 -     void clear()
 -     {
 -         filename.clear();
 - 
 -         info = nullptr;
 - 
 -         if (jackbridge_shm_is_valid(shm))
 -             jackbridge_shm_close(shm);
 -     }
 - 
 -     bool mapData()
 -     {
 -         CARLA_ASSERT(info == nullptr);
 - 
 -         return jackbridge_shm_map2<BridgeTimeInfo>(shm, info);
 -     }
 - 
 -     CARLA_DECLARE_NON_COPY_STRUCT(BridgeTime)
 - };
 - 
 - // -------------------------------------------------------------------
 - 
 - class CarlaEngineBridge : public CarlaEngine,
 -                           public CarlaThread
 - {
 - public:
 -     CarlaEngineBridge(const char* const audioBaseName, const char* const controlBaseName, const char* const timeBaseName)
 -         : CarlaEngine(),
 -           CarlaThread("CarlaEngineBridge"),
 -           fIsRunning(false)
 -     {
 -         carla_debug("CarlaEngineBridge::CarlaEngineBridge()");
 - 
 -         fShmAudioPool.filename  = "/carla-bridge_shm_";
 -         fShmAudioPool.filename += audioBaseName;
 - 
 -         fShmControl.filename  = "/carla-bridge_shc_";
 -         fShmControl.filename += controlBaseName;
 - 
 -         fShmTime.filename  = "/carla-bridge_sht_";
 -         fShmTime.filename += timeBaseName;
 -     }
 - 
 -     ~CarlaEngineBridge() noexcept override
 -     {
 -         carla_debug("CarlaEngineBridge::~CarlaEngineBridge()");
 -     }
 - 
 -     // -------------------------------------
 -     // CarlaEngine virtual calls
 - 
 -     bool init(const char* const clientName) override
 -     {
 -         carla_debug("CarlaEngineBridge::init(\"%s\")", clientName);
 - 
 -         // SHM Audio Pool
 -         {
 -             if (! fShmAudioPool.attach())
 -             {
 -                 carla_stdout("Failed to open or create shared memory file #1");
 -                 return false;
 -             }
 -         }
 - 
 -         // SHM Control
 -         {
 -             if (! fShmControl.attach())
 -             {
 -                 carla_stdout("Failed to open or create shared memory file #2");
 -                 // clear
 -                 fShmAudioPool.clear();
 -                 return false;
 -             }
 - 
 -             if (! fShmControl.mapData())
 -             {
 -                 carla_stdout("Failed to map shared memory file #2");
 -                 // clear
 -                 fShmControl.clear();
 -                 fShmAudioPool.clear();
 -                 return false;
 -             }
 -         }
 - 
 -         // SHM Transport
 -         {
 -             if (! fShmTime.attach())
 -             {
 -                 carla_stdout("Failed to open or create shared memory file #3");
 -                 // clear
 -                 fShmControl.clear();
 -                 fShmAudioPool.clear();
 -                 return false;
 -             }
 - 
 -             if (! fShmTime.mapData())
 -             {
 -                 carla_stdout("Failed to map shared memory file #3");
 -                 // clear
 -                 fShmTime.clear();
 -                 fShmControl.clear();
 -                 fShmAudioPool.clear();
 -                 return false;
 -             }
 -         }
 - 
 -         // Read values from memory
 -         PluginBridgeOpcode opcode;
 - 
 -         opcode = fShmControl.readOpcode();
 -         CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeOpcodeNull, opcode);
 - 
 -         const uint32_t shmStructSize = fShmControl.readUInt();
 -         CARLA_SAFE_ASSERT_INT2(shmStructSize == sizeof(BridgeShmControl), shmStructSize, sizeof(BridgeShmControl));
 - 
 -         const uint32_t timeStructSize = fShmControl.readUInt();
 -         CARLA_SAFE_ASSERT_INT2(timeStructSize == sizeof(BridgeTimeInfo), timeStructSize, sizeof(BridgeTimeInfo));
 - 
 -         opcode = fShmControl.readOpcode();
 -         CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeOpcodeSetBufferSize, opcode);
 -         pData->bufferSize = fShmControl.readUInt();
 - 
 -         opcode = fShmControl.readOpcode();
 -         CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeOpcodeSetSampleRate, opcode);
 -         pData->sampleRate = fShmControl.readFloat();
 - 
 -         carla_stdout("Carla Client Info:");
 -         carla_stdout("  BufferSize: %i", pData->bufferSize);
 -         carla_stdout("  SampleRate: %f", pData->sampleRate);
 -         carla_stdout("  sizeof(BridgeShmControl): %i/" P_SIZE, shmStructSize,  sizeof(BridgeShmControl));
 -         carla_stdout("  sizeof(BridgeTimeInfo):   %i/" P_SIZE, timeStructSize, sizeof(BridgeTimeInfo));
 - 
 -         CarlaThread::startThread();
 -         CarlaEngine::init(clientName);
 -         return true;
 -     }
 - 
 -     bool close() override
 -     {
 -         carla_debug("CarlaEnginePlugin::close()");
 -         CarlaEngine::close();
 - 
 -         CarlaThread::stopThread(6000);
 - 
 -         fShmTime.clear();
 -         fShmControl.clear();
 -         fShmAudioPool.clear();
 - 
 -         return true;
 -     }
 - 
 -     bool isRunning() const noexcept override
 -     {
 -         return fIsRunning;
 -     }
 - 
 -     bool isOffline() const noexcept override
 -     {
 -         return false;
 -     }
 - 
 -     EngineType getType() const noexcept override
 -     {
 -         return kEngineTypeBridge;
 -     }
 - 
 -     const char* getCurrentDriverName() const noexcept
 -     {
 -         return "Bridge";
 -     }
 - 
 -     // -------------------------------------
 -     // CarlaThread virtual calls
 - 
 -     void run() override
 -     {
 -         fIsRunning = true;
 - 
 -         // TODO - set RT permissions
 -         carla_debug("CarlaEngineBridge::run()");
 - 
 -         for (; ! shouldThreadExit();)
 -         {
 -             if (! jackbridge_sem_timedwait(&fShmControl.data->runServer, 5))
 -             {
 -                 if (errno == ETIMEDOUT)
 -                 {
 -                     fIsRunning = false;
 -                     signalThreadShouldExit();
 -                     return;
 -                 }
 -             }
 - 
 -             for (; fShmControl.isDataAvailable();)
 -             {
 -                 const PluginBridgeOpcode opcode(fShmControl.readOpcode());
 - 
 -                 if (opcode != kPluginBridgeOpcodeProcess) {
 -                     carla_debug("CarlaEngineBridge::run() - got opcode: %s", PluginBridgeOpcode2str(opcode));
 -                 }
 - 
 -                 switch (opcode)
 -                 {
 -                 case kPluginBridgeOpcodeNull:
 -                     break;
 - 
 -                 case kPluginBridgeOpcodeSetAudioPool: {
 -                     const int64_t poolSize(fShmControl.readLong());
 -                     CARLA_SAFE_ASSERT_BREAK(poolSize > 0);
 -                     fShmAudioPool.data = (float*)jackbridge_shm_map(fShmAudioPool.shm, static_cast<size_t>(poolSize));
 -                     break;
 -                 }
 - 
 -                 case kPluginBridgeOpcodeSetBufferSize: {
 -                     const uint32_t bufferSize(fShmControl.readUInt());
 -                     bufferSizeChanged(bufferSize);
 -                     break;
 -                 }
 - 
 -                 case kPluginBridgeOpcodeSetSampleRate: {
 -                     const float sampleRate(fShmControl.readFloat());
 -                     sampleRateChanged(sampleRate);
 -                     break;
 -                 }
 - 
 -                 case kPluginBridgeOpcodeSetParameterRt:
 -                 case kPluginBridgeOpcodeSetParameterNonRt:{
 -                     const int32_t index(fShmControl.readInt());
 -                     const float   value(fShmControl.readFloat());
 - 
 -                     CarlaPlugin* const plugin(getPluginUnchecked(0));
 - 
 -                     if (plugin != nullptr && plugin->isEnabled())
 -                     {
 -                         if (index == PARAMETER_ACTIVE)
 -                         {
 -                             plugin->setActive((value > 0.0f), false, false);
 -                             break;
 -                         }
 - 
 -                         CARLA_SAFE_ASSERT_BREAK(index >= 0);
 - 
 -                         plugin->setParameterValue(static_cast<uint32_t>(index), value, (opcode == kPluginBridgeOpcodeSetParameterNonRt), false, false);
 -                     }
 -                     break;
 -                 }
 - 
 -                 case kPluginBridgeOpcodeSetProgram: {
 -                     const int32_t index(fShmControl.readInt());
 -                     CARLA_SAFE_ASSERT_BREAK(index >= 0);
 - 
 -                     CarlaPlugin* const plugin(getPluginUnchecked(0));
 - 
 -                     if (plugin != nullptr && plugin->isEnabled())
 -                     {
 -                         plugin->setProgram(index, false, false, false);
 -                         //plugin->postponeRtEvent(kPluginPostRtEventProgramChange, index, 0, 0.0f);
 -                     }
 -                     break;
 -                 }
 - 
 -                 case kPluginBridgeOpcodeSetMidiProgram: {
 -                     const int32_t index(fShmControl.readInt());
 -                     CARLA_SAFE_ASSERT_BREAK(index >= 0);
 - 
 -                     CarlaPlugin* const plugin(getPluginUnchecked(0));
 - 
 -                     if (plugin != nullptr && plugin->isEnabled())
 -                     {
 -                         plugin->setMidiProgram(index, false, false, false);
 -                         //plugin->postponeRtEvent(kPluginPostRtEventMidiProgramChange, index, 0, 0.0f);
 -                     }
 - 
 -                     break;
 -                 }
 - 
 -                 case kPluginBridgeOpcodeMidiEvent: {
 -                     const int64_t time(fShmControl.readLong());
 -                     const int32_t size(fShmControl.readInt());
 -                     CARLA_SAFE_ASSERT_BREAK(time >= 0);
 -                     CARLA_SAFE_ASSERT_BREAK(size > 0 && size <= 4);
 - 
 -                     uint8_t data[size];
 - 
 -                     for (int32_t i=0; i < size; ++i)
 -                         data[i] = static_cast<uint8_t>(fShmControl.readChar());
 - 
 -                     CARLA_SAFE_ASSERT_BREAK(pData->events.in != nullptr);
 - 
 -                     for (ushort i=0; i < kMaxEngineEventInternalCount; ++i)
 -                     {
 -                         EngineEvent& event(pData->events.in[i]);
 - 
 -                         if (event.type != kEngineEventTypeNull)
 -                             continue;
 - 
 -                         event.fillFromMidiData(static_cast<uint8_t>(size), data);
 -                         break;
 -                     }
 -                     break;
 -                 }
 - 
 -                 case kPluginBridgeOpcodeProcess: {
 -                     CARLA_SAFE_ASSERT_BREAK(fShmAudioPool.data != nullptr);
 -                     CarlaPlugin* const plugin(getPluginUnchecked(0));
 - 
 -                     BridgeTimeInfo* const bridgeInfo(fShmTime.info);
 -                     CARLA_SAFE_ASSERT_BREAK(bridgeInfo != nullptr);
 - 
 -                     if (plugin != nullptr && plugin->isEnabled() && plugin->tryLock(true)) // FIXME - always lock?
 -                     {
 -                         const uint32_t inCount(plugin->getAudioInCount());
 -                         const uint32_t outCount(plugin->getAudioOutCount());
 - 
 -                         float* inBuffer[inCount];
 -                         float* outBuffer[outCount];
 - 
 -                         for (uint32_t i=0; i < inCount; ++i)
 -                             inBuffer[i] = fShmAudioPool.data + i*pData->bufferSize;
 -                         for (uint32_t i=0; i < outCount; ++i)
 -                             outBuffer[i] = fShmAudioPool.data + (i+inCount)*pData->bufferSize;
 - 
 -                         EngineTimeInfo& timeInfo(pData->timeInfo);
 - 
 -                         timeInfo.playing = bridgeInfo->playing;
 -                         timeInfo.frame   = bridgeInfo->frame;
 -                         timeInfo.usecs   = bridgeInfo->usecs;
 -                         timeInfo.valid   = bridgeInfo->valid;
 - 
 -                         if (timeInfo.valid & EngineTimeInfo::kValidBBT)
 -                         {
 -                             timeInfo.bbt.bar  = bridgeInfo->bar;
 -                             timeInfo.bbt.beat = bridgeInfo->beat;
 -                             timeInfo.bbt.tick = bridgeInfo->tick;
 - 
 -                             timeInfo.bbt.beatsPerBar = bridgeInfo->beatsPerBar;
 -                             timeInfo.bbt.beatType    = bridgeInfo->beatType;
 - 
 -                             timeInfo.bbt.ticksPerBeat   = bridgeInfo->ticksPerBeat;
 -                             timeInfo.bbt.beatsPerMinute = bridgeInfo->beatsPerMinute;
 -                             timeInfo.bbt.barStartTick   = bridgeInfo->barStartTick;
 -                         }
 - 
 -                         plugin->initBuffers();
 -                         plugin->process(inBuffer, outBuffer, 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 kPluginBridgeOpcodeQuit:
 -                     signalThreadShouldExit();
 -                     fIsRunning = false;
 -                     break;
 -                 }
 -             }
 - 
 -             if (! jackbridge_sem_post(&fShmControl.data->runClient))
 -                 carla_stderr2("Could not post to semaphore");
 -         }
 - 
 -         fIsRunning = false;
 -     }
 - 
 - private:
 -     BridgeAudioPool fShmAudioPool;
 -     BridgeControl   fShmControl;
 -     BridgeTime      fShmTime;
 - 
 -     volatile bool fIsRunning;
 - 
 -     CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineBridge)
 - };
 - 
 - // -----------------------------------------
 - 
 - CarlaEngine* CarlaEngine::newBridge(const char* const audioBaseName, const char* const controlBaseName, const char* const timeBaseName)
 - {
 -     return new CarlaEngineBridge(audioBaseName, controlBaseName, timeBaseName);
 - }
 - 
 - CARLA_BACKEND_END_NAMESPACE
 - 
 - // -----------------------------------------------------------------------
 - // Extra stuff for linking purposes
 - 
 - CARLA_BACKEND_START_NAMESPACE
 - 
 - // CarlaEngine*       CarlaEngine::newRtAudio(const AudioApi) { return nullptr; }
 - // unsigned int       CarlaEngine::getRtAudioApiCount() { return 0; }
 - // const char*        CarlaEngine::getRtAudioApiName(const unsigned int) { return nullptr; }
 - // const char* const* CarlaEngine::getRtAudioApiDeviceNames(const unsigned int) { return nullptr; }
 - // const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const unsigned int, const char* const) { return nullptr; }
 - //
 - // #ifdef HAVE_JUCE
 - // CarlaEngine*       CarlaEngine::newJuce(const AudioApi) { return nullptr; }
 - // unsigned int       CarlaEngine::getJuceApiCount() { return 0; }
 - // const char*        CarlaEngine::getJuceApiName(const unsigned int) { return nullptr; }
 - // const char* const* CarlaEngine::getJuceApiDeviceNames(const unsigned int) { return nullptr; }
 - // const EngineDriverDeviceInfo* CarlaEngine::getJuceDeviceInfo(const unsigned int, const char* const) { 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(){}
 - 
 - // -----------------------------------------------------------------------
 
 
  |