Browse Source

Continue rework, now working properly I think...

tags/1.9.6
falkTX 10 years ago
parent
commit
5ac57536ef
8 changed files with 499 additions and 472 deletions
  1. +5
    -7
      source/backend/CarlaEngine.hpp
  2. +6
    -2
      source/backend/engine/CarlaEngine.cpp
  3. +298
    -250
      source/backend/engine/CarlaEngineGraph.cpp
  4. +29
    -24
      source/backend/engine/CarlaEngineGraph.hpp
  5. +1
    -0
      source/backend/engine/CarlaEngineInternal.hpp
  6. +2
    -3
      source/backend/engine/CarlaEngineJack.cpp
  7. +157
    -185
      source/backend/engine/CarlaEngineRtAudio.cpp
  8. +1
    -1
      source/modules/juce_audio_devices.h

+ 5
- 7
source/backend/CarlaEngine.hpp View File

@@ -1043,19 +1043,17 @@ public:
// Helper functions // Helper functions


/*! /*!
* Return internal data, needed for EventPorts when used in Rack and Bridge modes.
* Return internal data, needed for EventPorts when used in Rack, Patchbay and Bridge modes.
* @note RT call * @note RT call
*/ */
EngineEvent* getInternalEventBuffer(const bool isInput) const noexcept; EngineEvent* getInternalEventBuffer(const bool isInput) const noexcept;


#ifndef BUILD_BRIDGE #ifndef BUILD_BRIDGE
/*! /*!
* Virtual functions for handling MIDI ports in the rack graph.
* Virtual functions for handling external graph ports.
*/ */
virtual bool connectRackMidiInPort(const char* const) { return false; }
virtual bool connectRackMidiOutPort(const char* const) { return false; }
virtual bool disconnectRackMidiInPort(const char* const) { return false; }
virtual bool disconnectRackMidiOutPort(const char* const) { return false; }
virtual bool connectExternalGraphPort(const uint, const uint, const char* const);
virtual bool disconnectExternalGraphPort(const uint, const uint, const char* const);
#endif #endif


// ------------------------------------------------------------------- // -------------------------------------------------------------------
@@ -1122,7 +1120,7 @@ protected:
* Do not free returned data. * Do not free returned data.
*/ */
virtual const char* const* getPatchbayConnections(const bool external) const; virtual const char* const* getPatchbayConnections(const bool external) const;
virtual void restorePatchbayConnection(const bool external, const char* const sourcePort, const char* const targetPort);
virtual void restorePatchbayConnection(const bool external, const char* const sourcePort, const char* const targetPort, const bool sendCallback);
#endif #endif


// ------------------------------------------------------------------- // -------------------------------------------------------------------


+ 6
- 2
source/backend/engine/CarlaEngine.cpp View File

@@ -1928,6 +1928,8 @@ bool CarlaEngine::loadProjectInternal(juce::XmlDocument& xmlDoc)
// handle connections (internal) // handle connections (internal)
if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{ {
const bool isUsingExternal(pData->graph.isUsingExternal());

for (XmlElement* elem = xmlElement->getFirstChildElement(); elem != nullptr; elem = elem->getNextElement()) for (XmlElement* elem = xmlElement->getFirstChildElement(); elem != nullptr; elem = elem->getNextElement())
{ {
const String& tagName(elem->getTagName()); const String& tagName(elem->getTagName());
@@ -1959,7 +1961,7 @@ bool CarlaEngine::loadProjectInternal(juce::XmlDocument& xmlDoc)
} }


if (sourcePort.isNotEmpty() && targetPort.isNotEmpty()) if (sourcePort.isNotEmpty() && targetPort.isNotEmpty())
restorePatchbayConnection(false, sourcePort, targetPort);
restorePatchbayConnection(false, sourcePort, targetPort, !isUsingExternal);
} }
break; break;
} }
@@ -1986,6 +1988,8 @@ bool CarlaEngine::loadProjectInternal(juce::XmlDocument& xmlDoc)
// handle connections (external) // handle connections (external)
if (loadExternalConnections) if (loadExternalConnections)
{ {
const bool isUsingExternal(pData->graph.isUsingExternal());

for (XmlElement* elem = xmlElement->getFirstChildElement(); elem != nullptr; elem = elem->getNextElement()) for (XmlElement* elem = xmlElement->getFirstChildElement(); elem != nullptr; elem = elem->getNextElement())
{ {
const String& tagName(elem->getTagName()); const String& tagName(elem->getTagName());
@@ -2019,7 +2023,7 @@ bool CarlaEngine::loadProjectInternal(juce::XmlDocument& xmlDoc)
} }


if (sourcePort.isNotEmpty() && targetPort.isNotEmpty()) if (sourcePort.isNotEmpty() && targetPort.isNotEmpty())
restorePatchbayConnection(true, sourcePort, targetPort);
restorePatchbayConnection(true, sourcePort, targetPort, isUsingExternal);
} }
break; break;
} }


+ 298
- 250
source/backend/engine/CarlaEngineGraph.cpp View File

