Browse Source

Some renaming, rework and misc fixing

tags/1.9.6
falkTX 11 years ago
parent
commit
b6a823457e
6 changed files with 538 additions and 456 deletions
  1. +1
    -1
      source/backend/engine/CarlaEngine.cpp
  2. +394
    -169
      source/backend/engine/CarlaEngineGraph.cpp
  3. +24
    -18
      source/backend/engine/CarlaEngineGraph.hpp
  4. +57
    -131
      source/backend/engine/CarlaEngineJuce.cpp
  5. +56
    -137
      source/backend/engine/CarlaEngineRtAudio.cpp
  6. +6
    -0
      source/utils/CarlaPatchbayUtils.hpp

+ 1
- 1
source/backend/engine/CarlaEngine.cpp View File

@@ -543,7 +543,7 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype,
}
else if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
/**/ if (plugin->getMidiInCount() > 0 || plugin->getMidiOutCount() > 0)
/**/ if (plugin->getMidiInCount() > 1 || plugin->getMidiOutCount() > 1)
{
setLastError("Carla's patchbay mode cannot work with plugins that have multiple MIDI ports, sorry!");
canRun = false;


+ 394
- 169
source/backend/engine/CarlaEngineGraph.cpp View File

@@ -33,6 +33,51 @@ using juce::jmax;

CARLA_BACKEND_START_NAMESPACE

// -----------------------------------------------------------------------
// Graph Ports

GraphPorts::GraphPorts() noexcept
: ins(),
outs() {}

const char* GraphPorts::getName(const bool isInput, const uint portId) const noexcept
{
for (LinkedList<PortNameToId>::Itenerator it = isInput ? ins.begin() : outs.begin(); it.valid(); it.next())
{
static const PortNameToId portNameFallback = { 0, 0, { '\0' }, { '\0' } };

const PortNameToId& portNameToId(it.getValue(portNameFallback));
CARLA_SAFE_ASSERT_CONTINUE(portNameToId.group != 0);

if (portNameToId.port == portId)
return portNameToId.name;
}

return nullptr;
}

uint GraphPorts::getPortId(const bool isInput, const char portName[], bool* const ok) const noexcept
{
for (LinkedList<PortNameToId>::Itenerator it = isInput ? ins.begin() : outs.begin(); it.valid(); it.next())
{
static const PortNameToId portNameFallback = { 0, 0, { '\0' }, { '\0' } };

const PortNameToId& portNameToId(it.getValue(portNameFallback));
CARLA_SAFE_ASSERT_CONTINUE(portNameToId.group != 0);

if (std::strncmp(portNameToId.name, portName, STR_MAX) == 0)
{
if (ok != nullptr)
*ok = true;
return portNameToId.port;
}
}

if (ok != nullptr)
*ok = false;
return 0;
}

// -----------------------------------------------------------------------
// Rack Graph stuff

@@ -83,9 +128,9 @@ const char* getCarlaRackFullPortNameFromId(const /*RackGraphCarlaPortIds*/ uint
}

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

RackGraph::Audio::Audio() noexcept
RackGraph::AudioBuffers::AudioBuffers() noexcept
: mutex(),
connectedIn1(),
connectedIn2(),
@@ -103,51 +148,6 @@ RackGraph::Audio::Audio() noexcept
}
#endif

// -----------------------------------------------------------------------
// RackGraph MIDI

RackGraph::MIDI::MIDI() noexcept
: ins(),
outs() {}

const char* RackGraph::MIDI::getName(const bool isInput, const uint portId) const noexcept
{
for (LinkedList<PortNameToId>::Itenerator it = isInput ? ins.begin() : outs.begin(); it.valid(); it.next())
{
static const PortNameToId portNameFallback = { 0, 0, { '\0' }, { '\0' } };

const PortNameToId& portNameToId(it.getValue(portNameFallback));
CARLA_SAFE_ASSERT_CONTINUE(portNameToId.group != 0);

if (portNameToId.port == portId)
return portNameToId.name;
}

return nullptr;
}

uint RackGraph::MIDI::getPortId(const bool isInput, const char portName[], bool* const ok) const noexcept
{
for (LinkedList<PortNameToId>::Itenerator it = isInput ? ins.begin() : outs.begin(); it.valid(); it.next())
{
static const PortNameToId portNameFallback = { 0, 0, { '\0' }, { '\0' } };

const PortNameToId& portNameToId(it.getValue(portNameFallback));
CARLA_SAFE_ASSERT_CONTINUE(portNameToId.group != 0);

if (std::strncmp(portNameToId.name, portName, STR_MAX) == 0)
{
if (ok != nullptr)
*ok = true;
return portNameToId.port;
}
}

if (ok != nullptr)
*ok = false;
return 0;
}

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

