@@ -266,6 +266,9 @@ | |||||
<addaction name="act_canvas_zoom_out"/> | <addaction name="act_canvas_zoom_out"/> | ||||
<addaction name="act_canvas_zoom_100"/> | <addaction name="act_canvas_zoom_100"/> | ||||
</widget> | </widget> | ||||
<addaction name="act_canvas_show_internal"/> | |||||
<addaction name="act_canvas_show_external"/> | |||||
<addaction name="separator"/> | |||||
<addaction name="act_canvas_arrange"/> | <addaction name="act_canvas_arrange"/> | ||||
<addaction name="act_canvas_refresh"/> | <addaction name="act_canvas_refresh"/> | ||||
<addaction name="menu_Canvas_Zoom"/> | <addaction name="menu_Canvas_Zoom"/> | ||||
@@ -797,6 +797,11 @@ | |||||
<string>Continuous Rack</string> | <string>Continuous Rack</string> | ||||
</property> | </property> | ||||
</item> | </item> | ||||
<item> | |||||
<property name="text"> | |||||
<string>Patchbay</string> | |||||
</property> | |||||
</item> | |||||
</widget> | </widget> | ||||
</item> | </item> | ||||
</layout> | </layout> | ||||
@@ -816,6 +821,11 @@ | |||||
<string>Continuous Rack</string> | <string>Continuous Rack</string> | ||||
</property> | </property> | ||||
</item> | </item> | ||||
<item> | |||||
<property name="text"> | |||||
<string>Patchbay</string> | |||||
</property> | |||||
</item> | |||||
</widget> | </widget> | ||||
</item> | </item> | ||||
</layout> | </layout> | ||||
@@ -25,6 +25,7 @@ | |||||
#include "CarlaMIDI.h" | #include "CarlaMIDI.h" | ||||
using water::jmax; | using water::jmax; | ||||
using water::jmin; | |||||
using water::AudioProcessor; | using water::AudioProcessor; | ||||
using water::MidiBuffer; | using water::MidiBuffer; | ||||
using water::String; | using water::String; | ||||
@@ -1152,14 +1153,7 @@ public: | |||||
void processBlock(AudioSampleBuffer& audio, MidiBuffer& midi) override | void processBlock(AudioSampleBuffer& audio, MidiBuffer& midi) override | ||||
{ | { | ||||
if (fPlugin == nullptr || ! fPlugin->isEnabled()) | |||||
{ | |||||
audio.clear(); | |||||
midi.clear(); | |||||
return; | |||||
} | |||||
if (! fPlugin->tryLock(kEngine->isOffline())) | |||||
if (fPlugin == nullptr || ! fPlugin->isEnabled() || ! fPlugin->tryLock(kEngine->isOffline())) | |||||
{ | { | ||||
audio.clear(); | audio.clear(); | ||||
midi.clear(); | midi.clear(); | ||||
@@ -1181,7 +1175,7 @@ public: | |||||
// TODO - CV support | // TODO - CV support | ||||
const int numSamples(audio.getNumSamples()); | |||||
const uint32_t numSamples(static_cast<uint32_t>(audio.getNumSamples())); | |||||
if (const int numChan = audio.getNumChannels()) | if (const int numChan = audio.getNumChannels()) | ||||
{ | { | ||||
@@ -1193,33 +1187,22 @@ public: | |||||
for (int i=0; i<numChan; ++i) | for (int i=0; i<numChan; ++i) | ||||
audioBuffers[i] = audio.getWritePointer(i); | audioBuffers[i] = audio.getWritePointer(i); | ||||
#if 0 | |||||
float inPeaks[2] = { 0.0f }; | float inPeaks[2] = { 0.0f }; | ||||
float outPeaks[2] = { 0.0f }; | float outPeaks[2] = { 0.0f }; | ||||
juce::Range<float> range; | |||||
for (int i=static_cast<int>(jmin(fPlugin->getAudioInCount(), 2U)); --i>=0;) | |||||
{ | |||||
range = FloatVectorOperations::findMinAndMax(audioBuffers[i], numSamples); | |||||
inPeaks[i] = carla_maxLimited<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); | |||||
} | |||||
#endif | |||||
for (uint32_t i=0, count=jmin(fPlugin->getAudioInCount(), 2U); i<count; ++i) | |||||
inPeaks[i] = carla_findMaxNormalizedFloat(audioBuffers[i], numSamples); | |||||
fPlugin->process(const_cast<const float**>(audioBuffers), audioBuffers, nullptr, nullptr, static_cast<uint32_t>(numSamples)); | |||||
fPlugin->process(const_cast<const float**>(audioBuffers), audioBuffers, nullptr, nullptr, numSamples); | |||||
#if 0 | |||||
for (int i=static_cast<int>(jmin(fPlugin->getAudioOutCount(), 2U)); --i>=0;) | |||||
{ | |||||
range = FloatVectorOperations::findMinAndMax(audioBuffers[i], numSamples); | |||||
outPeaks[i] = carla_maxLimited<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); | |||||
} | |||||
for (uint32_t i=0, count=jmin(fPlugin->getAudioOutCount(), 2U); i<count; ++i) | |||||
outPeaks[i] = carla_findMaxNormalizedFloat(audioBuffers[i], numSamples); | |||||
kEngine->setPluginPeaks(fPlugin->getId(), inPeaks, outPeaks); | kEngine->setPluginPeaks(fPlugin->getId(), inPeaks, outPeaks); | ||||
#endif | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
fPlugin->process(nullptr, nullptr, nullptr, nullptr, static_cast<uint32_t>(numSamples)); | |||||
fPlugin->process(nullptr, nullptr, nullptr, nullptr, numSamples); | |||||
} | } | ||||
midi.clear(); | midi.clear(); | ||||
@@ -1302,7 +1285,8 @@ private: | |||||
}; | }; | ||||
PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, const uint32_t outs) | PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, const uint32_t outs) | ||||
: connections(), | |||||
: CarlaThread("PatchbayReorderThread"), | |||||
connections(), | |||||
graph(), | graph(), | ||||
audioBuffer(), | audioBuffer(), | ||||
midiBuffer(), | midiBuffer(), | ||||
@@ -1390,10 +1374,14 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons | |||||
node->properties.set("isMIDI", true); | node->properties.set("isMIDI", true); | ||||
node->properties.set("isOSC", false); | node->properties.set("isOSC", false); | ||||
} | } | ||||
startThread(); | |||||
} | } | ||||
PatchbayGraph::~PatchbayGraph() | PatchbayGraph::~PatchbayGraph() | ||||
{ | { | ||||
stopThread(-1); | |||||
connections.clear(); | connections.clear(); | ||||
extGraph.clear(); | extGraph.clear(); | ||||
@@ -1852,6 +1840,15 @@ void PatchbayGraph::process(CarlaEngine::ProtectedData* const data, const float* | |||||
} | } | ||||
} | } | ||||
void PatchbayGraph::run() | |||||
{ | |||||
while (! shouldThreadExit()) | |||||
{ | |||||
carla_msleep(100); | |||||
graph.reorderNowIfNeeded(); | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// InternalGraph | // InternalGraph | ||||
@@ -22,6 +22,7 @@ | |||||
#include "CarlaMutex.hpp" | #include "CarlaMutex.hpp" | ||||
#include "CarlaPatchbayUtils.hpp" | #include "CarlaPatchbayUtils.hpp" | ||||
#include "CarlaStringList.hpp" | #include "CarlaStringList.hpp" | ||||
#include "CarlaThread.hpp" | |||||
#include "water/water.h" | #include "water/water.h" | ||||
@@ -145,7 +146,8 @@ struct RackGraph { | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// PatchbayGraph | // PatchbayGraph | ||||
struct PatchbayGraph { | |||||
class PatchbayGraph : private CarlaThread { | |||||
public: | |||||
PatchbayConnectionList connections; | PatchbayConnectionList connections; | ||||
AudioProcessorGraph graph; | AudioProcessorGraph graph; | ||||
AudioSampleBuffer audioBuffer; | AudioSampleBuffer audioBuffer; | ||||
@@ -180,6 +182,9 @@ struct PatchbayGraph { | |||||
void process(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const int frames); | void process(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const int frames); | ||||
private: | |||||
void run() override; | |||||
CarlaEngine* const kEngine; | CarlaEngine* const kEngine; | ||||
CARLA_DECLARE_NON_COPY_CLASS(PatchbayGraph) | CARLA_DECLARE_NON_COPY_CLASS(PatchbayGraph) | ||||
}; | }; | ||||
@@ -202,9 +202,9 @@ class CarlaSettingsW(QDialog): | |||||
PATH_INDEX_DSSI = 1 | PATH_INDEX_DSSI = 1 | ||||
PATH_INDEX_LV2 = 2 | PATH_INDEX_LV2 = 2 | ||||
PATH_INDEX_VST2 = 3 | PATH_INDEX_VST2 = 3 | ||||
PATH_INDEX_GIG = 5 | |||||
PATH_INDEX_SF2 = 6 | |||||
PATH_INDEX_SFZ = 7 | |||||
PATH_INDEX_GIG = 4 | |||||
PATH_INDEX_SF2 = 5 | |||||
PATH_INDEX_SFZ = 6 | |||||
# Single and Multiple client mode is only for JACK, | # Single and Multiple client mode is only for JACK, | ||||
# but we still want to match QComboBox index to backend defines, | # but we still want to match QComboBox index to backend defines, | ||||
@@ -64,7 +64,6 @@ public: | |||||
virtual void cleanUp (ValueUnion&) const noexcept {} | virtual void cleanUp (ValueUnion&) const noexcept {} | ||||
virtual void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest = source; } | virtual void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest = source; } | ||||
virtual bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept = 0; | virtual bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept = 0; | ||||
virtual void writeToStream (const ValueUnion& data, OutputStream& output) const = 0; | |||||
}; | }; | ||||
//============================================================================== | //============================================================================== | ||||
@@ -76,7 +75,6 @@ public: | |||||
bool isVoid() const noexcept override { return true; } | bool isVoid() const noexcept override { return true; } | ||||
bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept override { return otherType.isVoid() || otherType.isUndefined(); } | bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept override { return otherType.isVoid() || otherType.isUndefined(); } | ||||
void writeToStream (const ValueUnion&, OutputStream& output) const override { output.writeCompressedInt (0); } | |||||
}; | }; | ||||
//============================================================================== | //============================================================================== | ||||
@@ -89,12 +87,6 @@ public: | |||||
bool isUndefined() const noexcept override { return true; } | bool isUndefined() const noexcept override { return true; } | ||||
String toString (const ValueUnion&) const override { return "undefined"; } | String toString (const ValueUnion&) const override { return "undefined"; } | ||||
bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept override { return otherType.isVoid() || otherType.isUndefined(); } | bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept override { return otherType.isVoid() || otherType.isUndefined(); } | ||||
void writeToStream (const ValueUnion&, OutputStream& output) const override | |||||
{ | |||||
output.writeCompressedInt (1); | |||||
output.writeByte (varMarker_Undefined); | |||||
} | |||||
}; | }; | ||||
//============================================================================== | //============================================================================== | ||||
@@ -118,13 +110,6 @@ public: | |||||
return otherType.toInt (otherData) == data.intValue; | return otherType.toInt (otherData) == data.intValue; | ||||
} | } | ||||
void writeToStream (const ValueUnion& data, OutputStream& output) const override | |||||
{ | |||||
output.writeCompressedInt (5); | |||||
output.writeByte (varMarker_Int); | |||||
output.writeInt (data.intValue); | |||||
} | |||||
}; | }; | ||||
//============================================================================== | //============================================================================== | ||||
@@ -148,13 +133,6 @@ public: | |||||
return otherType.toInt64 (otherData) == data.int64Value; | return otherType.toInt64 (otherData) == data.int64Value; | ||||
} | } | ||||
void writeToStream (const ValueUnion& data, OutputStream& output) const override | |||||
{ | |||||
output.writeCompressedInt (9); | |||||
output.writeByte (varMarker_Int64); | |||||
output.writeInt64 (data.int64Value); | |||||
} | |||||
}; | }; | ||||
//============================================================================== | //============================================================================== | ||||
@@ -175,13 +153,6 @@ public: | |||||
{ | { | ||||
return std::abs (otherType.toDouble (otherData) - data.doubleValue) < std::numeric_limits<double>::epsilon(); | return std::abs (otherType.toDouble (otherData) - data.doubleValue) < std::numeric_limits<double>::epsilon(); | ||||
} | } | ||||
void writeToStream (const ValueUnion& data, OutputStream& output) const override | |||||
{ | |||||
output.writeCompressedInt (9); | |||||
output.writeByte (varMarker_Double); | |||||
output.writeDouble (data.doubleValue); | |||||
} | |||||
}; | }; | ||||
//============================================================================== | //============================================================================== | ||||
@@ -202,12 +173,6 @@ public: | |||||
{ | { | ||||
return otherType.toBool (otherData) == data.boolValue; | return otherType.toBool (otherData) == data.boolValue; | ||||
} | } | ||||
void writeToStream (const ValueUnion& data, OutputStream& output) const override | |||||
{ | |||||
output.writeCompressedInt (1); | |||||
output.writeByte (data.boolValue ? (char) varMarker_BoolTrue : (char) varMarker_BoolFalse); | |||||
} | |||||
}; | }; | ||||
//============================================================================== | //============================================================================== | ||||
@@ -234,17 +199,6 @@ public: | |||||
return otherType.toString (otherData) == *getString (data); | return otherType.toString (otherData) == *getString (data); | ||||
} | } | ||||
void writeToStream (const ValueUnion& data, OutputStream& output) const override | |||||
{ | |||||
const String* const s = getString (data); | |||||
const size_t len = s->getNumBytesAsUTF8() + 1; | |||||
HeapBlock<char> temp (len); | |||||
s->copyToUTF8 (temp, len); | |||||
output.writeCompressedInt ((int) (len + 1)); | |||||
output.writeByte (varMarker_String); | |||||
output.write (temp, len); | |||||
} | |||||
private: | private: | ||||
static inline const String* getString (const ValueUnion& data) noexcept { return reinterpret_cast<const String*> (data.stringValue); } | static inline const String* getString (const ValueUnion& data) noexcept { return reinterpret_cast<const String*> (data.stringValue); } | ||||
static inline String* getString (ValueUnion& data) noexcept { return reinterpret_cast<String*> (data.stringValue); } | static inline String* getString (ValueUnion& data) noexcept { return reinterpret_cast<String*> (data.stringValue); } | ||||