From 33de508be240dfd0802178caca74fe1099e9b2e8 Mon Sep 17 00:00:00 2001 From: falkTX Date: Fri, 21 Jun 2013 12:55:37 +0100 Subject: [PATCH] Engine CV Port --- source/backend/CarlaEngine.hpp | 73 +++++++++++- source/backend/engine/CarlaEngine.cpp | 75 +++++++++++-- source/backend/engine/CarlaEngineInternal.hpp | 2 + source/backend/engine/CarlaEngineJack.cpp | 104 ++++++++++++++++-- 4 files changed, 232 insertions(+), 22 deletions(-) diff --git a/source/backend/CarlaEngine.hpp b/source/backend/CarlaEngine.hpp index 59b6491c9..97fa9509d 100644 --- a/source/backend/CarlaEngine.hpp +++ b/source/backend/CarlaEngine.hpp @@ -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; diff --git a/source/backend/engine/CarlaEngine.cpp b/source/backend/engine/CarlaEngine.cpp index 252e40c31..eb9730543 100644 --- a/source/backend/engine/CarlaEngine.cpp +++ b/source/backend/engine/CarlaEngine.cpp @@ -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); } // ----------------------------------------------------------------------- diff --git a/source/backend/engine/CarlaEngineInternal.hpp b/source/backend/engine/CarlaEngineInternal.hpp index 4531e8eb1..0b3f785a9 100644 --- a/source/backend/engine/CarlaEngineInternal.hpp +++ b/source/backend/engine/CarlaEngineInternal.hpp @@ -61,6 +61,8 @@ const char* EnginePortType2Str(const EnginePortType type) return "kEnginePortTypeNull"; case kEnginePortTypeAudio: return "kEnginePortTypeAudio"; + case kEnginePortTypeCV: + return "kEnginePortTypeCV"; case kEnginePortTypeEvent: return "kEnginePortTypeEvent"; } diff --git a/source/backend/engine/CarlaEngineJack.cpp b/source/backend/engine/CarlaEngineJack.cpp index 39ca4d048..8941c5e60 100644 --- a/source/backend/engine/CarlaEngineJack.cpp +++ b/source/backend/engine/CarlaEngineJack.cpp @@ -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