@@ -157,8 +157,9 @@ RackGraph::RackGraph(CarlaEngine* const engine, const uint32_t ins, const uint32
outputs(outs),
isOffline(false),
retCon(),
audio(),
midi(),
audioBuffers(),
audioPorts(),
midiPorts(),
kEngine(engine)
{
setBufferSize(engine->getBufferSize());
@@ -167,56 +168,57 @@ RackGraph::RackGraph(CarlaEngine* const engine, const uint32_t ins, const uint32
RackGraph::~RackGraph() noexcept
{
clearConnections();
clearPorts();
}

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

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

CARLA_SAFE_ASSERT_RETURN(bufferSize > 0,);

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

if (inputs > 0 || outputs > 0)
{
audio.inBuf[0] = new float[bufferSize];
audio.inBuf[1] = new float[bufferSize];
audio.outBuf[0] = new float[bufferSize];
audio.outBuf[1] = new float[bufferSize];
audioBuffers.inBuf[0] = new float[bufferSize];
audioBuffers.inBuf[1] = new float[bufferSize];
audioBuffers.outBuf[0] = new float[bufferSize];
audioBuffers.outBuf[1] = new float[bufferSize];
}
}
catch(...) {
if (audio.inBufTmp[0] != nullptr) { delete[] audio.inBufTmp[0]; audio.inBufTmp[0] = nullptr; }
if (audio.inBufTmp[1] != nullptr) { delete[] audio.inBufTmp[1]; audio.inBufTmp[1] = nullptr; }
if (audioBuffers.inBufTmp[0] != nullptr) { delete[] audioBuffers.inBufTmp[0]; audioBuffers.inBufTmp[0] = nullptr; }
if (audioBuffers.inBufTmp[1] != nullptr) { delete[] audioBuffers.inBufTmp[1]; audioBuffers.inBufTmp[1] = nullptr; }

if (inputs > 0 || outputs > 0)
{
if (audio.inBuf[0] != nullptr) { delete[] audio.inBuf[0]; audio.inBuf[0] = nullptr; }
if (audio.inBuf[1] != nullptr) { delete[] audio.inBuf[1]; audio.inBuf[1] = nullptr; }
if (audio.outBuf[0] != nullptr) { delete[] audio.outBuf[0]; audio.outBuf[0] = nullptr; }
if (audio.outBuf[1] != nullptr) { delete[] audio.outBuf[1]; audio.outBuf[1] = nullptr; }
if (audioBuffers.inBuf[0] != nullptr) { delete[] audioBuffers.inBuf[0]; audioBuffers.inBuf[0] = nullptr; }
if (audioBuffers.inBuf[1] != nullptr) { delete[] audioBuffers.inBuf[1]; audioBuffers.inBuf[1] = nullptr; }
if (audioBuffers.outBuf[0] != nullptr) { delete[] audioBuffers.outBuf[0]; audioBuffers.outBuf[0] = nullptr; }
if (audioBuffers.outBuf[1] != nullptr) { delete[] audioBuffers.outBuf[1]; audioBuffers.outBuf[1] = nullptr; }
}
return;
}

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

if (inputs > 0 || outputs > 0)
{
FloatVectorOperations::clear(audio.inBuf[0], bufferSizei);
FloatVectorOperations::clear(audio.inBuf[1], bufferSizei);
FloatVectorOperations::clear(audio.outBuf[0], bufferSizei);
FloatVectorOperations::clear(audio.outBuf[1], bufferSizei);
FloatVectorOperations::clear(audioBuffers.inBuf[0], bufferSizei);
FloatVectorOperations::clear(audioBuffers.inBuf[1], bufferSizei);
FloatVectorOperations::clear(audioBuffers.outBuf[0], bufferSizei);
FloatVectorOperations::clear(audioBuffers.outBuf[1], bufferSizei);
}
}

@@ -255,41 +257,41 @@ bool RackGraph::connect(const uint groupA, const uint portA, const uint groupB,
{
case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_AUDIO_IN, false);
audio.mutex.lock();
makeConnection = audio.connectedIn1.append(otherPort);
audio.mutex.unlock();
audioBuffers.mutex.lock();
makeConnection = audioBuffers.connectedIn1.append(otherPort);
audioBuffers.mutex.unlock();
break;

case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_AUDIO_IN, false);
audio.mutex.lock();
makeConnection = audio.connectedIn2.append(otherPort);
audio.mutex.unlock();
audioBuffers.mutex.lock();
makeConnection = audioBuffers.connectedIn2.append(otherPort);
audioBuffers.mutex.unlock();
break;

case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_AUDIO_OUT, false);
audio.mutex.lock();
makeConnection = audio.connectedOut1.append(otherPort);
audio.mutex.unlock();
audioBuffers.mutex.lock();
makeConnection = audioBuffers.connectedOut1.append(otherPort);
audioBuffers.mutex.unlock();
break;

case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_AUDIO_OUT, false);
audio.mutex.lock();
makeConnection = audio.connectedOut2.append(otherPort);
audio.mutex.unlock();
audioBuffers.mutex.lock();
makeConnection = audioBuffers.connectedOut2.append(otherPort);
audioBuffers.mutex.unlock();
break;

case RACK_GRAPH_CARLA_PORT_MIDI_IN:
CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_MIDI_IN, false);
if (const char* const portName = midi.getName(true, otherPort))
if (const char* const portName = midiPorts.getName(true, otherPort))
makeConnection = kEngine->connectRackMidiInPort(portName);
break;

case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_MIDI_OUT, false);
if (const char* const portName = midi.getName(false, otherPort))
if (const char* const portName = midiPorts.getName(false, otherPort))
makeConnection = kEngine->connectRackMidiOutPort(portName);
break;
}
@@ -354,36 +356,36 @@ bool RackGraph::disconnect(const uint connectionId) noexcept
switch (carlaPort)
{
case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
audio.mutex.lock();
makeDisconnection = audio.connectedIn1.removeOne(otherPort);
audio.mutex.unlock();
audioBuffers.mutex.lock();
makeDisconnection = audioBuffers.connectedIn1.removeOne(otherPort);
audioBuffers.mutex.unlock();
break;

case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
audio.mutex.lock();
makeDisconnection = audio.connectedIn2.removeOne(otherPort);
audio.mutex.unlock();
audioBuffers.mutex.lock();
makeDisconnection = audioBuffers.connectedIn2.removeOne(otherPort);
audioBuffers.mutex.unlock();
break;

case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
audio.mutex.lock();
makeDisconnection = audio.connectedOut1.removeOne(otherPort);
audio.mutex.unlock();
audioBuffers.mutex.lock();
makeDisconnection = audioBuffers.connectedOut1.removeOne(otherPort);
audioBuffers.mutex.unlock();
break;

case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
audio.mutex.lock();
makeDisconnection = audio.connectedOut2.removeOne(otherPort);
audio.mutex.unlock();
audioBuffers.mutex.lock();
makeDisconnection = audioBuffers.connectedOut2.removeOne(otherPort);
audioBuffers.mutex.unlock();
break;

case RACK_GRAPH_CARLA_PORT_MIDI_IN:
if (const char* const portName = midi.getName(true, otherPort))
if (const char* const portName = midiPorts.getName(true, otherPort))
makeDisconnection = kEngine->disconnectRackMidiInPort(portName);
break;

case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
if (const char* const portName = midi.getName(false, otherPort))
if (const char* const portName = midiPorts.getName(false, otherPort))
makeDisconnection = kEngine->disconnectRackMidiOutPort(portName);
break;
}
@@ -404,22 +406,28 @@ bool RackGraph::disconnect(const uint connectionId) noexcept
return false;
}

void RackGraph::clearPorts() noexcept
{
audioPorts.ins.clear();
audioPorts.outs.clear();

midiPorts.ins.clear();
midiPorts.outs.clear();
}

void RackGraph::clearConnections() noexcept
{
connections.clear();

audio.mutex.lock();
audio.connectedIn1.clear();
audio.connectedIn2.clear();
audio.connectedOut1.clear();
audio.connectedOut2.clear();
audio.mutex.unlock();

midi.ins.clear();
midi.outs.clear();
audioBuffers.mutex.lock();
audioBuffers.connectedIn1.clear();
audioBuffers.connectedIn2.clear();
audioBuffers.connectedOut1.clear();
audioBuffers.connectedOut2.clear();
audioBuffers.mutex.unlock();
}

