Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@

## [1.2.x]

### Added
- CLAP plugins now appear in the Unverified plugin menu and can be added to a graph without a prior scan.
- Graph Mixer: channel strips can be hidden via right-click and restored from the mixer background's right-click menu.

### Changed
- 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.
- Graph Mixer: larger fonts for node names, dB readouts and the meter scale, plus a higher-contrast layout.
- Graph Mixer: channel strip name headers now use the node's block color from the graph editor.
- Double-clicking a channel strip fader resets it to 0 dB.
- Selected nodes now show the same accent outline in both the graph editor and the Graph Mixer.
- Note names throughout the UI now use scientific pitch notation (middle C = C4), matching the convention used by most DAWs.

### Fixed
Expand Down
14 changes: 13 additions & 1 deletion include/element/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class EL_API Node : public Model {
juce::Value getMutedValue() { return getPropertyAsValue (tags::mute); }

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

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

/** Change whether this node's strip is hidden in the graph mixer. */
void setHiddenInMixer (bool hidden)
{
getUIValueTree().setProperty (tags::hiddenInMixer, hidden, nullptr);
}

/** Returns true if this node's strip should be hidden in the graph mixer. */
bool isHiddenInMixer() const noexcept
{
return (bool) getUIValueTree().getProperty (tags::hiddenInMixer, false);
}

/** Add a script to this node.
If failure, the returned will be invalid;
*/
Expand Down
2 changes: 1 addition & 1 deletion include/element/porttype.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#endif

#ifndef EL_INVALID_PORT
#define EL_INVALID_PORT ((uint32_t) -1)
#define EL_INVALID_PORT ((uint32_t) - 1)
#endif

#ifndef EL_INVALID_NODE
Expand Down
2 changes: 2 additions & 0 deletions include/element/tags.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,15 @@ static const juce::Identifier lastDisplayMode = "lastDisplayMode";
static const juce::Identifier enabled = "enabled";
static const juce::Identifier gain = "gain";
static const juce::Identifier graphs = "graphs";
static const juce::Identifier hiddenInMixer = "hiddenInMixer";
static const juce::Identifier hiddenPorts = "hiddenPorts";
static const juce::Identifier inputGain = "inputGain";
static const juce::Identifier mappingData = "mappingData";
static const juce::Identifier map = "map";
static const juce::Identifier maps = "maps";
static const juce::Identifier missing = "missing";
static const juce::Identifier mute = "mute";
static const juce::Identifier muteInput = "muteInput";
static const juce::Identifier node = "node";
static const juce::Identifier nodes = "nodes";
static const juce::Identifier notes = "notes";
Expand Down
6 changes: 6 additions & 0 deletions include/element/ui/style.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ struct Style {
e.g. standard Labels, Textboxes, ComboBoxes, etc etc */
static constexpr float fontSizeDefault = 12.0f;

/** Font size for fine print such as scales and small annotations. */
static constexpr float fontSizeSmall = 9.0f;

/** Font size for emphasized readouts such as the channel strip's dB value. */
static constexpr float fontSizeLarge = 14.0f;

/** Draws text rotated by 90 or -90 degrees */
static void drawVerticalText (juce::Graphics& g,
const juce::String& text,
Expand Down
4 changes: 3 additions & 1 deletion src/engine/clapprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,9 @@ class CLAPHost final : public CLAPBaseHost
pfds.reserve (fds.size());
for (const auto& f : fds)
{
struct pollfd p {};
struct pollfd p
{
};
p.fd = f.first;
if (f.second & CLAP_POSIX_FD_READ)
p.events |= POLLIN;
Expand Down
4 changes: 3 additions & 1 deletion src/filesystemwatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ class FileSystemWatcher::Impl
CFArrayRef paths { nullptr };
dispatch_queue_t queue { nullptr };
FSEventStreamRef stream { nullptr };
struct FSEventStreamContext context {};
struct FSEventStreamContext context
{
};
};
#endif

Expand Down
6 changes: 3 additions & 3 deletions src/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,7 @@ void Node::restorePluginState()
obj->setMidiProgramsState (getProperty (tags::midiProgramsState).toString().trim());

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

if (hasProperty (tags::transpose))
obj->setTransposeOffset (getProperty (tags::transpose));
Expand Down Expand Up @@ -1006,7 +1006,7 @@ void Node::savePluginState()
setProperty (tags::globalMidiPrograms, obj->useGlobalMidiPrograms());
setProperty (tags::midiProgramsEnabled, obj->areMidiProgramsEnabled());
setProperty (tags::mute, obj->isMuted());
setProperty ("muteInput", obj->isMutingInputs());
setProperty (tags::muteInput, obj->isMutingInputs());
String mps;
obj->getMidiProgramsState (mps);
setProperty (tags::midiProgramsState, mps);
Expand Down Expand Up @@ -1194,7 +1194,7 @@ void Node::setMuted (bool shouldBeMuted)
void Node::setMuteInput (bool shouldMuteInputs)
{
if (shouldMuteInputs != isMutingInputs())
setProperty ("muteInput", shouldMuteInputs);
setProperty (tags::muteInput, shouldMuteInputs);
if (auto* obj = getObject())
obj->setMuteInput (isMutingInputs());
}
Expand Down
28 changes: 25 additions & 3 deletions src/pluginmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -901,9 +901,18 @@ class UnverifiedPlugins : private Thread
ScopedLock sl (lock);
if (plugins.contains (format))
{
const auto types = list.getTypes();
for (const auto& file : plugins.getReference (format))
{
if (nullptr != list.getTypeForFile (file))
bool known = nullptr != list.getTypeForFile (file);
// Provider formats (e.g. CLAP) store types as "pluginID:filePath".
for (int i = types.size(); --i >= 0 && ! known;)
{
const auto& d = types.getReference (i);
known = d.pluginFormatName == format
&& d.fileOrIdentifier.fromFirstOccurrenceOf (":", false, false) == file;
}
if (known)
continue;
auto* const desc = plugs.add (new PluginDescription());
desc->pluginFormatName = format;
Expand Down Expand Up @@ -931,6 +940,7 @@ class UnverifiedPlugins : private Thread
cancelFlag.set (0);

PluginManager pluginManager;
pluginManager.getNodeFactory().add (new CLAPProvider());
pluginManager.addDefaultFormats();
auto& manager (pluginManager.getAudioPluginFormats());

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

// Element Node Providers
auto& factory = pluginManager.getNodeFactory();
for (auto provider : factory.providers())
for (auto* const provider : factory.providers())
{
// FIXME: CLAP and other unverified support.
if (threadShouldExit() || cancelFlag.get() != 0)
break;

const auto formatName = provider->format();
FileSearchPath path = paths[formatName];
path.addPath (provider->defaultSearchPath());
// Providers with no search path (e.g. internal nodes) aren't file-based.
if (path.getNumPaths() <= 0)
continue;
const auto found = provider->findTypes (path, true, false);

ScopedLock sl (lock);
plugins.set (formatName, found);
}

cancelFlag.set (0);
Expand Down
51 changes: 39 additions & 12 deletions src/services/engineservice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <element/engine.hpp>
#include <element/graph.hpp>
#include <element/node.hpp>
#include <element/nodefactory.hpp>
#include <element/plugins.hpp>
#include <element/services.hpp>
#include <element/settings.hpp>
Expand Down Expand Up @@ -35,6 +36,42 @@ static void initializeRootGraphPorts (RootGraph* root, const Node& model)
root->setNumPorts (PortType::Midi, ins.size(), true, false);
root->setNumPorts (PortType::Midi, outs.size(), false, false);
}

/** Scans an unverified plugin and registers it with the known plugins list.

Handles both JUCE audio plugin formats and Element node providers such
as CLAP, whose identifiers from the unverified scan are bare file paths.

@param plugins the plugin manager to verify against.
@param desc description of the unverified plugin to scan.
@param out receives the full descriptions produced by the scan.
@return true if at least one description was found and added.
*/
static bool verifyPlugin (PluginManager& plugins, const PluginDescription& desc, OwnedArray<PluginDescription>& out)
{
auto& list = plugins.getKnownPlugins();

if (auto* const format = plugins.getAudioPluginFormat (desc.pluginFormatName))
{
list.removeFromBlacklist (desc.fileOrIdentifier);
list.removeType (desc);
return list.scanAndAddFile (desc.fileOrIdentifier, false, out, *format);
}

if (auto* const provider = plugins.getProvider (desc.pluginFormatName))
{
list.removeFromBlacklist (desc.fileOrIdentifier);
provider->scan (desc.fileOrIdentifier, out);
for (auto* const d : out)
{
list.removeType (*d);
list.addType (*d);
}
return ! out.isEmpty();
}

return false;
}
} // namespace detail

struct RootGraphHolder
Expand Down Expand Up @@ -596,12 +633,7 @@ Node EngineService::addPlugin (const PluginDescription& desc, const bool verifie
OwnedArray<PluginDescription> plugs;
if (! verified)
{
auto* format = context().plugins().getAudioPluginFormat (desc.pluginFormatName);
jassert (format != nullptr);
auto& list (context().plugins().getKnownPlugins());
list.removeFromBlacklist (desc.fileOrIdentifier);
list.removeType (desc);
if (list.scanAndAddFile (desc.fileOrIdentifier, false, plugs, *format))
if (detail::verifyPlugin (context().plugins(), desc, plugs))
{
context().plugins().saveUserPlugins (context().settings());
}
Expand Down Expand Up @@ -875,12 +907,7 @@ Node EngineService::addPlugin (const Node& graph, const PluginDescription& desc,
}
else
{
auto* format = context().plugins().getAudioPluginFormat (desc.pluginFormatName);
jassert (format != nullptr);

list.removeFromBlacklist (desc.fileOrIdentifier);

if (list.scanAndAddFile (desc.fileOrIdentifier, false, plugs, *format))
if (detail::verifyPlugin (context().plugins(), desc, plugs))
{
context().plugins().saveUserPlugins (context().settings());
}
Expand Down
10 changes: 8 additions & 2 deletions src/ui/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ void BlockComponent::paint (Graphics& g)

if (isSelected())
{
bgc = bgc.brighter (0.55f);
bgc = bgc.brighter (0.1f);
}

if (colorize)
Expand All @@ -841,7 +841,7 @@ void BlockComponent::paint (Graphics& g)
{
case Compact:
case Small: {
g.setColour (selected ? barColor.brighter (0.275f) : barColor);
g.setColour (selected ? barColor.brighter (0.1f) : barColor);
g.fillRoundedRectangle (box.toFloat(), cornerSize);
break;
}
Expand Down Expand Up @@ -874,6 +874,12 @@ void BlockComponent::paint (Graphics& g)
g.drawRoundedRectangle (box.toFloat(), cornerSize, 1.3f);
}

if (isSelected())
{
g.setColour (Colors::toggleBlue);
g.drawRoundedRectangle (box.toFloat(), cornerSize, 1.5f);
}

auto displayName = node.getDisplayName();
auto subName = node.hasModifiedName() ? node.getPluginName() : String();

Expand Down
2 changes: 1 addition & 1 deletion src/ui/buttons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ void SettingButton::paintButton (Graphics& g, bool isMouseOverButton, bool isBut

if (text.isEmpty() && getClickingTogglesState())
text = (getToggleState()) ? yes : no;
g.setFont (12.f);
g.setFont (Style::fontSizeDefault);
g.setColour (getTextColour());
g.drawText (text, getLocalBounds(), Justification::centred);
}
Expand Down
12 changes: 10 additions & 2 deletions src/ui/buttons.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ class DragableIntLabel : public Component,

if (text.isNotEmpty())
{
g.setFont (12.f);
g.setFont (fontSize);
g.setColour (isEnabled() ? Colours::black : Colours::darkgrey);
g.drawText (text, getLocalBounds(), Justification::centred);
}
Expand Down Expand Up @@ -247,6 +247,13 @@ class DragableIntLabel : public Component,

void setDragable (const bool yn) { dragable = yn; }

/** Change the font size used to draw the value. */
void setFontSize (float newSize)
{
fontSize = newSize;
repaint();
}

inline void setValue (double value)
{
if (useMinMax)
Expand Down Expand Up @@ -298,6 +305,7 @@ class DragableIntLabel : public Component,
int places = 0;
bool useMinMax = false;
double minValue = 0.0, maxValue = 0.0;
float fontSize = Style::fontSizeDefault;

private:
bool dragable = true;
Expand Down Expand Up @@ -332,7 +340,7 @@ class TimeSignatureSetting : public Component

if (text.isNotEmpty())
{
g.setFont (12.f);
g.setFont (Style::fontSizeDefault);
g.setColour (isEnabled() ? Colours::black : Colours::darkgrey);
g.drawText (text, getLocalBounds(), Justification::centred);
}
Expand Down
Loading
Loading