| @@ -82,11 +82,17 @@ enum EnginePortType { | |||
| */ | |||
| kEnginePortTypeAudio = 1, | |||
| /*! | |||
| * CV port type. | |||
| * \see CarlaEngineCVPort | |||
| */ | |||
| kEnginePortTypeCV = 2, | |||
| /*! | |||
| * Event port type. | |||
| ** \see CarlaEngineEventPort | |||
| */ | |||
| kEnginePortTypeEvent = 2 | |||
| kEnginePortTypeEvent = 3 | |||
| }; | |||
| /*! | |||
| @@ -478,6 +484,66 @@ protected: | |||
| // ----------------------------------------------------------------------- | |||
| /*! | |||
| * Carla Engine CV port. | |||
| */ | |||
| class CarlaEngineCVPort : public CarlaEnginePort | |||
| { | |||
| public: | |||
| /*! | |||
| * The contructor.\n | |||
| * All constructor parameters are constant and will never change in the lifetime of the port. | |||
| */ | |||
| CarlaEngineCVPort(const bool isInput, const ProcessMode processMode, const uint32_t bufferSize); | |||
| /*! | |||
| * The destructor. | |||
| */ | |||
| virtual ~CarlaEngineCVPort() override; | |||
| /*! | |||
| * Get the type of the port, in this case CarlaEnginePortTypeAudio. | |||
| */ | |||
| EnginePortType type() const override | |||
| { | |||
| return kEnginePortTypeCV; | |||
| } | |||
| /*! | |||
| * Initialize the port's internal buffer for \a engine. | |||
| */ | |||
| virtual void initBuffer(CarlaEngine* const engine) override; | |||
| /*! | |||
| * Write buffer.\n | |||
| * This is a handy function for the JACK engine only, where we need to write buffer to output ports. | |||
| */ | |||
| virtual void writeBuffer(CarlaEngine* const engine); | |||
| /*! | |||
| * Set a new buffer size. | |||
| */ | |||
| void setBufferSize(const uint32_t bufferSize); | |||
| /*! | |||
| * Direct access to the port's audio buffer. | |||
| */ | |||
| float* getBuffer() const | |||
| { | |||
| return fBuffer; | |||
| } | |||
| #ifndef DOXYGEN | |||
| protected: | |||
| float* fBuffer; | |||
| uint32_t fBufferSize; | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineCVPort) | |||
| #endif | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| /*! | |||
| * Carla Engine Event port. | |||
| */ | |||
| @@ -581,7 +647,7 @@ public: | |||
| * All constructor parameters are constant and will never change in the lifetime of the client.\n | |||
| * Client starts in deactivated state. | |||
| */ | |||
| CarlaEngineClient(const CarlaBackend::EngineType engineType, const CarlaBackend::ProcessMode processMode); | |||
| CarlaEngineClient(const CarlaEngine& engine); | |||
| /*! | |||
| * The destructor. | |||
| @@ -630,8 +696,7 @@ public: | |||
| #ifndef DOXYGEN | |||
| protected: | |||
| const EngineType kEngineType; | |||
| const ProcessMode kProcessMode; | |||
| const CarlaEngine& kEngine; | |||
| bool fActive; | |||
| uint32_t fLatency; | |||
| @@ -114,6 +114,65 @@ void CarlaEngineAudioPort::initBuffer(CarlaEngine* const) | |||
| carla_zeroFloat(fBuffer, PATCHBAY_BUFFER_SIZE); | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // Carla Engine CV port | |||
| CarlaEngineCVPort::CarlaEngineCVPort(const bool isInput, const ProcessMode processMode, const uint32_t bufferSize) | |||
| : CarlaEnginePort(isInput, processMode), | |||
| fBuffer(new float[bufferSize]), | |||
| fBufferSize(bufferSize) | |||
| { | |||
| carla_debug("CarlaEngineCVPort::CarlaEngineCVPort(%s, %s)", bool2str(isInput), ProcessMode2Str(processMode)); | |||
| } | |||
| CarlaEngineCVPort::~CarlaEngineCVPort() | |||
| { | |||
| carla_debug("CarlaEngineCVPort::~CarlaEngineCVPort()"); | |||
| CARLA_ASSERT(fBuffer != nullptr); | |||
| if (fBuffer != nullptr) | |||
| { | |||
| delete[] fBuffer; | |||
| fBuffer = nullptr; | |||
| } | |||
| } | |||
| void CarlaEngineCVPort::initBuffer(CarlaEngine* const engine) | |||
| { | |||
| CARLA_ASSERT(engine != nullptr && engine->getBufferSize() == fBufferSize); | |||
| if (! kIsInput) | |||
| carla_zeroFloat(fBuffer, fBufferSize); | |||
| } | |||
| void CarlaEngineCVPort::writeBuffer(CarlaEngine* const engine) | |||
| { | |||
| CARLA_ASSERT(! kIsInput); | |||
| CARLA_ASSERT(engine != nullptr); | |||
| if (kIsInput) | |||
| return; | |||
| if (engine == nullptr) | |||
| return; | |||
| CARLA_ASSERT(engine->getBufferSize() == fBufferSize); | |||
| } | |||
| void CarlaEngineCVPort::setBufferSize(const uint32_t bufferSize) | |||
| { | |||
| CARLA_ASSERT(fBuffer != nullptr); | |||
| if (fBufferSize == bufferSize) | |||
| return; | |||
| if (fBuffer != nullptr) | |||
| delete[] fBuffer; | |||
| fBuffer = new float[bufferSize]; | |||
| fBufferSize = bufferSize; | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // Carla Engine Event port | |||
| @@ -288,14 +347,12 @@ void CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t cha | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // Carla Engine client (Abstract) | |||
| CarlaEngineClient::CarlaEngineClient(const EngineType engineType, const ProcessMode processMode) | |||
| : kEngineType(engineType), | |||
| kProcessMode(processMode), | |||
| CarlaEngineClient::CarlaEngineClient(const CarlaEngine& engine) | |||
| : kEngine(engine), | |||
| fActive(false), | |||
| fLatency(0) | |||
| { | |||
| CARLA_ASSERT(engineType != kEngineTypeNull); | |||
| carla_debug("CarlaEngineClient::CarlaEngineClient(%s, %s)", EngineType2Str(engineType), ProcessMode2Str(processMode)); | |||
| carla_debug("CarlaEngineClient::CarlaEngineClient(name:\"%s\")", engine.getName()); | |||
| } | |||
| CarlaEngineClient::~CarlaEngineClient() | |||
| @@ -353,9 +410,11 @@ CarlaEnginePort* CarlaEngineClient::addPort(const EnginePortType portType, const | |||
| case kEnginePortTypeNull: | |||
| break; | |||
| case kEnginePortTypeAudio: | |||
| return new CarlaEngineAudioPort(isInput, kProcessMode); | |||
| return new CarlaEngineAudioPort(isInput, kEngine.getProccessMode()); | |||
| case kEnginePortTypeCV: | |||
| return new CarlaEngineCVPort(isInput, kEngine.getProccessMode(), kEngine.getBufferSize()); | |||
| case kEnginePortTypeEvent: | |||
| return new CarlaEngineEventPort(isInput, kProcessMode); | |||
| return new CarlaEngineEventPort(isInput, kEngine.getProccessMode()); | |||
| } | |||
| carla_stderr("CarlaEngineClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput)); | |||
| @@ -663,7 +722,7 @@ void CarlaEngine::idle() | |||
| CarlaEngineClient* CarlaEngine::addClient(CarlaPlugin* const) | |||
| { | |||
| return new CarlaEngineClient(type(), fOptions.processMode); | |||
| return new CarlaEngineClient(*this); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -61,6 +61,8 @@ const char* EnginePortType2Str(const EnginePortType type) | |||
| return "kEnginePortTypeNull"; | |||
| case kEnginePortTypeAudio: | |||
| return "kEnginePortTypeAudio"; | |||
| case kEnginePortTypeCV: | |||
| return "kEnginePortTypeCV"; | |||
| case kEnginePortTypeEvent: | |||
| return "kEnginePortTypeEvent"; | |||
| } | |||
| @@ -106,6 +106,85 @@ private: | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackAudioPort) | |||
| }; | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // Carla Engine JACK-CV port | |||
| class CarlaEngineJackCVPort : public CarlaEngineCVPort | |||
| { | |||
| public: | |||
| CarlaEngineJackCVPort(const bool isInput, const ProcessMode processMode, const uint32_t bufferSize, jack_client_t* const client, jack_port_t* const port) | |||
| : CarlaEngineCVPort(isInput, processMode, bufferSize), | |||
| kClient(client), | |||
| kPort(port) | |||
| { | |||
| carla_debug("CarlaEngineJackCVPort::CarlaEngineJackCVPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port); | |||
| if (processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
| { | |||
| CARLA_ASSERT(client != nullptr && port != nullptr); | |||
| } | |||
| else | |||
| { | |||
| CARLA_ASSERT(client == nullptr && port == nullptr); | |||
| } | |||
| } | |||
| ~CarlaEngineJackCVPort() override | |||
| { | |||
| carla_debug("CarlaEngineJackCVPort::~CarlaEngineJackCVPort()"); | |||
| if (kClient != nullptr && kPort != nullptr) | |||
| jackbridge_port_unregister(kClient, kPort); | |||
| } | |||
| void initBuffer(CarlaEngine* const engine) override | |||
| { | |||
| CARLA_ASSERT(engine != nullptr); | |||
| if (engine == nullptr) | |||
| return; | |||
| if (kPort == nullptr) | |||
| return CarlaEngineCVPort::initBuffer(engine); | |||
| CARLA_ASSERT(engine->getBufferSize() == fBufferSize); | |||
| if (kIsInput) | |||
| { | |||
| float* const jackBuffer = (float*)jackbridge_port_get_buffer(kPort, fBufferSize); | |||
| carla_copyFloat(fBuffer, jackBuffer, fBufferSize); | |||
| } | |||
| else | |||
| { | |||
| carla_zeroFloat(fBuffer, fBufferSize); | |||
| } | |||
| } | |||
| void writeBuffer(CarlaEngine* const engine) override | |||
| { | |||
| CARLA_ASSERT(! kIsInput); | |||
| CARLA_ASSERT(engine != nullptr); | |||
| if (kIsInput) | |||
| return; | |||
| if (engine == nullptr) | |||
| return; | |||
| CARLA_ASSERT(engine->getBufferSize() == fBufferSize); | |||
| float* const jackBuffer = (float*)jackbridge_port_get_buffer(kPort, fBufferSize); | |||
| carla_copyFloat(jackBuffer, fBuffer, fBufferSize); | |||
| } | |||
| private: | |||
| jack_client_t* const kClient; | |||
| jack_port_t* const kPort; | |||
| friend class CarlaEngineJack; | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackCVPort) | |||
| }; | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // Carla Engine JACK-Event port | |||
| @@ -378,12 +457,12 @@ private: | |||
| class CarlaEngineJackClient : public CarlaEngineClient | |||
| { | |||
| public: | |||
| CarlaEngineJackClient(const EngineType engineType, const ProcessMode processMode, jack_client_t* const client) | |||
| : CarlaEngineClient(engineType, processMode), | |||
| CarlaEngineJackClient(const CarlaEngine& engine, jack_client_t* const client) | |||
| : CarlaEngineClient(engine), | |||
| kClient(client), | |||
| kUseClient(processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
| kUseClient(engine.getProccessMode() == PROCESS_MODE_SINGLE_CLIENT || engine.getProccessMode() == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
| { | |||
| carla_debug("CarlaEngineJackClient::CarlaEngineJackClient(%s, %s, %p)", EngineType2Str(engineType), ProcessMode2Str(processMode), client); | |||
| carla_debug("CarlaEngineJackClient::CarlaEngineJackClient(name:\"%s\", %p)", engine.getName(), client); | |||
| if (kUseClient) | |||
| { | |||
| @@ -399,7 +478,7 @@ public: | |||
| { | |||
| carla_debug("CarlaEngineClient::~CarlaEngineClient()"); | |||
| if (kProcessMode == PROCESS_MODE_MULTIPLE_CLIENTS && kClient != nullptr) | |||
| if (kEngine.getProccessMode() == PROCESS_MODE_MULTIPLE_CLIENTS && kClient != nullptr) | |||
| jackbridge_client_close(kClient); | |||
| } | |||
| @@ -407,7 +486,7 @@ public: | |||
| { | |||
| carla_debug("CarlaEngineJackClient::activate()"); | |||
| if (kProcessMode == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
| if (kEngine.getProccessMode() == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
| { | |||
| CARLA_ASSERT(kClient != nullptr && ! fActive); | |||
| @@ -422,7 +501,7 @@ public: | |||
| { | |||
| carla_debug("CarlaEngineJackClient::deactivate()"); | |||
| if (kProcessMode == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
| if (kEngine.getProccessMode() == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
| { | |||
| CARLA_ASSERT(kClient != nullptr && fActive); | |||
| @@ -469,6 +548,9 @@ public: | |||
| case kEnginePortTypeAudio: | |||
| port = jackbridge_port_register(kClient, name, JACK_DEFAULT_AUDIO_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); | |||
| break; | |||
| case kEnginePortTypeCV: | |||
| port = jackbridge_port_register(kClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsControlVoltage | (isInput ? JackPortIsInput : JackPortIsOutput), 0); | |||
| break; | |||
| case kEnginePortTypeEvent: | |||
| port = jackbridge_port_register(kClient, name, JACK_DEFAULT_MIDI_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); | |||
| break; | |||
| @@ -481,9 +563,11 @@ public: | |||
| case kEnginePortTypeNull: | |||
| break; | |||
| case kEnginePortTypeAudio: | |||
| return new CarlaEngineJackAudioPort(isInput, kProcessMode, kClient, port); | |||
| return new CarlaEngineJackAudioPort(isInput, kEngine.getProccessMode(), kClient, port); | |||
| case kEnginePortTypeCV: | |||
| return new CarlaEngineJackCVPort(isInput, kEngine.getProccessMode(), kEngine.getBufferSize(), kClient, port); | |||
| case kEnginePortTypeEvent: | |||
| return new CarlaEngineJackEventPort(isInput, kProcessMode, kClient, port); | |||
| return new CarlaEngineJackEventPort(isInput, kEngine.getProccessMode(), kClient, port); | |||
| } | |||
| carla_stderr("CarlaEngineJackClient::addPort(%s, \"%s\", %s) - invalid type", EnginePortType2Str(portType), name, bool2str(isInput)); | |||
| @@ -758,7 +842,7 @@ public: | |||
| } | |||
| #endif | |||
| return new CarlaEngineJackClient(kEngineTypeJack, fOptions.processMode, client); | |||
| return new CarlaEngineJackClient(*this, client); | |||
| } | |||
| #ifndef BUILD_BRIDGE | |||