void RackGraph::refreshConnections(const char* const deviceName)
void RackGraph::refresh(const char* const deviceName)
{
CARLA_SAFE_ASSERT_RETURN(deviceName != nullptr,);

@@ -437,9 +445,155 @@ void RackGraph::refreshConnections(const char* const deviceName)
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_MIDI_OUT, PATCHBAY_PORT_TYPE_MIDI, 0.0f, "midi-out");
}

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

// Audio In
{
if (deviceName[0] != '\0')
std::snprintf(strBuf, STR_MAX, "Capture (%s)", deviceName);
else
std::strncpy(strBuf, "Capture", STR_MAX);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_AUDIO_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, strBuf);

const CarlaString groupName(strBuf);

int h = 0;
for (LinkedList<PortNameToId>::Itenerator it = audioPorts.ins.begin(); it.valid(); it.next())
{
PortNameToId& portNameToId(it.getValue());
portNameToId.setFullName(groupName + portNameToId.name);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_AUDIO_IN, ++h,
PATCHBAY_PORT_TYPE_AUDIO, 0.0f, portNameToId.name);
}
}

// Audio Out
{
if (deviceName[0] != '\0')
std::snprintf(strBuf, STR_MAX, "Playback (%s)", deviceName);
else
std::strncpy(strBuf, "Playback", STR_MAX);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_AUDIO_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, strBuf);

const CarlaString groupName(strBuf);

int h = 0;
for (LinkedList<PortNameToId>::Itenerator it = audioPorts.outs.begin(); it.valid(); it.next())
{
PortNameToId& portNameToId(it.getValue());
portNameToId.setFullName(groupName + portNameToId.name);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_AUDIO_OUT, ++h,
PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, portNameToId.name);
}
}

// MIDI In
{
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Readable MIDI ports");

const CarlaString groupNamePlus("Readable MIDI ports:");

int h = 0;
for (LinkedList<PortNameToId>::Itenerator it = midiPorts.ins.begin(); it.valid(); it.next())
{
PortNameToId& portNameToId(it.getValue());
portNameToId.setFullName(groupNamePlus + portNameToId.name);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, ++h,
PATCHBAY_PORT_TYPE_MIDI, 0.0f, portNameToId.name);
}
}

// MIDI Out
{
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Writable MIDI ports");

const CarlaString groupNamePlus("Writable MIDI ports:");

int h = 0;
for (LinkedList<PortNameToId>::Itenerator it = midiPorts.outs.begin(); it.valid(); it.next())
{
PortNameToId& portNameToId(it.getValue());
portNameToId.setFullName(groupNamePlus + portNameToId.name);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, ++h,
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());

ConnectionToId connectionToId;
connectionToId.setData(++(connections.lastId), RACK_GRAPH_GROUP_AUDIO_IN, portId, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_IN1);

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());

ConnectionToId connectionToId;
connectionToId.setData(++(connections.lastId), RACK_GRAPH_GROUP_AUDIO_IN, portId, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_IN2);

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());

ConnectionToId connectionToId;
connectionToId.setData(++(connections.lastId), RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_OUT1, RACK_GRAPH_GROUP_AUDIO_OUT, 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());