@@ -84,79 +84,6 @@ const char* getExternalGraphFullPortNameFromId(const /*RackGraphCarlaPortIds*/ u


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------


ExternalGraphBuffers::ExternalGraphBuffers() noexcept
: mutex(),
connectedIn1(),
connectedIn2(),
connectedOut1(),
connectedOut2()
#ifdef CARLA_PROPER_CPP11_SUPPORT
, inBuf{nullptr, nullptr},
inBufTmp{nullptr, nullptr},
outBuf{nullptr, nullptr} {}
#else
{
inBuf[0] = inBuf[1] = nullptr;
inBufTmp[0] = inBufTmp[1] = nullptr;
outBuf[0] = outBuf[1] = nullptr;
}
#endif

void ExternalGraphBuffers::setBufferSize(const uint32_t bufferSize, const bool createBuffers) noexcept
{
const int bufferSizei(static_cast<int>(bufferSize));

const CarlaRecursiveMutexLocker cml(mutex);

if (inBuf[0] != nullptr) { delete[] inBuf[0]; inBuf[0] = nullptr; }
if (inBuf[1] != nullptr) { delete[] inBuf[1]; inBuf[1] = nullptr; }
if (inBufTmp[0] != nullptr) { delete[] inBufTmp[0]; inBufTmp[0] = nullptr; }
if (inBufTmp[1] != nullptr) { delete[] inBufTmp[1]; inBufTmp[1] = nullptr; }
if (outBuf[0] != nullptr) { delete[] outBuf[0]; outBuf[0] = nullptr; }
if (outBuf[1] != nullptr) { delete[] outBuf[1]; outBuf[1] = nullptr; }

CARLA_SAFE_ASSERT_RETURN(bufferSize > 0,);

try {
inBufTmp[0] = new float[bufferSize];
inBufTmp[1] = new float[bufferSize];

if (createBuffers)
{
inBuf[0] = new float[bufferSize];
inBuf[1] = new float[bufferSize];
outBuf[0] = new float[bufferSize];
outBuf[1] = new float[bufferSize];
}
}
catch(...) {
if (inBufTmp[0] != nullptr) { delete[] inBufTmp[0]; inBufTmp[0] = nullptr; }
if (inBufTmp[1] != nullptr) { delete[] inBufTmp[1]; inBufTmp[1] = nullptr; }

if (createBuffers)
{
if (inBuf[0] != nullptr) { delete[] inBuf[0]; inBuf[0] = nullptr; }
if (inBuf[1] != nullptr) { delete[] inBuf[1]; inBuf[1] = nullptr; }
if (outBuf[0] != nullptr) { delete[] outBuf[0]; outBuf[0] = nullptr; }
if (outBuf[1] != nullptr) { delete[] outBuf[1]; outBuf[1] = nullptr; }
}
return;
}

FloatVectorOperations::clear(inBufTmp[0], bufferSizei);
FloatVectorOperations::clear(inBufTmp[1], bufferSizei);

if (createBuffers)
{
FloatVectorOperations::clear(inBuf[0], bufferSizei);
FloatVectorOperations::clear(inBuf[1], bufferSizei);
FloatVectorOperations::clear(outBuf[0], bufferSizei);
FloatVectorOperations::clear(outBuf[1], bufferSizei);
}
}

// -----------------------------------------------------------------------

ExternalGraphPorts::ExternalGraphPorts() noexcept ExternalGraphPorts::ExternalGraphPorts() noexcept
: ins(), : ins(),
outs() {} outs() {}
@@ -203,32 +130,21 @@ uint ExternalGraphPorts::getPortId(const bool isInput, const char portName[], bo


ExternalGraph::ExternalGraph(CarlaEngine* const engine) noexcept ExternalGraph::ExternalGraph(CarlaEngine* const engine) noexcept
: connections(), : connections(),
audioBuffers(),
audioPorts(), audioPorts(),
midiPorts(), midiPorts(),
retCon(), retCon(),
kEngine(engine) {} kEngine(engine) {}


void ExternalGraph::clearConnections() noexcept
void ExternalGraph::clear() noexcept
{ {
audioBuffers.mutex.lock();
audioBuffers.connectedIn1.clear();
audioBuffers.connectedIn2.clear();
audioBuffers.connectedOut1.clear();
audioBuffers.connectedOut2.clear();
audioBuffers.mutex.unlock();
connections.clear(); connections.clear();
}

void ExternalGraph::clearPorts() noexcept
{
audioPorts.ins.clear(); audioPorts.ins.clear();
audioPorts.outs.clear(); audioPorts.outs.clear();
midiPorts.ins.clear(); midiPorts.ins.clear();
midiPorts.outs.clear(); midiPorts.outs.clear();
} }


bool ExternalGraph::connect(const uint groupA, const uint portA, const uint groupB, const uint portB) noexcept
bool ExternalGraph::connect(const uint groupA, const uint portA, const uint groupB, const uint portB, const bool sendCallback) noexcept
{ {
uint otherGroup, otherPort, carlaPort; uint otherGroup, otherPort, carlaPort;


@@ -258,42 +174,34 @@ bool ExternalGraph::connect(const uint groupA, const uint portA, const uint grou
{ {
case kExternalGraphCarlaPortAudioIn1: case kExternalGraphCarlaPortAudioIn1:
CARLA_SAFE_ASSERT_RETURN(otherGroup == kExternalGraphGroupAudioIn, false); CARLA_SAFE_ASSERT_RETURN(otherGroup == kExternalGraphGroupAudioIn, false);
audioBuffers.mutex.lock();
makeConnection = audioBuffers.connectedIn1.append(otherPort);
audioBuffers.mutex.unlock();
makeConnection = kEngine->connectExternalGraphPort(kExternalGraphConnectionAudioIn1, otherPort, nullptr);
break; break;


case kExternalGraphCarlaPortAudioIn2: case kExternalGraphCarlaPortAudioIn2:
CARLA_SAFE_ASSERT_RETURN(otherGroup == kExternalGraphGroupAudioIn, false); CARLA_SAFE_ASSERT_RETURN(otherGroup == kExternalGraphGroupAudioIn, false);
audioBuffers.mutex.lock();
makeConnection = audioBuffers.connectedIn2.append(otherPort);
audioBuffers.mutex.unlock();
makeConnection = kEngine->connectExternalGraphPort(kExternalGraphConnectionAudioIn2, otherPort, nullptr);
break; break;


case kExternalGraphCarlaPortAudioOut1: case kExternalGraphCarlaPortAudioOut1:
CARLA_SAFE_ASSERT_RETURN(otherGroup == kExternalGraphGroupAudioOut, false); CARLA_SAFE_ASSERT_RETURN(otherGroup == kExternalGraphGroupAudioOut, false);
audioBuffers.mutex.lock();
makeConnection = audioBuffers.connectedOut1.append(otherPort);
audioBuffers.mutex.unlock();
makeConnection = kEngine->connectExternalGraphPort(kExternalGraphConnectionAudioOut1, otherPort, nullptr);
break; break;


case kExternalGraphCarlaPortAudioOut2: case kExternalGraphCarlaPortAudioOut2:
CARLA_SAFE_ASSERT_RETURN(otherGroup == kExternalGraphGroupAudioOut, false); CARLA_SAFE_ASSERT_RETURN(otherGroup == kExternalGraphGroupAudioOut, false);
audioBuffers.mutex.lock();
makeConnection = audioBuffers.connectedOut2.append(otherPort);
audioBuffers.mutex.unlock();
makeConnection = kEngine->connectExternalGraphPort(kExternalGraphConnectionAudioOut2, otherPort, nullptr);
break; break;


case kExternalGraphCarlaPortMidiIn: case kExternalGraphCarlaPortMidiIn:
CARLA_SAFE_ASSERT_RETURN(otherGroup == kExternalGraphGroupMidiIn, false); CARLA_SAFE_ASSERT_RETURN(otherGroup == kExternalGraphGroupMidiIn, false);
if (const char* const portName = midiPorts.getName(true, otherPort)) if (const char* const portName = midiPorts.getName(true, otherPort))
makeConnection = kEngine->connectRackMidiInPort(portName);
makeConnection = kEngine->connectExternalGraphPort(kExternalGraphConnectionMidiInput, 0, portName);
break; break;


case kExternalGraphCarlaPortMidiOut: case kExternalGraphCarlaPortMidiOut:
CARLA_SAFE_ASSERT_RETURN(otherGroup == kExternalGraphGroupMidiOut, false); CARLA_SAFE_ASSERT_RETURN(otherGroup == kExternalGraphGroupMidiOut, false);
if (const char* const portName = midiPorts.getName(false, otherPort)) if (const char* const portName = midiPorts.getName(false, otherPort))
makeConnection = kEngine->connectRackMidiOutPort(portName);
makeConnection = kEngine->connectExternalGraphPort(kExternalGraphConnectionMidiOutput, 0, portName);
break; break;
} }


@@ -310,7 +218,8 @@ bool ExternalGraph::connect(const uint groupA, const uint portA, const uint grou
strBuf[STR_MAX] = '\0'; strBuf[STR_MAX] = '\0';
std::snprintf(strBuf, STR_MAX, "%u:%u:%u:%u", groupA, portA, groupB, portB); std::snprintf(strBuf, STR_MAX, "%u:%u:%u:%u", groupA, portA, groupB, portB);


kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
if (sendCallback)
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);


connections.list.append(connectionToId); connections.list.append(connectionToId);
return true; return true;
@@ -357,37 +266,29 @@ bool ExternalGraph::disconnect(const uint connectionId) noexcept
switch (carlaPort) switch (carlaPort)
{ {
case kExternalGraphCarlaPortAudioIn1: case kExternalGraphCarlaPortAudioIn1:
audioBuffers.mutex.lock();
makeDisconnection = audioBuffers.connectedIn1.removeOne(otherPort);
audioBuffers.mutex.unlock();
makeDisconnection = kEngine->disconnectExternalGraphPort(kExternalGraphConnectionAudioIn1, otherPort, nullptr);
break; break;


case kExternalGraphCarlaPortAudioIn2: case kExternalGraphCarlaPortAudioIn2:
audioBuffers.mutex.lock();
makeDisconnection = audioBuffers.connectedIn2.removeOne(otherPort);
audioBuffers.mutex.unlock();
makeDisconnection = kEngine->disconnectExternalGraphPort(kExternalGraphConnectionAudioIn2, otherPort, nullptr);
break; break;


case kExternalGraphCarlaPortAudioOut1: case kExternalGraphCarlaPortAudioOut1:
audioBuffers.mutex.lock();
makeDisconnection = audioBuffers.connectedOut1.removeOne(otherPort);
audioBuffers.mutex.unlock();
makeDisconnection = kEngine->disconnectExternalGraphPort(kExternalGraphConnectionAudioOut1, otherPort, nullptr);
break; break;


case kExternalGraphCarlaPortAudioOut2: case kExternalGraphCarlaPortAudioOut2:
audioBuffers.mutex.lock();
makeDisconnection = audioBuffers.connectedOut2.removeOne(otherPort);
audioBuffers.mutex.unlock();
makeDisconnection = kEngine->disconnectExternalGraphPort(kExternalGraphConnectionAudioOut2, otherPort, nullptr);
break; break;


case kExternalGraphCarlaPortMidiIn: case kExternalGraphCarlaPortMidiIn:
if (const char* const portName = midiPorts.getName(true, otherPort)) if (const char* const portName = midiPorts.getName(true, otherPort))
makeDisconnection = kEngine->disconnectRackMidiInPort(portName);
makeDisconnection = kEngine->disconnectExternalGraphPort(kExternalGraphConnectionMidiInput, 0, portName);
break; break;


case kExternalGraphCarlaPortMidiOut: case kExternalGraphCarlaPortMidiOut:
if (const char* const portName = midiPorts.getName(false, otherPort)) if (const char* const portName = midiPorts.getName(false, otherPort))
makeDisconnection = kEngine->disconnectRackMidiOutPort(portName);
makeDisconnection = kEngine->disconnectExternalGraphPort(kExternalGraphConnectionMidiOutput, 0, portName);
break; break;
} }


@@ -411,16 +312,20 @@ void ExternalGraph::refresh(const char* const deviceName)
{ {
CARLA_SAFE_ASSERT_RETURN(deviceName != nullptr,); CARLA_SAFE_ASSERT_RETURN(deviceName != nullptr,);


connections.clear();
const bool isRack(kEngine->getOptions().processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK);


// Main // Main
{ {
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, kExternalGraphGroupCarla, PATCHBAY_ICON_CARLA, -1, 0.0f, kEngine->getName()); kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, kExternalGraphGroupCarla, PATCHBAY_ICON_CARLA, -1, 0.0f, kEngine->getName());


kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioIn1, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, "audio-in1");
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioIn2, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, "audio-in2");
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioOut1, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, "audio-out1");
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioOut2, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, "audio-out2");
if (isRack)
{
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioIn1, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, "audio-in1");
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioIn2, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, "audio-in2");
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioOut1, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, "audio-out1");
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioOut2, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, "audio-out2");
}

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, kExternalGraphGroupCarla, kExternalGraphCarlaPortMidiIn, PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, "midi-in"); kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, kExternalGraphGroupCarla, kExternalGraphCarlaPortMidiIn, PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, "midi-in");
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, kExternalGraphGroupCarla, kExternalGraphCarlaPortMidiOut, PATCHBAY_PORT_TYPE_MIDI, 0.0f, "midi-out"); kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, kExternalGraphGroupCarla, kExternalGraphCarlaPortMidiOut, PATCHBAY_PORT_TYPE_MIDI, 0.0f, "midi-out");
} }
@@ -429,6 +334,7 @@ void ExternalGraph::refresh(const char* const deviceName)
strBuf[STR_MAX] = '\0'; strBuf[STR_MAX] = '\0';


