Browse Source

Re-add patchbay mode to backend

tags/1.9.8
falkTX 7 years ago
parent
commit
6743921cea
20 changed files with 1838 additions and 798 deletions
  1. +1
    -1
      source/backend/CarlaEngine.hpp
  2. +156
    -25
      source/backend/engine/CarlaEngine.cpp
  3. +1
    -1
      source/backend/engine/CarlaEngineData.cpp
  4. +1153
    -85
      source/backend/engine/CarlaEngineGraph.cpp
  5. +48
    -0
      source/backend/engine/CarlaEngineGraph.hpp
  6. +8
    -0
      source/backend/engine/CarlaEngineInternal.cpp
  7. +20
    -2
      source/backend/engine/CarlaEngineInternal.hpp
  8. +68
    -13
      source/backend/engine/CarlaEngineJack.cpp
  9. +243
    -13
      source/backend/engine/CarlaEngineNative.cpp
  10. +13
    -0
      source/backend/engine/CarlaEnginePorts.cpp
  11. +28
    -9
      source/backend/engine/CarlaEngineRtAudio.cpp
  12. +0
    -42
      source/modules/water/containers/juce_NamedValueSet.cpp
  13. +0
    -425
      source/modules/water/containers/juce_Variant.cpp
  14. +0
    -168
      source/modules/water/containers/juce_Variant.h
  15. +3
    -3
      source/modules/water/processors/juce_AudioProcessor.h
  16. +0
    -6
      source/modules/water/processors/juce_AudioProcessorGraph.cpp
  17. +0
    -2
      source/modules/water/processors/juce_AudioProcessorGraph.h
  18. +3
    -3
      source/modules/water/water.cpp
  19. +2
    -0
      source/utils/CarlaBackendUtils.hpp
  20. +91
    -0
      source/utils/CarlaEngineUtils.hpp

+ 1
- 1
source/backend/CarlaEngine.hpp View File

@@ -1150,7 +1150,7 @@ protected:
* Do not free returned data.
*/
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

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


+ 156
- 25
source/backend/engine/CarlaEngine.cpp View File

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

if (! canRun)
{
@@ -630,6 +643,9 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype,

const ScopedThreadStopper sts(this);

if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
pData->graph.replacePlugin(oldPlugin, plugin);

const bool wasActive = oldPlugin->getInternalParameterValue(PARAMETER_ACTIVE) >= 0.5f;
const float oldDryWet = oldPlugin->getInternalParameterValue(PARAMETER_DRYWET);
const float oldVolume = oldPlugin->getInternalParameterValue(PARAMETER_VOLUME);
@@ -655,6 +671,11 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype,

++pData->curPluginCount;
callback(ENGINE_CALLBACK_PLUGIN_ADDED, id, 0, 0, 0.0f, plugin->getName());

#ifndef BUILD_BRIDGE
if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
pData->graph.addPlugin(plugin);
#endif
}

return true;
@@ -684,6 +705,9 @@ bool CarlaEngine::removePlugin(const uint id)
const ScopedThreadStopper sts(this);

#ifndef BUILD_BRIDGE
if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
pData->graph.removePlugin(plugin);

const bool lockWait(isRunning() /*&& pData->options.processMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS*/);
const ScopedActionLock sal(this, kEnginePostActionRemovePlugin, id, 0, lockWait);

@@ -728,12 +752,17 @@ bool CarlaEngine::removeAllPlugins()

const uint curPluginCount(pData->curPluginCount);

#if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE)
#ifndef BUILD_BRIDGE
if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
pData->graph.removeAllPlugins();

# ifdef HAVE_LIBLO
if (isOscControlRegistered())
{
for (uint i=0; i < curPluginCount; ++i)
oscSend_control_remove_plugin(curPluginCount-i-1);
}
# endif
#endif

const bool lockWait(isRunning());
@@ -782,6 +811,9 @@ const char* CarlaEngine::renamePlugin(const uint id, const char* const newName)

plugin->setName(uniqueName);

if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
pData->graph.renamePlugin(plugin, uniqueName);

delete[] uniqueName;
return plugin->getName();
}
@@ -867,6 +899,9 @@ bool CarlaEngine::switchPlugins(const uint idA, const uint idB) noexcept

const ScopedThreadStopper sts(this);

if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
pData->graph.replacePlugin(pluginA, pluginB);

const bool lockWait(isRunning() /*&& pData->options.processMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS*/);
const ScopedActionLock sal(this, kEnginePostActionSwitchPlugins, idA, idB, lockWait);

@@ -1610,8 +1645,11 @@ void CarlaEngine::bufferSizeChanged(const uint32_t newBufferSize)
carla_debug("CarlaEngine::bufferSizeChanged(%i)", newBufferSize);

#ifndef BUILD_BRIDGE
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
pData->graph.setBufferSize(newBufferSize);
}
#endif

pData->time.updateAudioValues(newBufferSize, pData->sampleRate);
@@ -1631,6 +1669,14 @@ void CarlaEngine::sampleRateChanged(const double newSampleRate)
{
carla_debug("CarlaEngine::sampleRateChanged(%g)", newSampleRate);

#ifndef BUILD_BRIDGE
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
pData->graph.setSampleRate(newSampleRate);
}
#endif

pData->time.updateAudioValues(pData->bufferSize, newSampleRate);

for (uint i=0; i < pData->curPluginCount; ++i)
@@ -1649,8 +1695,11 @@ void CarlaEngine::offlineModeChanged(const bool isOfflineNow)
carla_debug("CarlaEngine::offlineModeChanged(%s)", bool2str(isOfflineNow));

#ifndef BUILD_BRIDGE
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
pData->graph.setOffline(isOfflineNow);
}
#endif

for (uint i=0; i < pData->curPluginCount; ++i)
@@ -1763,29 +1812,57 @@ void CarlaEngine::saveProjectInternal(water::MemoryOutputStream& outStream) cons
plugin->setCustomData(CUSTOM_DATA_TYPE_STRING, "__CarlaPingOnOff__", "true", false);
}

// save internal connections
if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
if (const char* const* const patchbayConns = getPatchbayConnections(false))
{
MemoryOutputStream outPatchbay(2048);

outPatchbay << "\n <Patchbay>\n";

for (int i=0; patchbayConns[i] != nullptr && patchbayConns[i+1] != nullptr; ++i, ++i )
{
const char* const connSource(patchbayConns[i]);
const char* const connTarget(patchbayConns[i+1]);

CARLA_SAFE_ASSERT_CONTINUE(connSource != nullptr && connSource[0] != '\0');
CARLA_SAFE_ASSERT_CONTINUE(connTarget != nullptr && connTarget[0] != '\0');

outPatchbay << " <Connection>\n";
outPatchbay << " <Source>" << xmlSafeString(connSource, true) << "</Source>\n";
outPatchbay << " <Target>" << xmlSafeString(connTarget, true) << "</Target>\n";
outPatchbay << " </Connection>\n";
}

outPatchbay << " </Patchbay>\n";
outStream << outPatchbay;
}
}

// if we're running inside some session-manager (and using JACK), let them handle the connections
bool saveConnections;
bool saveExternalConnections;

/**/ if (isPlugin)
saveConnections = false;
saveExternalConnections = false;
else if (std::strcmp(getCurrentDriverName(), "JACK") != 0)
saveConnections = true;
saveExternalConnections = true;
else if (std::getenv("CARLA_DONT_MANAGE_CONNECTIONS") != nullptr)
saveConnections = false;
saveExternalConnections = false;
else if (std::getenv("LADISH_APP_NAME") != nullptr)
saveConnections = false;
saveExternalConnections = false;
else if (std::getenv("NSM_URL") != nullptr)
saveConnections = false;
saveExternalConnections = false;
else
saveConnections = true;
saveExternalConnections = true;

if (saveConnections)
if (saveExternalConnections)
{
if (const char* const* const patchbayConns = getPatchbayConnections())
if (const char* const* const patchbayConns = getPatchbayConnections(true))
{
MemoryOutputStream outPatchbay(2048);

outPatchbay << "\n <Patchbay>\n";
outPatchbay << "\n <ExternalPatchbay>\n";

for (int i=0; patchbayConns[i] != nullptr && patchbayConns[i+1] != nullptr; ++i, ++i )
{
@@ -1801,7 +1878,7 @@ void CarlaEngine::saveProjectInternal(water::MemoryOutputStream& outStream) cons
outPatchbay << " </Connection>\n";
}

outPatchbay << " </Patchbay>\n";
outPatchbay << " </ExternalPatchbay>\n";
outStream << outPatchbay;
}
}
@@ -2132,6 +2209,11 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc)

plugin->setEnabled(true);
callback(ENGINE_CALLBACK_PLUGIN_ADDED, pluginId, 0, 0, 0.0f, plugin->getName());

#ifndef BUILD_BRIDGE
if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
pData->graph.addPlugin(plugin);
#endif
}
else
{
@@ -2163,30 +2245,79 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc)
if (pData->aboutToClose)
return true;