ConnectionToId connectionToId;
connectionToId.setData(++(connections.lastId), RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_OUT2, RACK_GRAPH_GROUP_AUDIO_OUT, 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* RackGraph::getConnections() const noexcept
@@ -485,26 +639,26 @@ const char* const* RackGraph::getConnections() const noexcept
{
case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
std::snprintf(strBuf, STR_MAX, "AudioIn:%i", otherPort);
std::snprintf(strBuf, STR_MAX, "AudioIn:%s", audioPorts.getName(true, otherPort));
connList.append(strBuf);
connList.append(getCarlaRackFullPortNameFromId(carlaPort));
break;

case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
std::snprintf(strBuf, STR_MAX, "AudioOut:%i", otherPort);
std::snprintf(strBuf, STR_MAX, "AudioOut:%s", audioPorts.getName(false, otherPort));
connList.append(getCarlaRackFullPortNameFromId(carlaPort));
connList.append(strBuf);
break;

case RACK_GRAPH_CARLA_PORT_MIDI_IN:
std::snprintf(strBuf, STR_MAX, "MidiIn:%s", midi.getName(true, otherPort));
std::snprintf(strBuf, STR_MAX, "MidiIn:%s", midiPorts.getName(true, otherPort));
connList.append(strBuf);
connList.append(getCarlaRackFullPortNameFromId(carlaPort));
break;

case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
std::snprintf(strBuf, STR_MAX, "MidiOut:%s", midi.getName(false, otherPort));
std::snprintf(strBuf, STR_MAX, "MidiOut:%s", midiPorts.getName(false, otherPort));
connList.append(getCarlaRackFullPortNameFromId(carlaPort));
connList.append(strBuf);
break;
@@ -535,20 +689,22 @@ bool RackGraph::getGroupAndPortIdFromFullName(const char* const fullPortName, ui
{
groupId = RACK_GRAPH_GROUP_AUDIO_IN;

if (const int portTest = std::atoi(fullPortName+8))
if (const char* const portName = fullPortName+8)
{
portId = static_cast<uint>(portTest);
return true;
bool ok;
portId = audioPorts.getPortId(true, portName, &ok);
return ok;
}
}
else if (std::strncmp(fullPortName, "AudioOut:", 9) == 0)
{
groupId = RACK_GRAPH_GROUP_AUDIO_OUT;

if (const int portTest = std::atoi(fullPortName+9))
if (const char* const portName = fullPortName+8)
{
portId = static_cast<uint>(portTest);
return true;
bool ok;
portId = audioPorts.getPortId(false, portName, &ok);
return ok;
}
}
else if (std::strncmp(fullPortName, "MidiIn:", 7) == 0)
@@ -558,7 +714,7 @@ bool RackGraph::getGroupAndPortIdFromFullName(const char* const fullPortName, ui
if (const char* const portName = fullPortName+7)
{
bool ok;
portId = midi.getPortId(true, portName, &ok);
portId = midiPorts.getPortId(true, portName, &ok);
return ok;
}
}
@@ -569,7 +725,7 @@ bool RackGraph::getGroupAndPortIdFromFullName(const char* const fullPortName, ui
if (const char* const portName = fullPortName+8)
{
bool ok;
portId = midi.getPortId(false, portName, &ok);
portId = midiPorts.getPortId(false, portName, &ok);
return ok;
}
}
@@ -699,18 +855,18 @@ 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)
{
CARLA_SAFE_ASSERT_RETURN(audio.outBuf[1] != nullptr,);
CARLA_SAFE_ASSERT_RETURN(audioBuffers.outBuf[1] != nullptr,);

const int iframes(static_cast<int>(frames));

const CarlaRecursiveMutexLocker _cml(audio.mutex);
const CarlaRecursiveMutexLocker _cml(audioBuffers.mutex);

if (inBuf != nullptr && inputs > 0)
{
bool noConnections = true;

// connect input buffers
for (LinkedList<uint>::Itenerator it = audio.connectedIn1.begin(); it.valid(); it.next())
for (LinkedList<uint>::Itenerator it = audioBuffers.connectedIn1.begin(); it.valid(); it.next())
{
const uint& port(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(port != 0);
@@ -718,21 +874,21 @@ void RackGraph::processHelper(CarlaEngine::ProtectedData* const data, const floa

if (noConnections)
{
FloatVectorOperations::copy(audio.inBuf[0], inBuf[port], iframes);
FloatVectorOperations::copy(audioBuffers.inBuf[0], inBuf[port], iframes);
noConnections = false;
}
else
{
FloatVectorOperations::add(audio.inBuf[0], inBuf[port], iframes);
FloatVectorOperations::add(audioBuffers.inBuf[0], inBuf[port], iframes);
}
}

if (noConnections)
FloatVectorOperations::clear(audio.inBuf[0], iframes);
FloatVectorOperations::clear(audioBuffers.inBuf[0], iframes);

noConnections = true;

for (LinkedList<uint>::Itenerator it = audio.connectedIn2.begin(); it.valid(); it.next())
for (LinkedList<uint>::Itenerator it = audioBuffers.connectedIn2.begin(); it.valid(); it.next())
{
const uint& port(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(port != 0);
@@ -740,52 +896,52 @@ void RackGraph::processHelper(CarlaEngine::ProtectedData* const data, const floa

if (noConnections)
{
FloatVectorOperations::copy(audio.inBuf[1], inBuf[port], iframes);
FloatVectorOperations::copy(audioBuffers.inBuf[1], inBuf[port], iframes);
noConnections = false;
}
else
{
FloatVectorOperations::add(audio.inBuf[1], inBuf[port], iframes);
FloatVectorOperations::add(audioBuffers.inBuf[1], inBuf[port], iframes);
}
}

if (noConnections)
FloatVectorOperations::clear(audio.inBuf[1], iframes);
FloatVectorOperations::clear(audioBuffers.inBuf[1], iframes);
}
else
{
FloatVectorOperations::clear(audio.inBuf[0], iframes);
FloatVectorOperations::clear(audio.inBuf[1], iframes);
FloatVectorOperations::clear(audioBuffers.inBuf[0], iframes);
FloatVectorOperations::clear(audioBuffers.inBuf[1], iframes);
}

FloatVectorOperations::clear(audio.outBuf[0], iframes);
FloatVectorOperations::clear(audio.outBuf[1], iframes);
FloatVectorOperations::clear(audioBuffers.outBuf[0], iframes);
FloatVectorOperations::clear(audioBuffers.outBuf[1], iframes);

// process
process(data, const_cast<const float**>(audio.inBuf), audio.outBuf, frames);
process(data, const_cast<const float**>(audioBuffers.inBuf), audioBuffers.outBuf, frames);

// connect output buffers
if (audio.connectedOut1.count() != 0)
if (audioBuffers.connectedOut1.count() != 0)
{
for (LinkedList<uint>::Itenerator it = audio.connectedOut1.begin(); it.valid(); it.next())
for (LinkedList<uint>::Itenerator it = audioBuffers.connectedOut1.begin(); it.valid(); it.next())
{
const uint& port(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(port > 0);
CARLA_SAFE_ASSERT_CONTINUE(port <= outputs);

FloatVectorOperations::add(outBuf[port-1], audio.outBuf[0], iframes);
FloatVectorOperations::add(outBuf[port-1], audioBuffers.outBuf[0], iframes);
}
}

if (audio.connectedOut2.count() != 0)
if (audioBuffers.connectedOut2.count() != 0)
{
for (LinkedList<uint>::Itenerator it = audio.connectedOut2.begin(); it.valid(); it.next())
for (LinkedList<uint>::Itenerator it = audioBuffers.connectedOut2.begin(); it.valid(); it.next())
{
const uint& port(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(port > 0);
CARLA_SAFE_ASSERT_CONTINUE(port <= outputs);

FloatVectorOperations::add(outBuf[port-1], audio.outBuf[1], iframes);
FloatVectorOperations::add(outBuf[port-1], audioBuffers.outBuf[1], iframes);
}
}
}
@@ -1106,11 +1262,11 @@ public:
void prepareToPlay(double, int) override {}
void releaseResources() override {}

const String getParameterName(int) override { return String(); }
String getParameterName(int, int) override { return String(); }
const String getParameterText(int) override { return String(); }
String getParameterText(int, int) override { return String(); }
const String getProgramName(int) override { return String(); }
const String getParameterName(int) override { return String(); }
String getParameterName(int, int) override { return String(); }
const String getParameterText(int) override { return String(); }
String getParameterText(int, int) override { return String(); }
const String getProgramName(int) override { return String(); }

double getTailLengthSeconds() const override { return 0.0; }
float getParameter(int) override { return 0.0f; }
@@ -1157,6 +1313,8 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons
outputs(carla_fixValue(0U, MAX_PATCHBAY_PLUGINS-2, outs)),
ignorePathbay(false),
retCon(),
audioPorts(),
midiPorts(),
kEngine(engine)
{
const int bufferSize(static_cast<int>(engine->getBufferSize()));
@@ -1176,7 +1334,9 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons
node->properties.set("isPlugin", false);
node->properties.set("isOutput", false);
node->properties.set("isAudio", true);
node->properties.set("isCV", false);
node->properties.set("isMIDI", false);
node->properties.set("isOSC", false);
}

{
@@ -1185,7 +1345,9 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons
node->properties.set("isPlugin", false);
node->properties.set("isOutput", false);
node->properties.set("isAudio", true);
node->properties.set("isCV", false);
node->properties.set("isMIDI", false);
node->properties.set("isOSC", false);
}

{
@@ -1194,7 +1356,9 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons
node->properties.set("isPlugin", false);
node->properties.set("isOutput", false);
node->properties.set("isAudio", false);
node->properties.set("isCV", false);
node->properties.set("isMIDI", true);
node->properties.set("isOSC", false);
}

{
@@ -1203,13 +1367,16 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons
node->properties.set("isPlugin", false);
node->properties.set("isOutput", true);
node->properties.set("isAudio", false);
node->properties.set("isCV", false);
node->properties.set("isMIDI", true);
node->properties.set("isOSC", false);
}
}

PatchbayGraph::~PatchbayGraph()
{
clearConnections();
clearPorts();
graph.releaseResources();
graph.clear();
audioBuffer.clear();
@@ -1434,6 +1601,15 @@ void PatchbayGraph::disconnectGroup(const uint groupId) noexcept
}
}

void PatchbayGraph::clearPorts() noexcept
{
audioPorts.ins.clear();
audioPorts.outs.clear();

midiPorts.ins.clear();
midiPorts.outs.clear();
}

void PatchbayGraph::clearConnections()
{
connections.clear();
@@ -1442,7 +1618,7 @@ void PatchbayGraph::clearConnections()
graph.removeConnection(0);
}

void PatchbayGraph::refreshConnections(const char* const deviceName)
void PatchbayGraph::refresh(const char* const deviceName)
{
CARLA_SAFE_ASSERT_RETURN(deviceName != nullptr,);

@@ -1461,13 +1637,61 @@ void PatchbayGraph::refreshConnections(const char* const deviceName)

int clientId = -1;

// plugin node
if (node->properties.getWithDefault("isPlugin", false) == juce::var(true))
{
clientId = node->properties.getWithDefault("pluginId", -1);
}
#if 0
// hardware node
else
{
// skip hardware midi nodes
if (node->properties.getWithDefault("isMIDI", false) == juce::var(true))
continue;
}
#endif

addNodeToPatchbay(kEngine, node->nodeId, clientId, proc);
}
}

#if 0
// MIDI In
{
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Readable MIDI ports");

const CarlaString groupNamePlus("Readable MIDI ports:");

int h = 0;
for (LinkedList<PortNameToId>::Itenerator it = midiPorts.ins.begin(); it.valid(); it.next())
{
PortNameToId& portNameToId(it.getValue());
portNameToId.setFullName(groupNamePlus + portNameToId.name);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, ++h,
PATCHBAY_PORT_TYPE_MIDI, 0.0f, portNameToId.name);
}
}

// MIDI Out
{
kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Writable MIDI ports");

const CarlaString groupNamePlus("Writable MIDI ports:");

int h = 0;
for (LinkedList<PortNameToId>::Itenerator it = midiPorts.outs.begin(); it.valid(); it.next())
{
PortNameToId& portNameToId(it.getValue());
portNameToId.setFullName(groupNamePlus + portNameToId.name);

kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, ++h,
PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, portNameToId.name);
}
}
#endif

char strBuf[STR_MAX+1];

for (int i=0, count=graph.getNumConnections(); i<count; ++i)
@@ -1572,30 +1796,29 @@ bool PatchbayGraph::getGroupAndPortIdFromFullName(const char* const fullPortName
portId = kMidiInputPortOffset;
return true;
}

if (portName == "events-out")
{
portId = kMidiOutputPortOffset;
return true;
}
else

for (int j=0, numInputs=proc->getNumInputChannels(); j<numInputs; ++j)
{
for (int j=0, numInputs=proc->getNumInputChannels(); j<numInputs; ++j)
{
if (proc->getInputChannelName(j) != portName)
continue;
if (proc->getInputChannelName(j) != portName)
continue;

portId = kAudioInputPortOffset+static_cast<uint>(j);
return true;
}
portId = kAudioInputPortOffset+static_cast<uint>(j);
return true;
}

for (int j=0, numOutputs=proc->getNumOutputChannels(); j<numOutputs; ++j)
{
if (proc->getOutputChannelName(j) != portName)
continue;
for (int j=0, numOutputs=proc->getNumOutputChannels(); j<numOutputs; ++j)
{
if (proc->getOutputChannelName(j) != portName)
continue;

portId = kAudioOutputPortOffset+static_cast<uint>(j);
return true;
}
portId = kAudioOutputPortOffset+static_cast<uint>(j);
return true;
}
}

@@ -1882,12 +2105,14 @@ bool CarlaEngine::patchbayRefresh(const bool external)
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
{
if (RackGraph* const graph = pData->graph.getRackGraph())
graph->refreshConnections("");
graph->refresh("");
}
else
{
if (PatchbayGraph* const graph = pData->graph.getPatchbayGraph())
graph->refreshConnections("");
{
graph->refresh("");
}
}

return true;


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

@@ -30,6 +30,18 @@ using juce::MidiBuffer;

CARLA_BACKEND_START_NAMESPACE

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

struct GraphPorts {
LinkedList<PortNameToId> ins;
LinkedList<PortNameToId> outs;
const char* getName(const bool isInput, const uint portId) const noexcept;
uint getPortId(const bool isInput, const char portName[], bool* const ok = nullptr) const noexcept;
GraphPorts() noexcept;
CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(GraphPorts)
};

// -----------------------------------------------------------------------
// Rack Graph stuff

@@ -64,7 +76,7 @@ struct RackGraph {
bool isOffline;
mutable CharStringListPtr retCon;

struct Audio {
struct AudioBuffers {
CarlaRecursiveMutex mutex;
LinkedList<uint> connectedIn1;
LinkedList<uint> connectedIn2;
@@ -73,22 +85,12 @@ struct RackGraph {
float* inBuf[2];
float* inBufTmp[2];
float* outBuf[2];
// c++ compat stuff
Audio() noexcept;
AudioBuffers() noexcept;
CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(Audio)
} audio;

struct MIDI {
LinkedList<PortNameToId> ins;
LinkedList<PortNameToId> outs;
const char* getName(const bool isInput, const uint portId) const noexcept;
uint getPortId(const bool isInput, const char portName[], bool* const ok = nullptr) const noexcept;
// c++ compat stuff
MIDI() noexcept;
CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(MIDI)
} midi;
CARLA_DECLARE_NON_COPY_CLASS(AudioBuffers)
} audioBuffers;

GraphPorts audioPorts, midiPorts;

RackGraph(CarlaEngine* const engine, const uint32_t inputs, const uint32_t outputs) noexcept;
~RackGraph() noexcept;
@@ -98,8 +100,9 @@ struct RackGraph {

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

const char* const* getConnections() const noexcept;
bool getGroupAndPortIdFromFullName(const char* const fullPortName, uint& groupId, uint& portId) const noexcept;
@@ -127,6 +130,8 @@ struct PatchbayGraph {
bool ignorePathbay;
mutable CharStringListPtr retCon;

GraphPorts audioPorts, midiPorts;

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

@@ -142,8 +147,9 @@ struct PatchbayGraph {
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 clearPorts() noexcept;
void clearConnections();
void refreshConnections(const char* const deviceName);
void refresh(const char* const deviceName);

const char* const* getConnections() const;
bool getGroupAndPortIdFromFullName(const char* const fullPortName, uint& groupId, uint& portId) const;


+ 57
- 131
source/backend/engine/CarlaEngineJuce.cpp View File

@@ -73,7 +73,6 @@ static void initJuceDevicesIfNeeded()
// Juce Engine

class CarlaEngineJuce : public CarlaEngine,
public CarlaEngineGraphImpl,
public AudioIODeviceCallback,
public MidiInputCallback
{
@@ -262,83 +261,54 @@ public:
// -------------------------------------------------------------------
// Patchbay

bool patchbayRefresh(const bool /*external*/) override
{
CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), false);

//fUsedMidiPorts.clear();

if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
patchbayRefreshRack();
else
patchbayRefreshPatchbay();

return true;
}

void patchbayRefreshRack()
template<class Graph>
void refreshGraphPorts(Graph* const graph)
{
RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr,);

String deviceName(fDevice->getName());
char strBuf[STR_MAX+1];
strBuf[STR_MAX] = '\0';

if (deviceName.isNotEmpty())
deviceName = deviceName.dropLastCharacters(deviceName.fromFirstOccurrenceOf(", ", true, false).length());
// ---------------------------------------------------------------
// clear last ports

graph->refreshConnections(this, deviceName.toRawUTF8());
graph->clearPorts();

char strBuf[STR_MAX+1];
strBuf[STR_MAX] = '\0';
// ---------------------------------------------------------------
// fill in new ones

// Audio In
{
StringArray inputNames(fDevice->getInputChannelNames());

if (deviceName.isNotEmpty())
std::snprintf(strBuf, STR_MAX, "Capture (%s)", deviceName.toRawUTF8());
else
std::strncpy(strBuf, "Capture", STR_MAX);

callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_AUDIO_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, strBuf);

for (int i=0, count=inputNames.size(); i<count; ++i)
callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_AUDIO_IN, static_cast<int>(i)+1, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, inputNames[i].toRawUTF8());
{
PortNameToId portNameToId;
portNameToId.setData(RACK_GRAPH_GROUP_AUDIO_IN, uint(i+1), inputNames[i].toRawUTF8(), "");

graph->audioPorts.ins.append(portNameToId);
}
}

// Audio Out
{
StringArray outputNames(fDevice->getOutputChannelNames());

if (deviceName.isNotEmpty())
std::snprintf(strBuf, STR_MAX, "Playback (%s)", deviceName.toRawUTF8());
else
std::strncpy(strBuf, "Playback", STR_MAX);

callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_AUDIO_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, strBuf);

for (int i=0, count=outputNames.size(); i<count; ++i)
callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_AUDIO_OUT, static_cast<int>(i)+1, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, outputNames[i].toRawUTF8());
{
PortNameToId portNameToId;
portNameToId.setData(RACK_GRAPH_GROUP_AUDIO_OUT, uint(i+1), outputNames[i].toRawUTF8(), "");
}
}

// MIDI In
{
StringArray midiIns(MidiInput::getDevices());

callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Readable MIDI ports");

for (int i=0, count=midiIns.size(); i<count; ++i)
{
String portName(midiIns[i]);

std::snprintf(strBuf, STR_MAX, "Readable MIDI ports:%s", portName.toRawUTF8());

PortNameToId portNameToId;
portNameToId.setData(RACK_GRAPH_GROUP_MIDI_IN, static_cast<uint>(i)+1, portName.toRawUTF8(), strBuf);

callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, portNameToId.group, static_cast<int>(portNameToId.port), PATCHBAY_PORT_TYPE_MIDI, 0.0f, portNameToId.name);
portNameToId.setData(RACK_GRAPH_GROUP_MIDI_IN, uint(i+1), midiIns[i].toRawUTF8(), "");

graph->midi.ins.append(portNameToId);
graph->midiPorts.ins.append(portNameToId);
}
}

@@ -346,94 +316,36 @@ public:
{
StringArray midiOuts(MidiOutput::getDevices());

callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Writable MIDI ports");

for (int i=0, count=midiOuts.size(); i<count; ++i)
{
String portName(midiOuts[i]);

std::snprintf(strBuf, STR_MAX, "Writable MIDI ports:%s", portName.toRawUTF8());

PortNameToId portNameToId;
portNameToId.setData(RACK_GRAPH_GROUP_MIDI_OUT, static_cast<uint>(i)+1, portName.toRawUTF8(), strBuf);
portNameToId.setData(RACK_GRAPH_GROUP_MIDI_OUT, uint(i+1), midiOuts[i].toRawUTF8(), "");

callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, portNameToId.group, static_cast<int>(portNameToId.port), PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, portNameToId.name);

graph->midi.outs.append(portNameToId);
graph->midiPorts.outs.append(portNameToId);
}
}