// Audio In // Audio In
if (isRack)
{ {
if (deviceName[0] != '\0') if (deviceName[0] != '\0')
std::snprintf(strBuf, STR_MAX, "Capture (%s)", deviceName); std::snprintf(strBuf, STR_MAX, "Capture (%s)", deviceName);
@@ -451,6 +357,7 @@ void ExternalGraph::refresh(const char* const deviceName)
} }


// Audio Out // Audio Out
if (isRack)
{ {
if (deviceName[0] != '\0') if (deviceName[0] != '\0')
std::snprintf(strBuf, STR_MAX, "Playback (%s)", deviceName); std::snprintf(strBuf, STR_MAX, "Playback (%s)", deviceName);
@@ -505,75 +412,6 @@ void ExternalGraph::refresh(const char* const deviceName)
PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, portNameToId.name); PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, portNameToId.name);
} }
} }

// Connections
audioBuffers.mutex.lock();

for (LinkedList<uint>::Itenerator it = audioBuffers.connectedIn1.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
CARLA_SAFE_ASSERT_CONTINUE(portId <= audioPorts.ins.count()); // FIXME <=

ConnectionToId connectionToId;
connectionToId.setData(++(connections.lastId), kExternalGraphGroupAudioIn, portId, kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioIn1);

std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);

connections.list.append(connectionToId);
}

for (LinkedList<uint>::Itenerator it = audioBuffers.connectedIn2.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
CARLA_SAFE_ASSERT_CONTINUE(portId <= audioPorts.ins.count()); // FIXME <=

ConnectionToId connectionToId;
connectionToId.setData(++(connections.lastId), kExternalGraphGroupAudioIn, portId, kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioIn2);

std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);

connections.list.append(connectionToId);
}

for (LinkedList<uint>::Itenerator it = audioBuffers.connectedOut1.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
CARLA_SAFE_ASSERT_CONTINUE(portId <= audioPorts.outs.count()); // FIXME <=

ConnectionToId connectionToId;
connectionToId.setData(++(connections.lastId), kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioOut1, kExternalGraphGroupAudioOut, portId);

std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);

connections.list.append(connectionToId);
}

for (LinkedList<uint>::Itenerator it = audioBuffers.connectedOut2.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
CARLA_SAFE_ASSERT_CONTINUE(portId <= audioPorts.outs.count()); // FIXME <=

ConnectionToId connectionToId;
connectionToId.setData(++(connections.lastId), kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioOut2, kExternalGraphGroupAudioOut, portId);

std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);

connections.list.append(connectionToId);
}

audioBuffers.mutex.unlock();
} }