// if we're running inside some session-manager (and using JACK), let them handle the connections
bool loadConnections;
// handle connections (internal)
if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
const bool isUsingExternal(pData->graph.isUsingExternal());

for (XmlElement* elem = xmlElement->getFirstChildElement(); elem != nullptr; elem = elem->getNextElement())
{
const String& tagName(elem->getTagName());

if (! tagName.equalsIgnoreCase("patchbay"))
continue;

CarlaString sourcePort, targetPort;

for (XmlElement* patchElem = elem->getFirstChildElement(); patchElem != nullptr; patchElem = patchElem->getNextElement())
{
const String& patchTag(patchElem->getTagName());

sourcePort.clear();
targetPort.clear();

if (! patchTag.equalsIgnoreCase("connection"))
continue;

for (XmlElement* connElem = patchElem->getFirstChildElement(); connElem != nullptr; connElem = connElem->getNextElement())
{
const String& tag(connElem->getTagName());
const String text(connElem->getAllSubText().trim());

/**/ if (tag.equalsIgnoreCase("source"))
sourcePort = xmlSafeString(text, false).toRawUTF8();
else if (tag.equalsIgnoreCase("target"))
targetPort = xmlSafeString(text, false).toRawUTF8();
}

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

callback(ENGINE_CALLBACK_IDLE, 0, 0, 0, 0.0f, nullptr);

if (pData->aboutToClose)
return true;
}

// if we're running inside some session-manager (and using JACK), let them handle the external connections
bool loadExternalConnections;

/**/ if (isPlugin)
loadConnections = false;
loadExternalConnections = false;
else if (std::strcmp(getCurrentDriverName(), "JACK") != 0)
loadConnections = true;
loadExternalConnections = true;
else if (std::getenv("CARLA_DONT_MANAGE_CONNECTIONS") != nullptr)
loadConnections = false;
loadExternalConnections = false;
else if (std::getenv("LADISH_APP_NAME") != nullptr)
loadConnections = false;
loadExternalConnections = false;
else if (std::getenv("NSM_URL") != nullptr)
loadConnections = false;
loadExternalConnections = false;
else
loadConnections = true;
loadExternalConnections = true;

// handle connections
if (loadConnections)
if (loadExternalConnections)
{
const bool isUsingExternal(pData->graph.isUsingExternal());

for (XmlElement* elem = xmlElement->getFirstChildElement(); elem != nullptr; elem = elem->getNextElement())
{
const String& tagName(elem->getTagName());

if (! tagName.equalsIgnoreCase("patchbay") && ! tagName.equalsIgnoreCase("externalpatchbay"))
if (! tagName.equalsIgnoreCase("externalpatchbay"))
continue;

CarlaString sourcePort, targetPort;
@@ -2213,7 +2344,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc)
}

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


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

@@ -187,7 +187,7 @@ EngineOptions::EngineOptions() noexcept
: processMode(ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS),
transportMode(ENGINE_TRANSPORT_MODE_JACK),
#else
: processMode(ENGINE_PROCESS_MODE_CONTINUOUS_RACK),
: processMode(ENGINE_PROCESS_MODE_PATCHBAY),
transportMode(ENGINE_TRANSPORT_MODE_INTERNAL),
#endif
transportExtra(nullptr),


+ 1153
- 85
source/backend/engine/CarlaEngineGraph.cpp
File diff suppressed because it is too large
View File


+ 48
- 0
source/backend/engine/CarlaEngineGraph.hpp View File

@@ -23,6 +23,12 @@
#include "CarlaPatchbayUtils.hpp"
#include "CarlaStringList.hpp"

#include "water/water.h"

using water::AudioProcessorGraph;
using water::AudioSampleBuffer;
using water::MidiBuffer;

CARLA_BACKEND_START_NAMESPACE

// -----------------------------------------------------------------------
@@ -136,6 +142,48 @@ struct RackGraph {
CARLA_DECLARE_NON_COPY_CLASS(RackGraph)
};

// -----------------------------------------------------------------------
// PatchbayGraph

struct PatchbayGraph {
PatchbayConnectionList connections;
AudioProcessorGraph graph;
AudioSampleBuffer audioBuffer;
MidiBuffer midiBuffer;
const uint32_t inputs;
const uint32_t outputs;
mutable CharStringListPtr retCon;
bool usingExternal;

ExternalGraph extGraph;

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

void setBufferSize(const uint32_t bufferSize);
void setSampleRate(const double sampleRate);
void setOffline(const bool offline);

void addPlugin(CarlaPlugin* const plugin);
void replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* const newPlugin);
void renamePlugin(CarlaPlugin* const plugin, const char* const newName);
void removePlugin(CarlaPlugin* const plugin);
void removeAllPlugins();

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

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

void process(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const int frames);

CarlaEngine* const kEngine;
CARLA_DECLARE_NON_COPY_CLASS(PatchbayGraph)
};

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

CARLA_BACKEND_END_NAMESPACE


+ 8
- 0
source/backend/engine/CarlaEngineInternal.cpp View File

@@ -468,6 +468,13 @@ bool CarlaEngine::ProtectedData::init(const char* const clientName)

switch (options.processMode)
{
case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
maxPluginNumber = MAX_RACK_PLUGINS;
options.forceStereo = true;
break;
case ENGINE_PROCESS_MODE_PATCHBAY:
maxPluginNumber = MAX_PATCHBAY_PLUGINS;
break;
case ENGINE_PROCESS_MODE_BRIDGE:
maxPluginNumber = 1;
break;
@@ -479,6 +486,7 @@ bool CarlaEngine::ProtectedData::init(const char* const clientName)
switch (options.processMode)
{
case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
case ENGINE_PROCESS_MODE_PATCHBAY:
case ENGINE_PROCESS_MODE_BRIDGE:
events.in = new EngineEvent[kMaxEngineEventInternalCount];
events.out = new EngineEvent[kMaxEngineEventInternalCount];


+ 20
- 2
source/backend/engine/CarlaEngineInternal.hpp View File

@@ -71,19 +71,37 @@ public:
void destroy() noexcept;

void setBufferSize(const uint32_t bufferSize);
void setSampleRate(const double sampleRate);
void setOffline(const bool offline);

bool isReady() const noexcept;
RackGraph* getGraph() const noexcept;

RackGraph* getRackGraph() const noexcept;
PatchbayGraph* getPatchbayGraph() const noexcept;

void process(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const uint32_t frames);

// special direct process with connections already handled, used in JACK and Plugin
void processRack(CarlaEngine::ProtectedData* const data, const float* inBuf[2], float* outBuf[2], const uint32_t frames);

// used for internal patchbay mode
void addPlugin(CarlaPlugin* const plugin);
void replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* const newPlugin);
void renamePlugin(CarlaPlugin* const plugin, const char* const newName);
void removePlugin(CarlaPlugin* const plugin);
void removeAllPlugins();

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

private:
bool fIsRack;
bool fIsReady;
RackGraph* fRack;

union {
RackGraph* fRack;
PatchbayGraph* fPatchbay;
};

CarlaEngine* const kEngine;



+ 68
- 13
source/backend/engine/CarlaEngineJack.cpp View File

@@ -806,6 +806,7 @@ public:
CarlaThread("CarlaEngineJackCallbacks"),
#endif
fClient(nullptr),
fExternalPatchbay(true),
fFreewheel(false),
#ifdef BUILD_BRIDGE
fIsRunning(false)
@@ -882,7 +883,8 @@ public:
CARLA_SAFE_ASSERT_RETURN(jackbridge_is_ok(), false);
carla_debug("CarlaEngineJack::init(\"%s\")", clientName);

fFreewheel = false;
fFreewheel = false;
fExternalPatchbay = true;

CarlaString truncatedClientName(clientName);
truncatedClientName.truncate(getMaxClientNameSize());
@@ -949,14 +951,16 @@ public:

fTimebaseMaster = jackbridge_set_timebase_callback(fClient, true, carla_jack_timebase_callback, this);

initJackPatchbay(jackClientName);
if (pData->options.processMode != ENGINE_PROCESS_MODE_PATCHBAY)
initJackPatchbay(jackClientName);

jackbridge_set_client_registration_callback(fClient, carla_jack_client_registration_callback, this);
jackbridge_set_port_registration_callback(fClient, carla_jack_port_registration_callback, this);
jackbridge_set_port_connect_callback(fClient, carla_jack_port_connect_callback, this);
jackbridge_set_port_rename_callback(fClient, carla_jack_port_rename_callback, this);

if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
fRackPorts[kRackPortAudioIn1] = jackbridge_port_register(fClient, "audio-in1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
fRackPorts[kRackPortAudioIn2] = jackbridge_port_register(fClient, "audio-in2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
@@ -965,8 +969,16 @@ public:
fRackPorts[kRackPortEventIn] = jackbridge_port_register(fClient, "events-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
fRackPorts[kRackPortEventOut] = jackbridge_port_register(fClient, "events-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);

// FIXME
pData->graph.create(0, 0);
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
{
// FIXME?
pData->graph.create(0, 0);
}
else
{
pData->graph.create(2, 2);
patchbayRefresh(false);
}
}

if (jackbridge_activate(fClient))
@@ -976,8 +988,11 @@ public:
return true;
}

if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
pData->graph.destroy();
}

pData->close();
jackbridge_client_close(fClient);
@@ -1016,7 +1031,8 @@ public:
fPostPonedEvents.clear();

// clear rack/patchbay stuff
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
if (deactivated)
{
@@ -1108,8 +1124,11 @@ public:
#ifndef BUILD_BRIDGE
const char* renamePlugin(const uint id, const char* const newName) override
{
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
return CarlaEngine::renamePlugin(id, newName);
}

CARLA_SAFE_ASSERT_RETURN(pData->plugins != nullptr, nullptr);
CARLA_SAFE_ASSERT_RETURN(pData->curPluginCount != 0, nullptr);
@@ -1257,6 +1276,9 @@ public:
{
CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);

if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! fExternalPatchbay)
return CarlaEngine::patchbayConnect(groupA, portA, groupB, portB);

const char* const fullPortNameA = fUsedPorts.getFullPortName(groupA, portA);
CARLA_SAFE_ASSERT_RETURN(fullPortNameA != nullptr && fullPortNameA[0] != '\0', false);

@@ -1276,6 +1298,9 @@ public:
{
CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);

if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! fExternalPatchbay)
return CarlaEngine::patchbayDisconnect(connectionId);

ConnectionToId connectionToId = { 0, 0, 0, 0, 0 };

{
@@ -1312,10 +1337,19 @@ public:
return true;
}

bool patchbayRefresh() override
bool patchbayRefresh(const bool external) override
{
CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);

if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
fExternalPatchbay = external;
pData->graph.setUsingExternal(external);

if (! external)
return CarlaEngine::patchbayRefresh(false);
}

