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