const char* const* ExternalGraph::getConnections() const noexcept const char* const* ExternalGraph::getConnections() const noexcept
@@ -656,6 +494,7 @@ const char* const* ExternalGraph::getConnections() const noexcept
bool ExternalGraph::getGroupAndPortIdFromFullName(const char* const fullPortName, uint& groupId, uint& portId) const noexcept bool ExternalGraph::getGroupAndPortIdFromFullName(const char* const fullPortName, uint& groupId, uint& portId) const noexcept
{ {
CARLA_SAFE_ASSERT_RETURN(fullPortName != nullptr && fullPortName[0] != '\0', false); CARLA_SAFE_ASSERT_RETURN(fullPortName != nullptr && fullPortName[0] != '\0', false);
carla_stdout("%s", fullPortName);


if (std::strncmp(fullPortName, "Carla:", 6) == 0) if (std::strncmp(fullPortName, "Carla:", 6) == 0)
{ {
@@ -695,6 +534,7 @@ bool ExternalGraph::getGroupAndPortIdFromFullName(const char* const fullPortName
{ {
bool ok; bool ok;
portId = midiPorts.getPortId(true, portName, &ok); portId = midiPorts.getPortId(true, portName, &ok);
carla_stdout("test %s %s", bool2str(ok), portName);
return ok; return ok;
} }
} }
@@ -713,6 +553,97 @@ bool ExternalGraph::getGroupAndPortIdFromFullName(const char* const fullPortName
return false; return false;
} }


// -----------------------------------------------------------------------
// RackGraph Buffers

RackGraph::Buffers::Buffers() noexcept
: mutex(),
connectedIn1(),
connectedIn2(),
connectedOut1(),
connectedOut2()
#ifdef CARLA_PROPER_CPP11_SUPPORT
, inBuf{nullptr, nullptr},
inBufTmp{nullptr, nullptr},
outBuf{nullptr, nullptr} {}
#else
{
inBuf[0] = inBuf[1] = nullptr;
inBufTmp[0] = inBufTmp[1] = nullptr;
outBuf[0] = outBuf[1] = nullptr;
}
#endif

RackGraph::Buffers::~Buffers() noexcept
{
const CarlaRecursiveMutexLocker cml(mutex);

if (inBuf[0] != nullptr) { delete[] inBuf[0]; inBuf[0] = nullptr; }
if (inBuf[1] != nullptr) { delete[] inBuf[1]; inBuf[1] = nullptr; }
if (inBufTmp[0] != nullptr) { delete[] inBufTmp[0]; inBufTmp[0] = nullptr; }
if (inBufTmp[1] != nullptr) { delete[] inBufTmp[1]; inBufTmp[1] = nullptr; }
if (outBuf[0] != nullptr) { delete[] outBuf[0]; outBuf[0] = nullptr; }
if (outBuf[1] != nullptr) { delete[] outBuf[1]; outBuf[1] = nullptr; }

connectedIn1.clear();
connectedIn2.clear();
connectedOut1.clear();
connectedOut2.clear();
}

void RackGraph::Buffers::setBufferSize(const uint32_t bufferSize, const bool createBuffers) noexcept
{
const int bufferSizei(static_cast<int>(bufferSize));

const CarlaRecursiveMutexLocker cml(mutex);

if (inBuf[0] != nullptr) { delete[] inBuf[0]; inBuf[0] = nullptr; }
if (inBuf[1] != nullptr) { delete[] inBuf[1]; inBuf[1] = nullptr; }
if (inBufTmp[0] != nullptr) { delete[] inBufTmp[0]; inBufTmp[0] = nullptr; }
if (inBufTmp[1] != nullptr) { delete[] inBufTmp[1]; inBufTmp[1] = nullptr; }
if (outBuf[0] != nullptr) { delete[] outBuf[0]; outBuf[0] = nullptr; }
if (outBuf[1] != nullptr) { delete[] outBuf[1]; outBuf[1] = nullptr; }

CARLA_SAFE_ASSERT_RETURN(bufferSize > 0,);

try {
inBufTmp[0] = new float[bufferSize];
inBufTmp[1] = new float[bufferSize];

if (createBuffers)
{
inBuf[0] = new float[bufferSize];
inBuf[1] = new float[bufferSize];
outBuf[0] = new float[bufferSize];
outBuf[1] = new float[bufferSize];
}
}
catch(...) {
if (inBufTmp[0] != nullptr) { delete[] inBufTmp[0]; inBufTmp[0] = nullptr; }
if (inBufTmp[1] != nullptr) { delete[] inBufTmp[1]; inBufTmp[1] = nullptr; }

if (createBuffers)
{
if (inBuf[0] != nullptr) { delete[] inBuf[0]; inBuf[0] = nullptr; }
if (inBuf[1] != nullptr) { delete[] inBuf[1]; inBuf[1] = nullptr; }
if (outBuf[0] != nullptr) { delete[] outBuf[0]; outBuf[0] = nullptr; }
if (outBuf[1] != nullptr) { delete[] outBuf[1]; outBuf[1] = nullptr; }
}
return;
}

FloatVectorOperations::clear(inBufTmp[0], bufferSizei);
FloatVectorOperations::clear(inBufTmp[1], bufferSizei);

if (createBuffers)
{
FloatVectorOperations::clear(inBuf[0], bufferSizei);
FloatVectorOperations::clear(inBuf[1], bufferSizei);
FloatVectorOperations::clear(outBuf[0], bufferSizei);
FloatVectorOperations::clear(outBuf[1], bufferSizei);
}
}

// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// RackGraph // RackGraph


@@ -721,6 +652,7 @@ RackGraph::RackGraph(CarlaEngine* const engine, const uint32_t ins, const uint32
inputs(ins), inputs(ins),
outputs(outs), outputs(outs),
isOffline(false), isOffline(false),
audioBuffers(),
kEngine(engine) kEngine(engine)
{ {
setBufferSize(engine->getBufferSize()); setBufferSize(engine->getBufferSize());
@@ -728,13 +660,12 @@ RackGraph::RackGraph(CarlaEngine* const engine, const uint32_t ins, const uint32


RackGraph::~RackGraph() noexcept RackGraph::~RackGraph() noexcept
{ {
extGraph.clearConnections();
extGraph.clearPorts();
extGraph.clear();
} }


void RackGraph::setBufferSize(const uint32_t bufferSize) noexcept void RackGraph::setBufferSize(const uint32_t bufferSize) noexcept
{ {
extGraph.audioBuffers.setBufferSize(bufferSize, (inputs > 0 || outputs > 0));
audioBuffers.setBufferSize(bufferSize, (inputs > 0 || outputs > 0));
} }


void RackGraph::setOffline(const bool offline) noexcept void RackGraph::setOffline(const bool offline) noexcept
@@ -744,7 +675,7 @@ void RackGraph::setOffline(const bool offline) noexcept


bool RackGraph::connect(const uint groupA, const uint portA, const uint groupB, const uint portB) noexcept bool RackGraph::connect(const uint groupA, const uint portA, const uint groupB, const uint portB) noexcept
{ {
return extGraph.connect(groupA, portA, groupB, portB);
return extGraph.connect(groupA, portA, groupB, portB, true);
} }


bool RackGraph::disconnect(const uint connectionId) noexcept bool RackGraph::disconnect(const uint connectionId) noexcept
@@ -752,19 +683,79 @@ bool RackGraph::disconnect(const uint connectionId) noexcept
return extGraph.disconnect(connectionId); return extGraph.disconnect(connectionId);
} }


void RackGraph::clearPorts() noexcept
{
extGraph.clearPorts();
}

void RackGraph::clearConnections() noexcept
{
extGraph.clearConnections();
}

void RackGraph::refresh(const char* const deviceName) void RackGraph::refresh(const char* const deviceName)
{ {
extGraph.refresh(deviceName); extGraph.refresh(deviceName);

char strBuf[STR_MAX+1];
strBuf[STR_MAX] = '\0';

// Connections
const CarlaRecursiveMutexLocker cml(audioBuffers.mutex);

for (LinkedList<uint>::Itenerator it = audioBuffers.connectedIn1.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
CARLA_SAFE_ASSERT_CONTINUE(portId <= extGraph.audioPorts.ins.count()); // FIXME <=

ConnectionToId connectionToId;
connectionToId.setData(++(extGraph.connections.lastId), kExternalGraphGroupAudioIn, portId, kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioIn1);

std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);

extGraph.connections.list.append(connectionToId);
}

for (LinkedList<uint>::Itenerator it = audioBuffers.connectedIn2.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
CARLA_SAFE_ASSERT_CONTINUE(portId <= extGraph.audioPorts.ins.count()); // FIXME <=

ConnectionToId connectionToId;
connectionToId.setData(++(extGraph.connections.lastId), kExternalGraphGroupAudioIn, portId, kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioIn2);

std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);

extGraph.connections.list.append(connectionToId);
}

for (LinkedList<uint>::Itenerator it = audioBuffers.connectedOut1.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
CARLA_SAFE_ASSERT_CONTINUE(portId <= extGraph.audioPorts.outs.count()); // FIXME <=

ConnectionToId connectionToId;
connectionToId.setData(++(extGraph.connections.lastId), kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioOut1, kExternalGraphGroupAudioOut, portId);

std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);

extGraph.connections.list.append(connectionToId);
}

for (LinkedList<uint>::Itenerator it = audioBuffers.connectedOut2.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
CARLA_SAFE_ASSERT_CONTINUE(portId <= extGraph.audioPorts.outs.count()); // FIXME <=

ConnectionToId connectionToId;
connectionToId.setData(++(extGraph.connections.lastId), kExternalGraphGroupCarla, kExternalGraphCarlaPortAudioOut2, kExternalGraphGroupAudioOut, portId);

std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);

extGraph.connections.list.append(connectionToId);
}
} }


const char* const* RackGraph::getConnections() const noexcept const char* const* RackGraph::getConnections() const noexcept
@@ -899,9 +890,6 @@ void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inB


void RackGraph::processHelper(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const uint32_t frames) void RackGraph::processHelper(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const uint32_t frames)
{ {
// FIXME
ExternalGraphBuffers& audioBuffers(extGraph.audioBuffers);

CARLA_SAFE_ASSERT_RETURN(audioBuffers.outBuf[1] != nullptr,); CARLA_SAFE_ASSERT_RETURN(audioBuffers.outBuf[1] != nullptr,);


const int iframes(static_cast<int>(frames)); const int iframes(static_cast<int>(frames));
@@ -1363,20 +1351,17 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons
extGraph(engine), extGraph(engine),
kEngine(engine) kEngine(engine)
{ {
const uint32_t bufferSize(engine->getBufferSize());
const int bufferSizei(static_cast<int>(bufferSize));
const double sampleRate(engine->getSampleRate());
const int bufferSize(static_cast<int>(engine->getBufferSize()));
const double sampleRate(engine->getSampleRate());


graph.setPlayConfigDetails(static_cast<int>(inputs), static_cast<int>(outputs), sampleRate, bufferSizei);
graph.prepareToPlay(sampleRate, bufferSizei);
graph.setPlayConfigDetails(static_cast<int>(inputs), static_cast<int>(outputs), sampleRate, bufferSize);
graph.prepareToPlay(sampleRate, bufferSize);


audioBuffer.setSize(static_cast<int>(jmax(inputs, outputs)), bufferSizei);
audioBuffer.setSize(static_cast<int>(jmax(inputs, outputs)), bufferSize);


midiBuffer.ensureSize(kMaxEngineEventInternalCount*2); midiBuffer.ensureSize(kMaxEngineEventInternalCount*2);
midiBuffer.clear(); midiBuffer.clear();


extGraph.audioBuffers.setBufferSize(bufferSize, (inputs > 0 || outputs > 0));

{ {
AudioProcessorGraph::AudioGraphIOProcessor* const proc(new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode)); AudioProcessorGraph::AudioGraphIOProcessor* const proc(new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode));
AudioProcessorGraph::Node* const node(graph.addNode(proc)); AudioProcessorGraph::Node* const node(graph.addNode(proc));
@@ -1424,9 +1409,8 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons


PatchbayGraph::~PatchbayGraph() PatchbayGraph::~PatchbayGraph()
{ {
clearInternalConnections();
extGraph.clearConnections();
extGraph.clearPorts();
connections.clear();
extGraph.clear();


graph.releaseResources(); graph.releaseResources();
graph.clear(); graph.clear();
@@ -1440,8 +1424,6 @@ void PatchbayGraph::setBufferSize(const uint32_t bufferSize)
graph.releaseResources(); graph.releaseResources();
graph.prepareToPlay(kEngine->getSampleRate(), bufferSizei); graph.prepareToPlay(kEngine->getSampleRate(), bufferSizei);
audioBuffer.setSize(audioBuffer.getNumChannels(), bufferSizei); audioBuffer.setSize(audioBuffer.getNumChannels(), bufferSizei);

extGraph.audioBuffers.setBufferSize(bufferSize, (inputs > 0 || outputs > 0));
} }


void PatchbayGraph::setSampleRate(const double sampleRate) void PatchbayGraph::setSampleRate(const double sampleRate)
@@ -1485,7 +1467,7 @@ void PatchbayGraph::replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* con


if (! usingExternal) if (! usingExternal)
{ {
disconnectGroup(oldNode->nodeId);
disconnectInternalGroup(oldNode->nodeId);
removeNodeFromPatchbay(kEngine, oldNode->nodeId, oldNode->getProcessor()); removeNodeFromPatchbay(kEngine, oldNode->nodeId, oldNode->getProcessor());
} }


@@ -1516,7 +1498,7 @@ void PatchbayGraph::removePlugin(CarlaPlugin* const plugin)


if (! usingExternal) if (! usingExternal)
{ {
disconnectGroup(node->nodeId);
disconnectInternalGroup(node->nodeId);
removeNodeFromPatchbay(kEngine, node->nodeId, node->getProcessor()); removeNodeFromPatchbay(kEngine, node->nodeId, node->getProcessor());
} }


@@ -1552,7 +1534,7 @@ void PatchbayGraph::removeAllPlugins()


if (! usingExternal) if (! usingExternal)
{ {
disconnectGroup(node->nodeId);
disconnectInternalGroup(node->nodeId);
removeNodeFromPatchbay(kEngine, node->nodeId, node->getProcessor()); removeNodeFromPatchbay(kEngine, node->nodeId, node->getProcessor());
} }


@@ -1562,10 +1544,10 @@ void PatchbayGraph::removeAllPlugins()
} }
} }