fUsedGroups.clear();
fUsedPorts.clear();
fUsedConnections.clear();
@@ -1403,10 +1437,13 @@ public:
// -------------------------------------------------------------------
// Patchbay stuff

const char* const* getPatchbayConnections() const override
const char* const* getPatchbayConnections(const bool external) const override
{
CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, nullptr);
carla_debug("CarlaEngineJack::getPatchbayConnections()");
carla_debug("CarlaEngineJack::getPatchbayConnections(%s)", bool2str(external));

if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! external)
return CarlaEngine::getPatchbayConnections(external);

CarlaStringList connList;

@@ -1442,13 +1479,16 @@ public:
return fRetConns;
}

void restorePatchbayConnection(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(connSource != nullptr && connSource[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(connTarget != nullptr && connTarget[0] != '\0',);
carla_debug("CarlaEngineJack::restorePatchbayConnection(\"%s\", \"%s\")", connSource, connTarget);

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

if (const jack_port_t* const port = jackbridge_port_by_name(fClient, connSource))
{
if (jackbridge_port_by_name(fClient, connTarget) == nullptr)
@@ -1599,7 +1639,8 @@ protected:
}
}
}
else if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
else if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
CARLA_SAFE_ASSERT_RETURN(pData->events.in != nullptr,);
CARLA_SAFE_ASSERT_RETURN(pData->events.out != nullptr,);
@@ -1719,6 +1760,9 @@ protected:
{
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);

// ignore this if on internal patchbay mode
if (! fExternalPatchbay) return;

// do nothing on client registration, wait for first port
if (reg) return;

@@ -1736,6 +1780,9 @@ protected:

void handleJackPortRegistrationCallback(const jack_port_id_t port, const bool reg)
{
// ignore this if on internal patchbay mode
if (! fExternalPatchbay) return;

const jack_port_t* const jackPort(jackbridge_port_by_id(fClient, port));
CARLA_SAFE_ASSERT_RETURN(jackPort != nullptr,);

@@ -1788,6 +1835,9 @@ protected:

void handleJackPortConnectCallback(const jack_port_id_t a, const jack_port_id_t b, const bool connect)
{
// ignore this if on internal patchbay mode
if (! fExternalPatchbay) return;

const jack_port_t* const jackPortA(jackbridge_port_by_id(fClient, a));
CARLA_SAFE_ASSERT_RETURN(jackPortA != nullptr,);

@@ -1850,6 +1900,9 @@ protected:

void handleJackPortRenameCallback(const jack_port_id_t port, const char* const oldFullName, const char* const newFullName)
{
// ignore this if on internal patchbay mode
if (! fExternalPatchbay) return;

CARLA_SAFE_ASSERT_RETURN(oldFullName != nullptr && oldFullName[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(newFullName != nullptr && newFullName[0] != '\0',);

@@ -1937,6 +1990,7 @@ protected:

private:
jack_client_t* fClient;
bool fExternalPatchbay;
bool fFreewheel;

// -------------------------------------------------------------------
@@ -2017,6 +2071,7 @@ private:

void initJackPatchbay(const char* const ourName)
{
CARLA_SAFE_ASSERT_RETURN(pData->options.processMode != ENGINE_PROCESS_MODE_PATCHBAY || fExternalPatchbay,);
CARLA_SAFE_ASSERT_RETURN(ourName != nullptr && ourName[0] != '\0',);

CarlaStringList parsedGroups;


+ 243
- 13
source/backend/engine/CarlaEngineNative.cpp View File

@@ -158,7 +158,7 @@ protected:
else if (std::strcmp(msg, "patchbay_refresh") == 0)
{
try {
ok = fEngine->patchbayRefresh();
ok = fEngine->patchbayRefresh(false);
} CARLA_SAFE_EXCEPTION("patchbayRefresh");
}
else if (std::strcmp(msg, "transport_play") == 0)
@@ -586,9 +586,10 @@ private:
class CarlaEngineNative : public CarlaEngine
{
public:
CarlaEngineNative(const NativeHostDescriptor* const host, const uint32_t inChan = 2, uint32_t outChan = 0)
CarlaEngineNative(const NativeHostDescriptor* const host, const bool isPatchbay, const uint32_t inChan = 2, uint32_t outChan = 0)
: CarlaEngine(),
pHost(host),
kIsPatchbay(isPatchbay),
fIsActive(false),
fIsRunning(false),
fUiServer(this),
@@ -606,15 +607,29 @@ public:
if (outChan == 0)
outChan = inChan;

CARLA_SAFE_ASSERT(inChan == 2);
CARLA_SAFE_ASSERT(outChan == 2);
pData->options.processMode = ENGINE_PROCESS_MODE_CONTINUOUS_RACK;
pData->options.transportMode = ENGINE_TRANSPORT_MODE_PLUGIN;
pData->options.forceStereo = true;
pData->options.preferPluginBridges = false;
pData->options.preferUiBridges = false;
init("Carla-Rack");
pData->graph.create(0, 0); // FIXME?
// set-up engine
if (kIsPatchbay)
{
pData->options.processMode = ENGINE_PROCESS_MODE_PATCHBAY;
pData->options.transportMode = ENGINE_TRANSPORT_MODE_PLUGIN;
pData->options.forceStereo = false;
pData->options.preferPluginBridges = false;
pData->options.preferUiBridges = false;
init("Carla-Patchbay");
pData->graph.create(inChan, outChan);
}
else
{
CARLA_SAFE_ASSERT(inChan == 2);
CARLA_SAFE_ASSERT(outChan == 2);
pData->options.processMode = ENGINE_PROCESS_MODE_CONTINUOUS_RACK;
pData->options.transportMode = ENGINE_TRANSPORT_MODE_PLUGIN;
pData->options.forceStereo = true;
pData->options.preferPluginBridges = false;
pData->options.preferUiBridges = false;
init("Carla-Rack");
pData->graph.create(0, 0); // FIXME?
}

if (pData->options.resourceDir != nullptr)
delete[] pData->options.resourceDir;
@@ -1341,7 +1356,7 @@ protected:
// ---------------------------------------------------------------
// Do nothing if no plugins and rack mode

if (pData->curPluginCount == 0)
if (pData->curPluginCount == 0 && ! kIsPatchbay)
{
if (outBuffer[0] != inBuffer[0])
carla_copyFloats(outBuffer[0], inBuffer[0], frames);
@@ -1382,6 +1397,14 @@ protected:
}
}

if (kIsPatchbay)
{
// -----------------------------------------------------------
// process

pData->graph.process(pData, inBuffer, outBuffer, frames);
}
else
{
// -----------------------------------------------------------
// create audio buffers
@@ -1456,7 +1479,10 @@ protected:

CarlaString path(pHost->resourceDir);

path += CARLA_OS_SEP_STR "carla-plugin";
if (kIsPatchbay)
path += CARLA_OS_SEP_STR "carla-plugin-patchbay";
else
path += CARLA_OS_SEP_STR "carla-plugin";
#ifdef CARLA_OS_WIN
path += ".exe";
#endif
@@ -1486,6 +1512,9 @@ protected:
}
}

if (kIsPatchbay)
patchbayRefresh(false);

if (fWaitForReadyMsg)
{
carla_stdout("Using Carla plugin embedded, waiting for it to be ready...");
@@ -1653,6 +1682,26 @@ public:
return new CarlaEngineNative(host, false);
}

static NativePluginHandle _instantiatePatchbay(const NativeHostDescriptor* host)
{
return new CarlaEngineNative(host, true);
}

static NativePluginHandle _instantiatePatchbay3s(const NativeHostDescriptor* host)
{
return new CarlaEngineNative(host, true, 3, 2);
}

static NativePluginHandle _instantiatePatchbay16(const NativeHostDescriptor* host)
{
return new CarlaEngineNative(host, true, 16);
}

static NativePluginHandle _instantiatePatchbay32(const NativeHostDescriptor* host)
{
return new CarlaEngineNative(host, true, 32);
}

static void _cleanup(NativePluginHandle handle)
{
delete handlePtr;
@@ -1776,6 +1825,7 @@ public:
private:
const NativeHostDescriptor* const pHost;

const bool kIsPatchbay; // rack if false
bool fIsActive, fIsRunning;
CarlaEngineNativeUI fUiServer;

@@ -1843,6 +1893,174 @@ static const NativePluginDescriptor carlaRackDesc = {
CarlaEngineNative::_dispatcher
};

static const NativePluginDescriptor carlaPatchbayDesc = {
/* category */ NATIVE_PLUGIN_CATEGORY_OTHER,
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_SYNTH
|NATIVE_PLUGIN_HAS_UI
//|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD
|NATIVE_PLUGIN_USES_STATE
|NATIVE_PLUGIN_USES_TIME),
/* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_EVERYTHING),
/* audioIns */ 2,
/* audioOuts */ 2,
/* midiIns */ 1,
/* midiOuts */ 1,
/* paramIns */ 0,
/* paramOuts */ 0,
/* name */ "Carla-Patchbay",
/* label */ "carlapatchbay",
/* maker */ "falkTX",
/* copyright */ "GNU GPL v2+",
CarlaEngineNative::_instantiatePatchbay,
CarlaEngineNative::_cleanup,
CarlaEngineNative::_get_parameter_count,
CarlaEngineNative::_get_parameter_info,
CarlaEngineNative::_get_parameter_value,
CarlaEngineNative::_get_midi_program_count,
CarlaEngineNative::_get_midi_program_info,
CarlaEngineNative::_set_parameter_value,
CarlaEngineNative::_set_midi_program,
/* _set_custom_data */ nullptr,
CarlaEngineNative::_ui_show,
CarlaEngineNative::_ui_idle,
/* _ui_set_parameter_value */ nullptr,
/* _ui_set_midi_program */ nullptr,
/* _ui_set_custom_data */ nullptr,
CarlaEngineNative::_activate,
CarlaEngineNative::_deactivate,
CarlaEngineNative::_process,
CarlaEngineNative::_get_state,
CarlaEngineNative::_set_state,
CarlaEngineNative::_dispatcher
};

static const NativePluginDescriptor carlaPatchbay3sDesc = {
/* category */ NATIVE_PLUGIN_CATEGORY_OTHER,
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_SYNTH
|NATIVE_PLUGIN_HAS_UI
//|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD
|NATIVE_PLUGIN_USES_STATE
|NATIVE_PLUGIN_USES_TIME),
/* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_EVERYTHING),
/* audioIns */ 3,
/* audioOuts */ 2,
/* midiIns */ 1,
/* midiOuts */ 1,
/* paramIns */ 0,
/* paramOuts */ 0,
/* name */ "Carla-Patchbay (sidechain)",
/* label */ "carlapatchbay3s",
/* maker */ "falkTX",
/* copyright */ "GNU GPL v2+",
CarlaEngineNative::_instantiatePatchbay3s,
CarlaEngineNative::_cleanup,
CarlaEngineNative::_get_parameter_count,
CarlaEngineNative::_get_parameter_info,
CarlaEngineNative::_get_parameter_value,
CarlaEngineNative::_get_midi_program_count,
CarlaEngineNative::_get_midi_program_info,
CarlaEngineNative::_set_parameter_value,
CarlaEngineNative::_set_midi_program,
/* _set_custom_data */ nullptr,
CarlaEngineNative::_ui_show,
CarlaEngineNative::_ui_idle,
/* _ui_set_parameter_value */ nullptr,
/* _ui_set_midi_program */ nullptr,
/* _ui_set_custom_data */ nullptr,
CarlaEngineNative::_activate,
CarlaEngineNative::_deactivate,
CarlaEngineNative::_process,
CarlaEngineNative::_get_state,
CarlaEngineNative::_set_state,
CarlaEngineNative::_dispatcher
};

static const NativePluginDescriptor carlaPatchbay16Desc = {
/* category */ NATIVE_PLUGIN_CATEGORY_OTHER,
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_SYNTH
|NATIVE_PLUGIN_HAS_UI
//|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD
|NATIVE_PLUGIN_USES_STATE
|NATIVE_PLUGIN_USES_TIME),
/* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_EVERYTHING),
/* audioIns */ 16,
/* audioOuts */ 16,
/* midiIns */ 1,
/* midiOuts */ 1,
/* paramIns */ 0,
/* paramOuts */ 0,
/* name */ "Carla-Patchbay (16chan)",
/* label */ "carlapatchbay16",
/* maker */ "falkTX",
/* copyright */ "GNU GPL v2+",
CarlaEngineNative::_instantiatePatchbay16,
CarlaEngineNative::_cleanup,
CarlaEngineNative::_get_parameter_count,
CarlaEngineNative::_get_parameter_info,
CarlaEngineNative::_get_parameter_value,
CarlaEngineNative::_get_midi_program_count,
CarlaEngineNative::_get_midi_program_info,
CarlaEngineNative::_set_parameter_value,
CarlaEngineNative::_set_midi_program,
/* _set_custom_data */ nullptr,
CarlaEngineNative::_ui_show,
CarlaEngineNative::_ui_idle,
/* _ui_set_parameter_value */ nullptr,
/* _ui_set_midi_program */ nullptr,
/* _ui_set_custom_data */ nullptr,
CarlaEngineNative::_activate,
CarlaEngineNative::_deactivate,
CarlaEngineNative::_process,
CarlaEngineNative::_get_state,
CarlaEngineNative::_set_state,
CarlaEngineNative::_dispatcher
};

static const NativePluginDescriptor carlaPatchbay32Desc = {
/* category */ NATIVE_PLUGIN_CATEGORY_OTHER,
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_SYNTH
|NATIVE_PLUGIN_HAS_UI
//|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD
|NATIVE_PLUGIN_USES_STATE
|NATIVE_PLUGIN_USES_TIME),
/* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_EVERYTHING),
/* audioIns */ 32,
/* audioOuts */ 32,
/* midiIns */ 1,
/* midiOuts */ 1,
/* paramIns */ 0,
/* paramOuts */ 0,
/* name */ "Carla-Patchbay (32chan)",
/* label */ "carlapatchbay32",
/* maker */ "falkTX",
/* copyright */ "GNU GPL v2+",
CarlaEngineNative::_instantiatePatchbay32,
CarlaEngineNative::_cleanup,
CarlaEngineNative::_get_parameter_count,
CarlaEngineNative::_get_parameter_info,
CarlaEngineNative::_get_parameter_value,
CarlaEngineNative::_get_midi_program_count,
CarlaEngineNative::_get_midi_program_info,
CarlaEngineNative::_set_parameter_value,
CarlaEngineNative::_set_midi_program,
/* _set_custom_data */ nullptr,
CarlaEngineNative::_ui_show,
CarlaEngineNative::_ui_idle,
/* _ui_set_parameter_value */ nullptr,
/* _ui_set_midi_program */ nullptr,
/* _ui_set_custom_data */ nullptr,
CarlaEngineNative::_activate,
CarlaEngineNative::_deactivate,
CarlaEngineNative::_process,
CarlaEngineNative::_get_state,
CarlaEngineNative::_set_state,
CarlaEngineNative::_dispatcher
};

CARLA_BACKEND_END_NAMESPACE

// -----------------------------------------------------------------------
@@ -1854,6 +2072,10 @@ void carla_register_native_plugin_carla()
{
CARLA_BACKEND_USE_NAMESPACE;
carla_register_native_plugin(&carlaRackDesc);
carla_register_native_plugin(&carlaPatchbayDesc);
carla_register_native_plugin(&carlaPatchbay3sDesc);
carla_register_native_plugin(&carlaPatchbay16Desc);
carla_register_native_plugin(&carlaPatchbay32Desc);
}

// -----------------------------------------------------------------------
@@ -1866,6 +2088,14 @@ const NativePluginDescriptor* carla_get_native_rack_plugin()
return &carlaRackDesc;
}

CARLA_EXPORT
const NativePluginDescriptor* carla_get_native_patchbay_plugin();
const NativePluginDescriptor* carla_get_native_patchbay_plugin()
{
CARLA_BACKEND_USE_NAMESPACE;
return &carlaPatchbayDesc;
}

// -----------------------------------------------------------------------
// Extra stuff for linking purposes



+ 13
- 0
source/backend/engine/CarlaEnginePorts.cpp View File

@@ -89,17 +89,30 @@ CarlaEngineEventPort::CarlaEngineEventPort(const CarlaEngineClient& client, cons
kProcessMode(client.getEngine().getProccessMode())
{
carla_debug("CarlaEngineEventPort::CarlaEngineEventPort(%s)", bool2str(isInputPort));

if (kProcessMode == ENGINE_PROCESS_MODE_PATCHBAY)
fBuffer = new EngineEvent[kMaxEngineEventInternalCount];
}

CarlaEngineEventPort::~CarlaEngineEventPort() noexcept
{
carla_debug("CarlaEngineEventPort::~CarlaEngineEventPort()");

if (kProcessMode == ENGINE_PROCESS_MODE_PATCHBAY)
{
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);

delete[] fBuffer;
fBuffer = nullptr;
}
}

void CarlaEngineEventPort::initBuffer() noexcept
{
if (kProcessMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || kProcessMode == ENGINE_PROCESS_MODE_BRIDGE)
fBuffer = kClient.getEngine().getInternalEventBuffer(kIsInput);
else if (kProcessMode == ENGINE_PROCESS_MODE_PATCHBAY && ! kIsInput)
carla_zeroStructs(fBuffer, kMaxEngineEventInternalCount);
}

uint32_t CarlaEngineEventPort::getEventCount() const noexcept


+ 28
- 9
source/backend/engine/CarlaEngineRtAudio.cpp View File

@@ -183,7 +183,7 @@ public:
CARLA_SAFE_ASSERT_RETURN(clientName != nullptr && clientName[0] != '\0', false);
carla_debug("CarlaEngineRtAudio::init(\"%s\")", clientName);

if (pData->options.processMode != ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
if (pData->options.processMode != ENGINE_PROCESS_MODE_CONTINUOUS_RACK && pData->options.processMode != ENGINE_PROCESS_MODE_PATCHBAY)
{
setLastError("Invalid process mode");
return false;
@@ -293,7 +293,10 @@ public:
return false;
}

patchbayRefresh();
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());
return true;
@@ -402,11 +405,9 @@ public:
// -------------------------------------------------------------------
// Patchbay

bool patchbayRefresh() override
template<class Graph>
bool refreshExternalGraphPorts(Graph* const graph, const bool sendCallback)
{
CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), false);

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

char strBuf[STR_MAX+1];
@@ -473,7 +474,8 @@ public:
// ---------------------------------------------------------------
// now refresh

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

// ---------------------------------------------------------------
// add midi connections
@@ -495,7 +497,8 @@ public:

extGraph.connections.list.append(connectionToId);

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

fMidiOutMutex.lock();
@@ -517,7 +520,8 @@ public:

extGraph.connections.list.append(connectionToId);

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

fMidiOutMutex.unlock();
@@ -525,6 +529,21 @@ public:
return true;
}

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