// Connections
graph->audio.mutex.lock();

for (LinkedList<uint>::Itenerator it = graph->audio.connectedIn1.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue());
//CARLA_SAFE_ASSERT_CONTINUE(portId < fAudioInCount);

ConnectionToId connectionToId;
connectionToId.setData(++(graph->connections.lastId), RACK_GRAPH_GROUP_AUDIO_IN, portId, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_IN1);

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);

graph->connections.list.append(connectionToId);
}

for (LinkedList<uint>::Itenerator it = graph->audio.connectedIn2.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue());
//CARLA_SAFE_ASSERT_CONTINUE(portId < fAudioInCount);

ConnectionToId connectionToId;
connectionToId.setData(++(graph->connections.lastId), RACK_GRAPH_GROUP_AUDIO_IN, portId, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_IN2);

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);
// ---------------------------------------------------------------
// now refresh

graph->connections.list.append(connectionToId);
}

for (LinkedList<uint>::Itenerator it = graph->audio.connectedOut1.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue());
//CARLA_SAFE_ASSERT_CONTINUE(portId < fAudioOutCount);
String deviceName(fDevice->getName());

ConnectionToId connectionToId;
connectionToId.setData(++(graph->connections.lastId), RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_OUT1, RACK_GRAPH_GROUP_AUDIO_OUT, portId);

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);