bool PatchbayGraph::connect(const uint groupA, const uint portA, const uint groupB, const uint portB) noexcept
bool PatchbayGraph::connect(const bool external, const uint groupA, const uint portA, const uint groupB, const uint portB, const bool sendCallback)
{ {
if (usingExternal)
return extGraph.connect(groupA, portA, groupB, portB);
if (external)
return extGraph.connect(groupA, portA, groupB, portB, sendCallback);


uint adjustedPortA = portA; uint adjustedPortA = portA;
uint adjustedPortB = portB; uint adjustedPortB = portB;
@@ -1588,13 +1570,14 @@ bool PatchbayGraph::connect(const uint groupA, const uint portA, const uint grou
strBuf[STR_MAX] = '\0'; strBuf[STR_MAX] = '\0';
std::snprintf(strBuf, STR_MAX, "%u:%u:%u:%u", groupA, portA, groupB, portB); std::snprintf(strBuf, STR_MAX, "%u:%u:%u:%u", groupA, portA, groupB, portB);


kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
if (sendCallback)
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);


connections.list.append(connectionToId); connections.list.append(connectionToId);
return true; return true;
} }


bool PatchbayGraph::disconnect(const uint connectionId) noexcept
bool PatchbayGraph::disconnect(const uint connectionId)
{ {
if (usingExternal) if (usingExternal)
return extGraph.disconnect(connectionId); return extGraph.disconnect(connectionId);
@@ -1631,7 +1614,7 @@ bool PatchbayGraph::disconnect(const uint connectionId) noexcept
return false; return false;
} }


void PatchbayGraph::disconnectGroup(const uint groupId) noexcept
void PatchbayGraph::disconnectInternalGroup(const uint groupId) noexcept
{ {
CARLA_SAFE_ASSERT(! usingExternal); CARLA_SAFE_ASSERT(! usingExternal);


@@ -1658,20 +1641,13 @@ void PatchbayGraph::disconnectGroup(const uint groupId) noexcept
connectionToId.groupB, static_cast<int>(adjustedPortB)); connectionToId.groupB, static_cast<int>(adjustedPortB));
*/ */


kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED, connectionToId.id, 0, 0, 0.0f, nullptr);
if (! usingExternal)
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED, connectionToId.id, 0, 0, 0.0f, nullptr);


connections.list.remove(it); connections.list.remove(it);
} }
} }


void PatchbayGraph::clearInternalConnections()
{
connections.clear();

for (int i=0, count=graph.getNumConnections(); i<count; ++i)
graph.removeConnection(0);
}

void PatchbayGraph::refresh(const char* const deviceName) void PatchbayGraph::refresh(const char* const deviceName)
{ {
if (usingExternal) if (usingExternal)
@@ -2053,6 +2029,15 @@ void EngineInternalGraph::removeAllPlugins()
fPatchbay->removeAllPlugins(); fPatchbay->removeAllPlugins();
} }


bool EngineInternalGraph::isUsingExternal() const noexcept
{
if (fIsRack)
return true;

CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr, false);
return fPatchbay->usingExternal;
}

void EngineInternalGraph::setUsingExternal(const bool usingExternal) noexcept void EngineInternalGraph::setUsingExternal(const bool usingExternal) noexcept
{ {
CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
@@ -2070,13 +2055,17 @@ bool CarlaEngine::patchbayConnect(const uint groupA, const uint portA, const uin


if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
{ {
if (RackGraph* const graph = pData->graph.getRackGraph())
return graph->connect(groupA, portA, groupB, portB);
RackGraph* const graph = pData->graph.getRackGraph();
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);

return graph->connect(groupA, portA, groupB, portB);
} }
else else
{ {
if (PatchbayGraph* const graph = pData->graph.getPatchbayGraph())
return graph->connect(groupA, portA, groupB, portB);
PatchbayGraph* const graph = pData->graph.getPatchbayGraph();
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);

return graph->connect(graph->usingExternal, groupA, portA, groupB, portB, true);
} }


return false; return false;
@@ -2090,13 +2079,17 @@ bool CarlaEngine::patchbayDisconnect(const uint connectionId)


if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
{ {
if (RackGraph* const graph = pData->graph.getRackGraph())
return graph->disconnect(connectionId);
RackGraph* const graph = pData->graph.getRackGraph();
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);

return graph->disconnect(connectionId);
} }
else else
{ {
if (PatchbayGraph* const graph = pData->graph.getPatchbayGraph())
return graph->disconnect(connectionId);
PatchbayGraph* const graph = pData->graph.getPatchbayGraph();
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);

return graph->disconnect(connectionId);
} }


return false; return false;
@@ -2116,9 +2109,10 @@ bool CarlaEngine::patchbayRefresh(const bool external)


if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{ {
if (PatchbayGraph* const graph = pData->graph.getPatchbayGraph())
graph->refresh("");
PatchbayGraph* const graph = pData->graph.getPatchbayGraph();
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);


graph->refresh("");
return true; return true;
} }


@@ -2152,12 +2146,12 @@ const char* const* CarlaEngine::getPatchbayConnections(const bool external) cons
return nullptr; return nullptr;
} }


void CarlaEngine::restorePatchbayConnection(const bool external, const char* const sourcePort, const char* const targetPort)
void CarlaEngine::restorePatchbayConnection(const bool external, const char* const sourcePort, const char* const targetPort, const bool sendCallback)
{ {
CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(),); CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(),);
CARLA_SAFE_ASSERT_RETURN(sourcePort != nullptr && sourcePort[0] != '\0',); CARLA_SAFE_ASSERT_RETURN(sourcePort != nullptr && sourcePort[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(targetPort != nullptr && targetPort[0] != '\0',); CARLA_SAFE_ASSERT_RETURN(targetPort != nullptr && targetPort[0] != '\0',);
carla_debug("CarlaEngine::restorePatchbayConnection(%s, \"%s\", \"%s\")", bool2str(external), sourcePort, targetPort);
carla_stdout("CarlaEngine::restorePatchbayConnection(%s, \"%s\", \"%s\")", bool2str(external), sourcePort, targetPort);


uint groupA, portA; uint groupA, portA;
uint groupB, portB; uint groupB, portB;
@@ -2172,6 +2166,8 @@ void CarlaEngine::restorePatchbayConnection(const bool external, const char* con
return; return;
if (! graph->getGroupAndPortIdFromFullName(targetPort, groupB, portB)) if (! graph->getGroupAndPortIdFromFullName(targetPort, groupB, portB))
return; return;

graph->connect(groupA, portA, groupB, portB);
} }
else else
{ {
@@ -2182,9 +2178,61 @@ void CarlaEngine::restorePatchbayConnection(const bool external, const char* con
return; return;
if (! graph->getGroupAndPortIdFromFullName(external, targetPort, groupB, portB)) if (! graph->getGroupAndPortIdFromFullName(external, targetPort, groupB, portB))
return; return;

graph->connect(external, groupA, portA, groupB, portB, sendCallback);
} }
}

// -----------------------------------------------------------------------

bool CarlaEngine::connectExternalGraphPort(const uint connectionType, const uint portId, const char* const portName)
{
CARLA_SAFE_ASSERT_RETURN(connectionType != 0 || (portName != nullptr && portName[0] != '\0'), false);
CARLA_SAFE_ASSERT_RETURN(pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK, false);

RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);


patchbayConnect(groupA, portA, groupB, portB);
const CarlaRecursiveMutexLocker cml(graph->audioBuffers.mutex);

switch (connectionType)
{
case kExternalGraphConnectionAudioIn1:
return graph->audioBuffers.connectedIn1.append(portId);
case kExternalGraphConnectionAudioIn2:
return graph->audioBuffers.connectedIn2.append(portId);
case kExternalGraphConnectionAudioOut1:
return graph->audioBuffers.connectedOut1.append(portId);
case kExternalGraphConnectionAudioOut2:
return graph->audioBuffers.connectedOut2.append(portId);
}

return false;
}

