Almost finished
This commit is contained in:
parent
0eb6325e2e
commit
f270e4613e
@ -38,7 +38,6 @@ namespace AXIOM {
|
||||
static inline const juce::Colour SURFACEBYPASS = juce::Colour::fromRGB(42, 42, 42); // #2A2A2A
|
||||
static inline const juce::Colour MUTEDTEXTBYPASS = juce::Colour::fromRGB(230, 230, 230); // #E6E6E6
|
||||
static inline const juce::Colour ACCENTWEAKBYPASS = juce::Colour::fromRGB(82, 210, 210); // #52D2D2
|
||||
|
||||
};
|
||||
|
||||
struct Spacing {
|
||||
@ -291,12 +290,14 @@ namespace AXIOM {
|
||||
L,
|
||||
XL
|
||||
};
|
||||
|
||||
enum class StrokeMode {
|
||||
Hairline,
|
||||
Thin,
|
||||
Regular,
|
||||
Bold
|
||||
};
|
||||
|
||||
enum class CornerStyle {
|
||||
Rounded,
|
||||
Cut,
|
||||
@ -313,6 +314,7 @@ namespace AXIOM {
|
||||
static constexpr float MINSTROKE = 1.0f;
|
||||
static constexpr float MAXSTROKE = 3.0f;
|
||||
};
|
||||
|
||||
inline static Scale scale{};
|
||||
|
||||
static constexpr int getRadiusUnits(RadiusMode mode) {
|
||||
@ -359,7 +361,6 @@ namespace AXIOM {
|
||||
width = juce::jlimit(scale.MINSTROKE, scale.MAXSTROKE, width);
|
||||
return width;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
struct Shadows {
|
||||
@ -369,30 +370,35 @@ namespace AXIOM {
|
||||
static constexpr float MINALPHA = 0.04f;
|
||||
static constexpr float MAXALPHA = 0.95f;
|
||||
static constexpr float MUTEDMUL = 0.5f;
|
||||
|
||||
struct AlphaToken {
|
||||
enum class Role {
|
||||
Text, Icon, Surface, Overlay, Stroke, FocusGlow, Disabled, InteractiveFill
|
||||
};
|
||||
|
||||
enum class State {
|
||||
Rest, Hover, Active, Checked, Dragged, Disabled
|
||||
};
|
||||
|
||||
enum class Emphasis {
|
||||
High, Medium, Low, Muted
|
||||
};
|
||||
|
||||
Role role;
|
||||
State state;
|
||||
Emphasis emphasis;
|
||||
};
|
||||
|
||||
static AlphaToken getAlphaToken(AlphaToken::Role role, AlphaToken::State state, AlphaToken::Emphasis emphasis) {
|
||||
return AlphaToken{ role, state, emphasis };
|
||||
static AlphaToken getAlphaToken(AlphaToken::Role role, AlphaToken::State state,
|
||||
AlphaToken::Emphasis emphasis) {
|
||||
return AlphaToken{role, state, emphasis};
|
||||
};
|
||||
|
||||
static float getAlphaFactor(AlphaToken::Role role, AlphaToken::State state, AlphaToken::Emphasis emphasis) {
|
||||
float alphaFactor;
|
||||
if (role == AlphaToken::Role::Text || role == AlphaToken::Role::Icon) {
|
||||
alphaFactor = fromEmphasis(emphasis);
|
||||
}else {
|
||||
} else {
|
||||
alphaFactor = fromRole(role);
|
||||
}
|
||||
alphaFactor += fromState(state);
|
||||
@ -527,20 +533,16 @@ namespace AXIOM {
|
||||
};*/
|
||||
|
||||
struct Components {
|
||||
|
||||
class BypassButtonLookAndFeel : public juce::LookAndFeel_V4 {
|
||||
public:
|
||||
BypassButtonLookAndFeel()
|
||||
{
|
||||
svgXml = juce::XmlDocument::parse(BinaryData::bypass_icon_svg);}
|
||||
BypassButtonLookAndFeel() {
|
||||
svgXml = juce::XmlDocument::parse(BinaryData::bypass_icon_svg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void drawToggleButton(juce::Graphics& g, juce::ToggleButton& button,
|
||||
void drawToggleButton(juce::Graphics &g, juce::ToggleButton &button,
|
||||
bool shouldDrawButtonAsHighlighted,
|
||||
bool shouldDrawButtonAsDown) override
|
||||
{
|
||||
|
||||
bool shouldDrawButtonAsDown) override {
|
||||
bool isHovered = button.isMouseOverOrDragging();
|
||||
bool isToggled = button.getToggleState();
|
||||
bool isEnabled = button.isEnabled();
|
||||
@ -556,14 +558,11 @@ namespace AXIOM {
|
||||
if (svgXml != nullptr) {
|
||||
// WICHTIG: Erstelle für jeden Frame ein NEUES Drawable!
|
||||
auto icon = juce::Drawable::createFromSVG(*svgXml);
|
||||
if (icon != nullptr)
|
||||
{
|
||||
|
||||
if (icon != nullptr) {
|
||||
juce::Colour colour;
|
||||
if (!isEnabled) {
|
||||
colour = isToggled ? Colours::SURFACEBYPASS : Colours::ACCENTWEAKCOLOUR;
|
||||
}
|
||||
else if (isHovered) {
|
||||
} else if (isHovered) {
|
||||
colour = isToggled ? Colours::SURFACEHOVER : Colours::ACCENTHOVER;
|
||||
} else {
|
||||
colour = isToggled
|
||||
@ -578,7 +577,6 @@ namespace AXIOM {
|
||||
juce::RectanglePlacement::centred, bypassOpacity);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
@ -587,16 +585,13 @@ namespace AXIOM {
|
||||
|
||||
class PresetMenuButtonLookAndFeel : public juce::LookAndFeel_V4 {
|
||||
public:
|
||||
PresetMenuButtonLookAndFeel()
|
||||
{
|
||||
PresetMenuButtonLookAndFeel() {
|
||||
presetMenuButton = juce::XmlDocument::parse(BinaryData::preset_menu_icon_svg);
|
||||
}
|
||||
|
||||
void drawToggleButton(juce::Graphics& g, juce::ToggleButton& button,
|
||||
void drawToggleButton(juce::Graphics &g, juce::ToggleButton &button,
|
||||
bool shouldDrawButtonAsHighlighted,
|
||||
bool shouldDrawButtonAsDown) override
|
||||
{
|
||||
|
||||
bool shouldDrawButtonAsDown) override {
|
||||
bool isHovered = button.isMouseOverOrDragging();
|
||||
bool isToggled = button.getToggleState();
|
||||
bool isEnabled = button.isEnabled();
|
||||
@ -626,7 +621,6 @@ namespace AXIOM {
|
||||
menuIcon->drawWithin(g, iconBounds,
|
||||
juce::RectanglePlacement::centred, 1.0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
@ -643,15 +637,13 @@ namespace AXIOM {
|
||||
float activeIconOpacity = 0.0f;
|
||||
|
||||
|
||||
void drawToggleButton(juce::Graphics& g, juce::ToggleButton& button,
|
||||
void drawToggleButton(juce::Graphics &g, juce::ToggleButton &button,
|
||||
bool shouldDrawButtonAsHighlighted,
|
||||
bool shouldDrawButtonAsDown) override {
|
||||
|
||||
|
||||
const bool isHovered = button.isMouseOverOrDragging();
|
||||
const bool isToggled = button.getToggleState();
|
||||
auto bounds = button.getLocalBounds().toFloat();
|
||||
auto iconSize = juce::jmin(bounds.getWidth(), bounds.getHeight()) * 0.5f;
|
||||
auto iconSize = juce::jmin(bounds.getWidth(), bounds.getHeight()) * 2 * 0.95f;
|
||||
|
||||
auto hoverFactor = isHovered ? 1.05f : 1.0f;
|
||||
|
||||
@ -662,39 +654,31 @@ namespace AXIOM {
|
||||
auto activeIcon = juce::Drawable::createFromSVG(*activeSvg);
|
||||
|
||||
if (passiveIcon != nullptr && activeIcon != nullptr) {
|
||||
|
||||
activeIcon->drawWithin(g, iconBounds,
|
||||
juce::RectanglePlacement::centred, activeIconOpacity);
|
||||
passiveIcon->drawWithin(g, iconBounds,
|
||||
juce::RectanglePlacement::centred, passiveIconOpacity);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<juce::XmlElement> passiveSvg;
|
||||
std::unique_ptr<juce::XmlElement> activeSvg;
|
||||
|
||||
};
|
||||
|
||||
class lowBandButtonLookAndFeel : public juce::LookAndFeel_V4 {
|
||||
public:
|
||||
lowBandButtonLookAndFeel()
|
||||
{
|
||||
lowBandButtonLookAndFeel() {
|
||||
lowBypassIcon = juce::XmlDocument::parse(BinaryData::bypass_icon_svg);
|
||||
lowCutIcon = juce::XmlDocument::parse(BinaryData::low_cut_icon_svg);
|
||||
lowBellIcon = juce::XmlDocument::parse(BinaryData::bell_icon_svg);
|
||||
lowShelfIcon = juce::XmlDocument::parse(BinaryData::low_shelf_icon_svg);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void drawToggleButton(juce::Graphics& g, juce::ToggleButton& button,
|
||||
void drawToggleButton(juce::Graphics &g, juce::ToggleButton &button,
|
||||
bool shouldDrawButtonAsHighlighted,
|
||||
bool shouldDrawButtonAsDown) override
|
||||
{
|
||||
|
||||
bool shouldDrawButtonAsDown) override {
|
||||
bool isHovered = button.isMouseOverOrDragging();
|
||||
bool isToggled = button.getToggleState();
|
||||
bool isEnabled = button.isEnabled();
|
||||
@ -707,21 +691,20 @@ namespace AXIOM {
|
||||
|
||||
float bypassOpacity = 1.0f;
|
||||
|
||||
if (lowBypassIcon != nullptr && lowCutIcon != nullptr && lowBellIcon != nullptr && lowShelfIcon != nullptr) {
|
||||
if (lowBypassIcon != nullptr && lowCutIcon != nullptr && lowBellIcon != nullptr && lowShelfIcon !=
|
||||
nullptr) {
|
||||
// WICHTIG: Erstelle für jeden Frame ein NEUES Drawable!
|
||||
auto bypassIcon = juce::Drawable::createFromSVG(*lowBypassIcon);
|
||||
auto cutIcon = juce::Drawable::createFromSVG(*lowCutIcon);
|
||||
auto bellIcon = juce::Drawable::createFromSVG(*lowBellIcon);
|
||||
auto shelfIcon = juce::Drawable::createFromSVG(*lowShelfIcon);
|
||||
|
||||
if (bypassIcon != nullptr && cutIcon != nullptr && bellIcon != nullptr && shelfIcon != nullptr)
|
||||
{
|
||||
|
||||
if (bypassIcon != nullptr && cutIcon != nullptr && bellIcon != nullptr && shelfIcon !=
|
||||
nullptr) {
|
||||
juce::Colour colour;
|
||||
if (!isEnabled) {
|
||||
colour = isToggled ? Colours::ACCENTWEAKCOLOUR : Colours::SURFACEBYPASS;
|
||||
}
|
||||
else if (isHovered) {
|
||||
} else if (isHovered) {
|
||||
colour = isToggled ? Colours::ACCENTHOVER : Colours::SURFACEHOVER;
|
||||
} else {
|
||||
colour = isToggled
|
||||
@ -735,26 +718,21 @@ namespace AXIOM {
|
||||
bypassIcon->replaceColour(juce::Colours::black, colour);
|
||||
bypassIcon->drawWithin(g, iconBounds,
|
||||
juce::RectanglePlacement::centred, bypassOpacity);
|
||||
}
|
||||
else if (button.getName() == "LowCut") {
|
||||
} else if (button.getName() == "LowCut") {
|
||||
cutIcon->replaceColour(juce::Colours::black, colour);
|
||||
cutIcon->drawWithin(g, iconBounds,
|
||||
juce::RectanglePlacement::centred, bypassOpacity);
|
||||
}
|
||||
else if (button.getName() == "LowBell") {
|
||||
} else if (button.getName() == "LowBell") {
|
||||
bellIcon->replaceColour(juce::Colours::black, colour);
|
||||
bellIcon->drawWithin(g, iconBounds,
|
||||
juce::RectanglePlacement::centred, bypassOpacity);
|
||||
}
|
||||
else if (button.getName() == "LowShelf") {
|
||||
} else if (button.getName() == "LowShelf") {
|
||||
shelfIcon->replaceColour(juce::Colours::black, colour);
|
||||
shelfIcon->drawWithin(g, iconBounds,
|
||||
juce::RectanglePlacement::centred, bypassOpacity);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
@ -766,22 +744,17 @@ namespace AXIOM {
|
||||
|
||||
class highBandButtonLookAndFeel : public juce::LookAndFeel_V4 {
|
||||
public:
|
||||
highBandButtonLookAndFeel()
|
||||
{
|
||||
highBandButtonLookAndFeel() {
|
||||
highBypassIcon = juce::XmlDocument::parse(BinaryData::bypass_icon_svg);
|
||||
highCutIcon = juce::XmlDocument::parse(BinaryData::high_cut_icon_svg);
|
||||
highBellIcon = juce::XmlDocument::parse(BinaryData::bell_icon_svg);
|
||||
highShelfIcon = juce::XmlDocument::parse(BinaryData::high_shelf_icon_svg);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void drawToggleButton(juce::Graphics& g, juce::ToggleButton& button,
|
||||
void drawToggleButton(juce::Graphics &g, juce::ToggleButton &button,
|
||||
bool shouldDrawButtonAsHighlighted,
|
||||
bool shouldDrawButtonAsDown) override
|
||||
{
|
||||
|
||||
bool shouldDrawButtonAsDown) override {
|
||||
bool isHovered = button.isMouseOverOrDragging();
|
||||
bool isToggled = button.getToggleState();
|
||||
bool isEnabled = button.isEnabled();
|
||||
@ -794,21 +767,20 @@ namespace AXIOM {
|
||||
|
||||
float bypassOpacity = 1.0f;
|
||||
|
||||
if (highBypassIcon != nullptr && highCutIcon != nullptr && highBellIcon != nullptr && highShelfIcon != nullptr) {
|
||||
if (highBypassIcon != nullptr && highCutIcon != nullptr && highBellIcon != nullptr && highShelfIcon
|
||||
!= nullptr) {
|
||||
// WICHTIG: Erstelle für jeden Frame ein NEUES Drawable!
|
||||
auto bypassIcon = juce::Drawable::createFromSVG(*highBypassIcon);
|
||||
auto cutIcon = juce::Drawable::createFromSVG(*highCutIcon);
|
||||
auto bellIcon = juce::Drawable::createFromSVG(*highBellIcon);
|
||||
auto shelfIcon = juce::Drawable::createFromSVG(*highShelfIcon);
|
||||
|
||||
if (bypassIcon != nullptr && cutIcon != nullptr && bellIcon != nullptr && shelfIcon != nullptr)
|
||||
{
|
||||
|
||||
if (bypassIcon != nullptr && cutIcon != nullptr && bellIcon != nullptr && shelfIcon !=
|
||||
nullptr) {
|
||||
juce::Colour colour;
|
||||
if (!isEnabled) {
|
||||
colour = isToggled ? Colours::ACCENTWEAKCOLOUR : Colours::SURFACEBYPASS;
|
||||
}
|
||||
else if (isHovered) {
|
||||
} else if (isHovered) {
|
||||
colour = isToggled ? Colours::ACCENTHOVER : Colours::SURFACEHOVER;
|
||||
} else {
|
||||
colour = isToggled
|
||||
@ -822,25 +794,21 @@ namespace AXIOM {
|
||||
bypassIcon->replaceColour(juce::Colours::black, colour);
|
||||
bypassIcon->drawWithin(g, iconBounds,
|
||||
juce::RectanglePlacement::centred, bypassOpacity);
|
||||
}
|
||||
else if (button.getName() == "HighCut") {
|
||||
} else if (button.getName() == "HighCut") {
|
||||
cutIcon->replaceColour(juce::Colours::black, colour);
|
||||
cutIcon->drawWithin(g, iconBounds,
|
||||
juce::RectanglePlacement::centred, bypassOpacity);
|
||||
}
|
||||
else if (button.getName() == "HighBell") {
|
||||
} else if (button.getName() == "HighBell") {
|
||||
bellIcon->replaceColour(juce::Colours::black, colour);
|
||||
bellIcon->drawWithin(g, iconBounds,
|
||||
juce::RectanglePlacement::centred, bypassOpacity);
|
||||
}
|
||||
else if (button.getName() == "HighShelf") {
|
||||
} else if (button.getName() == "HighShelf") {
|
||||
shelfIcon->replaceColour(juce::Colours::black, colour);
|
||||
shelfIcon->drawWithin(g, iconBounds,
|
||||
juce::RectanglePlacement::centred, bypassOpacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
@ -855,23 +823,21 @@ namespace AXIOM {
|
||||
};
|
||||
|
||||
|
||||
class BaseSliderLookAndFeel : public juce::LookAndFeel_V4
|
||||
{
|
||||
class BaseSliderLookAndFeel : public juce::LookAndFeel_V4 {
|
||||
public:
|
||||
juce::Label* createSliderTextBox(juce::Slider& slider) override
|
||||
{
|
||||
auto* label = juce::LookAndFeel_V4::createSliderTextBox(slider);
|
||||
juce::Label *createSliderTextBox(juce::Slider &slider) override {
|
||||
auto *label = juce::LookAndFeel_V4::createSliderTextBox(slider);
|
||||
|
||||
label->setColour(juce::Label::backgroundColourId, juce::Colours::transparentBlack);
|
||||
label->setColour(juce::Label::outlineColourId, juce::Colours::transparentBlack);
|
||||
label->setColour(juce::Label::textColourId, Colours::FOREGROUNDCOLOUR);
|
||||
label->setJustificationType(juce::Justification::centred);
|
||||
label->setInterceptsMouseClicks (false, false);
|
||||
label->setInterceptsMouseClicks(false, false);
|
||||
Typography::applyToLabel(*label, Typography::Style::Mono, 1.f);
|
||||
return label;
|
||||
}
|
||||
juce::Slider::SliderLayout getSliderLayout (juce::Slider& slider) override
|
||||
{
|
||||
|
||||
juce::Slider::SliderLayout getSliderLayout(juce::Slider &slider) override {
|
||||
juce::Slider::SliderLayout layout;
|
||||
if (slider.getName() == "LowBand Slope" || slider.getName() == "HighBand Slope") {
|
||||
layout.textBoxBounds = {};
|
||||
@ -883,7 +849,7 @@ namespace AXIOM {
|
||||
const int w = slider.getWidth();
|
||||
const int h = slider.getHeight();
|
||||
|
||||
layout.textBoxBounds = juce::Rectangle<int> (
|
||||
layout.textBoxBounds = juce::Rectangle<int>(
|
||||
r.getCentreX() - w / 2,
|
||||
r.getCentreY() - h / 2,
|
||||
w, h);
|
||||
@ -893,10 +859,9 @@ namespace AXIOM {
|
||||
return layout;
|
||||
}
|
||||
|
||||
void drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height,
|
||||
void drawRotarySlider(juce::Graphics &g, int x, int y, int width, int height,
|
||||
float sliderPos, float rotaryStartAngle, float rotaryEndAngle,
|
||||
juce::Slider& slider) override
|
||||
{
|
||||
juce::Slider &slider) override {
|
||||
// Basis-Implementation - wird in Subklassen überschrieben
|
||||
auto radius = juce::jmin(width / 2, height / 2) - 4.0f;
|
||||
auto centreX = x + width * 0.5f;
|
||||
@ -918,13 +883,12 @@ namespace AXIOM {
|
||||
g.fillPath(p);
|
||||
}
|
||||
};
|
||||
class GainSliderLookAndFeel : public BaseSliderLookAndFeel
|
||||
{
|
||||
|
||||
class GainSliderLookAndFeel : public BaseSliderLookAndFeel {
|
||||
public:
|
||||
void drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height,
|
||||
void drawRotarySlider(juce::Graphics &g, int x, int y, int width, int height,
|
||||
float sliderPos, float rotaryStartAngle, float rotaryEndAngle,
|
||||
juce::Slider& slider) override
|
||||
{
|
||||
juce::Slider &slider) override {
|
||||
bool isHovered = slider.isMouseOverOrDragging();
|
||||
auto isEnabled = slider.isEnabled();
|
||||
float hoverFactor = 1.0f;
|
||||
@ -949,7 +913,7 @@ namespace AXIOM {
|
||||
|
||||
// Background
|
||||
g.setColour(Colours::BACKGROUNDCOLOUR);
|
||||
g.fillEllipse(centreX - radius, centreY - radius, radius * 2.0f , radius * 2.0f);
|
||||
g.fillEllipse(centreX - radius, centreY - radius, radius * 2.0f, radius * 2.0f);
|
||||
|
||||
g.setColour(surfaceCol);
|
||||
g.drawEllipse(centreX - radius, centreY - radius, radius * 2.0f, radius * 2.0f, arcPathWidth);
|
||||
@ -965,20 +929,18 @@ namespace AXIOM {
|
||||
|
||||
// Pointer
|
||||
juce::Path p;
|
||||
p.addRectangle(-arcPathWidth / 2, (-radius - arcPathWidth) * hoverFactor, arcPathWidth, radius * 0.5f * hoverFactor);
|
||||
p.addRectangle(-arcPathWidth / 2, (-radius - arcPathWidth) * hoverFactor, arcPathWidth,
|
||||
radius * 0.5f * hoverFactor);
|
||||
p.applyTransform(juce::AffineTransform::rotation(angle).translated(centreX, centreY));
|
||||
g.fillPath(p);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class FreqQSliderLookAndFeel : public BaseSliderLookAndFeel
|
||||
{
|
||||
class FreqQSliderLookAndFeel : public BaseSliderLookAndFeel {
|
||||
public:
|
||||
void drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height,
|
||||
void drawRotarySlider(juce::Graphics &g, int x, int y, int width, int height,
|
||||
float sliderPos, float rotaryStartAngle, float rotaryEndAngle,
|
||||
juce::Slider& slider) override
|
||||
{
|
||||
juce::Slider &slider) override {
|
||||
auto radius = juce::jmin(width / 2, height / 2) - 4.0f;
|
||||
auto centreX = x + width * 0.5f;
|
||||
auto centreY = y + height * 0.5f;
|
||||
@ -1011,7 +973,8 @@ namespace AXIOM {
|
||||
g.strokePath(valueArc, juce::PathStrokeType(arcPathWidth));
|
||||
// Dünner Pointer
|
||||
juce::Path p;
|
||||
p.addRectangle(-1.0f, (-radius - arcPathWidth) * hoverFactor, arcPathWidth, radius * 0.4f * hoverFactor);
|
||||
p.addRectangle(-1.0f, (-radius - arcPathWidth) * hoverFactor, arcPathWidth,
|
||||
radius * 0.4f * hoverFactor);
|
||||
p.applyTransform(juce::AffineTransform::rotation(angle).translated(centreX, centreY));
|
||||
|
||||
g.setColour(accentCol);
|
||||
@ -1023,8 +986,7 @@ namespace AXIOM {
|
||||
public:
|
||||
static constexpr float labelPadding = 20.0f;
|
||||
|
||||
juce::Slider::SliderLayout getSliderLayout(juce::Slider& slider) override
|
||||
{
|
||||
juce::Slider::SliderLayout getSliderLayout(juce::Slider &slider) override {
|
||||
juce::Slider::SliderLayout layout;
|
||||
auto bounds = slider.getLocalBounds();
|
||||
|
||||
@ -1043,10 +1005,9 @@ namespace AXIOM {
|
||||
return layout;
|
||||
}
|
||||
|
||||
void drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height,
|
||||
void drawRotarySlider(juce::Graphics &g, int x, int y, int width, int height,
|
||||
float sliderPos, float rotaryStartAngle, float rotaryEndAngle,
|
||||
juce::Slider& slider) override
|
||||
{
|
||||
juce::Slider &slider) override {
|
||||
// Basis-Implementation - wird in Subklassen überschrieben
|
||||
auto radius = juce::jmin(width / 2, height / 2) - 4.0f;
|
||||
auto centreX = x + width * 0.5f;
|
||||
@ -1082,16 +1043,16 @@ namespace AXIOM {
|
||||
g.setFont(12.0f);
|
||||
auto value = slider.getValue();
|
||||
|
||||
for (int i = 0; i < labels.size(); ++i)
|
||||
{
|
||||
for (int i = 0; i < labels.size(); ++i) {
|
||||
const double labelVal = labels[i].getDoubleValue(); // "12" -> 12.0 usw.
|
||||
const bool isMatch = value == i; // Toleranz: 0.5
|
||||
|
||||
juce::Colour colour;
|
||||
if (!isEnabled) {
|
||||
colour = isMatch ? Colours::ACCENTWEAKCOLOUR : Colours::FOREGROUNDCOLOUR.withMultipliedAlpha (0.4f);
|
||||
}
|
||||
else {
|
||||
colour = isMatch
|
||||
? Colours::ACCENTWEAKCOLOUR
|
||||
: Colours::FOREGROUNDCOLOUR.withMultipliedAlpha(0.4f);
|
||||
} else {
|
||||
colour = isMatch
|
||||
? Colours::ACCENTCOLOUR
|
||||
: Colours::FOREGROUNDCOLOUR;
|
||||
@ -1099,7 +1060,7 @@ namespace AXIOM {
|
||||
g.setColour(colour);
|
||||
|
||||
|
||||
const double position = (double)i / 3.0;
|
||||
const double position = (double) i / 3.0;
|
||||
const float ang = rotaryStartAngle + position * (rotaryEndAngle - rotaryStartAngle);
|
||||
|
||||
juce::Point<float> pos(
|
||||
@ -1112,17 +1073,14 @@ namespace AXIOM {
|
||||
|
||||
g.drawText(labels[i], textRect, juce::Justification::centred);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class GlobalSliderLookAndFeel : public BaseSliderLookAndFeel
|
||||
{
|
||||
class GlobalSliderLookAndFeel : public BaseSliderLookAndFeel {
|
||||
public:
|
||||
void drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height,
|
||||
void drawRotarySlider(juce::Graphics &g, int x, int y, int width, int height,
|
||||
float sliderPos, float rotaryStartAngle, float rotaryEndAngle,
|
||||
juce::Slider& slider) override
|
||||
{
|
||||
juce::Slider &slider) override {
|
||||
auto radius = juce::jmin(width / 2, height / 2) - 4.0f;
|
||||
auto centreX = x + width * 0.5f;
|
||||
auto centreY = y + height * 0.5f;
|
||||
@ -1149,7 +1107,7 @@ namespace AXIOM {
|
||||
|
||||
// Einfacher Ring
|
||||
g.setColour(surfaceCol);
|
||||
g.fillEllipse(centreX - radius, centreY - radius, radius * 2.0f , radius * 2.0f);
|
||||
g.fillEllipse(centreX - radius, centreY - radius, radius * 2.0f, radius * 2.0f);
|
||||
|
||||
g.setColour(ringCol);
|
||||
g.drawEllipse(centreX - radius, centreY - radius, radius * 2.0f, radius * 2.0f, arcPathWidth);
|
||||
@ -1162,7 +1120,8 @@ namespace AXIOM {
|
||||
g.strokePath(valueArc, juce::PathStrokeType(arcPathWidth));
|
||||
// Dünner Pointer
|
||||
juce::Path p;
|
||||
p.addRectangle(-1.0f, (-radius - arcPathWidth) * hoverFactor, arcPathWidth, radius * 0.4f * hoverFactor);
|
||||
p.addRectangle(-1.0f, (-radius - arcPathWidth) * hoverFactor, arcPathWidth,
|
||||
radius * 0.4f * hoverFactor);
|
||||
p.applyTransform(juce::AffineTransform::rotation(angle).translated(centreX, centreY));
|
||||
|
||||
g.setColour(accentCol);
|
||||
@ -1180,6 +1139,7 @@ namespace AXIOM {
|
||||
Global,
|
||||
Mix
|
||||
};
|
||||
|
||||
static float getSliderSizeMod(SizeMode mode) {
|
||||
switch (mode) {
|
||||
case SizeMode::Gain: return 1.25f;
|
||||
@ -1191,7 +1151,6 @@ namespace AXIOM {
|
||||
default: return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@ -1209,7 +1168,6 @@ namespace AXIOM {
|
||||
};
|
||||
|
||||
struct Layout {
|
||||
|
||||
///
|
||||
/// @param mode Spacing mode -- e.g. Spacing::SizeMode::XS
|
||||
/// @return Gap size in px as int
|
||||
@ -1228,13 +1186,12 @@ namespace AXIOM {
|
||||
return rect;
|
||||
}
|
||||
|
||||
static juce::FlexItem flexItem(juce::Component& component,
|
||||
static juce::FlexItem flexItem(juce::Component &component,
|
||||
float flexGrow = 1.f,
|
||||
float flexShrink = 1.f,
|
||||
float basisPx = -1.f,
|
||||
Spacing::SizeMode margin = Spacing::SizeMode::XS) {
|
||||
|
||||
juce::FlexItem item{ component };
|
||||
juce::FlexItem item{component};
|
||||
item.flexGrow = flexGrow;
|
||||
item.flexShrink = flexShrink;
|
||||
|
||||
@ -1242,7 +1199,7 @@ namespace AXIOM {
|
||||
item.flexBasis = basisPx;
|
||||
|
||||
const float half = (float) gap(margin) * 0.5f;
|
||||
item.margin = juce::FlexItem::Margin{ half, half, half, half };
|
||||
item.margin = juce::FlexItem::Margin{half, half, half, half};
|
||||
|
||||
return item;
|
||||
}
|
||||
@ -1263,7 +1220,6 @@ namespace AXIOM {
|
||||
fb.items.addArray(items);
|
||||
|
||||
fb.performLayout(content(bounds, pad));
|
||||
|
||||
}
|
||||
|
||||
static void flexColumn(juce::Rectangle<int> bounds,
|
||||
@ -1301,28 +1257,26 @@ namespace AXIOM {
|
||||
struct GridSpec {
|
||||
std::vector<juce::Grid::TrackInfo> cols;
|
||||
std::vector<juce::Grid::TrackInfo> rows;
|
||||
Spacing::SizeMode colGap { Spacing::SizeMode::M };
|
||||
Spacing::SizeMode rowGap { Spacing::SizeMode::M };
|
||||
juce::BorderSize<int> pad { 0, 0, 0, 0 };
|
||||
Spacing::SizeMode colGap{Spacing::SizeMode::M};
|
||||
Spacing::SizeMode rowGap{Spacing::SizeMode::M};
|
||||
juce::BorderSize<int> pad{0, 0, 0, 0};
|
||||
};
|
||||
|
||||
static juce::GridItem area(juce::Component& c,
|
||||
static juce::GridItem area(juce::Component &c,
|
||||
int rowStart, int colStart,
|
||||
int rowEnd, int colEnd)
|
||||
{
|
||||
int rowEnd, int colEnd) {
|
||||
return juce::GridItem(c)
|
||||
.withArea(rowStart, colStart, rowEnd, colEnd);
|
||||
|
||||
}
|
||||
|
||||
static void grid(juce::Rectangle<int> bounds,
|
||||
const GridSpec& spec,
|
||||
const GridSpec &spec,
|
||||
std::initializer_list<juce::GridItem> children,
|
||||
juce::Grid::AutoFlow autoFlow = juce::Grid::AutoFlow::row) {
|
||||
juce::Grid g;
|
||||
|
||||
for (const auto& t : spec.cols) g.templateColumns.add(t);
|
||||
for (const auto& t : spec.rows) g.templateRows.add(t);
|
||||
for (const auto &t: spec.cols) g.templateColumns.add(t);
|
||||
for (const auto &t: spec.rows) g.templateRows.add(t);
|
||||
|
||||
g.autoFlow = autoFlow;
|
||||
g.autoColumns = juce::Grid::TrackInfo(juce::Grid::Fr(1));
|
||||
@ -1331,7 +1285,7 @@ namespace AXIOM {
|
||||
g.columnGap = px((float) gap(spec.colGap));
|
||||
g.rowGap = px((float) gap(spec.rowGap));
|
||||
|
||||
for (const auto& c : children)
|
||||
for (const auto &c: children)
|
||||
g.items.add(c);
|
||||
|
||||
const auto inner = spec.pad.subtractedFrom(bounds);
|
||||
@ -1341,36 +1295,36 @@ namespace AXIOM {
|
||||
|
||||
class PresetMenu : public juce::Component {
|
||||
public:
|
||||
PresetMenu(juce::TextEditor* inputField,
|
||||
juce::TextButton* saveButton,
|
||||
juce::TextButton* deleteButton) {
|
||||
PresetMenu(juce::TextEditor *inputField,
|
||||
juce::TextButton *saveButton,
|
||||
juce::TextButton *deleteButton) {
|
||||
addAndMakeVisible(*inputField);
|
||||
addAndMakeVisible(*saveButton);
|
||||
addAndMakeVisible(*deleteButton);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class PresetMenuLookAndFeel : public juce::LookAndFeel_V4 {
|
||||
public:
|
||||
void drawCallOutBoxBackground(juce::CallOutBox &callOutBox, juce::Graphics &g, const juce::Path &path, juce::Image &image) override {
|
||||
void drawCallOutBoxBackground(juce::CallOutBox &callOutBox, juce::Graphics &g, const juce::Path &path,
|
||||
juce::Image &image) override {
|
||||
g.setColour(Colours::SURFACECOLOUR);
|
||||
g.fillPath(path);
|
||||
|
||||
g.setColour (Colours::FOREGROUNDCOLOUR.withAlpha(0.3f));
|
||||
g.strokePath (path, juce::PathStrokeType (1.0f));
|
||||
g.setColour(Colours::FOREGROUNDCOLOUR.withAlpha(0.3f));
|
||||
g.strokePath(path, juce::PathStrokeType(1.0f));
|
||||
};
|
||||
|
||||
|
||||
int getCallOutBoxBorderSize (const juce::CallOutBox&) override
|
||||
{
|
||||
int getCallOutBoxBorderSize(const juce::CallOutBox &) override {
|
||||
return 4;
|
||||
}
|
||||
};
|
||||
|
||||
class PresetButtonsLookAndFeel : public juce::LookAndFeel_V4 {
|
||||
public:
|
||||
|
||||
void drawButtonText(juce::Graphics &g, juce::TextButton &button, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override {
|
||||
void drawButtonText(juce::Graphics &g, juce::TextButton &button, bool shouldDrawButtonAsHighlighted,
|
||||
bool shouldDrawButtonAsDown) override {
|
||||
auto bounds = button.getLocalBounds();
|
||||
|
||||
// Text holen
|
||||
@ -1396,11 +1350,11 @@ namespace AXIOM {
|
||||
juce::Justification::centred,
|
||||
1);
|
||||
}
|
||||
void drawButtonBackground(juce::Graphics& g, juce::Button& button,
|
||||
const juce::Colour& backgroundColour,
|
||||
|
||||
void drawButtonBackground(juce::Graphics &g, juce::Button &button,
|
||||
const juce::Colour &backgroundColour,
|
||||
bool shouldDrawButtonAsHighlighted,
|
||||
bool shouldDrawButtonAsDown) override
|
||||
{
|
||||
bool shouldDrawButtonAsDown) override {
|
||||
auto bounds = button.getLocalBounds().toFloat();
|
||||
|
||||
bool isHovered = button.isMouseOver();
|
||||
@ -1414,48 +1368,226 @@ namespace AXIOM {
|
||||
}
|
||||
};
|
||||
|
||||
class PresetComboBoxLookAndFeel : public juce::LookAndFeel_V4 {
|
||||
class ClickableTextEditor : public juce::TextEditor {
|
||||
public:
|
||||
juce::PopupMenu::Options getOptionsForComboBoxPopupMenu(juce::ComboBox& box,
|
||||
juce::Label& label) override
|
||||
{
|
||||
// Basis-Options holen
|
||||
auto options = juce::LookAndFeel_V4::getOptionsForComboBoxPopupMenu(box, label);
|
||||
std::function<void()> onMouseDown;
|
||||
|
||||
// Anzahl der sichtbaren Einträge
|
||||
const int visibleRows = 5;
|
||||
|
||||
// Höhe einer Zeile
|
||||
auto font = getComboBoxFont(box);
|
||||
int rowHeight = (int)std::ceil(font.getHeight() * 1.6f);
|
||||
|
||||
// Maximale Höhe des Popups
|
||||
int maxPopupHeight = visibleRows * rowHeight;
|
||||
|
||||
// Screen-Bounds der ComboBox
|
||||
auto boxScreen = box.getScreenBounds();
|
||||
|
||||
// Wichtig: Ein sehr breiter aber in der Höhe begrenzter Bereich
|
||||
// JUCE wird das Popup darin zentrieren
|
||||
juce::Rectangle<int> constrainedArea(
|
||||
0, // X: ganze Screen-Breite
|
||||
boxScreen.getBottom(), // Y: direkt unter der Box
|
||||
juce::Desktop::getInstance().getDisplays()
|
||||
.getPrimaryDisplay()->totalArea.getWidth(),
|
||||
maxPopupHeight // Höhe: nur unsere gewünschten Zeilen
|
||||
);
|
||||
|
||||
options = options.withTargetScreenArea(constrainedArea)
|
||||
.withStandardItemHeight(rowHeight);
|
||||
|
||||
return options;
|
||||
void mouseDown(const juce::MouseEvent &event) override {
|
||||
juce::TextEditor::mouseDown(event); // Wichtig: Original-Verhalten beibehalten
|
||||
if (onMouseDown)
|
||||
onMouseDown();
|
||||
}
|
||||
};
|
||||
|
||||
class PresetInputLookAndFeel : public juce::LookAndFeel_V4 {
|
||||
public:
|
||||
void fillTextEditorBackground(juce::Graphics &g, int width, int height,
|
||||
juce::TextEditor &textEditor) override {
|
||||
// Hintergrundfarbe
|
||||
if (textEditor.isEnabled()) {
|
||||
g.setColour(Colours::SURFACECOLOUR);
|
||||
} else {
|
||||
g.setColour(Colours::SURFACEBYPASS);
|
||||
}
|
||||
g.fillRoundedRectangle(0, 0, width, height,
|
||||
Shape::getRadius(Shape::RadiusMode::S,
|
||||
juce::Rectangle<float>(0, 0, width, height)));
|
||||
|
||||
if (textEditor.getText().isEmpty() && !textEditor.hasKeyboardFocus(true)) {
|
||||
g.setColour(placeholderColour);
|
||||
g.setFont(Typography::getFont(Typography::Style::Body, 1.0f));
|
||||
|
||||
auto textBounds = juce::Rectangle<int>(0, 0, width, height).reduced(5);
|
||||
g.drawText(placeholderText, textBounds, juce::Justification::centred, true);
|
||||
}
|
||||
}
|
||||
|
||||
void drawTextEditorOutline(juce::Graphics &g, int width, int height,
|
||||
juce::TextEditor &textEditor) override {
|
||||
// Rahmen
|
||||
auto bounds = juce::Rectangle<float>(0, 0, width, height);
|
||||
auto radius = Shape::getRadius(Shape::RadiusMode::S, bounds);
|
||||
auto strokeWidth = Shape::getStrokeWidth(Shape::StrokeMode::Thin);
|
||||
|
||||
juce::Colour outlineColour;
|
||||
|
||||
if (!textEditor.isEnabled()) {
|
||||
outlineColour = Colours::FOREGROUNDBYPASS.withAlpha(0.3f);
|
||||
} else if (textEditor.hasKeyboardFocus(true)) {
|
||||
// Fokussiert - Accent-Farbe
|
||||
outlineColour = Colours::ACCENTCOLOUR;
|
||||
} else if (textEditor.isMouseOver()) {
|
||||
// Hover
|
||||
outlineColour = Colours::FOREGROUNDHOVER.withAlpha(0.5f);
|
||||
} else {
|
||||
// Normal
|
||||
outlineColour = Colours::FOREGROUNDCOLOUR.withAlpha(0.3f);
|
||||
}
|
||||
|
||||
g.setColour(outlineColour);
|
||||
g.drawRoundedRectangle(bounds.reduced(strokeWidth * 0.5f), radius, strokeWidth);
|
||||
}
|
||||
|
||||
juce::CaretComponent *createCaretComponent(juce::Component *keyFocusOwner) override {
|
||||
auto *caret = new juce::CaretComponent(keyFocusOwner);
|
||||
caret->setColour(juce::CaretComponent::caretColourId, Colours::ACCENTCOLOUR);
|
||||
return caret;
|
||||
}
|
||||
|
||||
private:
|
||||
juce::String placeholderText = "Preset Name";
|
||||
juce::Colour placeholderColour = Colours::MUTEDTEXTCOLOUR;
|
||||
};
|
||||
|
||||
class PresetComboBoxLookAndFeel : public juce::LookAndFeel_V4,
|
||||
private juce::ComponentListener
|
||||
{
|
||||
public:
|
||||
PresetComboBoxLookAndFeel() = default;
|
||||
|
||||
~PresetComboBoxLookAndFeel() override
|
||||
{
|
||||
}
|
||||
|
||||
void getIdealPopupMenuItemSize (const juce::String& text, bool /*isSeparator*/,
|
||||
int /*standardMenuItemHeight*/, int& idealWidth,
|
||||
int& idealHeight) override
|
||||
{
|
||||
idealHeight = 50;
|
||||
|
||||
auto font = Typography::getFont (Typography::Style::Body, 1.0f);
|
||||
idealWidth = font.getStringWidth (text);
|
||||
}
|
||||
|
||||
void drawPopupMenuUpDownArrow(juce::Graphics& g, int width, int height,
|
||||
bool isScrollUpArrow) override
|
||||
{
|
||||
g.setColour(Colours::ACCENTCOLOUR);
|
||||
|
||||
auto arrowZone = juce::Rectangle<float>(0.0f, 0.0f, (float)width, (float)height);
|
||||
auto arrowWidth = arrowZone.getWidth() * 0.1f;
|
||||
auto arrowHeight = arrowZone.getHeight() * 0.1f;
|
||||
|
||||
juce::Path arrow;
|
||||
arrow.startNewSubPath(arrowZone.getCentreX() - arrowWidth * 0.5f,
|
||||
arrowZone.getCentreY() + (isScrollUpArrow ? arrowHeight * 0.5f : -arrowHeight * 0.5f));
|
||||
arrow.lineTo(arrowZone.getCentreX(),
|
||||
arrowZone.getCentreY() + (isScrollUpArrow ? -arrowHeight * 0.5f : arrowHeight * 0.5f));
|
||||
arrow.lineTo(arrowZone.getCentreX() + arrowWidth * 0.5f,
|
||||
arrowZone.getCentreY() + (isScrollUpArrow ? arrowHeight * 0.5f : -arrowHeight * 0.5f));
|
||||
|
||||
g.strokePath(arrow, juce::PathStrokeType(1.5f));
|
||||
}
|
||||
|
||||
void drawPopupMenuBackground(juce::Graphics& g, int width, int height) override
|
||||
{
|
||||
g.fillAll(Colours::SURFACECOLOUR);
|
||||
|
||||
}
|
||||
|
||||
void drawPopupMenuItem (juce::Graphics& g, const juce::Rectangle<int>& area,
|
||||
bool isSeparator, bool isActive, bool isHighlighted,
|
||||
bool isTicked, bool hasSubMenu, const juce::String& text,
|
||||
const juce::String& shortcutKeyText, const juce::Drawable* icon,
|
||||
const juce::Colour* textColourToUse) override {
|
||||
|
||||
juce::Colour backGroundColour = isHighlighted ? Colours::SURFACEHOVER : Colours::SURFACECOLOUR;
|
||||
|
||||
g.fillAll(backGroundColour);
|
||||
|
||||
g.setFont (Typography::getFont (Typography::Style::Mono, 1.0f));
|
||||
if (isTicked) {
|
||||
juce::Colour textColour = isHighlighted ? Colours::ACCENTHOVER : Colours::ACCENTCOLOUR;
|
||||
g.setColour (textColour);
|
||||
} else {
|
||||
juce::Colour textColour = isHighlighted ? Colours::FOREGROUNDHOVER : Colours::FOREGROUNDCOLOUR;
|
||||
g.setColour (textColour);
|
||||
}
|
||||
g.drawFittedText (text, area.reduced (10), juce::Justification::centredLeft, 1);
|
||||
}
|
||||
|
||||
void drawComboBox(juce::Graphics& g, int width, int height, bool isButtonDown,
|
||||
int buttonX, int buttonY, int buttonW, int buttonH,
|
||||
juce::ComboBox& box) override
|
||||
{
|
||||
auto bounds = juce::Rectangle<float>(0, 0, (float)width, (float)height);
|
||||
auto cornerSize = Shape::getRadius(Shape::RadiusMode::S, bounds);
|
||||
|
||||
bool isHovered = box.isMouseOver();
|
||||
bool isEnabled = box.isEnabled();
|
||||
|
||||
juce::Colour bgColour;
|
||||
if (!isEnabled) {
|
||||
bgColour = Colours::SURFACEBYPASS;
|
||||
} else if (isButtonDown) {
|
||||
bgColour = Colours::SURFACEHOVER;
|
||||
} else if (isHovered) {
|
||||
bgColour = Colours::SURFACECOLOUR.brighter(0.1f);
|
||||
} else {
|
||||
bgColour = Colours::SURFACECOLOUR;
|
||||
}
|
||||
|
||||
g.setColour(bgColour);
|
||||
g.fillRoundedRectangle(bounds, cornerSize);
|
||||
|
||||
juce::Colour outlineColour;
|
||||
if (!isEnabled) {
|
||||
outlineColour = Colours::FOREGROUNDCOLOUR.withAlpha(0.2f);
|
||||
} else if (isButtonDown) {
|
||||
outlineColour = Colours::ACCENTCOLOUR;
|
||||
} else if (isHovered) {
|
||||
outlineColour = Colours::FOREGROUNDHOVER.withAlpha(0.5f);
|
||||
} else {
|
||||
outlineColour = Colours::FOREGROUNDCOLOUR.withAlpha(0.3f);
|
||||
}
|
||||
|
||||
auto strokeWidth = Shape::getStrokeWidth(Shape::StrokeMode::Thin);
|
||||
g.setColour(outlineColour);
|
||||
g.drawRoundedRectangle(bounds.reduced(strokeWidth * 0.5f), cornerSize, strokeWidth);
|
||||
|
||||
auto arrowZone = juce::Rectangle<float>((float)buttonX, (float)buttonY,
|
||||
(float)buttonW, (float)buttonH);
|
||||
|
||||
juce::Colour arrowColour = isEnabled ? Colours::ACCENTCOLOUR : Colours::ACCENTWEAKCOLOUR;
|
||||
if (isHovered && isEnabled) {
|
||||
arrowColour = Colours::ACCENTHOVER;
|
||||
}
|
||||
|
||||
g.setColour(arrowColour);
|
||||
|
||||
juce::Path arrow;
|
||||
auto arrowW = arrowZone.getWidth() * 0.3f;
|
||||
auto arrowH = arrowZone.getHeight() * 0.15f;
|
||||
auto centreX = arrowZone.getCentreX();
|
||||
auto centreY = arrowZone.getCentreY();
|
||||
|
||||
arrow.startNewSubPath(centreX - arrowW * 0.5f, centreY - arrowH * 0.5f);
|
||||
arrow.lineTo(centreX, centreY + arrowH * 0.5f);
|
||||
arrow.lineTo(centreX + arrowW * 0.5f, centreY - arrowH * 0.5f);
|
||||
|
||||
g.strokePath(arrow, juce::PathStrokeType(1.5f));
|
||||
}
|
||||
|
||||
void positionComboBoxText(juce::ComboBox& box, juce::Label& label) override
|
||||
{
|
||||
label.setBounds(8, 0, box.getWidth() - 30, box.getHeight());
|
||||
label.setFont(Typography::getFont(Typography::Style::Mono, 1.0f));
|
||||
label.setJustificationType(juce::Justification::centredLeft);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
@ -11499,7 +11499,7 @@ static const unsigned char temp_binary_data_14[] =
|
||||
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 32\">\n"
|
||||
" <g id=\"Ebene_6\" data-name=\"Ebene 6\">\n"
|
||||
" <rect x=\"0\" y=\"0\" width=\"64\" height=\"32\" fill=\"#171a1a\"/>\n"
|
||||
" <polygon points=\"0 32 2 30 32 16 62 2 64 0 64 32 0 32\" fill=\"#262b2b\"/>\n"
|
||||
" <polygon points=\"64 0 62 2 32 16 2 30 0 32 0 0 64 0\" fill=\"#262b2b\"/>\n"
|
||||
" </g>\n"
|
||||
" <g id=\"Ebene_2\" data-name=\"Ebene 2\">\n"
|
||||
" <rect x=\"2\" y=\"2\" width=\"60\" height=\"28\" fill=\"#3db7b7\"/>\n"
|
||||
@ -11525,51 +11525,51 @@ static const unsigned char temp_binary_data_14[] =
|
||||
" </g>\n"
|
||||
" </g>\n"
|
||||
" <g id=\"Ebene_3_Kopie\" data-name=\"Ebene 3 Kopie\">\n"
|
||||
" <rect x=\"8\" y=\"8\" width=\"48\" height=\"16\" fill=\"#fffcfc\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"2 30 8 24 56 24 62 30 2 30\" fill=\"#fffcfc\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"62 2 56 8 8 8 2 2 62 2\" fill=\"#fffcfc\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"56 24 56 8 62 2 62 30 56 24\" fill=\"#fffcfc\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"8 8 8 24 2 30 2 2 8 8\" fill=\"#fffcfc\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"8 24 5 27 2 30 2 24 8 24\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"2 30 5 27 8 24 8 30 2 30\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"8 30 8 24 14 27 20 30 8 30\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"2 8 5 12 8 16 2 16 2 8\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"20 30 26 27 32 24 32 30 20 30\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"32 24 26 27 20 30 20 24 32 24\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"8 16 5 12 2 8 8 8 8 16\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"8 16 5 20 2 24 2 16 8 16\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"20 24 20 30 14 27 8 24 20 24\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"56 30 56 24 50 27 44 30 56 30\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"44 30 38 27 32 24 32 30 44 30\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"32 24 38 27 44 30 44 24 32 24\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"44 24 44 30 50 27 56 24 44 24\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"32 2 32 8 26 5 20 2 32 2\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"20 2 14 5 8 8 8 2 20 2\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"2 24 5 20 8 16 8 24 2 24\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"8 8 14 5 20 2 20 8 8 8\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"8 24 20 20 32 16 32 24 8 24\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"56 24 44 20 32 16 32 24 56 24\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"56 8 44 12 32 16 32 8 56 8\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"8 8 20 12 32 16 32 8 8 8\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"32 16 20 12 8 8 8 16 32 16\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"32 16 44 12 56 8 56 16 32 16\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"32 16 20 20 8 24 8 16 32 16\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"32 16 44 20 56 24 56 16 32 16\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"20 8 20 2 26 5 32 8 20 8\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"32 2 32 8 38 5 44 2 32 2\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"44 2 50 5 56 8 56 2 44 2\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"56 8 50 5 44 2 44 8 56 8\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"44 8 44 2 38 5 32 8 44 8\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"8 2 8 8 5 5 2 2 8 2\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"2 8 2 2 5 5 8 8 2 8\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"56 24 59 27 62 30 62 24 56 24\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"62 8 59 12 56 16 62 16 62 8\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"56 16 59 12 62 8 56 8 56 16\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"56 16 59 20 62 24 56 24 56 16\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"62 30 59 27 56 24 56 30 62 30\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"56 16 59 20 62 24 62 16 56 16\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"56 2 56 8 59 5 62 2 56 2\" fill=\"#fff\" opacity=\".21\"/>\n"
|
||||
" <polygon points=\"62 8 62 2 59 5 56 8 62 8\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||
" <rect x=\"8\" y=\"8\" width=\"48\" height=\"16\" fill=\"#fffcfc\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"2 30 8 24 56 24 62 30 2 30\" fill=\"#fffcfc\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"62 2 56 8 8 8 2 2 62 2\" fill=\"#fffcfc\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"56 24 56 8 62 2 62 30 56 24\" fill=\"#fffcfc\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"8 8 8 24 2 30 2 2 8 8\" fill=\"#fffcfc\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"8 24 5 27 2 30 2 24 8 24\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"2 30 5 27 8 24 8 30 2 30\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"8 30 8 24 14 27 20 30 8 30\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"2 8 5 12 8 16 2 16 2 8\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"20 30 26 27 32 24 32 30 20 30\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"32 24 26 27 20 30 20 24 32 24\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"8 16 5 12 2 8 8 8 8 16\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"8 16 5 20 2 24 2 16 8 16\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"20 24 20 30 14 27 8 24 20 24\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"56 30 56 24 50 27 44 30 56 30\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"44 30 38 27 32 24 32 30 44 30\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"32 24 38 27 44 30 44 24 32 24\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"44 24 44 30 50 27 56 24 44 24\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"32 2 32 8 26 5 20 2 32 2\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"20 2 14 5 8 8 8 2 20 2\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"2 24 5 20 8 16 8 24 2 24\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"8 8 14 5 20 2 20 8 8 8\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"8 24 20 20 32 16 32 24 8 24\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"56 24 44 20 32 16 32 24 56 24\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"56 8 44 12 32 16 32 8 56 8\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"8 8 20 12 32 16 32 8 8 8\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"32 16 20 12 8 8 8 16 32 16\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"32 16 44 12 56 8 56 16 32 16\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"32 16 20 20 8 24 8 16 32 16\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"32 16 44 20 56 24 56 16 32 16\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"20 8 20 2 26 5 32 8 20 8\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"32 2 32 8 38 5 44 2 32 2\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"44 2 50 5 56 8 56 2 44 2\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"56 8 50 5 44 2 44 8 56 8\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"44 8 44 2 38 5 32 8 44 8\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"8 2 8 8 5 5 2 2 8 2\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"2 8 2 2 5 5 8 8 2 8\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"56 24 59 27 62 30 62 24 56 24\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"62 8 59 12 56 16 62 16 62 8\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"56 16 59 12 62 8 56 8 56 16\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"56 16 59 20 62 24 56 24 56 16\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"62 30 59 27 56 24 56 30 62 30\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"56 16 59 20 62 24 62 16 56 16\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"56 2 56 8 59 5 62 2 56 2\" fill=\"#fff\" opacity=\".17\"/>\n"
|
||||
" <polygon points=\"62 8 62 2 59 5 56 8 62 8\" fill=\"#d1d1d1\" opacity=\".17\"/>\n"
|
||||
" </g>\n"
|
||||
"</svg>";
|
||||
|
||||
@ -11692,7 +11692,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes)
|
||||
case 0x31532e06: numBytes = 353; return low_cut_icon_svg;
|
||||
case 0x7e8ca05e: numBytes = 410; return low_shelf_icon_svg;
|
||||
case 0x4df4bf1e: numBytes = 350; return preset_menu_icon_svg;
|
||||
case 0xd842aaab: numBytes = 6343; return crystalize_button_active_icon_svg;
|
||||
case 0xd842aaab: numBytes = 6341; return crystalize_button_active_icon_svg;
|
||||
case 0x885a7642: numBytes = 6279; return crystalize_button_passive_icon_svg;
|
||||
case 0xe49e0f15: numBytes = 406; return bypass_icon_svg;
|
||||
default: break;
|
||||
|
||||
@ -51,7 +51,7 @@ namespace BinaryData
|
||||
const int preset_menu_icon_svgSize = 350;
|
||||
|
||||
extern const char* crystalize_button_active_icon_svg;
|
||||
const int crystalize_button_active_icon_svgSize = 6343;
|
||||
const int crystalize_button_active_icon_svgSize = 6341;
|
||||
|
||||
extern const char* crystalize_button_passive_icon_svg;
|
||||
const int crystalize_button_passive_icon_svgSize = 6279;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -19,9 +19,11 @@
|
||||
using AXIOM::DesignSystem;
|
||||
using Components = DesignSystem::Components;
|
||||
using SliderStyles = Components::SliderStyles;
|
||||
|
||||
class SpectrumAnalyzer {
|
||||
public:
|
||||
SpectrumAnalyzer(AudioFIFO& fifoRef, CrystalizerEQAudioProcessor& processor) : audioFIFO(fifoRef), audioProcessor(processor) {
|
||||
public:
|
||||
SpectrumAnalyzer(AudioFIFO &fifoRef, CrystalizerEQAudioProcessor &processor) : audioFIFO(fifoRef),
|
||||
audioProcessor(processor) {
|
||||
fftData.resize(2 * FFTSIZE);
|
||||
magnitudes.resize(BINS);
|
||||
magnitudesDb.resize(BINS);
|
||||
@ -33,15 +35,14 @@ class SpectrumAnalyzer {
|
||||
peakHoldMagnitudesDb.resize(BINS);
|
||||
DELTAT = static_cast<float>(HOPSIZE) / static_cast<float>(sampleRate);
|
||||
renderValuesDb.resize(BINS);
|
||||
|
||||
|
||||
}
|
||||
|
||||
~SpectrumAnalyzer() = default;
|
||||
|
||||
|
||||
AudioFIFO& audioFIFO;
|
||||
AudioFIFO &audioFIFO;
|
||||
|
||||
CrystalizerEQAudioProcessor& audioProcessor;
|
||||
CrystalizerEQAudioProcessor &audioProcessor;
|
||||
|
||||
static constexpr int FFTSIZE = 4096;
|
||||
|
||||
@ -52,7 +53,7 @@ class SpectrumAnalyzer {
|
||||
juce::Array<float> fftFrame;
|
||||
|
||||
//CHANGE FOR LOWER/HIGHER EMA-SMOOTHING //LOWER VALUE -> MORE SMOOTHING/SLOW RESPONSE -- HIGHER VALUE -> LESS SMOOTHING/FAST RESPONSE //MAX VALUE = 1.f
|
||||
float smoothingFactor = 0.3f;
|
||||
float smoothingFactor = 0.5f;
|
||||
|
||||
|
||||
void processSamples();
|
||||
@ -62,21 +63,20 @@ class SpectrumAnalyzer {
|
||||
void applyWindowOnFftFrame(std::vector<float> &fullFrame);
|
||||
|
||||
juce::dsp::WindowingFunction<float> window
|
||||
{
|
||||
{
|
||||
FFTSIZE,
|
||||
juce::dsp::WindowingFunction<float>::hann
|
||||
};
|
||||
};
|
||||
|
||||
void processWindowedFrame(std::vector<float> &windowedFrame);
|
||||
|
||||
|
||||
static constexpr int FFTORDER = 12;
|
||||
juce::dsp::FFT fft { FFTORDER };
|
||||
juce::dsp::FFT fft{FFTORDER};
|
||||
|
||||
std::vector<float> fftData;
|
||||
|
||||
|
||||
|
||||
const float MINDB = -90.f;
|
||||
const float MAXDB = 0.f;
|
||||
|
||||
@ -103,7 +103,7 @@ class SpectrumAnalyzer {
|
||||
std::vector<double> freqPerBin;
|
||||
|
||||
//CHANGE FOR FASTER FALLOFF -- VALUE IS IN DB/S
|
||||
const float FALLOFFRATE = 120.f;
|
||||
const float FALLOFFRATE = 240.f;
|
||||
|
||||
float DELTAT = 0.f;
|
||||
|
||||
@ -114,37 +114,43 @@ class SpectrumAnalyzer {
|
||||
const float MAXFREQ = static_cast<float>(sampleRate) / 2;
|
||||
|
||||
void fillFftDataFromFrame(std::vector<float> &windowedFrame);
|
||||
void buildMagnitudeSpectrum();
|
||||
void convertToDb();
|
||||
void applySmoothing();
|
||||
void applyEMA();
|
||||
void applyFreqSmoothing();
|
||||
void applyPeakHoldAndFalloff();
|
||||
std::vector<float> getRenderValues();
|
||||
|
||||
void buildMagnitudeSpectrum();
|
||||
|
||||
void convertToDb();
|
||||
|
||||
void applySmoothing();
|
||||
|
||||
void applyEMA();
|
||||
|
||||
void applyFreqSmoothing();
|
||||
|
||||
void applyPeakHoldAndFalloff();
|
||||
|
||||
std::vector<float> getRenderValues();
|
||||
};
|
||||
|
||||
|
||||
class CrystalizerEQAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::Timer
|
||||
|
||||
{
|
||||
class CrystalizerEQAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::Timer {
|
||||
public:
|
||||
CrystalizerEQAudioProcessorEditor(CrystalizerEQAudioProcessor &);
|
||||
|
||||
CrystalizerEQAudioProcessorEditor (CrystalizerEQAudioProcessor&);
|
||||
~CrystalizerEQAudioProcessorEditor() override;
|
||||
|
||||
void paintAnalyzer(juce::Graphics &g);
|
||||
|
||||
void paintModeBoxBorders(juce::Graphics &g);
|
||||
|
||||
void paintBorderLines(juce::Graphics& g);
|
||||
void paintBorderLines(juce::Graphics &g);
|
||||
|
||||
//===================================================================
|
||||
void timerCallback();
|
||||
void paint (juce::Graphics&) override;
|
||||
|
||||
void paint(juce::Graphics &) override;
|
||||
|
||||
|
||||
void resized() override;
|
||||
|
||||
void resetAllCheckboxes();
|
||||
|
||||
using SliderAttach = juce::AudioProcessorValueTreeState::SliderAttachment;
|
||||
@ -153,7 +159,7 @@ public:
|
||||
|
||||
using ComboBoxAttach = juce::AudioProcessorValueTreeState::ComboBoxAttachment;
|
||||
|
||||
juce::Slider testNoiseSlider,
|
||||
juce::Slider
|
||||
lowBandFreqSlider, lowBandSlopeSlider, lowBandGainSlider, lowBandQSlider,
|
||||
peak1FreqSlider, peak1GainSlider, peak1QSlider,
|
||||
peak2FreqSlider, peak2GainSlider, peak2QSlider,
|
||||
@ -161,7 +167,7 @@ public:
|
||||
highBandFreqSlider, highBandSlopeSlider, highBandGainSlider, highBandQSlider,
|
||||
inputSlider, outputSlider;
|
||||
|
||||
const juce::Array<juce::Slider*> sliders = {
|
||||
const juce::Array<juce::Slider *> sliders = {
|
||||
&lowBandGainSlider, &lowBandFreqSlider, &lowBandQSlider, &lowBandSlopeSlider,
|
||||
&peak1GainSlider, &peak1FreqSlider, &peak1QSlider,
|
||||
&peak2GainSlider, &peak2FreqSlider, &peak2QSlider,
|
||||
@ -170,7 +176,7 @@ public:
|
||||
&inputSlider, &outputSlider
|
||||
};
|
||||
|
||||
std::unique_ptr<SliderAttach> testNoiseAttach,
|
||||
std::unique_ptr<SliderAttach>
|
||||
lowBandFreqAttach, lowBandSlopeAttach, lowBandGainAttach, lowBandQAttach,
|
||||
peak1FreqAttach, peak1GainAttach, peak1QAttach,
|
||||
peak2FreqAttach, peak2GainAttach, peak2QAttach,
|
||||
@ -178,7 +184,7 @@ public:
|
||||
highBandFreqAttach, highBandSlopeAttach, highBandGainAttach, highBandQAttach,
|
||||
inputAttach, outputAttach;
|
||||
|
||||
juce::Label titleLabel, testNoiseLabel,
|
||||
juce::Label titleLabel,
|
||||
lowBandFreqLabel, lowBandSlopeLabel, lowBandGainLabel, lowBandQLabel, lowBandModeLabel,
|
||||
low12, low24, low36, low48, lowdBOctLabel,
|
||||
peak1FreqLabel, peak1GainLabel, peak1QLabel,
|
||||
@ -189,32 +195,35 @@ public:
|
||||
inputLabel, outputLabel,
|
||||
presetBoxLabel;
|
||||
|
||||
const juce::Array<juce::Label*> sliderLabels = {
|
||||
const juce::Array<juce::Label *> sliderLabels = {
|
||||
&lowBandFreqLabel, &lowBandSlopeLabel, &lowBandGainLabel, &lowBandQLabel, &lowBandModeLabel, &lowdBOctLabel,
|
||||
&peak1FreqLabel, &peak1GainLabel, &peak1QLabel,
|
||||
&peak2FreqLabel, &peak2GainLabel, &peak2QLabel,
|
||||
&peak3FreqLabel, &peak3GainLabel, &peak3QLabel,
|
||||
&highBandFreqLabel, &highBandSlopeLabel, &highBandGainLabel, &highBandQLabel, &highBandModeLabel, &highdBOctLabel,
|
||||
&highBandFreqLabel, &highBandSlopeLabel, &highBandGainLabel, &highBandQLabel, &highBandModeLabel,
|
||||
&highdBOctLabel,
|
||||
&inputLabel, &outputLabel
|
||||
};
|
||||
const juce::Array<juce::Label*> slopeLabels = {
|
||||
const juce::Array<juce::Label *> slopeLabels = {
|
||||
&low12, &low24, &low36, &low48,
|
||||
&high12, &high24, &high36, &high48
|
||||
};
|
||||
|
||||
|
||||
juce::TextButton resetButton, savePresetButton, deletePresetButton;
|
||||
|
||||
juce::TextButton testNoiseButton, resetButton, savePresetButton, deletePresetButton;
|
||||
juce::ToggleButton masterBypassButton, crystalizeButton, peak1BypassButton, peak2BypassButton, peak3BypassButton,
|
||||
presetMenuButton;
|
||||
|
||||
juce::ToggleButton masterBypassButton, crystalizeButton, peak1BypassButton, peak2BypassButton, peak3BypassButton, presetMenuButton;
|
||||
|
||||
const juce::Array<juce::ToggleButton*> peakBypassButtons = {&peak1BypassButton, &peak2BypassButton, &peak3BypassButton};
|
||||
const juce::Array<juce::ToggleButton *> peakBypassButtons = {
|
||||
&peak1BypassButton, &peak2BypassButton, &peak3BypassButton
|
||||
};
|
||||
|
||||
juce::ComboBox presetBox;
|
||||
|
||||
juce::Component lowBandModeBox, highBandModeBox;
|
||||
|
||||
juce::Array<juce::ToggleButton*> lowBandModeButtons, highBandModeButtons;
|
||||
juce::Array<juce::ToggleButton *> lowBandModeButtons, highBandModeButtons;
|
||||
|
||||
std::array<bool, 4> lowBandBools, highBandBools;
|
||||
|
||||
@ -222,16 +231,14 @@ public:
|
||||
juce::ToggleButton lowBypass, lowCut, lowBell, lowShelf,
|
||||
highBypass, highCut, highBell, highShelf;
|
||||
|
||||
juce::TextEditor presetNameInput;
|
||||
DesignSystem::ClickableTextEditor presetNameInput;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// This reference is provided as a quick way for your editor to
|
||||
// access the processor object that created it.
|
||||
CrystalizerEQAudioProcessor& audioProcessor;
|
||||
|
||||
|
||||
CrystalizerEQAudioProcessor &audioProcessor;
|
||||
|
||||
|
||||
void setKnobVisibility();
|
||||
@ -253,9 +260,13 @@ private:
|
||||
void setupToggleButtons();
|
||||
|
||||
void disableLowBand(float target);
|
||||
|
||||
void disableLowMidBand(float target);
|
||||
|
||||
void disableMidBand(float target);
|
||||
|
||||
void disableHighMidBand(float target);
|
||||
|
||||
void disableHighBand(float target);
|
||||
|
||||
void disableEverything(float target);
|
||||
@ -270,6 +281,10 @@ private:
|
||||
|
||||
void initPresetSystem();
|
||||
|
||||
void updateFrequencyRanges();
|
||||
|
||||
void updateModeButtons();
|
||||
|
||||
|
||||
std::unique_ptr<AXIOM::DesignSystem::Components::BaseSliderLookAndFeel> baseLookAndFeel;
|
||||
std::unique_ptr<DesignSystem::Components::GainSliderLookAndFeel> gainLookAndFeel;
|
||||
@ -284,6 +299,7 @@ private:
|
||||
std::unique_ptr<DesignSystem::PresetMenuLookAndFeel> presetMenuLookAndFeel;
|
||||
std::unique_ptr<DesignSystem::PresetButtonsLookAndFeel> presetButtonLookAndFeel;
|
||||
std::unique_ptr<DesignSystem::PresetComboBoxLookAndFeel> presetComboBoxLookAndFeel;
|
||||
std::unique_ptr<DesignSystem::PresetInputLookAndFeel> presetInputLookAndFeel;
|
||||
|
||||
|
||||
//SPECRTRUM ANALYZER
|
||||
@ -308,25 +324,31 @@ private:
|
||||
Component highMidFilterArea;
|
||||
Component highFilterArea;
|
||||
|
||||
const juce::Array<juce::Component*> filterAreas {
|
||||
const juce::Array<juce::Component *> filterAreas{
|
||||
&lowFilterArea, &lowMidFilterArea, &midFilterArea, &highMidFilterArea, &highFilterArea
|
||||
};
|
||||
|
||||
Component globalControlArea;
|
||||
|
||||
|
||||
|
||||
void scalePluginWindow(juce::Rectangle<int> area);
|
||||
|
||||
void setupMainGrid(juce::Rectangle<int> area);
|
||||
|
||||
void setupLowBandLayout();
|
||||
|
||||
void setupLowMidBandLayout();
|
||||
|
||||
void setupMidBandLayout();
|
||||
|
||||
void setupHighMidBandLayout();
|
||||
|
||||
void setupHighBandLayout();
|
||||
|
||||
void setupHeader();
|
||||
|
||||
void setupBody();
|
||||
|
||||
void setupFooter();
|
||||
|
||||
juce::Array<float> getReferenceCell();
|
||||
@ -344,13 +366,17 @@ private:
|
||||
|
||||
std::unique_ptr<juce::Drawable> logoDrawable;
|
||||
|
||||
DesignSystem::PresetMenu* test;
|
||||
juce::Component::SafePointer<DesignSystem::PresetMenu> presetMenuSafePtr;
|
||||
|
||||
bool inputFocused = false;
|
||||
|
||||
float mapFrequencyToX(float freq, float minFreq, float maxFreq, float width);
|
||||
|
||||
int getClosestBinForFrequency(float freq);
|
||||
void drawFrequencyGrid(juce::Graphics& g, const float dbRange);
|
||||
|
||||
void drawFrequencyGrid(juce::Graphics &g, const float dbRange);
|
||||
|
||||
float getInterpolatedDb(float exactBin);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CrystalizerEQAudioProcessorEditor)
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CrystalizerEQAudioProcessorEditor)
|
||||
};
|
||||
|
||||
@ -14,11 +14,6 @@ juce::AudioProcessorValueTreeState::ParameterLayout
|
||||
CrystalizerEQAudioProcessor::createParameterLayout() {
|
||||
std::vector<std::unique_ptr<juce::RangedAudioParameter>> params;
|
||||
|
||||
params.push_back (std::make_unique<juce::AudioParameterBool>(
|
||||
"TestNoiseEnabled", "Test Noise Enabled", false));
|
||||
|
||||
params.push_back (std::make_unique<juce::AudioParameterFloat>("TestNoiseLevel", "Test Noise Level", juce::NormalisableRange<float>(-60.f, 0.f, 0.1f), 0.f));
|
||||
|
||||
//LOW-BAND
|
||||
|
||||
params.push_back (std::make_unique<juce::AudioParameterFloat>(
|
||||
@ -429,7 +424,6 @@ void CrystalizerEQAudioProcessor::updateFilters()
|
||||
setCoeffs(rightChain.get<1>(), lowBand);
|
||||
leftChain .setBypassed<1>(false);
|
||||
rightChain.setBypassed<1>(false);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
@ -512,7 +506,8 @@ void CrystalizerEQAudioProcessor::updateFilters()
|
||||
|
||||
|
||||
|
||||
|
||||
lowCutActive = (lowBandModes == 1);
|
||||
highCutActive = (highBandModes == 1);
|
||||
|
||||
}
|
||||
|
||||
@ -520,13 +515,14 @@ juce::String CrystalizerEQAudioProcessor::savePresetToFile() const {
|
||||
const auto nameInput = getPresetName();
|
||||
|
||||
|
||||
auto desktop = juce::File::getSpecialLocation(juce::File::userDesktopDirectory);
|
||||
auto appData = juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory);
|
||||
|
||||
auto presetFolder = appData.getChildFile("AXIOM")
|
||||
.getChildFile("CrystalizerEQ")
|
||||
.getChildFile("Presets");
|
||||
|
||||
// Unterordner auf dem Desktop anlegen
|
||||
auto presetFolder = desktop.getChildFile("CrystalizerEQ_Presets");
|
||||
presetFolder.createDirectory();
|
||||
|
||||
// Datei vorbereiten
|
||||
auto file = presetFolder.getNonexistentChildFile(nameInput, ".xml");
|
||||
|
||||
juce::ValueTree preset ("Preset");
|
||||
@ -556,15 +552,12 @@ juce::String CrystalizerEQAudioProcessor::savePresetToFile() const {
|
||||
|
||||
void CrystalizerEQAudioProcessor::loadPreset(const juce::String &preset){
|
||||
|
||||
auto desktop = juce::File::getSpecialLocation(juce::File::userDesktopDirectory);
|
||||
auto appData = juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory);
|
||||
auto presetFolder = appData.getChildFile("AXIOM")
|
||||
.getChildFile("CrystalizerEQ")
|
||||
.getChildFile("Presets");
|
||||
|
||||
auto presetFolder = desktop.getChildFile("CrystalizerEQ_Presets");
|
||||
|
||||
juce::Array<juce::File> files = presetFolder.findChildFiles(
|
||||
juce::File::findFiles, // nur Dateien (nicht Ordner)
|
||||
false, // nicht rekursiv (kein Durchsuchen von Unterordnern)
|
||||
"*.xml" // Pattern: alle Dateien
|
||||
);
|
||||
auto files = presetFolder.findChildFiles(juce::File::findFiles, false, "*.xml");
|
||||
|
||||
for (const auto& f : files) {
|
||||
if (f.getFileName() != preset) {
|
||||
@ -601,10 +594,10 @@ void CrystalizerEQAudioProcessor::loadPreset(const juce::String &preset){
|
||||
}
|
||||
|
||||
void CrystalizerEQAudioProcessor::deletePreset(const juce::String &preset) const{
|
||||
auto desktop = juce::File::getSpecialLocation(juce::File::userDesktopDirectory);
|
||||
|
||||
// Unterordner auf dem Desktop anlegen
|
||||
auto presetFolder = desktop.getChildFile("CrystalizerEQ_Presets");
|
||||
auto appData = juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory);
|
||||
auto presetFolder = appData.getChildFile("AXIOM")
|
||||
.getChildFile("CrystalizerEQ")
|
||||
.getChildFile("Presets");
|
||||
|
||||
juce::Array<juce::File> files = presetFolder.findChildFiles(
|
||||
juce::File::findFiles, // nur Dateien (nicht Ordner)
|
||||
@ -644,10 +637,10 @@ void CrystalizerEQAudioProcessor::parameterChanged (const juce::String& id, floa
|
||||
juce::StringArray CrystalizerEQAudioProcessor::getPresetNamesArray() const{
|
||||
|
||||
juce::StringArray presetNames = {"Init"};
|
||||
auto desktop = juce::File::getSpecialLocation(juce::File::userDesktopDirectory);
|
||||
|
||||
// Unterordner auf dem Desktop anlegen
|
||||
auto presetFolder = desktop.getChildFile("CrystalizerEQ_Presets");
|
||||
auto appData = juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory);
|
||||
auto presetFolder = appData.getChildFile("AXIOM")
|
||||
.getChildFile("CrystalizerEQ")
|
||||
.getChildFile("Presets");
|
||||
|
||||
juce::Array<juce::File> files = presetFolder.findChildFiles(
|
||||
juce::File::findFiles, // nur Dateien (nicht Ordner)
|
||||
@ -704,57 +697,11 @@ void CrystalizerEQAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer
|
||||
auto totalNumInputChannels = getTotalNumInputChannels();
|
||||
auto totalNumOutputChannels = getTotalNumOutputChannels();
|
||||
|
||||
|
||||
|
||||
|
||||
// In case we have more outputs than inputs, this code clears any output
|
||||
// channels that didn't contain input data, (because these aren't
|
||||
// guaranteed to be empty - they may contain garbage).
|
||||
// This is here to avoid people getting screaming feedback
|
||||
// when they first compile a plugin, but obviously you don't need to keep
|
||||
// this code if your algorithm always overwrites all the output channels.
|
||||
for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
|
||||
buffer.clear (i, 0, buffer.getNumSamples());
|
||||
|
||||
juce::AudioBuffer<float> lowBuf, highBuf;
|
||||
|
||||
|
||||
|
||||
// This is the place where you'd normally do the guts of your plugin's
|
||||
// audio processing...
|
||||
// Make sure to reset the state if your inner loop is processing
|
||||
// the samples and the outer loop is handling the channels.
|
||||
// Alternatively, you can process the samples with the channels
|
||||
// interleaved by keeping the same state.
|
||||
// (Einfacher Weg) – pro Block Parameter lesen & Filter updaten
|
||||
|
||||
|
||||
|
||||
const bool testNoiseOn = apvts.getRawParameterValue("TestNoiseEnabled")->load() > 0.5f;
|
||||
|
||||
if (testNoiseOn)
|
||||
{
|
||||
buffer.clear();
|
||||
const float noiseLevelDb = apvts.getRawParameterValue("TestNoiseLevel")->load();
|
||||
const float gain = juce::Decibels::decibelsToGain (noiseLevelDb);
|
||||
|
||||
const int numSamples = buffer.getNumSamples();
|
||||
const int numChannels = buffer.getNumChannels();
|
||||
|
||||
for (int ch = 0; ch < numChannels; ++ch)
|
||||
{
|
||||
auto* write = buffer.getWritePointer (ch);
|
||||
auto& rng = (ch == 0 ? noiseRandL : noiseRandR);
|
||||
|
||||
for (int n = 0; n < numSamples; ++n)
|
||||
{
|
||||
// rng.nextFloat() ∈ [0,1) → in [-1,1)
|
||||
const float white = 2.0f * rng.nextFloat() - 1.0f;
|
||||
write[n] += white * gain; // ERSETZEN des Host-Inputs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bool masterBypassed = apvts.getRawParameterValue("MasterBypass")->load() > 0.5f;
|
||||
if (masterBypassed)
|
||||
return;
|
||||
@ -780,6 +727,7 @@ void CrystalizerEQAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer
|
||||
auto leftBlock = block.getSingleChannelBlock (0);
|
||||
auto rightBlock = block.getSingleChannelBlock (1);
|
||||
|
||||
|
||||
juce::dsp::ProcessContextReplacing<float> leftCtx (leftBlock);
|
||||
juce::dsp::ProcessContextReplacing<float> rightCtx(rightBlock);
|
||||
|
||||
|
||||
@ -90,6 +90,9 @@ public:
|
||||
|
||||
void resetAllParameters() const;
|
||||
|
||||
bool lowCutActive = false;
|
||||
bool highCutActive = false;
|
||||
|
||||
AudioFIFO audioFIFO;
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user