graph->connections.list.append(connectionToId);
}

for (LinkedList<uint>::Itenerator it = graph->audio.connectedOut2.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue());
//CARLA_SAFE_ASSERT_CONTINUE(portId < fAudioOutCount);

ConnectionToId connectionToId;
connectionToId.setData(++(graph->connections.lastId), RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_OUT2, RACK_GRAPH_GROUP_AUDIO_OUT, portId);

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);
if (deviceName.isNotEmpty())
deviceName = deviceName.dropLastCharacters(deviceName.fromFirstOccurrenceOf(", ", true, false).length());

graph->connections.list.append(connectionToId);
graph->refresh(deviceName.toRawUTF8());
}

graph->audio.mutex.unlock();
// ---------------------------------------------------------------
// add midi connections

for (LinkedList<MidiInPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
{
const MidiInPort& inPort(it.getValue());

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

ConnectionToId connectionToId;
connectionToId.setData(++(graph->connections.lastId), RACK_GRAPH_GROUP_MIDI_IN, portId, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_MIDI_IN);
@@ -451,8 +363,8 @@ public:
{
const MidiOutPort& outPort(it.getValue());

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

ConnectionToId connectionToId;
connectionToId.setData(++(graph->connections.lastId), RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_MIDI_OUT, RACK_GRAPH_GROUP_MIDI_OUT, portId);
@@ -467,12 +379,26 @@ public:
fMidiOutMutex.unlock();
}

void patchbayRefreshPatchbay() noexcept
bool patchbayRefresh(const bool /*external*/) override
{
PatchbayGraph* const graph(pData->graph.getPatchbayGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr,);
CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), false);

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

graph->refreshConnections(this);
refreshGraphPorts<RackGraph>(graph);
}
else
{
PatchbayGraph* const graph(pData->graph.getPatchbayGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);

refreshGraphPorts<PatchbayGraph>(graph);
}