bool CarlaEngine::disconnectExternalGraphPort(const uint connectionType, const uint portId, const char* const portName)
{
CARLA_SAFE_ASSERT_RETURN(connectionType != 0 || (portName != nullptr && portName[0] != '\0'), false);
CARLA_SAFE_ASSERT_RETURN(pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK, false);

RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);

const CarlaRecursiveMutexLocker cml(graph->audioBuffers.mutex);

switch (connectionType)
{
case kExternalGraphConnectionAudioIn1:
return graph->audioBuffers.connectedIn1.removeOne(portId);
case kExternalGraphConnectionAudioIn2:
return graph->audioBuffers.connectedIn2.removeOne(portId);
case kExternalGraphConnectionAudioOut1:
return graph->audioBuffers.connectedOut1.removeOne(portId);
case kExternalGraphConnectionAudioOut2:
return graph->audioBuffers.connectedOut2.removeOne(portId);
}

return false;
} }


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------


+ 29
- 24
source/backend/engine/CarlaEngineGraph.hpp View File

@@ -54,19 +54,14 @@ enum ExternalGraphCarlaPortIds {
kExternalGraphCarlaPortMax = 7 kExternalGraphCarlaPortMax = 7
}; };


struct ExternalGraphBuffers {
CarlaRecursiveMutex mutex;
LinkedList<uint> connectedIn1;
LinkedList<uint> connectedIn2;
LinkedList<uint> connectedOut1;
LinkedList<uint> connectedOut2;
float* inBuf[2];
float* inBufTmp[2];
float* outBuf[2];
ExternalGraphBuffers() noexcept;
void setBufferSize(const uint32_t bufferSize, const bool createBuffers) noexcept;
CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(ExternalGraphBuffers)
enum ExternalGraphConnectionType {
kExternalGraphConnectionNull = 0,
kExternalGraphConnectionAudioIn1 = 1,
kExternalGraphConnectionAudioIn2 = 2,
kExternalGraphConnectionAudioOut1 = 3,
kExternalGraphConnectionAudioOut2 = 4,
kExternalGraphConnectionMidiInput = 5,
kExternalGraphConnectionMidiOutput = 6
}; };


struct ExternalGraphPorts { struct ExternalGraphPorts {
@@ -81,15 +76,12 @@ struct ExternalGraphPorts {


struct ExternalGraph { struct ExternalGraph {
PatchbayConnectionList connections; PatchbayConnectionList connections;
ExternalGraphBuffers audioBuffers;
ExternalGraphPorts audioPorts, midiPorts; ExternalGraphPorts audioPorts, midiPorts;
mutable CharStringListPtr retCon; mutable CharStringListPtr retCon;
ExternalGraph(CarlaEngine* const engine) noexcept; ExternalGraph(CarlaEngine* const engine) noexcept;


void clearConnections() noexcept;
void clearPorts() noexcept;

bool connect(const uint groupA, const uint portA, const uint groupB, const uint portB) noexcept;
void clear() noexcept;
bool connect(const uint groupA, const uint portA, const uint groupB, const uint portB, const bool sendCallback) noexcept;
bool disconnect(const uint connectionId) noexcept; bool disconnect(const uint connectionId) noexcept;
void refresh(const char* const deviceName); void refresh(const char* const deviceName);


@@ -110,6 +102,22 @@ struct RackGraph {
const uint32_t outputs; const uint32_t outputs;
bool isOffline; bool isOffline;


struct Buffers {
CarlaRecursiveMutex mutex;
LinkedList<uint> connectedIn1;
LinkedList<uint> connectedIn2;
LinkedList<uint> connectedOut1;
LinkedList<uint> connectedOut2;
float* inBuf[2];
float* inBufTmp[2];
float* outBuf[2];
Buffers() noexcept;
~Buffers() noexcept;
void setBufferSize(const uint32_t bufferSize, const bool createBuffers) noexcept;
CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(Buffers)
} audioBuffers;

RackGraph(CarlaEngine* const engine, const uint32_t inputs, const uint32_t outputs) noexcept; RackGraph(CarlaEngine* const engine, const uint32_t inputs, const uint32_t outputs) noexcept;
~RackGraph() noexcept; ~RackGraph() noexcept;


@@ -118,8 +126,6 @@ struct RackGraph {


bool connect(const uint groupA, const uint portA, const uint groupB, const uint portB) noexcept; bool connect(const uint groupA, const uint portA, const uint groupB, const uint portB) noexcept;
bool disconnect(const uint connectionId) noexcept; bool disconnect(const uint connectionId) noexcept;
void clearPorts() noexcept;
void clearConnections() noexcept;
void refresh(const char* const deviceName); void refresh(const char* const deviceName);


const char* const* getConnections() const noexcept; const char* const* getConnections() const noexcept;
@@ -162,10 +168,9 @@ struct PatchbayGraph {
void removePlugin(CarlaPlugin* const plugin); void removePlugin(CarlaPlugin* const plugin);
void removeAllPlugins(); void removeAllPlugins();


bool connect(const uint groupA, const uint portA, const uint groupB, const uint portB) noexcept;
bool disconnect(const uint connectionId) noexcept;
void disconnectGroup(const uint groupId) noexcept;
void clearInternalConnections();
bool connect(const bool external, const uint groupA, const uint portA, const uint groupB, const uint portB, const bool sendCallback);
bool disconnect(const uint connectionId);
void disconnectInternalGroup(const uint groupId) noexcept;
void refresh(const char* const deviceName); void refresh(const char* const deviceName);


const char* const* getConnections(const bool external) const; const char* const* getConnections(const bool external) const;


+ 1
- 0
source/backend/engine/CarlaEngineInternal.hpp View File

@@ -86,6 +86,7 @@ public:
void removePlugin(CarlaPlugin* const plugin); void removePlugin(CarlaPlugin* const plugin);
void removeAllPlugins(); void removeAllPlugins();


bool isUsingExternal() const noexcept;
void setUsingExternal(const bool usingExternal) noexcept; void setUsingExternal(const bool usingExternal) noexcept;


private: private:


+ 2
- 3
source/backend/engine/CarlaEngineJack.cpp View File

@@ -817,7 +817,6 @@ public:
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
{ {
pData->graph.create(0, 0); pData->graph.create(0, 0);
patchbayRefresh(true);
} }
else else
{ {
@@ -1258,7 +1257,7 @@ public:
return fRetConns; return fRetConns;
} }


void restorePatchbayConnection(const bool external, const char* const connSource, const char* const connTarget) override
void restorePatchbayConnection(const bool external, const char* const connSource, const char* const connTarget, const bool sendCallback) override
{ {
CARLA_SAFE_ASSERT_RETURN(fClient != nullptr,); CARLA_SAFE_ASSERT_RETURN(fClient != nullptr,);
CARLA_SAFE_ASSERT_RETURN(connSource != nullptr && connSource[0] != '\0',); CARLA_SAFE_ASSERT_RETURN(connSource != nullptr && connSource[0] != '\0',);
@@ -1266,7 +1265,7 @@ public:
carla_debug("CarlaEngineJack::restorePatchbayConnection(\"%s\", \"%s\")", connSource, connTarget); carla_debug("CarlaEngineJack::restorePatchbayConnection(\"%s\", \"%s\")", connSource, connTarget);


if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! external) if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! external)
return CarlaEngine::restorePatchbayConnection(external, connSource, connTarget);
return CarlaEngine::restorePatchbayConnection(external, connSource, connTarget, sendCallback);


if (const jack_port_t* const port = jackbridge_port_by_name(fClient, connSource)) if (const jack_port_t* const port = jackbridge_port_by_name(fClient, connSource))
{ {


+ 157
- 185
source/backend/engine/CarlaEngineRtAudio.cpp View File

@@ -307,6 +307,9 @@ public:


patchbayRefresh(false); patchbayRefresh(false);


if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
refreshExternalGraphPorts<PatchbayGraph>(pData->graph.getPatchbayGraph(), false);

callback(ENGINE_CALLBACK_ENGINE_STARTED, 0, pData->options.processMode, pData->options.transportMode, 0.0f, getCurrentDriverName()); callback(ENGINE_CALLBACK_ENGINE_STARTED, 0, pData->options.processMode, pData->options.transportMode, 0.0f, getCurrentDriverName());
return true; return true;
} }
@@ -403,15 +406,19 @@ public:
// Patchbay // Patchbay


template<class Graph> template<class Graph>
bool refreshGraphPorts(Graph& graph)
bool refreshExternalGraphPorts(Graph* const graph, const bool sendCallback)
{ {
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);

char strBuf[STR_MAX+1]; char strBuf[STR_MAX+1];
strBuf[STR_MAX] = '\0'; strBuf[STR_MAX] = '\0';


ExternalGraph& extGraph(graph->extGraph);

// --------------------------------------------------------------- // ---------------------------------------------------------------
// clear last ports // clear last ports


graph.clearPorts();
extGraph.clear();


// --------------------------------------------------------------- // ---------------------------------------------------------------
// fill in new ones // fill in new ones
@@ -424,7 +431,7 @@ public:
PortNameToId portNameToId; PortNameToId portNameToId;
portNameToId.setData(kExternalGraphGroupAudioIn, i+1, strBuf, ""); portNameToId.setData(kExternalGraphGroupAudioIn, i+1, strBuf, "");


graph.audioPorts.ins.append(portNameToId);
extGraph.audioPorts.ins.append(portNameToId);
} }


// Audio Out // Audio Out
@@ -435,7 +442,7 @@ public:
PortNameToId portNameToId; PortNameToId portNameToId;
portNameToId.setData(kExternalGraphGroupAudioOut, i+1, strBuf, ""); portNameToId.setData(kExternalGraphGroupAudioOut, i+1, strBuf, "");


graph.audioPorts.outs.append(portNameToId);
extGraph.audioPorts.outs.append(portNameToId);
} }


// MIDI In // MIDI In
@@ -447,7 +454,7 @@ public:
PortNameToId portNameToId; PortNameToId portNameToId;
portNameToId.setData(kExternalGraphGroupMidiIn, i+1, midiIn.getPortName(i).c_str(), ""); portNameToId.setData(kExternalGraphGroupMidiIn, i+1, midiIn.getPortName(i).c_str(), "");


graph.midiPorts.ins.append(portNameToId);
extGraph.midiPorts.ins.append(portNameToId);
} }
} }


@@ -460,14 +467,15 @@ public:
PortNameToId portNameToId; PortNameToId portNameToId;
portNameToId.setData(kExternalGraphGroupMidiOut, i+1, midiOut.getPortName(i).c_str(), ""); portNameToId.setData(kExternalGraphGroupMidiOut, i+1, midiOut.getPortName(i).c_str(), "");


graph.midiPorts.outs.append(portNameToId);
extGraph.midiPorts.outs.append(portNameToId);
} }
} }


