Skip to content

Commit 77af32d

Browse files
authored
Merge pull request #1162 from kushview/unverified-claps
CLAP plugins now will show as unverified if not yet scanned... also .... The Graph Mixer got a round of polish: larger, easier-to-read node names, dB readouts and meter scales, plus a higher-contrast layout so channel strips stand out clearly. Strip headers now take on the node's block color from the graph editor, and selected nodes are highlighted with the same accent outline in both the graph and the mixer. You can double-click any fader to snap it back to 0 dB, and right-click a channel strip to hide it from the mixer — handy for MIDI utilities and other nodes you don't need to mix — then right-click the mixer background to bring hidden channels back.
2 parents 7fca84f + 1523761 commit 77af32d

22 files changed

Lines changed: 340 additions & 103 deletions

‎CHANGELOG.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@
22

33
## [1.2.x]
44

5+
### Added
6+
- CLAP plugins now appear in the Unverified plugin menu and can be added to a graph without a prior scan.
7+
- Graph Mixer: channel strips can be hidden via right-click and restored from the mixer background's right-click menu.
8+
59
### Changed
610
- Disconnected audio devices are no longer silently replaced with another device: Element closes the device, shows its status in the status bar, and automatically restores it when it reconnects. Double-click the status label to open audio settings.
11+
- Graph Mixer: larger fonts for node names, dB readouts and the meter scale, plus a higher-contrast layout.
12+
- Graph Mixer: channel strip name headers now use the node's block color from the graph editor.
13+
- Double-clicking a channel strip fader resets it to 0 dB.
14+
- Selected nodes now show the same accent outline in both the graph editor and the Graph Mixer.
715
- Note names throughout the UI now use scientific pitch notation (middle C = C4), matching the convention used by most DAWs.
816

917
### Fixed