return true;
}

// -------------------------------------------------------------------
@@ -634,7 +560,7 @@ protected:

RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->midi.ins.count() > 0, false);
CARLA_SAFE_ASSERT_RETURN(graph->midiPorts.ins.count() > 0, false);

StringArray midiIns(MidiInput::getDevices());

@@ -661,7 +587,7 @@ protected:

RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->midi.ins.count() > 0, false);
CARLA_SAFE_ASSERT_RETURN(graph->midiPorts.ins.count() > 0, false);

StringArray midiOuts(MidiOutput::getDevices());

@@ -690,7 +616,7 @@ protected:

RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->midi.ins.count() > 0, false);
CARLA_SAFE_ASSERT_RETURN(graph->midiPorts.ins.count() > 0, false);

for (LinkedList<MidiInPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
{
@@ -717,7 +643,7 @@ protected:

RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->midi.outs.count() > 0, false);
CARLA_SAFE_ASSERT_RETURN(graph->midiPorts.outs.count() > 0, false);

const CarlaMutexLocker cml(fMidiOutMutex);



+ 56
- 137
source/backend/engine/CarlaEngineRtAudio.cpp View File

@@ -402,170 +402,75 @@ public:
// -------------------------------------------------------------------
// Patchbay

bool patchbayRefresh(const bool /*external*/) override
template<class Graph>
void refreshGraphPorts(Graph* const graph)
{
CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), false);

if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
patchbayRefreshRack();
else
patchbayRefreshPatchbay();
char strBuf[STR_MAX+1];
strBuf[STR_MAX] = '\0';

return true;
}
// ---------------------------------------------------------------
// clear last ports

void patchbayRefreshRack()
{
RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr,);
graph->clearPorts();

graph->refreshConnections(fDeviceName.buffer());

char strBuf[STR_MAX+1];
strBuf[STR_MAX] = '\0';
// ---------------------------------------------------------------
// fill in new ones

// Audio In
for (uint i=0; i < fAudioInCount; ++i)
{
if (fDeviceName.isNotEmpty())
std::snprintf(strBuf, STR_MAX, "Capture (%s)", fDeviceName.buffer());
else
std::strncpy(strBuf, "Capture", STR_MAX);
std::snprintf(strBuf, STR_MAX, "capture_%i", i+1);

callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_AUDIO_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, strBuf);
PortNameToId portNameToId;
portNameToId.setData(RACK_GRAPH_GROUP_AUDIO_IN, i+1, strBuf, "");

for (uint i=0; i < fAudioInCount; ++i)
{
std::snprintf(strBuf, STR_MAX, "capture_%i", i+1);
callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_AUDIO_IN, static_cast<int>(i)+1, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, strBuf);
}
graph->audioPorts.ins.append(portNameToId);
}

// Audio Out
for (uint i=0; i < fAudioOutCount; ++i)
{
if (fDeviceName.isNotEmpty())
std::snprintf(strBuf, STR_MAX, "Playback (%s)", fDeviceName.buffer());
else
std::strncpy(strBuf, "Playback", STR_MAX);
std::snprintf(strBuf, STR_MAX, "playback_%i", i+1);

callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_AUDIO_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, strBuf);
PortNameToId portNameToId;
portNameToId.setData(RACK_GRAPH_GROUP_AUDIO_OUT, i+1, strBuf, "");

for (uint i=0; i < fAudioOutCount; ++i)
{
std::snprintf(strBuf, STR_MAX, "playback_%i", i+1);
callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_AUDIO_OUT, static_cast<int>(i)+1, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, strBuf);
}
graph->audioPorts.outs.append(portNameToId);
}

// MIDI In
{
RtMidiIn midiIn(getMatchedAudioMidiAPI(fAudio.getCurrentApi()), "carla-discovery");

callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Readable MIDI ports");
RtMidiIn midiIn(getMatchedAudioMidiAPI(fAudio.getCurrentApi()), "carla-discovery-in");

for (uint i=0, count = midiIn.getPortCount(); i < count; ++i)
{
std::string portName(midiIn.getPortName(i));

std::snprintf(strBuf, STR_MAX, "Readable MIDI ports:%s", portName.c_str());

PortNameToId portNameToId;
portNameToId.setData(RACK_GRAPH_GROUP_MIDI_IN, i+1, portName.c_str(), strBuf);

callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, portNameToId.group, static_cast<int>(portNameToId.port), PATCHBAY_PORT_TYPE_MIDI, 0.0f, portNameToId.name);
portNameToId.setData(RACK_GRAPH_GROUP_MIDI_IN, i+1, midiIn.getPortName(i).c_str(), "");

graph->midi.ins.append(portNameToId);
graph->midiPorts.ins.append(portNameToId);
}
}