if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
return refreshExternalGraphPorts<RackGraph>(pData->graph.getRackGraph(), true);

pData->graph.setUsingExternal(external);

if (external)
return refreshExternalGraphPorts<PatchbayGraph>(pData->graph.getPatchbayGraph(), true);

return CarlaEngine::patchbayRefresh(false);
}

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

protected:


+ 0
- 42
source/modules/water/containers/juce_NamedValueSet.cpp View File

@@ -207,45 +207,3 @@ var* NamedValueSet::getVarPointerAt (int index) const noexcept
return nullptr;
}
void NamedValueSet::setFromXmlAttributes (const XmlElement& xml)
{
values.clearQuick();
for (const XmlElement::XmlAttributeNode* att = xml.attributes; att != nullptr; att = att->nextListItem)
{
if (att->name.toString().startsWith ("base64:"))
{
MemoryBlock mb;
if (mb.fromBase64Encoding (att->value))
{
values.add (NamedValue (att->name.toString().substring (7), var (mb)));
continue;
}
}
values.add (NamedValue (att->name, var (att->value)));
}
}
void NamedValueSet::copyToXmlAttributes (XmlElement& xml) const
{
for (NamedValue* e = values.end(), *i = values.begin(); i != e; ++i)
{
if (const MemoryBlock* mb = i->value.getBinaryData())
{
xml.setAttribute ("base64:" + i->name.toString(), mb->toBase64Encoding());
}
else
{
// These types can't be stored as XML!
jassert (! i->value.isObject());
jassert (! i->value.isMethod());
jassert (! i->value.isArray());
xml.setAttribute (i->name.toString(),
i->value.toString());
}
}
}

