kopia lustrzana https://github.com/jameshball/osci-render
Make volume button mutable, and add ability to save global settings
rodzic
3580ef5fa4
commit
cdf3e88e17
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3,9H7L12,4V20L7,15H3V9M16.59,12L14,9.41L15.41,8L18,10.59L20.59,8L22,9.41L19.41,12L22,14.59L20.59,16L18,13.41L15.41,16L14,14.59L16.59,12Z" /></svg>
|
Po Szerokość: | Wysokość: | Rozmiar: 216 B |
|
@ -17,6 +17,20 @@ CommonAudioProcessor::CommonAudioProcessor(const BusesProperties& busesPropertie
|
|||
: AudioProcessor(busesProperties)
|
||||
#endif
|
||||
{
|
||||
// Initialize the global settings with the plugin name
|
||||
juce::PropertiesFile::Options options;
|
||||
options.applicationName = JucePlugin_Name + juce::String("_globals");
|
||||
options.filenameSuffix = ".settings";
|
||||
options.osxLibrarySubFolder = "Application Support";
|
||||
|
||||
#if JUCE_LINUX || JUCE_BSD
|
||||
options.folderName = "~/.config";
|
||||
#else
|
||||
options.folderName = "";
|
||||
#endif
|
||||
|
||||
globalSettings = std::make_unique<juce::PropertiesFile>(options);
|
||||
|
||||
// locking isn't necessary here because we are in the constructor
|
||||
|
||||
for (auto effect : visualiserParameters.effects) {
|
||||
|
@ -36,6 +50,9 @@ CommonAudioProcessor::CommonAudioProcessor(const BusesProperties& busesPropertie
|
|||
intParameters.push_back(parameter);
|
||||
}
|
||||
|
||||
muteParameter = new BooleanParameter("Mute", "mute", VERSION_HINT, false, "Mute audio output");
|
||||
booleanParameters.push_back(muteParameter);
|
||||
|
||||
permanentEffects.push_back(volumeEffect);
|
||||
permanentEffects.push_back(thresholdEffect);
|
||||
effects.push_back(volumeEffect);
|
||||
|
@ -67,7 +84,10 @@ void CommonAudioProcessor::addAllParameters() {
|
|||
}
|
||||
}
|
||||
|
||||
CommonAudioProcessor::~CommonAudioProcessor() {}
|
||||
CommonAudioProcessor::~CommonAudioProcessor()
|
||||
{
|
||||
saveGlobalSettings();
|
||||
}
|
||||
|
||||
const juce::String CommonAudioProcessor::getName() const {
|
||||
return JucePlugin_Name;
|
||||
|
@ -301,3 +321,41 @@ void CommonAudioProcessor::loadProperties(juce::XmlElement& xml) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CommonAudioProcessor::getGlobalBoolValue(const juce::String& keyName, bool defaultValue) const
|
||||
{
|
||||
return globalSettings != nullptr ? globalSettings->getBoolValue(keyName, defaultValue) : defaultValue;
|
||||
}
|
||||
|
||||
int CommonAudioProcessor::getGlobalIntValue(const juce::String& keyName, int defaultValue) const
|
||||
{
|
||||
return globalSettings != nullptr ? globalSettings->getIntValue(keyName, defaultValue) : defaultValue;
|
||||
}
|
||||
|
||||
double CommonAudioProcessor::getGlobalDoubleValue(const juce::String& keyName, double defaultValue) const
|
||||
{
|
||||
return globalSettings != nullptr ? globalSettings->getDoubleValue(keyName, defaultValue) : defaultValue;
|
||||
}
|
||||
|
||||
juce::String CommonAudioProcessor::getGlobalStringValue(const juce::String& keyName, const juce::String& defaultValue) const
|
||||
{
|
||||
return globalSettings != nullptr ? globalSettings->getValue(keyName, defaultValue) : defaultValue;
|
||||
}
|
||||
|
||||
void CommonAudioProcessor::setGlobalValue(const juce::String& keyName, const juce::var& value)
|
||||
{
|
||||
if (globalSettings != nullptr)
|
||||
globalSettings->setValue(keyName, value);
|
||||
}
|
||||
|
||||
void CommonAudioProcessor::removeGlobalValue(const juce::String& keyName)
|
||||
{
|
||||
if (globalSettings != nullptr)
|
||||
globalSettings->removeValue(keyName);
|
||||
}
|
||||
|
||||
void CommonAudioProcessor::saveGlobalSettings()
|
||||
{
|
||||
if (globalSettings != nullptr)
|
||||
globalSettings->saveIfNeeded();
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
This file contains the basic framework code for a JUCE plugin processor.
|
||||
|
||||
==============================================================================
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
@ -63,12 +64,22 @@ public:
|
|||
std::any getProperty(const std::string& key);
|
||||
std::any getProperty(const std::string& key, std::any defaultValue);
|
||||
void setProperty(const std::string& key, std::any value);
|
||||
|
||||
|
||||
// Global settings methods
|
||||
bool getGlobalBoolValue(const juce::String& keyName, bool defaultValue = false) const;
|
||||
int getGlobalIntValue(const juce::String& keyName, int defaultValue = 0) const;
|
||||
double getGlobalDoubleValue(const juce::String& keyName, double defaultValue = 0.0) const;
|
||||
juce::String getGlobalStringValue(const juce::String& keyName, const juce::String& defaultValue = "") const;
|
||||
void setGlobalValue(const juce::String& keyName, const juce::var& value);
|
||||
void removeGlobalValue(const juce::String& keyName);
|
||||
void saveGlobalSettings();
|
||||
|
||||
juce::SpinLock audioPlayerListenersLock;
|
||||
std::vector<AudioPlayerListener*> audioPlayerListeners;
|
||||
|
||||
std::atomic<double> volume = 1.0;
|
||||
std::atomic<double> threshold = 1.0;
|
||||
BooleanParameter* muteParameter = nullptr;
|
||||
|
||||
std::shared_ptr<Effect> volumeEffect = std::make_shared<Effect>(
|
||||
[this](int index, OsciPoint input, const std::vector<std::atomic<double>>& values, double sampleRate) {
|
||||
|
@ -132,6 +143,9 @@ protected:
|
|||
|
||||
juce::SpinLock propertiesLock;
|
||||
std::unordered_map<std::string, std::any> properties;
|
||||
|
||||
// Global settings that persist across plugin instances
|
||||
std::unique_ptr<juce::PropertiesFile> globalSettings;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CommonAudioProcessor)
|
||||
|
|
|
@ -612,14 +612,20 @@ void OscirenderAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, ju
|
|||
x = juce::jmax(-threshold, juce::jmin(threshold.load(), x));
|
||||
y = juce::jmax(-threshold, juce::jmin(threshold.load(), y));
|
||||
|
||||
threadManager.write(OsciPoint(x, y, 1));
|
||||
|
||||
// Apply mute if active
|
||||
if (muteParameter->getBoolValue()) {
|
||||
x = 0.0;
|
||||
y = 0.0;
|
||||
}
|
||||
|
||||
if (totalNumOutputChannels >= 2) {
|
||||
channelData[0][sample] = x;
|
||||
channelData[1][sample] = y;
|
||||
} else if (totalNumOutputChannels == 1) {
|
||||
channelData[0][sample] = x;
|
||||
}
|
||||
|
||||
threadManager.write(OsciPoint(x, y, 1));
|
||||
|
||||
if (isPlaying) {
|
||||
playTimeSeconds += sTimeSec;
|
||||
|
|
|
@ -69,6 +69,12 @@ void SosciAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::M
|
|||
point.x = juce::jmax(-threshold, juce::jmin(threshold.load(), point.x));
|
||||
point.y = juce::jmax(-threshold, juce::jmin(threshold.load(), point.y));
|
||||
|
||||
// Apply mute if active
|
||||
if (muteParameter->getBoolValue()) {
|
||||
point.x = 0.0;
|
||||
point.y = 0.0;
|
||||
}
|
||||
|
||||
// this is the point that the volume component will draw (i.e. post scale/clipping)
|
||||
threadManager.write(point, "VolumeComponent");
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
class SvgButton : public juce::DrawableButton, public juce::AudioProcessorParameter::Listener, public juce::AsyncUpdater {
|
||||
public:
|
||||
SvgButton(juce::String name, juce::String svg, juce::Colour colour, juce::Colour colourOn, BooleanParameter* toggle = nullptr) : juce::DrawableButton(name, juce::DrawableButton::ButtonStyle::ImageFitted), toggle(toggle) {
|
||||
SvgButton(juce::String name, juce::String svg, juce::Colour colour, juce::Colour colourOn, BooleanParameter* toggle = nullptr, juce::String toggledSvg = "") : juce::DrawableButton(name, juce::DrawableButton::ButtonStyle::ImageFitted), toggle(toggle) {
|
||||
auto doc = juce::XmlDocument::parse(svg);
|
||||
|
||||
changeSvgColour(doc.get(), colour);
|
||||
|
@ -16,14 +16,27 @@ class SvgButton : public juce::DrawableButton, public juce::AudioProcessorParame
|
|||
changeSvgColour(doc.get(), colour.withBrightness(0.3f));
|
||||
disabledImage = juce::Drawable::createFromSVG(*doc);
|
||||
|
||||
changeSvgColour(doc.get(), colourOn);
|
||||
normalImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colourOn.withBrightness(0.7f));
|
||||
overImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colourOn.withBrightness(0.5f));
|
||||
downImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colourOn.withBrightness(0.3f));
|
||||
disabledImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
// If a toggled SVG is provided, use it for the "on" state images
|
||||
if (toggledSvg.isNotEmpty()) {
|
||||
auto toggledDoc = juce::XmlDocument::parse(toggledSvg);
|
||||
changeSvgColour(toggledDoc.get(), colourOn);
|
||||
normalImageOn = juce::Drawable::createFromSVG(*toggledDoc);
|
||||
changeSvgColour(toggledDoc.get(), colourOn.withBrightness(0.7f));
|
||||
overImageOn = juce::Drawable::createFromSVG(*toggledDoc);
|
||||
changeSvgColour(toggledDoc.get(), colourOn.withBrightness(0.5f));
|
||||
downImageOn = juce::Drawable::createFromSVG(*toggledDoc);
|
||||
changeSvgColour(toggledDoc.get(), colourOn.withBrightness(0.3f));
|
||||
disabledImageOn = juce::Drawable::createFromSVG(*toggledDoc);
|
||||
} else {
|
||||
changeSvgColour(doc.get(), colourOn);
|
||||
normalImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colourOn.withBrightness(0.7f));
|
||||
overImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colourOn.withBrightness(0.5f));
|
||||
downImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colourOn.withBrightness(0.3f));
|
||||
disabledImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
}
|
||||
|
||||
basePath = normalImage->getOutlineAsPath();
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#include "VolumeComponent.h"
|
||||
|
||||
VolumeComponent::VolumeComponent(CommonAudioProcessor& p) : AudioBackgroundThread("VolumeComponent", p.threadManager), audioProcessor(p) {
|
||||
VolumeComponent::VolumeComponent(CommonAudioProcessor& p)
|
||||
: AudioBackgroundThread("VolumeComponent", p.threadManager),
|
||||
audioProcessor(p)
|
||||
{
|
||||
setOpaque(false);
|
||||
setShouldBeRunning(true);
|
||||
|
||||
|
@ -38,12 +41,14 @@ VolumeComponent::VolumeComponent(CommonAudioProcessor& p) : AudioBackgroundThrea
|
|||
audioProcessor.thresholdEffect->setValue(thresholdSlider.getValue());
|
||||
};
|
||||
|
||||
auto doc = juce::XmlDocument::parse(BinaryData::volume_svg);
|
||||
volumeIcon = juce::Drawable::createFromSVG(*doc);
|
||||
doc = juce::XmlDocument::parse(BinaryData::threshold_svg);
|
||||
addAndMakeVisible(volumeButton);
|
||||
volumeButton.onClick = [this] {
|
||||
audioProcessor.muteParameter->setBoolValueNotifyingHost(!audioProcessor.muteParameter->getBoolValue());
|
||||
};
|
||||
|
||||
auto doc = juce::XmlDocument::parse(BinaryData::threshold_svg);
|
||||
thresholdIcon = juce::Drawable::createFromSVG(*doc);
|
||||
|
||||
addAndMakeVisible(*volumeIcon);
|
||||
addAndMakeVisible(*thresholdIcon);
|
||||
}
|
||||
|
||||
|
@ -122,9 +127,11 @@ void VolumeComponent::stopTask() {}
|
|||
void VolumeComponent::resized() {
|
||||
auto r = getLocalBounds();
|
||||
|
||||
auto iconRow = r.removeFromTop(20).toFloat();
|
||||
volumeIcon->setTransformToFit(iconRow.removeFromLeft(iconRow.getWidth() / 2).reduced(1), juce::RectanglePlacement::centred);
|
||||
thresholdIcon->setTransformToFit(iconRow.reduced(2), juce::RectanglePlacement::centred);
|
||||
auto iconRow = r.removeFromTop(20);
|
||||
auto volumeRect = iconRow.removeFromLeft(iconRow.getWidth() / 2);
|
||||
volumeButton.setBounds(volumeRect.expanded(3));
|
||||
thresholdIcon->setTransformToFit(iconRow.reduced(2).toFloat(), juce::RectanglePlacement::centred);
|
||||
|
||||
volumeSlider.setBounds(r.removeFromLeft(r.getWidth() / 2));
|
||||
auto radius = volumeSlider.getLookAndFeel().getSliderThumbRadius(volumeSlider);
|
||||
thresholdSlider.setBounds(r.reduced(0, radius / 2));
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "../CommonPluginProcessor.h"
|
||||
#include "../LookAndFeel.h"
|
||||
#include "../concurrency/AudioBackgroundThread.h"
|
||||
#include "SvgButton.h"
|
||||
|
||||
class ThumbRadiusLookAndFeel : public OscirenderLookAndFeel {
|
||||
public:
|
||||
|
@ -88,7 +89,7 @@ private:
|
|||
ThresholdLookAndFeel thresholdLookAndFeel{7};
|
||||
juce::Slider thresholdSlider;
|
||||
|
||||
std::unique_ptr<juce::Drawable> volumeIcon;
|
||||
SvgButton volumeButton = SvgButton("VolumeButton", BinaryData::volume_svg, juce::Colours::white, juce::Colours::red, audioProcessor.muteParameter, BinaryData::mute_svg);
|
||||
std::unique_ptr<juce::Drawable> thresholdIcon;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VolumeComponent)
|
||||
|
|
|
@ -36,7 +36,7 @@ void TextParser::parse(juce::String text, juce::Font font) {
|
|||
|
||||
juce::String displayText = attributedString.getText();
|
||||
// remove all whitespace
|
||||
displayText = displayText.replaceCharacters(" \t\n\r", "");
|
||||
displayText = displayText.removeCharacters(" \t\n\r");
|
||||
int index = 0;
|
||||
|
||||
// Iterate through all lines and all runs in each line
|
||||
|
@ -50,6 +50,9 @@ void TextParser::parse(juce::String text, juce::Font font) {
|
|||
juce::GlyphArrangement glyphs;
|
||||
|
||||
for (int k = 0; k < run->glyphs.size(); ++k) {
|
||||
if (index >= displayText.length()) {
|
||||
break;
|
||||
}
|
||||
juce::juce_wchar character = displayText[index];
|
||||
juce::TextLayout::Glyph glyph = run->glyphs.getUnchecked(k);
|
||||
juce::PositionedGlyph positionedGlyph = juce::PositionedGlyph(
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
<FILE id="WIkl6l" name="fullscreen.svg" compile="0" resource="1" file="Resources/svg/fullscreen.svg"/>
|
||||
<FILE id="n1esUp" name="left_arrow.svg" compile="0" resource="1" file="Resources/svg/left_arrow.svg"/>
|
||||
<FILE id="PxYKbt" name="microphone.svg" compile="0" resource="1" file="Resources/svg/microphone.svg"/>
|
||||
<FILE id="eGMxwy" name="mute.svg" compile="0" resource="1" file="Resources/svg/mute.svg"/>
|
||||
<FILE id="hJHxFY" name="open_in_new.svg" compile="0" resource="1" file="Resources/svg/open_in_new.svg"/>
|
||||
<FILE id="pSc1mq" name="osci.svg" compile="0" resource="1" file="Resources/svg/osci.svg"/>
|
||||
<FILE id="f2D5tv" name="pause.svg" compile="0" resource="1" file="Resources/svg/pause.svg"/>
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
<FILE id="WIkl6l" name="fullscreen.svg" compile="0" resource="1" file="Resources/svg/fullscreen.svg"/>
|
||||
<FILE id="n1esUp" name="left_arrow.svg" compile="0" resource="1" file="Resources/svg/left_arrow.svg"/>
|
||||
<FILE id="PxYKbt" name="microphone.svg" compile="0" resource="1" file="Resources/svg/microphone.svg"/>
|
||||
<FILE id="WoY9r2" name="mute.svg" compile="0" resource="1" file="Resources/svg/mute.svg"/>
|
||||
<FILE id="hJHxFY" name="open_in_new.svg" compile="0" resource="1" file="Resources/svg/open_in_new.svg"/>
|
||||
<FILE id="pSc1mq" name="osci.svg" compile="0" resource="1" file="Resources/svg/osci.svg"/>
|
||||
<FILE id="f2D5tv" name="pause.svg" compile="0" resource="1" file="Resources/svg/pause.svg"/>
|
||||
|
|
Ładowanie…
Reference in New Issue