// --------------------------------------------------------------- // ---------------------------------------------------------------
// now refresh // now refresh


graph.refresh(fDeviceName.buffer());
if (sendCallback)
graph->refresh(fDeviceName.buffer());


// --------------------------------------------------------------- // ---------------------------------------------------------------
// add midi connections // add midi connections
@@ -479,17 +487,18 @@ public:
const MidiInPort& inPort(it.getValue(fallback)); const MidiInPort& inPort(it.getValue(fallback));
CARLA_SAFE_ASSERT_CONTINUE(inPort.port != nullptr); CARLA_SAFE_ASSERT_CONTINUE(inPort.port != nullptr);


const uint portId(graph.midiPorts.getPortId(true, inPort.name));
CARLA_SAFE_ASSERT_CONTINUE(portId < graph.midiPorts.ins.count());
const uint portId(extGraph.midiPorts.getPortId(true, inPort.name));
CARLA_SAFE_ASSERT_CONTINUE(portId < extGraph.midiPorts.ins.count());


ConnectionToId connectionToId; ConnectionToId connectionToId;
connectionToId.setData(++(graph.connections.lastId), kExternalGraphGroupMidiIn, portId, kExternalGraphGroupCarla, kExternalGraphCarlaPortMidiIn);
connectionToId.setData(++(extGraph.connections.lastId), kExternalGraphGroupMidiIn, portId, kExternalGraphGroupCarla, kExternalGraphCarlaPortMidiIn);


std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB); std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);


callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
extGraph.connections.list.append(connectionToId);


graph.connections.list.append(connectionToId);
if (sendCallback)
callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
} }


fMidiOutMutex.lock(); fMidiOutMutex.lock();
@@ -501,17 +510,18 @@ public:
const MidiOutPort& outPort(it.getValue(fallback)); const MidiOutPort& outPort(it.getValue(fallback));
CARLA_SAFE_ASSERT_CONTINUE(outPort.port != nullptr); CARLA_SAFE_ASSERT_CONTINUE(outPort.port != nullptr);


const uint portId(graph.midiPorts.getPortId(false, outPort.name));
CARLA_SAFE_ASSERT_CONTINUE(portId < graph.midiPorts.outs.count());
const uint portId(extGraph.midiPorts.getPortId(false, outPort.name));
CARLA_SAFE_ASSERT_CONTINUE(portId < extGraph.midiPorts.outs.count());


ConnectionToId connectionToId; ConnectionToId connectionToId;
connectionToId.setData(++(graph.connections.lastId), kExternalGraphGroupCarla, kExternalGraphCarlaPortMidiOut, kExternalGraphGroupMidiOut, portId);
connectionToId.setData(++(extGraph.connections.lastId), kExternalGraphGroupCarla, kExternalGraphCarlaPortMidiOut, kExternalGraphGroupMidiOut, portId);


std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB); std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);


callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
extGraph.connections.list.append(connectionToId);


graph.connections.list.append(connectionToId);
if (sendCallback)
callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
} }


fMidiOutMutex.unlock(); fMidiOutMutex.unlock();
@@ -525,16 +535,16 @@ public:


if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
{ {
return refreshGraphPorts<ExternalGraph>(pData->graph.getRackGraph()->extGraph);
return refreshExternalGraphPorts<RackGraph>(pData->graph.getRackGraph(), true);
} }
else else
{ {
pData->graph.setUsingExternal(external); pData->graph.setUsingExternal(external);


if (! external)
if (external)
return refreshExternalGraphPorts<PatchbayGraph>(pData->graph.getPatchbayGraph(), true);
else
return CarlaEngine::patchbayRefresh(false); return CarlaEngine::patchbayRefresh(false);

return refreshGraphPorts<ExternalGraph>(pData->graph.getPatchbayGraph()->extGraph);
} }


return true; return true;
@@ -734,208 +744,170 @@ protected:


// ------------------------------------------------------------------- // -------------------------------------------------------------------