+ 0
- 425
source/modules/water/containers/juce_Variant.cpp View File

@@ -36,8 +36,6 @@ enum VariantStreamMarkers
varMarker_Double = 4,
varMarker_String = 5,
varMarker_Int64 = 6,
varMarker_Array = 7,
varMarker_Binary = 8,
varMarker_Undefined = 9
};
@@ -53,9 +51,6 @@ public:
virtual double toDouble (const ValueUnion&) const noexcept { return 0; }
virtual String toString (const ValueUnion&) const { return String(); }
virtual bool toBool (const ValueUnion&) const noexcept { return false; }
virtual ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; }
virtual Array<var>* toArray (const ValueUnion&) const noexcept { return nullptr; }
virtual MemoryBlock* toBinary (const ValueUnion&) const noexcept { return nullptr; }
virtual var clone (const var& original) const { return original; }
virtual bool isVoid() const noexcept { return false; }
@@ -65,10 +60,6 @@ public:
virtual bool isBool() const noexcept { return false; }
virtual bool isDouble() const noexcept { return false; }
virtual bool isString() const noexcept { return false; }
virtual bool isObject() const noexcept { return false; }
virtual bool isArray() const noexcept { return false; }
virtual bool isBinary() const noexcept { return false; }
virtual bool isMethod() const noexcept { return false; }
virtual void cleanUp (ValueUnion&) const noexcept {}
virtual void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest = source; }
@@ -259,167 +250,6 @@ private:
static inline String* getString (ValueUnion& data) noexcept { return reinterpret_cast<String*> (data.stringValue); }
};
//==============================================================================
class var::VariantType_Object : public var::VariantType
{
public:
VariantType_Object() noexcept {}
static const VariantType_Object instance;
void cleanUp (ValueUnion& data) const noexcept override { if (data.objectValue != nullptr) data.objectValue->decReferenceCount(); }
void createCopy (ValueUnion& dest, const ValueUnion& source) const override
{
dest.objectValue = source.objectValue;
if (dest.objectValue != nullptr)
dest.objectValue->incReferenceCount();
}
String toString (const ValueUnion& data) const override { return "Object 0x" + String::toHexString ((int) (pointer_sized_int) data.objectValue); }
bool toBool (const ValueUnion& data) const noexcept override { return data.objectValue != nullptr; }
ReferenceCountedObject* toObject (const ValueUnion& data) const noexcept override { return data.objectValue; }
bool isObject() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{
return otherType.toObject (otherData) == data.objectValue;
}
var clone (const var& original) const override
{
if (DynamicObject* d = original.getDynamicObject())
return d->clone().get();
jassertfalse; // can only clone DynamicObjects!
return var();
}
void writeToStream (const ValueUnion&, OutputStream& output) const override
{
jassertfalse; // Can't write an object to a stream!
output.writeCompressedInt (0);
}
};
//==============================================================================
class var::VariantType_Array : public var::VariantType_Object
{
public:
VariantType_Array() noexcept {}
static const VariantType_Array instance;
String toString (const ValueUnion&) const override { return "[Array]"; }
ReferenceCountedObject* toObject (const ValueUnion&) const noexcept override { return nullptr; }
bool isArray() const noexcept override { return true; }
Array<var>* toArray (const ValueUnion& data) const noexcept override
{
if (RefCountedArray* a = dynamic_cast<RefCountedArray*> (data.objectValue))
return &(a->array);
return nullptr;
}
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{
const Array<var>* const thisArray = toArray (data);
const Array<var>* const otherArray = otherType.toArray (otherData);
return thisArray == otherArray || (thisArray != nullptr && otherArray != nullptr && *otherArray == *thisArray);
}
var clone (const var& original) const override
{
Array<var> arrayCopy;
if (const Array<var>* array = toArray (original.value))
for (int i = 0; i < array->size(); ++i)
arrayCopy.add (array->getReference(i).clone());
return var (arrayCopy);
}
void writeToStream (const ValueUnion& data, OutputStream& output) const override
{
if (const Array<var>* array = toArray (data))
{
MemoryOutputStream buffer (512);
const int numItems = array->size();
buffer.writeCompressedInt (numItems);
for (int i = 0; i < numItems; ++i)
array->getReference(i).writeToStream (buffer);
output.writeCompressedInt (1 + (int) buffer.getDataSize());
output.writeByte (varMarker_Array);
output << buffer;
}
}
struct RefCountedArray : public ReferenceCountedObject
{
RefCountedArray (const Array<var>& a) : array (a) { incReferenceCount(); }
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
RefCountedArray (Array<var>&& a) : array (static_cast<Array<var>&&> (a)) { incReferenceCount(); }
#endif
Array<var> array;
};
};
//==============================================================================
class var::VariantType_Binary : public var::VariantType
{
public:
VariantType_Binary() noexcept {}
static const VariantType_Binary instance;
void cleanUp (ValueUnion& data) const noexcept override { delete data.binaryValue; }
void createCopy (ValueUnion& dest, const ValueUnion& source) const override { dest.binaryValue = new MemoryBlock (*source.binaryValue); }
String toString (const ValueUnion& data) const override { return data.binaryValue->toBase64Encoding(); }
bool isBinary() const noexcept override { return true; }
MemoryBlock* toBinary (const ValueUnion& data) const noexcept override { return data.binaryValue; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{
const MemoryBlock* const otherBlock = otherType.toBinary (otherData);
return otherBlock != nullptr && *otherBlock == *data.binaryValue;
}
void writeToStream (const ValueUnion& data, OutputStream& output) const override
{
output.writeCompressedInt (1 + (int) data.binaryValue->getSize());
output.writeByte (varMarker_Binary);
output << *data.binaryValue;
}
};
//==============================================================================
class var::VariantType_Method : public var::VariantType
{
public:
VariantType_Method() noexcept {}
static const VariantType_Method instance;
void cleanUp (ValueUnion& data) const noexcept override { if (data.methodValue != nullptr ) delete data.methodValue; }
void createCopy (ValueUnion& dest, const ValueUnion& source) const override { dest.methodValue = new NativeFunction (*source.methodValue); }
String toString (const ValueUnion&) const override { return "Method"; }
bool toBool (const ValueUnion& data) const noexcept override { return data.methodValue != nullptr; }
bool isMethod() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{
return otherType.isMethod() && otherData.methodValue == data.methodValue;
}
void writeToStream (const ValueUnion&, OutputStream& output) const override
{
jassertfalse; // Can't write a method to a stream!
output.writeCompressedInt (0);
}
};
//==============================================================================
const var::VariantType_Void var::VariantType_Void::instance;
const var::VariantType_Undefined var::VariantType_Undefined::instance;
@@ -428,10 +258,6 @@ const var::VariantType_Int64 var::VariantType_Int64::instance;
const var::VariantType_Bool var::VariantType_Bool::instance;
const var::VariantType_Double var::VariantType_Double::instance;
const var::VariantType_String var::VariantType_String::instance;
const var::VariantType_Object var::VariantType_Object::instance;
const var::VariantType_Array var::VariantType_Array::instance;
const var::VariantType_Binary var::VariantType_Binary::instance;
const var::VariantType_Method var::VariantType_Method::instance;
//==============================================================================
@@ -449,32 +275,8 @@ var::var (const int v) noexcept : type (&VariantType_Int::instance) { v
var::var (const int64 v) noexcept : type (&VariantType_Int64::instance) { value.int64Value = v; }
var::var (const bool v) noexcept : type (&VariantType_Bool::instance) { value.boolValue = v; }
var::var (const double v) noexcept : type (&VariantType_Double::instance) { value.doubleValue = v; }
var::var (NativeFunction m) noexcept : type (&VariantType_Method::instance) { value.methodValue = new NativeFunction (m); }
var::var (const Array<var>& v) : type (&VariantType_Array::instance) { value.objectValue = new VariantType_Array::RefCountedArray(v); }
var::var (const String& v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
var::var (const char* const v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
var::var (const wchar_t* const v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
var::var (const void* v, size_t sz) : type (&VariantType_Binary::instance) { value.binaryValue = new MemoryBlock (v, sz); }
var::var (const MemoryBlock& v) : type (&VariantType_Binary::instance) { value.binaryValue = new MemoryBlock (v); }
var::var (const StringArray& v) : type (&VariantType_Array::instance)
{
Array<var> strings;
const int n = v.size();
for (int i = 0; i < n; ++i)
strings.add (var (v[i]));
value.objectValue = new VariantType_Array::RefCountedArray(strings);
}
var::var (ReferenceCountedObject* const object) : type (&VariantType_Object::instance)
{
value.objectValue = object;
if (object != nullptr)
object->incReferenceCount();
}
var var::undefined() noexcept { return var (VariantType_Undefined::instance); }
@@ -486,10 +288,6 @@ bool var::isInt64() const noexcept { return type->isInt64(); }
bool var::isBool() const noexcept { return type->isBool(); }
bool var::isDouble() const noexcept { return type->isDouble(); }
bool var::isString() const noexcept { return type->isString(); }
bool var::isObject() const noexcept { return type->isObject(); }
bool var::isArray() const noexcept { return type->isArray(); }
bool var::isBinaryData() const noexcept { return type->isBinary(); }
bool var::isMethod() const noexcept { return type->isMethod(); }
var::operator int() const noexcept { return type->toInt (value); }
var::operator int64() const noexcept { return type->toInt64 (value); }
@@ -498,10 +296,6 @@ var::operator float() const noexcept { return (float) type->t
var::operator double() const noexcept { return type->toDouble (value); }
String var::toString() const { return type->toString (value); }
var::operator String() const { return type->toString (value); }
ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); }
Array<var>* var::getArray() const noexcept { return type->toArray (value); }
MemoryBlock* var::getBinaryData() const noexcept { return type->toBinary (value); }
DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast<DynamicObject*> (getObject()); }
//==============================================================================
void var::swapWith (var& other) noexcept
@@ -516,12 +310,7 @@ var& var::operator= (const int64 v) { type->cleanUp (value); type =
var& var::operator= (const bool v) { type->cleanUp (value); type = &VariantType_Bool::instance; value.boolValue = v; return *this; }
var& var::operator= (const double v) { type->cleanUp (value); type = &VariantType_Double::instance; value.doubleValue = v; return *this; }
var& var::operator= (const char* const v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
var& var::operator= (const wchar_t* const v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
var& var::operator= (const String& v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
var& var::operator= (const MemoryBlock& v) { type->cleanUp (value); type = &VariantType_Binary::instance; value.binaryValue = new MemoryBlock (v); return *this; }
var& var::operator= (const Array<var>& v) { var v2 (v); swapWith (v2); return *this; }
var& var::operator= (ReferenceCountedObject* v) { var v2 (v); swapWith (v2); return *this; }
var& var::operator= (NativeFunction v) { var v2 (v); swapWith (v2); return *this; }
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
var::var (var&& other) noexcept
@@ -542,16 +331,6 @@ var::var (String&& v) : type (&VariantType_String::instance)
new (value.stringValue) String (static_cast<String&&> (v));
}
var::var (MemoryBlock&& v) : type (&VariantType_Binary::instance)
{
value.binaryValue = new MemoryBlock (static_cast<MemoryBlock&&> (v));
}
var::var (Array<var>&& v) : type (&VariantType_Array::instance)
{
value.objectValue = new VariantType_Array::RefCountedArray (static_cast<Array<var>&&> (v));
}
var& var::operator= (String&& v)
{
type->cleanUp (value);
@@ -589,207 +368,3 @@ var var::clone() const noexcept
{
return type->clone (*this);
}
//==============================================================================
const var& var::operator[] (const Identifier& propertyName) const
{
if (DynamicObject* const o = getDynamicObject())
return o->getProperty (propertyName);
return getNullVarRef();
}
const var& var::operator[] (const char* const propertyName) const
{
return operator[] (Identifier (propertyName));
}
var var::getProperty (const Identifier& propertyName, const var& defaultReturnValue) const
{
if (DynamicObject* const o = getDynamicObject())
return o->getProperties().getWithDefault (propertyName, defaultReturnValue);
return defaultReturnValue;
}
var::NativeFunction var::getNativeFunction() const
{
return isMethod() && (value.methodValue != nullptr) ? *value.methodValue : nullptr;
}
var var::invoke (const Identifier& method, const var* arguments, int numArguments) const
{
if (DynamicObject* const o = getDynamicObject())
return o->invokeMethod (method, var::NativeFunctionArgs (*this, arguments, numArguments));
return var();
}
var var::call (const Identifier& method) const
{
return invoke (method, nullptr, 0);
}
var var::call (const Identifier& method, const var& arg1) const
{
return invoke (method, &arg1, 1);
}
var var::call (const Identifier& method, const var& arg1, const var& arg2) const
{
var args[] = { arg1, arg2 };
return invoke (method, args, 2);
}
var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3)
{
var args[] = { arg1, arg2, arg3 };
return invoke (method, args, 3);
}
var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const
{
var args[] = { arg1, arg2, arg3, arg4 };
return invoke (method, args, 4);
}
var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const
{
var args[] = { arg1, arg2, arg3, arg4, arg5 };
return invoke (method, args, 5);
}
//==============================================================================
int var::size() const
{
if (const Array<var>* const array = getArray())
return array->size();
return 0;
}
const var& var::operator[] (int arrayIndex) const
{
const Array<var>* const array = getArray();
// When using this method, the var must actually be an array, and the index
// must be in-range!
jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
return array->getReference (arrayIndex);
}
var& var::operator[] (int arrayIndex)
{
const Array<var>* const array = getArray();
// When using this method, the var must actually be an array, and the index
// must be in-range!
jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
return array->getReference (arrayIndex);
}
Array<var>* var::convertToArray()
{
if (Array<var>* array = getArray())
return array;
Array<var> tempVar;
if (! isVoid())
tempVar.add (*this);
*this = tempVar;
return getArray();
}
void var::append (const var& n)
{
convertToArray()->add (n);
}
void var::remove (const int index)
{
if (Array<var>* const array = getArray())
array->remove (index);
}
void var::insert (const int index, const var& n)
{
convertToArray()->insert (index, n);
}
void var::resize (const int numArrayElementsWanted)
{
convertToArray()->resize (numArrayElementsWanted);
}
int var::indexOf (const var& n) const
{
if (const Array<var>* const array = getArray())
return array->indexOf (n);
return -1;
}
//==============================================================================
void var::writeToStream (OutputStream& output) const
{
type->writeToStream (value, output);
}
var var::readFromStream (InputStream& input)
{
const int numBytes = input.readCompressedInt();
if (numBytes > 0)
{
switch (input.readByte())
{
case varMarker_Int: return var (input.readInt());
case varMarker_Int64: return var (input.readInt64());
case varMarker_BoolTrue: return var (true);
case varMarker_BoolFalse: return var (false);
case varMarker_Double: return var (input.readDouble());
case varMarker_String:
{
MemoryOutputStream mo;
mo.writeFromInputStream (input, numBytes - 1);
return var (mo.toUTF8());
}
case varMarker_Binary:
{
MemoryBlock mb ((size_t) numBytes - 1);
if (numBytes > 1)
{
const int numRead = input.read (mb.getData(), numBytes - 1);
mb.setSize ((size_t) numRead);
}
return var (mb);
}
case varMarker_Array:
{
var v;
Array<var>* const destArray = v.convertToArray();
for (int i = input.readCompressedInt(); --i >= 0;)
destArray->add (readFromStream (input));
return v;
}
default:
input.skipNextBytes (numBytes - 1); break;
}
}
return var();
}
var::NativeFunctionArgs::NativeFunctionArgs (const var& t, const var* args, int numArgs) noexcept
: thisObject (t), arguments (args), numArguments (numArgs)
{}

+ 0
- 168
source/modules/water/containers/juce_Variant.h View File

@@ -48,27 +48,6 @@
class JUCE_API var
{
public:
//==============================================================================
/** This structure is passed to a NativeFunction callback, and contains invocation
details about the function's arguments and context.
*/
struct NativeFunctionArgs
{
NativeFunctionArgs (const var& thisObject, const var* args, int numArgs) noexcept;
const var& thisObject;
const var* arguments;
int numArguments;
JUCE_DECLARE_NON_COPYABLE (NativeFunctionArgs)
};
#if JUCE_COMPILER_SUPPORTS_LAMBDAS
using NativeFunction = std::function<var (const NativeFunctionArgs&)>;
#else
typedef var (*NativeFunction) (const NativeFunctionArgs&);
#endif
//==============================================================================
/** Creates a void variant. */
var() noexcept;
@@ -82,14 +61,7 @@ public:
var (bool value) noexcept;
var (double value) noexcept;
var (const char* value);
var (const wchar_t* value);
var (const String& value);
var (const Array<var>& value);
var (const StringArray& value);
var (ReferenceCountedObject* object);
var (NativeFunction method) noexcept;
var (const void* binaryData, size_t dataSize);
var (const MemoryBlock& binaryData);
var& operator= (const var& valueToCopy);
var& operator= (int value);
@@ -97,18 +69,11 @@ public:
var& operator= (bool value);
var& operator= (double value);
var& operator= (const char* value);
var& operator= (const wchar_t* value);
var& operator= (const String& value);
var& operator= (const MemoryBlock& value);
var& operator= (const Array<var>& value);
var& operator= (ReferenceCountedObject* object);
var& operator= (NativeFunction method);
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
var (var&&) noexcept;
var (String&&);
var (MemoryBlock&&);
var (Array<var>&&);
var& operator= (var&&) noexcept;
var& operator= (String&&);
#endif
@@ -127,25 +92,6 @@ public:
operator String() const;
String toString() const;
/** If this variant holds an array, this provides access to it.
NOTE: Beware when you use this - the array pointer is only valid for the lifetime
of the variant that returned it, so be very careful not to call this method on temporary
var objects that are the return-value of a function, and which may go out of scope before
you use the array!
*/
Array<var>* getArray() const noexcept;
/** If this variant holds a memory block, this provides access to it.
NOTE: Beware when you use this - the MemoryBlock pointer is only valid for the lifetime
of the variant that returned it, so be very careful not to call this method on temporary
var objects that are the return-value of a function, and which may go out of scope before
you use the MemoryBlock!
*/
MemoryBlock* getBinaryData() const noexcept;
ReferenceCountedObject* getObject() const noexcept;
DynamicObject* getDynamicObject() const noexcept;
//==============================================================================
bool isVoid() const noexcept;
bool isUndefined() const noexcept;
@@ -154,10 +100,6 @@ public:
bool isBool() const noexcept;
bool isDouble() const noexcept;
bool isString() const noexcept;
bool isObject() const noexcept;
bool isArray() const noexcept;
bool isBinaryData() const noexcept;
bool isMethod() const noexcept;
/** Returns true if this var has the same value as the one supplied.
Note that this ignores the type, so a string var "123" and an integer var with the
@@ -181,109 +123,6 @@ public:
*/
var clone() const noexcept;
//==============================================================================
/** If the var is an array, this returns the number of elements.
If the var isn't actually an array, this will return 0.
*/
int size() const;
/** If the var is an array, this can be used to return one of its elements.
To call this method, you must make sure that the var is actually an array, and
that the index is a valid number. If these conditions aren't met, behaviour is
undefined.
For more control over the array's contents, you can call getArray() and manipulate
it directly as an Array\<var\>.
*/
const var& operator[] (int arrayIndex) const;
/** If the var is an array, this can be used to return one of its elements.
To call this method, you must make sure that the var is actually an array, and
that the index is a valid number. If these conditions aren't met, behaviour is
undefined.
For more control over the array's contents, you can call getArray() and manipulate
it directly as an Array\<var\>.
*/
var& operator[] (int arrayIndex);
/** Appends an element to the var, converting it to an array if it isn't already one.
If the var isn't an array, it will be converted to one, and if its value was non-void,
this value will be kept as the first element of the new array. The parameter value
will then be appended to it.
For more control over the array's contents, you can call getArray() and manipulate
it directly as an Array\<var\>.
*/
void append (const var& valueToAppend);
/** Inserts an element to the var, converting it to an array if it isn't already one.
If the var isn't an array, it will be converted to one, and if its value was non-void,
this value will be kept as the first element of the new array. The parameter value
will then be inserted into it.
For more control over the array's contents, you can call getArray() and manipulate
it directly as an Array\<var\>.
*/
void insert (int index, const var& value);
/** If the var is an array, this removes one of its elements.
If the index is out-of-range or the var isn't an array, nothing will be done.
For more control over the array's contents, you can call getArray() and manipulate
it directly as an Array\<var\>.
*/
void remove (int index);
/** Treating the var as an array, this resizes it to contain the specified number of elements.
If the var isn't an array, it will be converted to one, and if its value was non-void,
this value will be kept as the first element of the new array before resizing.
For more control over the array's contents, you can call getArray() and manipulate
it directly as an Array\<var\>.
*/
void resize (int numArrayElementsWanted);
/** If the var is an array, this searches it for the first occurrence of the specified value,
and returns its index.
If the var isn't an array, or if the value isn't found, this returns -1.
*/
int indexOf (const var& value) const;
//==============================================================================
/** If this variant is an object, this returns one of its properties. */
const var& operator[] (const Identifier& propertyName) const;
/** If this variant is an object, this returns one of its properties. */
const var& operator[] (const char* propertyName) const;
/** If this variant is an object, this returns one of its properties, or a default
fallback value if the property is not set. */
var getProperty (const Identifier& propertyName, const var& defaultReturnValue) const;
/** Invokes a named method call with no arguments. */
var call (const Identifier& method) const;
/** Invokes a named method call with one argument. */
var call (const Identifier& method, const var& arg1) const;
/** Invokes a named method call with 2 arguments. */
var call (const Identifier& method, const var& arg1, const var& arg2) const;
/** Invokes a named method call with 3 arguments. */
var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3);
/** Invokes a named method call with 4 arguments. */
var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const;
/** Invokes a named method call with 5 arguments. */
var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const;
/** Invokes a named method call with a list of arguments. */
var invoke (const Identifier& method, const var* arguments, int numArguments) const;
/** If this object is a method, this returns the function pointer. */
NativeFunction getNativeFunction() const;
//==============================================================================
/** Writes a binary representation of this value to a stream.
The data can be read back later using readFromStream().
@see JSON
*/
void writeToStream (OutputStream& output) const;
/** Reads back a stored binary representation of a value.
The data in the stream must have been written using writeToStream(), or this
will have unpredictable results.
@see JSON
*/
static var readFromStream (InputStream& input);
private:
//==============================================================================
class VariantType; friend class VariantType;
@@ -294,10 +133,6 @@ private:
class VariantType_Double; friend class VariantType_Double;
class VariantType_Bool; friend class VariantType_Bool;
class VariantType_String; friend class VariantType_String;
class VariantType_Object; friend class VariantType_Object;
class VariantType_Array; friend class VariantType_Array;
class VariantType_Binary; friend class VariantType_Binary;
class VariantType_Method; friend class VariantType_Method;
union ValueUnion
{
@@ -306,9 +141,6 @@ private:
bool boolValue;
double doubleValue;
char stringValue [sizeof (String)];
ReferenceCountedObject* objectValue;
MemoryBlock* binaryValue;
NativeFunction* methodValue;
};
const VariantType* type;


+ 3
- 3
source/modules/water/processors/juce_AudioProcessor.h View File

@@ -246,9 +246,6 @@ public:
*/
void setLatencySamples (int newLatency);
/** Returns the length of the filter's tail, in seconds. */
virtual double getTailLengthSeconds() const = 0;
/** Returns true if the processor wants midi messages. */
virtual bool acceptsMidi() const = 0;
@@ -261,6 +258,9 @@ public:
/** Returns true if this is a midi effect plug-in and does no audio processing. */
virtual bool isMidiEffect() const { return false; }
virtual const String getInputChannelName (int) const { return String(); }
virtual const String getOutputChannelName (int) const { return String(); }
//==============================================================================
/** This returns a critical section that will automatically be locked while the host
is calling the processBlock() method.


+ 0
- 6
source/modules/water/processors/juce_AudioProcessorGraph.cpp View File

@@ -1390,7 +1390,6 @@ void AudioProcessorGraph::processAudio (AudioSampleBuffer& buffer, MidiBuffer& m
midiMessages.addEvents (currentMidiOutputBuffer, 0, buffer.getNumSamples(), 0);
}
double AudioProcessorGraph::getTailLengthSeconds() const { return 0; }
bool AudioProcessorGraph::acceptsMidi() const { return true; }
bool AudioProcessorGraph::producesMidi() const { return true; }
@@ -1516,11 +1515,6 @@ void AudioProcessorGraph::AudioGraphIOProcessor::processBlock (AudioSampleBuffer
processAudio (buffer, midiMessages);
}
double AudioProcessorGraph::AudioGraphIOProcessor::getTailLengthSeconds() const
{
return 0;
}
bool AudioProcessorGraph::AudioGraphIOProcessor::acceptsMidi() const
{
return type == midiOutputNode;


+ 0
- 2
source/modules/water/processors/juce_AudioProcessorGraph.h View File

@@ -319,7 +319,6 @@ public:
void releaseResources() override;
void processBlock (AudioSampleBuffer&, MidiBuffer&) override;
double getTailLengthSeconds() const override;
bool acceptsMidi() const override;
bool producesMidi() const override;
@@ -346,7 +345,6 @@ public:
void setNonRealtime (bool) noexcept override;
void setPlayHead (AudioPlayHead*) override;
double getTailLengthSeconds() const override;
bool acceptsMidi() const override;
bool producesMidi() const override;


+ 3
- 3
source/modules/water/water.cpp View File

@@ -101,8 +101,8 @@ static int64 juce_fileSetPosition (void* handle, int64 pos)
#include "text/juce_CharacterFunctions.cpp"
#include "text/juce_String.cpp"
//#include "containers/juce_NamedValueSet.cpp"
//#include "containers/juce_Variant.cpp"
#include "containers/juce_NamedValueSet.cpp"
#include "containers/juce_Variant.cpp"
#include "files/juce_DirectoryIterator.cpp"
#include "files/juce_File.cpp"
@@ -115,7 +115,7 @@ static int64 juce_fileSetPosition (void* handle, int64 pos)
#include "misc/juce_Result.cpp"
#include "processors/juce_AudioProcessor.cpp"
//#include "processors/juce_AudioProcessorGraph.cpp"
#include "processors/juce_AudioProcessorGraph.cpp"
#include "streams/juce_FileInputSource.cpp"
#include "streams/juce_FileInputStream.cpp"


+ 2
- 0
source/utils/CarlaBackendUtils.hpp View File

@@ -358,6 +358,8 @@ const char* EngineProcessMode2Str(const EngineProcessMode mode) noexcept
return "ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS";
case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
return "ENGINE_PROCESS_MODE_CONTINUOUS_RACK";
case ENGINE_PROCESS_MODE_PATCHBAY:
return "ENGINE_PROCESS_MODE_PATCHBAY";
case ENGINE_PROCESS_MODE_BRIDGE:
return "ENGINE_PROCESS_MODE_BRIDGE";
}


+ 91
- 0
source/utils/CarlaEngineUtils.hpp View File

@@ -20,6 +20,9 @@

#include "CarlaEngine.hpp"
#include "CarlaUtils.hpp"
#include "CarlaMIDI.h"

#include "water/water.h"

CARLA_BACKEND_START_NAMESPACE

@@ -110,6 +113,94 @@ const char* EngineControlEventType2Str(const EngineControlEventType type) noexce
return nullptr;
}

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

static inline
void fillEngineEventsFromWaterMidiBuffer(EngineEvent engineEvents[kMaxEngineEventInternalCount], const water::MidiBuffer& midiBuffer)
{
const uint8_t* midiData;
int numBytes, sampleNumber;
ushort engineEventIndex = 0;

for (ushort i=0; i < kMaxEngineEventInternalCount; ++i)
{
const EngineEvent& engineEvent(engineEvents[i]);

if (engineEvent.type != kEngineEventTypeNull)
continue;

engineEventIndex = i;
break;
}

for (water::MidiBuffer::Iterator midiBufferIterator(midiBuffer); midiBufferIterator.getNextEvent(midiData, numBytes, sampleNumber) && engineEventIndex < kMaxEngineEventInternalCount;)
{
CARLA_SAFE_ASSERT_CONTINUE(numBytes > 0);
CARLA_SAFE_ASSERT_CONTINUE(sampleNumber >= 0);
CARLA_SAFE_ASSERT_CONTINUE(numBytes < 0xFF /* uint8_t max */);

EngineEvent& engineEvent(engineEvents[engineEventIndex++]);

engineEvent.time = static_cast<uint32_t>(sampleNumber);
engineEvent.fillFromMidiData(static_cast<uint8_t>(numBytes), midiData, 0);
}
}

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

static inline
void fillWaterMidiBufferFromEngineEvents(water::MidiBuffer& midiBuffer, const EngineEvent engineEvents[kMaxEngineEventInternalCount])
{
uint8_t size = 0;
uint8_t mdata[3] = { 0, 0, 0 };
const uint8_t* mdataPtr = mdata;
uint8_t mdataTmp[EngineMidiEvent::kDataSize];

for (ushort i=0; i < kMaxEngineEventInternalCount; ++i)
{
const EngineEvent& engineEvent(engineEvents[i]);

if (engineEvent.type == kEngineEventTypeNull)
{
break;
}
else if (engineEvent.type == kEngineEventTypeControl)
{
const EngineControlEvent& ctrlEvent(engineEvent.ctrl);

ctrlEvent.convertToMidiData(engineEvent.channel, size, mdata);
mdataPtr = mdata;
}
else if (engineEvent.type == kEngineEventTypeMidi)
{
const EngineMidiEvent& midiEvent(engineEvent.midi);

size = midiEvent.size;

if (size > EngineMidiEvent::kDataSize && midiEvent.dataExt != nullptr)
{
mdataPtr = midiEvent.dataExt;
}
else
{
// copy
carla_copy<uint8_t>(mdataTmp, midiEvent.data, size);
// add channel
mdataTmp[0] = static_cast<uint8_t>(mdataTmp[0] | (engineEvent.channel & MIDI_CHANNEL_BIT));
// done
mdataPtr = mdataTmp;
}
}
else
{
continue;
}

if (size > 0)
midiBuffer.addEvent(mdataPtr, static_cast<int>(size), static_cast<int>(engineEvent.time));
}
}

// -------------------------------------------------------------------
// Helper classes



Loading…
Cancel
Save