@@ -619,14 +619,19 @@ public: | |||||
EngineProcessMode getProcessMode() const noexcept; | EngineProcessMode getProcessMode() const noexcept; | ||||
/*! | /*! | ||||
* Get an input port name. | |||||
* Get an audio port name. | |||||
*/ | */ | ||||
const char* getAudioInputPortName(const uint index) const noexcept; | |||||
const char* getAudioPortName(const bool isInput, const uint index) const noexcept; | |||||
/*! | /*! | ||||
* Get an input port name. | |||||
* Get a CV port name. | |||||
*/ | */ | ||||
const char* getAudioOutputPortName(const uint index) const noexcept; | |||||
const char* getCVPortName(const bool isInput, const uint index) const noexcept; | |||||
/*! | |||||
* Get an event port name. | |||||
*/ | |||||
const char* getEventPortName(const bool isInput, const uint index) const noexcept; | |||||
#ifndef DOXYGEN | #ifndef DOXYGEN | ||||
protected: | protected: | ||||
@@ -636,7 +641,10 @@ protected: | |||||
struct ProtectedData; | struct ProtectedData; | ||||
ProtectedData* const pData; | ProtectedData* const pData; | ||||
void _addName(const bool, const char* const); | |||||
void _addAudioPortName(const bool, const char* const); | |||||
void _addCVPortName(const bool, const char* const); | |||||
void _addEventPortName(const bool, const char* const); | |||||
const char* _getUniquePortName(const char* const); | |||||
CARLA_DECLARE_NON_COPY_CLASS(CarlaEngineClient) | CARLA_DECLARE_NON_COPY_CLASS(CarlaEngineClient) | ||||
#endif | #endif | ||||
@@ -855,12 +855,12 @@ const char* CarlaEngine::getUniquePluginName(const char* const name) const | |||||
// Check if string has already been modified | // Check if string has already been modified | ||||
{ | { | ||||
const size_t len(sname.length()); | |||||
const std::size_t len(sname.length()); | |||||
// 1 digit, ex: " (2)" | // 1 digit, ex: " (2)" | ||||
if (sname[len-4] == ' ' && sname[len-3] == '(' && sname.isDigit(len-2) && sname[len-1] == ')') | if (sname[len-4] == ' ' && sname[len-3] == '(' && sname.isDigit(len-2) && sname[len-1] == ')') | ||||
{ | { | ||||
int number = sname[len-2] - '0'; | |||||
const int number = sname[len-2] - '0'; | |||||
if (number == 9) | if (number == 9) | ||||
{ | { | ||||
@@ -17,6 +17,7 @@ | |||||
#include "CarlaEngineUtils.hpp" | #include "CarlaEngineUtils.hpp" | ||||
#include "CarlaString.hpp" | |||||
#include "CarlaStringList.hpp" | #include "CarlaStringList.hpp" | ||||
CARLA_BACKEND_START_NAMESPACE | CARLA_BACKEND_START_NAMESPACE | ||||
@@ -32,13 +33,21 @@ struct CarlaEngineClient::ProtectedData { | |||||
CarlaStringList audioInList; | CarlaStringList audioInList; | ||||
CarlaStringList audioOutList; | CarlaStringList audioOutList; | ||||
CarlaStringList cvInList; | |||||
CarlaStringList cvOutList; | |||||
CarlaStringList eventInList; | |||||
CarlaStringList eventOutList; | |||||
ProtectedData(const CarlaEngine& eng) | |||||
ProtectedData(const CarlaEngine& eng) noexcept | |||||
: engine(eng), | : engine(eng), | ||||
active(false), | active(false), | ||||
latency(0), | latency(0), | ||||
audioInList(), | audioInList(), | ||||
audioOutList() {} | |||||
audioOutList(), | |||||
cvInList(), | |||||
cvOutList(), | |||||
eventInList(), | |||||
eventOutList() {} | |||||
#ifdef CARLA_PROPER_CPP11_SUPPORT | #ifdef CARLA_PROPER_CPP11_SUPPORT | ||||
ProtectedData() = delete; | ProtectedData() = delete; | ||||
@@ -101,17 +110,18 @@ CarlaEnginePort* CarlaEngineClient::addPort(const EnginePortType portType, const | |||||
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr); | CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr); | ||||
carla_debug("CarlaEngineClient::addPort(%i:%s, \"%s\", %s)", portType, EnginePortType2Str(portType), name, bool2str(isInput)); | carla_debug("CarlaEngineClient::addPort(%i:%s, \"%s\", %s)", portType, EnginePortType2Str(portType), name, bool2str(isInput)); | ||||
_addName(isInput, name); | |||||
switch (portType) | switch (portType) | ||||
{ | { | ||||
case kEnginePortTypeNull: | case kEnginePortTypeNull: | ||||
break; | break; | ||||
case kEnginePortTypeAudio: | case kEnginePortTypeAudio: | ||||
_addAudioPortName(isInput, name); | |||||
return new CarlaEngineAudioPort(*this, isInput); | return new CarlaEngineAudioPort(*this, isInput); | ||||
case kEnginePortTypeCV: | case kEnginePortTypeCV: | ||||
_addCVPortName(isInput, name); | |||||
return new CarlaEngineCVPort(*this, isInput); | return new CarlaEngineCVPort(*this, isInput); | ||||
case kEnginePortTypeEvent: | case kEnginePortTypeEvent: | ||||
_addEventPortName(isInput, name); | |||||
return new CarlaEngineEventPort(*this, isInput); | return new CarlaEngineEventPort(*this, isInput); | ||||
} | } | ||||
@@ -129,28 +139,128 @@ EngineProcessMode CarlaEngineClient::getProcessMode() const noexcept | |||||
return pData->engine.getProccessMode(); | return pData->engine.getProccessMode(); | ||||
} | } | ||||
const char* CarlaEngineClient::getAudioInputPortName(const uint index) const noexcept | |||||
const char* CarlaEngineClient::getAudioPortName(const bool isInput, const uint index) const noexcept | |||||
{ | |||||
CarlaStringList& portList(isInput ? pData->audioInList : pData->audioOutList); | |||||
CARLA_SAFE_ASSERT_RETURN(index < portList.count(), nullptr); | |||||
return portList.getAt(index, nullptr); | |||||
} | |||||
const char* CarlaEngineClient::getCVPortName(const bool isInput, const uint index) const noexcept | |||||
{ | |||||
CarlaStringList& portList(isInput ? pData->cvInList : pData->cvOutList); | |||||
CARLA_SAFE_ASSERT_RETURN(index < portList.count(), nullptr); | |||||
return portList.getAt(index, nullptr); | |||||
} | |||||
const char* CarlaEngineClient::getEventPortName(const bool isInput, const uint index) const noexcept | |||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(index < pData->audioInList.count(), nullptr); | |||||
CarlaStringList& portList(isInput ? pData->eventInList : pData->eventOutList); | |||||
CARLA_SAFE_ASSERT_RETURN(index < portList.count(), nullptr); | |||||
return pData->audioInList.getAt(index, nullptr); | |||||
return portList.getAt(index, nullptr); | |||||
} | } | ||||
const char* CarlaEngineClient::getAudioOutputPortName(const uint index) const noexcept | |||||
void CarlaEngineClient::_addAudioPortName(const bool isInput, const char* const name) | |||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(index < pData->audioOutList.count(), nullptr); | |||||
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',); | |||||
return pData->audioOutList.getAt(index, nullptr); | |||||
CarlaStringList& portList(isInput ? pData->audioInList : pData->audioOutList); | |||||
portList.append(name); | |||||
} | } | ||||
void CarlaEngineClient::_addName(const bool isInput, const char* const name) | |||||
void CarlaEngineClient::_addCVPortName(const bool isInput, const char* const name) | |||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',); | CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',); | ||||
if (isInput) | |||||
pData->audioInList.append(name); | |||||
else | |||||
pData->audioOutList.append(name); | |||||
CarlaStringList& portList(isInput ? pData->cvInList : pData->cvOutList); | |||||
portList.append(name); | |||||
} | |||||
void CarlaEngineClient::_addEventPortName(const bool isInput, const char* const name) | |||||
{ | |||||
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',); | |||||
CarlaStringList& portList(isInput ? pData->eventInList : pData->eventOutList); | |||||
portList.append(name); | |||||
} | |||||
static void getUniquePortName(CarlaString& sname, const CarlaStringList& list) | |||||
{ | |||||
for (CarlaStringList::Itenerator it = list.begin(); it.valid(); it.next()) | |||||
{ | |||||
const char* const portName(it.getValue(nullptr)); | |||||
CARLA_SAFE_ASSERT_CONTINUE(portName != nullptr && portName[0] != '\0'); | |||||
// Check if unique name doesn't exist | |||||
if (sname != portName) | |||||
continue; | |||||
// Check if string has already been modified | |||||
{ | |||||
const std::size_t len(sname.length()); | |||||
// 1 digit, ex: " (2)" | |||||
if (sname[len-4] == ' ' && sname[len-3] == '(' && sname.isDigit(len-2) && sname[len-1] == ')') | |||||
{ | |||||
const int number = sname[len-2] - '0'; | |||||
if (number == 9) | |||||
{ | |||||
// next number is 10, 2 digits | |||||
sname.truncate(len-4); | |||||
sname += " (10)"; | |||||
//sname.replace(" (9)", " (10)"); | |||||
} | |||||
else | |||||
sname[len-2] = char('0' + number + 1); | |||||
continue; | |||||
} | |||||
// 2 digits, ex: " (11)" | |||||
if (sname[len-5] == ' ' && sname[len-4] == '(' && sname.isDigit(len-3) && sname.isDigit(len-2) && sname[len-1] == ')') | |||||
{ | |||||
char n2 = sname[len-2]; | |||||
char n3 = sname[len-3]; | |||||
if (n2 == '9') | |||||
{ | |||||
n2 = '0'; | |||||
n3 = static_cast<char>(n3 + 1); | |||||
} | |||||
else | |||||
n2 = static_cast<char>(n2 + 1); | |||||
sname[len-2] = n2; | |||||
sname[len-3] = n3; | |||||
continue; | |||||
} | |||||
} | |||||
// Modify string if not | |||||
sname += " (2)"; | |||||
} | |||||
} | |||||
const char* CarlaEngineClient::_getUniquePortName(const char* const name) | |||||
{ | |||||
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr); | |||||
CarlaString sname; | |||||
sname = name; | |||||
getUniquePortName(sname, pData->audioInList); | |||||
getUniquePortName(sname, pData->audioOutList); | |||||
getUniquePortName(sname, pData->cvInList); | |||||
getUniquePortName(sname, pData->cvOutList); | |||||
getUniquePortName(sname, pData->eventInList); | |||||
getUniquePortName(sname, pData->eventOutList); | |||||
return sname.dup(); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -1069,14 +1069,14 @@ public: | |||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(i >= 0, String()); | CARLA_SAFE_ASSERT_RETURN(i >= 0, String()); | ||||
CarlaEngineClient* const client(fPlugin->getEngineClient()); | CarlaEngineClient* const client(fPlugin->getEngineClient()); | ||||
return client->getAudioInputPortName(static_cast<uint>(i)); | |||||
return client->getAudioPortName(true, static_cast<uint>(i)); | |||||
} | } | ||||
const String getOutputChannelName(int i) const override | const String getOutputChannelName(int i) const override | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(i >= 0, String()); | CARLA_SAFE_ASSERT_RETURN(i >= 0, String()); | ||||
CarlaEngineClient* const client(fPlugin->getEngineClient()); | CarlaEngineClient* const client(fPlugin->getEngineClient()); | ||||
return client->getAudioOutputPortName(static_cast<uint>(i)); | |||||
return client->getAudioPortName(false, static_cast<uint>(i)); | |||||
} | } | ||||
void prepareToPlay(double, int) override {} | void prepareToPlay(double, int) override {} | ||||
@@ -514,46 +514,53 @@ public: | |||||
carla_debug("CarlaEngineJackClient::addPort(%i:%s, \"%s\", %s)", portType, EnginePortType2Str(portType), name, bool2str(isInput)); | carla_debug("CarlaEngineJackClient::addPort(%i:%s, \"%s\", %s)", portType, EnginePortType2Str(portType), name, bool2str(isInput)); | ||||
jack_port_t* jackPort = nullptr; | jack_port_t* jackPort = nullptr; | ||||
const char* realName = name; | |||||
// Create JACK port first, if needed | // Create JACK port first, if needed | ||||
if (fUseClient && fJackClient != nullptr) | if (fUseClient && fJackClient != nullptr) | ||||
{ | { | ||||
realName = _getUniquePortName(name); | |||||
switch (portType) | switch (portType) | ||||
{ | { | ||||
case kEnginePortTypeNull: | case kEnginePortTypeNull: | ||||
break; | break; | ||||
case kEnginePortTypeAudio: | case kEnginePortTypeAudio: | ||||
jackPort = jackbridge_port_register(fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); | |||||
jackPort = jackbridge_port_register(fJackClient, realName, JACK_DEFAULT_AUDIO_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); | |||||
break; | break; | ||||
case kEnginePortTypeCV: | case kEnginePortTypeCV: | ||||
jackPort = jackbridge_port_register(fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); | |||||
jackPort = jackbridge_port_register(fJackClient, realName, JACK_DEFAULT_AUDIO_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); | |||||
break; | break; | ||||
case kEnginePortTypeEvent: | case kEnginePortTypeEvent: | ||||
jackPort = jackbridge_port_register(fJackClient, name, JACK_DEFAULT_MIDI_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); | |||||
jackPort = jackbridge_port_register(fJackClient, realName, JACK_DEFAULT_MIDI_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); | |||||
break; | break; | ||||
} | } | ||||
CARLA_SAFE_ASSERT_RETURN(jackPort != nullptr, nullptr); | CARLA_SAFE_ASSERT_RETURN(jackPort != nullptr, nullptr); | ||||
} | } | ||||
_addName(isInput, name); | |||||
// Create Engine port | // Create Engine port | ||||
switch (portType) | switch (portType) | ||||
{ | { | ||||
case kEnginePortTypeNull: | case kEnginePortTypeNull: | ||||
break; | break; | ||||
case kEnginePortTypeAudio: { | case kEnginePortTypeAudio: { | ||||
_addAudioPortName(isInput, realName); | |||||
if (realName != name) delete[] realName; | |||||
CarlaEngineJackAudioPort* const enginePort(new CarlaEngineJackAudioPort(*this, isInput, fJackClient, jackPort, this)); | CarlaEngineJackAudioPort* const enginePort(new CarlaEngineJackAudioPort(*this, isInput, fJackClient, jackPort, this)); | ||||
fAudioPorts.append(enginePort); | fAudioPorts.append(enginePort); | ||||
return enginePort; | return enginePort; | ||||
} | } | ||||
case kEnginePortTypeCV: { | case kEnginePortTypeCV: { | ||||
_addCVPortName(isInput, realName); | |||||
if (realName != name) delete[] realName; | |||||
CarlaEngineJackCVPort* const enginePort(new CarlaEngineJackCVPort(*this, isInput, fJackClient, jackPort, this)); | CarlaEngineJackCVPort* const enginePort(new CarlaEngineJackCVPort(*this, isInput, fJackClient, jackPort, this)); | ||||
fCVPorts.append(enginePort); | fCVPorts.append(enginePort); | ||||
return enginePort; | return enginePort; | ||||
} | } | ||||
case kEnginePortTypeEvent: { | case kEnginePortTypeEvent: { | ||||
_addEventPortName(isInput, realName); | |||||
if (realName != name) delete[] realName; | |||||
CarlaEngineJackEventPort* const enginePort(new CarlaEngineJackEventPort(*this, isInput, fJackClient, jackPort, this)); | CarlaEngineJackEventPort* const enginePort(new CarlaEngineJackEventPort(*this, isInput, fJackClient, jackPort, this)); | ||||
fEventPorts.append(enginePort); | fEventPorts.append(enginePort); | ||||
return enginePort; | return enginePort; | ||||