‎include/element/node.hpp‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ class EL_API Node : public Model {
199199
juce::Value getMutedValue() { return getPropertyAsValue (tags::mute); }
200200

201201
/** Returns true if inputs are muted */
202-
bool isMutingInputs() const { return (bool) getProperty ("muteInput", false); }
202+
bool isMutingInputs() const { return (bool) getProperty (tags::muteInput, false); }
203203

204204
/** Change the mute status of this Node */
205205
void setMuted (bool);
@@ -458,6 +458,18 @@ class EL_API Node : public Model {
458458
return getUIValueTree().hasProperty ("color") ? getColor() : fallback;
459459
}
460460

461+
/** Change whether this node's strip is hidden in the graph mixer. */
462+
void setHiddenInMixer (bool hidden)
463+
{
464+
getUIValueTree().setProperty (tags::hiddenInMixer, hidden, nullptr);
465+
}
466+
467+
/** Returns true if this node's strip should be hidden in the graph mixer. */
468+
bool isHiddenInMixer() const noexcept
469+
{
470+
return (bool) getUIValueTree().getProperty (tags::hiddenInMixer, false);
471+
}
472+
461473
/** Add a script to this node.
462474
If failure, the returned will be invalid;
463475
*/

‎include/element/porttype.hpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#endif
1616

1717
#ifndef EL_INVALID_PORT
18-
#define EL_INVALID_PORT ((uint32_t) -1)
18+
#define EL_INVALID_PORT ((uint32_t) - 1)
1919
#endif
2020

2121
#ifndef EL_INVALID_NODE

‎include/element/tags.hpp‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,15 @@ static const juce::Identifier lastDisplayMode = "lastDisplayMode";
106106
static const juce::Identifier enabled = "enabled";
107107
static const juce::Identifier gain = "gain";
108108
static const juce::Identifier graphs = "graphs";
109+
static const juce::Identifier hiddenInMixer = "hiddenInMixer";
109110
static const juce::Identifier hiddenPorts = "hiddenPorts";
110111
static const juce::Identifier inputGain = "inputGain";
111112
static const juce::Identifier mappingData = "mappingData";
112113
static const juce::Identifier map = "map";
113114
static const juce::Identifier maps = "maps";
114115
static const juce::Identifier missing = "missing";
115116
static const juce::Identifier mute = "mute";
117+
static const juce::Identifier muteInput = "muteInput";
116118
static const juce::Identifier node = "node";
117119
static const juce::Identifier nodes = "nodes";
118120
static const juce::Identifier notes = "notes";

‎include/element/ui/style.hpp‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ struct Style {
4848
e.g. standard Labels, Textboxes, ComboBoxes, etc etc */
4949
static constexpr float fontSizeDefault = 12.0f;
5050

51+
/** Font size for fine print such as scales and small annotations. */
52+
static constexpr float fontSizeSmall = 9.0f;
53+
54+
/** Font size for emphasized readouts such as the channel strip's dB value. */
55+
static constexpr float fontSizeLarge = 14.0f;
56+
5157
/** Draws text rotated by 90 or -90 degrees */
5258
static void drawVerticalText (juce::Graphics& g,
5359
const juce::String& text,

‎src/engine/clapprovider.cpp‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,9 @@ class CLAPHost final : public CLAPBaseHost
389389
pfds.reserve (fds.size());
390390
for (const auto& f : fds)
391391
{
392-
struct pollfd p {};
392+
struct pollfd p
393+
{
394+
};
393395
p.fd = f.first;
394396
if (f.second & CLAP_POSIX_FD_READ)
395397
p.events |= POLLIN;

‎src/filesystemwatcher.cpp‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@ class FileSystemWatcher::Impl
140140
CFArrayRef paths { nullptr };
141141
dispatch_queue_t queue { nullptr };
142142
FSEventStreamRef stream { nullptr };
143-
struct FSEventStreamContext context {};
143+
struct FSEventStreamContext context
144+
{
145+
};
144146
};
145147
#endif
146148

‎src/node.cpp‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,7 @@ void Node::restorePluginState()
915915
obj->setMidiProgramsState (getProperty (tags::midiProgramsState).toString().trim());
916916

917917
obj->setMuted ((bool) getProperty (tags::mute, obj->isMuted()));
918-
obj->setMuteInput ((bool) getProperty ("muteInput", obj->isMutingInputs()));
918+
obj->setMuteInput ((bool) getProperty (tags::muteInput, obj->isMutingInputs()));
919919

920920
if (hasProperty (tags::transpose))
921921
obj->setTransposeOffset (getProperty (tags::transpose));
@@ -1006,7 +1006,7 @@ void Node::savePluginState()
10061006
setProperty (tags::globalMidiPrograms, obj->useGlobalMidiPrograms());
10071007
setProperty (tags::midiProgramsEnabled, obj->areMidiProgramsEnabled());
10081008
setProperty (tags::mute, obj->isMuted());
1009-
setProperty ("muteInput", obj->isMutingInputs());
1009+
setProperty (tags::muteInput, obj->isMutingInputs());
10101010
String mps;
10111011
obj->getMidiProgramsState (mps);
10121012
setProperty (tags::midiProgramsState, mps);
@@ -1194,7 +1194,7 @@ void Node::setMuted (bool shouldBeMuted)
11941194
void Node::setMuteInput (bool shouldMuteInputs)
11951195
{
11961196
if (shouldMuteInputs != isMutingInputs())
1197-
setProperty ("muteInput", shouldMuteInputs);
1197+
setProperty (tags::muteInput, shouldMuteInputs);
11981198
if (auto* obj = getObject())
11991199
obj->setMuteInput (isMutingInputs());
12001200
}

‎src/pluginmanager.cpp‎

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -901,9 +901,18 @@ class UnverifiedPlugins : private Thread
901901
ScopedLock sl (lock);
902902
if (plugins.contains (format))
903903
{
904+
const auto types = list.getTypes();
904905
for (const auto& file : plugins.getReference (format))
905906
{
906-
if (nullptr != list.getTypeForFile (file))
907+
bool known = nullptr != list.getTypeForFile (file);
908+
// Provider formats (e.g. CLAP) store types as "pluginID:filePath".
909+
for (int i = types.size(); --i >= 0 && ! known;)
910+
{
911+
const auto& d = types.getReference (i);
912+
known = d.pluginFormatName == format
913+
&& d.fileOrIdentifier.fromFirstOccurrenceOf (":", false, false) == file;
914+
}
915+
if (known)
907916
continue;
908917
auto* const desc = plugs.add (new PluginDescription());
909918
desc->pluginFormatName = format;
@@ -931,6 +940,7 @@ class UnverifiedPlugins : private Thread
931940
cancelFlag.set (0);
932941

933942
PluginManager pluginManager;
943+
pluginManager.getNodeFactory().add (new CLAPProvider());
934944
pluginManager.addDefaultFormats();
935945
auto& manager (pluginManager.getAudioPluginFormats());
936946

@@ -951,9 +961,21 @@ class UnverifiedPlugins : private Thread
951961

952962
// Element Node Providers
953963
auto& factory = pluginManager.getNodeFactory();
954-
for (auto provider : factory.providers())
964+
for (auto* const provider : factory.providers())
955965
{
956-
// FIXME: CLAP and other unverified support.
966+
if (threadShouldExit() || cancelFlag.get() != 0)
967+
break;
968+
969+
const auto formatName = provider->format();
970+
FileSearchPath path = paths[formatName];
971+
path.addPath (provider->defaultSearchPath());
972+
// Providers with no search path (e.g. internal nodes) aren't file-based.
973+
if (path.getNumPaths() <= 0)
974+
continue;
975+
const auto found = provider->findTypes (path, true, false);
976+
977+
ScopedLock sl (lock);
978+
plugins.set (formatName, found);
957979
}
958980

959981
cancelFlag.set (0);

‎src/services/engineservice.cpp‎

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <element/engine.hpp>
77
#include <element/graph.hpp>
88
#include <element/node.hpp>
9+
#include <element/nodefactory.hpp>
910
#include <element/plugins.hpp>
1011
#include <element/services.hpp>
1112
#include <element/settings.hpp>
@@ -35,6 +36,42 @@ static void initializeRootGraphPorts (RootGraph* root, const Node& model)
3536
root->setNumPorts (PortType::Midi, ins.size(), true, false);
3637
root->setNumPorts (PortType::Midi, outs.size(), false, false);
3738
}
39+
40+
/** Scans an unverified plugin and registers it with the known plugins list.
41+
42+
Handles both JUCE audio plugin formats and Element node providers such
43+
as CLAP, whose identifiers from the unverified scan are bare file paths.
44+
45+
@param plugins the plugin manager to verify against.
46+
@param desc description of the unverified plugin to scan.
47+
@param out receives the full descriptions produced by the scan.
48+
@return true if at least one description was found and added.
49+
*/
50+
static bool verifyPlugin (PluginManager& plugins, const PluginDescription& desc, OwnedArray<PluginDescription>& out)
51+
{
52+
auto& list = plugins.getKnownPlugins();
53+
54+
if (auto* const format = plugins.getAudioPluginFormat (desc.pluginFormatName))
55+
{
56+
list.removeFromBlacklist (desc.fileOrIdentifier);
57+
list.removeType (desc);
58+
return list.scanAndAddFile (desc.fileOrIdentifier, false, out, *format);
59+
}
60+
61+
if (auto* const provider = plugins.getProvider (desc.pluginFormatName))
62+
{
63+
list.removeFromBlacklist (desc.fileOrIdentifier);
64+
provider->scan (desc.fileOrIdentifier, out);
65+
for (auto* const d : out)
66+
{
67+
list.removeType (*d);
68+
list.addType (*d);
69+
}
70+
return ! out.isEmpty();
71+
}
72+
73+
return false;
74+
}
3875
} // namespace detail
3976

4077
struct RootGraphHolder
@@ -596,12 +633,7 @@ Node EngineService::addPlugin (const PluginDescription& desc, const bool verifie
596633
OwnedArray<PluginDescription> plugs;
597634
if (! verified)
598635
{
599-
auto* format = context().plugins().getAudioPluginFormat (desc.pluginFormatName);
600-
jassert (format != nullptr);
601-
auto& list (context().plugins().getKnownPlugins());
602-
list.removeFromBlacklist (desc.fileOrIdentifier);
603-
list.removeType (desc);
604-
if (list.scanAndAddFile (desc.fileOrIdentifier, false, plugs, *format))
636+
if (detail::verifyPlugin (context().plugins(), desc, plugs))
605637
{
606638
context().plugins().saveUserPlugins (context().settings());
607639
}
@@ -875,12 +907,7 @@ Node EngineService::addPlugin (const Node& graph, const PluginDescription& desc,
875907
}
876908
else
877909
{
878-
auto* format = context().plugins().getAudioPluginFormat (desc.pluginFormatName);
879-
jassert (format != nullptr);
880-
881-
list.removeFromBlacklist (desc.fileOrIdentifier);
882-
883-
if (list.scanAndAddFile (desc.fileOrIdentifier, false, plugs, *format))
910+
if (detail::verifyPlugin (context().plugins(), desc, plugs))
884911
{
885912
context().plugins().saveUserPlugins (context().settings());
886913
}

0 commit comments

Comments
 (0)