// MIDI Out
{
RtMidiOut midiOut(getMatchedAudioMidiAPI(fAudio.getCurrentApi()), "carla-discovery");

callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Writable MIDI ports");
RtMidiOut midiOut(getMatchedAudioMidiAPI(fAudio.getCurrentApi()), "carla-discovery-out");

for (uint i=0, count = midiOut.getPortCount(); i < count; ++i)
{
std::string portName(midiOut.getPortName(i));

std::snprintf(strBuf, STR_MAX, "Writable MIDI ports:%s", portName.c_str());

PortNameToId portNameToId;
portNameToId.setData(RACK_GRAPH_GROUP_MIDI_OUT, i+1, portName.c_str(), strBuf);
portNameToId.setData(RACK_GRAPH_GROUP_MIDI_OUT, i+1, midiOut.getPortName(i).c_str(), "");

callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, portNameToId.group, static_cast<int>(portNameToId.port), PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, portNameToId.name);

graph->midi.outs.append(portNameToId);
graph->midiPorts.outs.append(portNameToId);
}
}

// Connections
graph->audio.mutex.lock();
// ---------------------------------------------------------------
// now refresh

for (LinkedList<uint>::Itenerator it = graph->audio.connectedIn1.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
CARLA_SAFE_ASSERT_CONTINUE(portId < fAudioInCount);
graph->refresh(fDeviceName.buffer());

ConnectionToId connectionToId;
connectionToId.setData(++(graph->connections.lastId), RACK_GRAPH_GROUP_AUDIO_IN, portId, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_IN1);

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);

graph->connections.list.append(connectionToId);
}

for (LinkedList<uint>::Itenerator it = graph->audio.connectedIn2.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
CARLA_SAFE_ASSERT_CONTINUE(portId < fAudioInCount);

ConnectionToId connectionToId;
connectionToId.setData(++(graph->connections.lastId), RACK_GRAPH_GROUP_AUDIO_IN, portId, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_IN2);

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);

graph->connections.list.append(connectionToId);
}

for (LinkedList<uint>::Itenerator it = graph->audio.connectedOut1.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
CARLA_SAFE_ASSERT_CONTINUE(portId < fAudioOutCount);

ConnectionToId connectionToId;
connectionToId.setData(++(graph->connections.lastId), RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_OUT1, RACK_GRAPH_GROUP_AUDIO_OUT, portId);

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);

graph->connections.list.append(connectionToId);
}

for (LinkedList<uint>::Itenerator it = graph->audio.connectedOut2.begin(); it.valid(); it.next())
{
const uint& portId(it.getValue(0));
CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
CARLA_SAFE_ASSERT_CONTINUE(portId < fAudioOutCount);

ConnectionToId connectionToId;
connectionToId.setData(++(graph->connections.lastId), RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_OUT2, RACK_GRAPH_GROUP_AUDIO_OUT, portId);

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);

graph->connections.list.append(connectionToId);
}

graph->audio.mutex.unlock();
// ---------------------------------------------------------------
// add midi connections

for (LinkedList<MidiInPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
{
@@ -574,8 +479,8 @@ public:
const MidiInPort& inPort(it.getValue(fallback));
CARLA_SAFE_ASSERT_CONTINUE(inPort.port != nullptr);

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

ConnectionToId connectionToId;
connectionToId.setData(++(graph->connections.lastId), RACK_GRAPH_GROUP_MIDI_IN, portId, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_MIDI_IN);
@@ -596,8 +501,8 @@ public:
const MidiOutPort& outPort(it.getValue(fallback));
CARLA_SAFE_ASSERT_CONTINUE(outPort.port != nullptr);

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

ConnectionToId connectionToId;
connectionToId.setData(++(graph->connections.lastId), RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_MIDI_OUT, RACK_GRAPH_GROUP_MIDI_OUT, portId);
@@ -612,12 +517,26 @@ public:
fMidiOutMutex.unlock();
}

void patchbayRefreshPatchbay() noexcept
bool patchbayRefresh(const bool /*external*/) override
{
PatchbayGraph* const graph(pData->graph.getPatchbayGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr,);
CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), false);

graph->refreshConnections(fDeviceName.buffer());
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
{
RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);

refreshGraphPorts<RackGraph>(graph);
}
else
{
PatchbayGraph* const graph(pData->graph.getPatchbayGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);

refreshGraphPorts<PatchbayGraph>(graph);
}

return true;
}

// -------------------------------------------------------------------
@@ -821,7 +740,7 @@ protected:

RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->midi.ins.count() > 0, false);
CARLA_SAFE_ASSERT_RETURN(graph->midiPorts.ins.count() > 0, false);

CarlaString newRtMidiPortName;
newRtMidiPortName += getName();
@@ -876,7 +795,7 @@ protected:

RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->midi.ins.count() > 0, false);
CARLA_SAFE_ASSERT_RETURN(graph->midiPorts.ins.count() > 0, false);

CarlaString newRtMidiPortName;
newRtMidiPortName += getName();
@@ -931,7 +850,7 @@ protected:

RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->midi.ins.count() > 0, false);
CARLA_SAFE_ASSERT_RETURN(graph->midiPorts.ins.count() > 0, false);

for (LinkedList<MidiInPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
{
@@ -961,7 +880,7 @@ protected:

RackGraph* const graph(pData->graph.getRackGraph());
CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(graph->midi.outs.count() > 0, false);
CARLA_SAFE_ASSERT_RETURN(graph->midiPorts.outs.count() > 0, false);

const CarlaMutexLocker cml(fMidiOutMutex);



+ 6
- 0
source/utils/CarlaPatchbayUtils.hpp View File

@@ -104,6 +104,12 @@ struct PortNameToId {
rename(n, fn);
}

void setFullName(const char fn[]) noexcept
{
std::strncpy(fullName, fn, STR_MAX);
fullName[STR_MAX] = '\0';
}

void rename(const char n[], const char fn[]) noexcept
{
std::strncpy(name, n, STR_MAX);


Loading…
Cancel
Save