bool connectRackMidiInPort(const char* const portName) override
bool connectExternalGraphPort(const uint connectionType, const uint portId, const char* const portName) override
{ {
CARLA_SAFE_ASSERT_RETURN(portName != nullptr && portName[0] != '\0', false);
carla_debug("CarlaEngineRtAudio::connectRackMidiInPort(\"%s\")", portName);

if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
{
RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->extGraph.midiPorts.ins.count() > 0, false);
}
else
{
PatchbayGraph* const graph(pData->graph.getPatchbayGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->extGraph.midiPorts.ins.count() > 0, false);
}

CarlaString newRtMidiPortName;
newRtMidiPortName += getName();
newRtMidiPortName += ":";
newRtMidiPortName += portName;

RtMidiIn* const rtMidiIn(new RtMidiIn(getMatchedAudioMidiAPI(fAudio.getCurrentApi()), newRtMidiPortName.buffer(), 512));
rtMidiIn->ignoreTypes();
rtMidiIn->setCallback(carla_rtmidi_callback, this);
CARLA_SAFE_ASSERT_RETURN(connectionType != 0 || (portName != nullptr && portName[0] != '\0'), false);
carla_stdout("CarlaEngineRtAudio::connectExternalGraphPort(%u, %u, \"%s\")", connectionType, portId, portName);


bool found = false;
uint rtMidiPortIndex;

for (uint i=0, count=rtMidiIn->getPortCount(); i < count; ++i)
switch (connectionType)
{ {
if (rtMidiIn->getPortName(i) == portName)
case kExternalGraphConnectionAudioIn1:
case kExternalGraphConnectionAudioIn2:
case kExternalGraphConnectionAudioOut1:
case kExternalGraphConnectionAudioOut2:
return CarlaEngine::connectExternalGraphPort(connectionType, portId, portName);

case kExternalGraphConnectionMidiInput: {
CarlaString newRtMidiPortName;
newRtMidiPortName += getName();
newRtMidiPortName += ":";
newRtMidiPortName += portName;

RtMidiIn* const rtMidiIn(new RtMidiIn(getMatchedAudioMidiAPI(fAudio.getCurrentApi()), newRtMidiPortName.buffer(), 512));
rtMidiIn->ignoreTypes();
rtMidiIn->setCallback(carla_rtmidi_callback, this);

bool found = false;
uint rtMidiPortIndex;

for (uint i=0, count=rtMidiIn->getPortCount(); i < count; ++i)
{ {
found = true;
rtMidiPortIndex = i;
break;
if (rtMidiIn->getPortName(i) == portName)
{
found = true;
rtMidiPortIndex = i;
break;
}
} }
}


if (! found)
{
delete rtMidiIn;
return false;
}

try {
rtMidiIn->openPort(rtMidiPortIndex, portName);
}
catch(...) {
delete rtMidiIn;
return false;
};
if (! found)
{
delete rtMidiIn;
return false;
}


MidiInPort midiPort;
midiPort.port = rtMidiIn;
try {
rtMidiIn->openPort(rtMidiPortIndex, portName);
}
catch(...) {
delete rtMidiIn;
return false;
};


std::strncpy(midiPort.name, portName, STR_MAX);
midiPort.name[STR_MAX] = '\0';
MidiInPort midiPort;
midiPort.port = rtMidiIn;


fMidiIns.append(midiPort);
return true;
}
std::strncpy(midiPort.name, portName, STR_MAX);
midiPort.name[STR_MAX] = '\0';


bool connectRackMidiOutPort(const char* const portName) override
{
CARLA_SAFE_ASSERT_RETURN(portName != nullptr && portName[0] != '\0', false);
carla_debug("CarlaEngineRtAudio::connectRackMidiOutPort(\"%s\")", portName);
fMidiIns.append(midiPort);
return true;
} break;


if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
{
RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->extGraph.midiPorts.outs.count() > 0, false);
}
else
{
PatchbayGraph* const graph(pData->graph.getPatchbayGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->extGraph.midiPorts.outs.count() > 0, false);
}
case kExternalGraphConnectionMidiOutput: {
CarlaString newRtMidiPortName;
newRtMidiPortName += getName();
newRtMidiPortName += ":";
newRtMidiPortName += portName;


CarlaString newRtMidiPortName;
newRtMidiPortName += getName();
newRtMidiPortName += ":";
newRtMidiPortName += portName;
RtMidiOut* const rtMidiOut(new RtMidiOut(getMatchedAudioMidiAPI(fAudio.getCurrentApi()), newRtMidiPortName.buffer()));


RtMidiOut* const rtMidiOut(new RtMidiOut(getMatchedAudioMidiAPI(fAudio.getCurrentApi()), newRtMidiPortName.buffer()));
bool found = false;
uint rtMidiPortIndex;


bool found = false;
uint rtMidiPortIndex;
for (uint i=0, count=rtMidiOut->getPortCount(); i < count; ++i)
{
if (rtMidiOut->getPortName(i) == portName)
{
found = true;
rtMidiPortIndex = i;
break;
}
}


for (uint i=0, count=rtMidiOut->getPortCount(); i < count; ++i)
{
if (rtMidiOut->getPortName(i) == portName)
if (! found)
{ {
found = true;
rtMidiPortIndex = i;
break;
delete rtMidiOut;
return false;
} }
}


if (! found)
{
delete rtMidiOut;
return false;
}
try {
rtMidiOut->openPort(rtMidiPortIndex, portName);
}
catch(...) {
delete rtMidiOut;
return false;
};


try {
rtMidiOut->openPort(rtMidiPortIndex, portName);
}
catch(...) {
delete rtMidiOut;
return false;
};
MidiOutPort midiPort;
midiPort.port = rtMidiOut;


MidiOutPort midiPort;
midiPort.port = rtMidiOut;
std::strncpy(midiPort.name, portName, STR_MAX);
midiPort.name[STR_MAX] = '\0';


std::strncpy(midiPort.name, portName, STR_MAX);
midiPort.name[STR_MAX] = '\0';
const CarlaMutexLocker cml(fMidiOutMutex);


const CarlaMutexLocker cml(fMidiOutMutex);
fMidiOuts.append(midiPort);
return true;
} break;
}


fMidiOuts.append(midiPort);
return true;
return false;
} }


bool disconnectRackMidiInPort(const char* const portName) override
bool disconnectExternalGraphPort(const uint connectionType, const uint portId, const char* const portName) override
{ {
CARLA_SAFE_ASSERT_RETURN(portName != nullptr && portName[0] != '\0', false);
carla_debug("CarlaEngineRtAudio::disconnectRackMidiInPort(\"%s\")", portName);
CARLA_SAFE_ASSERT_RETURN(connectionType != 0 || (portName != nullptr && portName[0] != '\0'), false);
carla_debug("CarlaEngineRtAudio::disconnectExternalGraphPort(%u, %u, \"%s\")", connectionType, portId, portName);


if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
{
RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->extGraph.midiPorts.ins.count() > 0, false);
}
else
switch (connectionType)
{ {
PatchbayGraph* const graph(pData->graph.getPatchbayGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->extGraph.midiPorts.ins.count() > 0, false);
}

for (LinkedList<MidiInPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
{
static MidiInPort fallback = { nullptr, { '\0' } };

MidiInPort& inPort(it.getValue(fallback));
CARLA_SAFE_ASSERT_CONTINUE(inPort.port != nullptr);

if (std::strncmp(inPort.name, portName, STR_MAX) != 0)
continue;

inPort.port->cancelCallback();
inPort.port->closePort();
delete inPort.port;
case kExternalGraphConnectionAudioIn1:
case kExternalGraphConnectionAudioIn2:
case kExternalGraphConnectionAudioOut1:
case kExternalGraphConnectionAudioOut2:
return CarlaEngine::disconnectExternalGraphPort(connectionType, portId, portName);

case kExternalGraphConnectionMidiInput:
for (LinkedList<MidiInPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
{
static MidiInPort fallback = { nullptr, { '\0' } };


fMidiIns.remove(it);
return true;
}
MidiInPort& inPort(it.getValue(fallback));
CARLA_SAFE_ASSERT_CONTINUE(inPort.port != nullptr);


return false;
}
if (std::strncmp(inPort.name, portName, STR_MAX) != 0)
continue;


bool disconnectRackMidiOutPort(const char* const portName) override
{
CARLA_SAFE_ASSERT_RETURN(portName != nullptr && portName[0] != '\0', false);
carla_debug("CarlaEngineRtAudio::disconnectRackMidiOutPort(\"%s\")", portName);
inPort.port->cancelCallback();
inPort.port->closePort();
delete inPort.port;


if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
{
RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->extGraph.midiPorts.outs.count() > 0, false);
}
else
{
PatchbayGraph* const graph(pData->graph.getPatchbayGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->extGraph.midiPorts.outs.count() > 0, false);
}
fMidiIns.remove(it);
return true;
}
break;


const CarlaMutexLocker cml(fMidiOutMutex);
case kExternalGraphConnectionMidiOutput: {
const CarlaMutexLocker cml(fMidiOutMutex);


for (LinkedList<MidiOutPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
{
static MidiOutPort fallback = { nullptr, { '\0' } };
for (LinkedList<MidiOutPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
{
static MidiOutPort fallback = { nullptr, { '\0' } };


MidiOutPort& outPort(it.getValue(fallback));
CARLA_SAFE_ASSERT_CONTINUE(outPort.port != nullptr);
MidiOutPort& outPort(it.getValue(fallback));
CARLA_SAFE_ASSERT_CONTINUE(outPort.port != nullptr);


if (std::strncmp(outPort.name, portName, STR_MAX) != 0)
continue;
if (std::strncmp(outPort.name, portName, STR_MAX) != 0)
continue;


outPort.port->closePort();
delete outPort.port;
outPort.port->closePort();
delete outPort.port;


fMidiOuts.remove(it);
return true;
fMidiOuts.remove(it);
return true;
}
} break;
} }


return false; return false;


+ 1
- 1
source/modules/juce_audio_devices.h View File

@@ -22,7 +22,7 @@
#include "juce_audio_basics.h" #include "juce_audio_basics.h"
#include "juce_audio_formats.h" #include "juce_audio_formats.h"


#if JUCE_MAC || JUCE_WINDOWS
#if 1 //JUCE_MAC || JUCE_WINDOWS
# include "juce_audio_devices/AppConfig.h" # include "juce_audio_devices/AppConfig.h"
# include "juce_audio_devices/juce_audio_devices.h" # include "juce_audio_devices/juce_audio_devices.h"
#endif #endif


Loading…
Cancel
Save