Compare commits
No commits in common. "e239d3e955c38bf69ba062c5406f940ef48cc67c" and "0eb6325e2e92cd64390c7bd768d312591ece489a" have entirely different histories.
e239d3e955
...
0eb6325e2e
@ -38,6 +38,7 @@ namespace AXIOM {
|
|||||||
static inline const juce::Colour SURFACEBYPASS = juce::Colour::fromRGB(42, 42, 42); // #2A2A2A
|
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 MUTEDTEXTBYPASS = juce::Colour::fromRGB(230, 230, 230); // #E6E6E6
|
||||||
static inline const juce::Colour ACCENTWEAKBYPASS = juce::Colour::fromRGB(82, 210, 210); // #52D2D2
|
static inline const juce::Colour ACCENTWEAKBYPASS = juce::Colour::fromRGB(82, 210, 210); // #52D2D2
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Spacing {
|
struct Spacing {
|
||||||
@ -179,6 +180,7 @@ namespace AXIOM {
|
|||||||
float ratio = 1.125f;
|
float ratio = 1.125f;
|
||||||
|
|
||||||
float sizeFor(int step) const noexcept {
|
float sizeFor(int step) const noexcept {
|
||||||
|
// step = 0 => basePx, step = 1 => base*ratio, step = -1 => base/ratio, ...
|
||||||
return basePx * std::pow(ratio, static_cast<float>(step));
|
return basePx * std::pow(ratio, static_cast<float>(step));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -289,14 +291,12 @@ namespace AXIOM {
|
|||||||
L,
|
L,
|
||||||
XL
|
XL
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class StrokeMode {
|
enum class StrokeMode {
|
||||||
Hairline,
|
Hairline,
|
||||||
Thin,
|
Thin,
|
||||||
Regular,
|
Regular,
|
||||||
Bold
|
Bold
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class CornerStyle {
|
enum class CornerStyle {
|
||||||
Rounded,
|
Rounded,
|
||||||
Cut,
|
Cut,
|
||||||
@ -313,7 +313,6 @@ namespace AXIOM {
|
|||||||
static constexpr float MINSTROKE = 1.0f;
|
static constexpr float MINSTROKE = 1.0f;
|
||||||
static constexpr float MAXSTROKE = 3.0f;
|
static constexpr float MAXSTROKE = 3.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static Scale scale{};
|
inline static Scale scale{};
|
||||||
|
|
||||||
static constexpr int getRadiusUnits(RadiusMode mode) {
|
static constexpr int getRadiusUnits(RadiusMode mode) {
|
||||||
@ -360,6 +359,7 @@ namespace AXIOM {
|
|||||||
width = juce::jlimit(scale.MINSTROKE, scale.MAXSTROKE, width);
|
width = juce::jlimit(scale.MINSTROKE, scale.MAXSTROKE, width);
|
||||||
return width;
|
return width;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Shadows {
|
struct Shadows {
|
||||||
@ -369,27 +369,22 @@ namespace AXIOM {
|
|||||||
static constexpr float MINALPHA = 0.04f;
|
static constexpr float MINALPHA = 0.04f;
|
||||||
static constexpr float MAXALPHA = 0.95f;
|
static constexpr float MAXALPHA = 0.95f;
|
||||||
static constexpr float MUTEDMUL = 0.5f;
|
static constexpr float MUTEDMUL = 0.5f;
|
||||||
|
|
||||||
struct AlphaToken {
|
struct AlphaToken {
|
||||||
enum class Role {
|
enum class Role {
|
||||||
Text, Icon, Surface, Overlay, Stroke, FocusGlow, Disabled, InteractiveFill
|
Text, Icon, Surface, Overlay, Stroke, FocusGlow, Disabled, InteractiveFill
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class State {
|
enum class State {
|
||||||
Rest, Hover, Active, Checked, Dragged, Disabled
|
Rest, Hover, Active, Checked, Dragged, Disabled
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Emphasis {
|
enum class Emphasis {
|
||||||
High, Medium, Low, Muted
|
High, Medium, Low, Muted
|
||||||
};
|
};
|
||||||
|
|
||||||
Role role;
|
Role role;
|
||||||
State state;
|
State state;
|
||||||
Emphasis emphasis;
|
Emphasis emphasis;
|
||||||
};
|
};
|
||||||
|
|
||||||
static AlphaToken getAlphaToken(AlphaToken::Role role, AlphaToken::State state,
|
static AlphaToken getAlphaToken(AlphaToken::Role role, AlphaToken::State state, AlphaToken::Emphasis emphasis) {
|
||||||
AlphaToken::Emphasis emphasis) {
|
|
||||||
return AlphaToken{ role, state, emphasis };
|
return AlphaToken{ role, state, emphasis };
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -532,16 +527,20 @@ namespace AXIOM {
|
|||||||
};*/
|
};*/
|
||||||
|
|
||||||
struct Components {
|
struct Components {
|
||||||
|
|
||||||
class BypassButtonLookAndFeel : public juce::LookAndFeel_V4 {
|
class BypassButtonLookAndFeel : public juce::LookAndFeel_V4 {
|
||||||
public:
|
public:
|
||||||
BypassButtonLookAndFeel() {
|
BypassButtonLookAndFeel()
|
||||||
svgXml = juce::XmlDocument::parse(BinaryData::bypass_icon_svg);
|
{
|
||||||
}
|
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 shouldDrawButtonAsHighlighted,
|
||||||
bool shouldDrawButtonAsDown) override {
|
bool shouldDrawButtonAsDown) override
|
||||||
|
{
|
||||||
|
|
||||||
bool isHovered = button.isMouseOverOrDragging();
|
bool isHovered = button.isMouseOverOrDragging();
|
||||||
bool isToggled = button.getToggleState();
|
bool isToggled = button.getToggleState();
|
||||||
bool isEnabled = button.isEnabled();
|
bool isEnabled = button.isEnabled();
|
||||||
@ -555,12 +554,16 @@ namespace AXIOM {
|
|||||||
float bypassOpacity = 1.0f;
|
float bypassOpacity = 1.0f;
|
||||||
|
|
||||||
if (svgXml != nullptr) {
|
if (svgXml != nullptr) {
|
||||||
|
// WICHTIG: Erstelle für jeden Frame ein NEUES Drawable!
|
||||||
auto icon = juce::Drawable::createFromSVG(*svgXml);
|
auto icon = juce::Drawable::createFromSVG(*svgXml);
|
||||||
if (icon != nullptr) {
|
if (icon != nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
juce::Colour colour;
|
juce::Colour colour;
|
||||||
if (!isEnabled) {
|
if (!isEnabled) {
|
||||||
colour = isToggled ? Colours::SURFACEBYPASS : Colours::ACCENTWEAKCOLOUR;
|
colour = isToggled ? Colours::SURFACEBYPASS : Colours::ACCENTWEAKCOLOUR;
|
||||||
} else if (isHovered) {
|
}
|
||||||
|
else if (isHovered) {
|
||||||
colour = isToggled ? Colours::SURFACEHOVER : Colours::ACCENTHOVER;
|
colour = isToggled ? Colours::SURFACEHOVER : Colours::ACCENTHOVER;
|
||||||
} else {
|
} else {
|
||||||
colour = isToggled
|
colour = isToggled
|
||||||
@ -568,11 +571,14 @@ namespace AXIOM {
|
|||||||
: Colours::ACCENTCOLOUR;
|
: Colours::ACCENTCOLOUR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Icon zeichnen
|
||||||
icon->replaceColour(juce::Colours::black, colour);
|
icon->replaceColour(juce::Colours::black, colour);
|
||||||
icon->drawWithin(g, iconBounds,
|
icon->drawWithin(g, iconBounds,
|
||||||
juce::RectanglePlacement::centred, bypassOpacity);
|
juce::RectanglePlacement::centred, bypassOpacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -581,15 +587,19 @@ namespace AXIOM {
|
|||||||
|
|
||||||
class PresetMenuButtonLookAndFeel : public juce::LookAndFeel_V4 {
|
class PresetMenuButtonLookAndFeel : public juce::LookAndFeel_V4 {
|
||||||
public:
|
public:
|
||||||
PresetMenuButtonLookAndFeel() {
|
PresetMenuButtonLookAndFeel()
|
||||||
|
{
|
||||||
presetMenuButton = juce::XmlDocument::parse(BinaryData::preset_menu_icon_svg);
|
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 shouldDrawButtonAsHighlighted,
|
||||||
bool shouldDrawButtonAsDown) override {
|
bool shouldDrawButtonAsDown) override
|
||||||
|
{
|
||||||
|
|
||||||
bool isHovered = button.isMouseOverOrDragging();
|
bool isHovered = button.isMouseOverOrDragging();
|
||||||
bool isToggled = button.getToggleState();
|
bool isToggled = button.getToggleState();
|
||||||
|
bool isEnabled = button.isEnabled();
|
||||||
auto bounds = button.getLocalBounds().toFloat();
|
auto bounds = button.getLocalBounds().toFloat();
|
||||||
auto iconSize = juce::jmin(bounds.getWidth(), bounds.getHeight()) * 1.5f;
|
auto iconSize = juce::jmin(bounds.getWidth(), bounds.getHeight()) * 1.5f;
|
||||||
auto hoverFactor = isHovered ? 1.05f : 1.0f;
|
auto hoverFactor = isHovered ? 1.05f : 1.0f;
|
||||||
@ -597,6 +607,8 @@ namespace AXIOM {
|
|||||||
auto iconBounds = juce::Rectangle<float>(iconSize * hoverFactor, iconSize * hoverFactor)
|
auto iconBounds = juce::Rectangle<float>(iconSize * hoverFactor, iconSize * hoverFactor)
|
||||||
.withCentre(bounds.getCentre());
|
.withCentre(bounds.getCentre());
|
||||||
|
|
||||||
|
float bypassOpacity = 1.0f;
|
||||||
|
|
||||||
if (presetMenuButton != nullptr) {
|
if (presetMenuButton != nullptr) {
|
||||||
auto menuIcon = juce::Drawable::createFromSVG(*presetMenuButton);
|
auto menuIcon = juce::Drawable::createFromSVG(*presetMenuButton);
|
||||||
juce::Colour colour;
|
juce::Colour colour;
|
||||||
@ -608,10 +620,13 @@ namespace AXIOM {
|
|||||||
: Colours::BACKGROUNDCOLOUR;
|
: Colours::BACKGROUNDCOLOUR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Icon zeichnen
|
||||||
menuIcon->replaceColour(juce::Colours::black, colour);
|
menuIcon->replaceColour(juce::Colours::black, colour);
|
||||||
menuIcon->drawWithin(g, iconBounds,
|
menuIcon->drawWithin(g, iconBounds,
|
||||||
juce::RectanglePlacement::centred, 1.0f);
|
juce::RectanglePlacement::centred, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -631,9 +646,12 @@ namespace AXIOM {
|
|||||||
void drawToggleButton(juce::Graphics& g, juce::ToggleButton& button,
|
void drawToggleButton(juce::Graphics& g, juce::ToggleButton& button,
|
||||||
bool shouldDrawButtonAsHighlighted,
|
bool shouldDrawButtonAsHighlighted,
|
||||||
bool shouldDrawButtonAsDown) override {
|
bool shouldDrawButtonAsDown) override {
|
||||||
|
|
||||||
|
|
||||||
const bool isHovered = button.isMouseOverOrDragging();
|
const bool isHovered = button.isMouseOverOrDragging();
|
||||||
|
const bool isToggled = button.getToggleState();
|
||||||
auto bounds = button.getLocalBounds().toFloat();
|
auto bounds = button.getLocalBounds().toFloat();
|
||||||
auto iconSize = juce::jmin(bounds.getWidth(), bounds.getHeight()) * 2 * 0.95f;
|
auto iconSize = juce::jmin(bounds.getWidth(), bounds.getHeight()) * 0.5f;
|
||||||
|
|
||||||
auto hoverFactor = isHovered ? 1.05f : 1.0f;
|
auto hoverFactor = isHovered ? 1.05f : 1.0f;
|
||||||
|
|
||||||
@ -644,31 +662,39 @@ namespace AXIOM {
|
|||||||
auto activeIcon = juce::Drawable::createFromSVG(*activeSvg);
|
auto activeIcon = juce::Drawable::createFromSVG(*activeSvg);
|
||||||
|
|
||||||
if (passiveIcon != nullptr && activeIcon != nullptr) {
|
if (passiveIcon != nullptr && activeIcon != nullptr) {
|
||||||
|
|
||||||
activeIcon->drawWithin(g, iconBounds,
|
activeIcon->drawWithin(g, iconBounds,
|
||||||
juce::RectanglePlacement::centred, activeIconOpacity);
|
juce::RectanglePlacement::centred, activeIconOpacity);
|
||||||
passiveIcon->drawWithin(g, iconBounds,
|
passiveIcon->drawWithin(g, iconBounds,
|
||||||
juce::RectanglePlacement::centred, passiveIconOpacity);
|
juce::RectanglePlacement::centred, passiveIconOpacity);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<juce::XmlElement> passiveSvg;
|
std::unique_ptr<juce::XmlElement> passiveSvg;
|
||||||
std::unique_ptr<juce::XmlElement> activeSvg;
|
std::unique_ptr<juce::XmlElement> activeSvg;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class lowBandButtonLookAndFeel : public juce::LookAndFeel_V4 {
|
class lowBandButtonLookAndFeel : public juce::LookAndFeel_V4 {
|
||||||
public:
|
public:
|
||||||
lowBandButtonLookAndFeel() {
|
lowBandButtonLookAndFeel()
|
||||||
|
{
|
||||||
lowBypassIcon = juce::XmlDocument::parse(BinaryData::bypass_icon_svg);
|
lowBypassIcon = juce::XmlDocument::parse(BinaryData::bypass_icon_svg);
|
||||||
lowCutIcon = juce::XmlDocument::parse(BinaryData::low_cut_icon_svg);
|
lowCutIcon = juce::XmlDocument::parse(BinaryData::low_cut_icon_svg);
|
||||||
lowBellIcon = juce::XmlDocument::parse(BinaryData::bell_icon_svg);
|
lowBellIcon = juce::XmlDocument::parse(BinaryData::bell_icon_svg);
|
||||||
lowShelfIcon = juce::XmlDocument::parse(BinaryData::low_shelf_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 shouldDrawButtonAsHighlighted,
|
||||||
bool shouldDrawButtonAsDown) override {
|
bool shouldDrawButtonAsDown) override
|
||||||
|
{
|
||||||
|
|
||||||
bool isHovered = button.isMouseOverOrDragging();
|
bool isHovered = button.isMouseOverOrDragging();
|
||||||
bool isToggled = button.getToggleState();
|
bool isToggled = button.getToggleState();
|
||||||
bool isEnabled = button.isEnabled();
|
bool isEnabled = button.isEnabled();
|
||||||
@ -681,19 +707,21 @@ namespace AXIOM {
|
|||||||
|
|
||||||
float bypassOpacity = 1.0f;
|
float bypassOpacity = 1.0f;
|
||||||
|
|
||||||
if (lowBypassIcon != nullptr && lowCutIcon != nullptr && lowBellIcon != nullptr && lowShelfIcon !=
|
if (lowBypassIcon != nullptr && lowCutIcon != nullptr && lowBellIcon != nullptr && lowShelfIcon != nullptr) {
|
||||||
nullptr) {
|
// WICHTIG: Erstelle für jeden Frame ein NEUES Drawable!
|
||||||
auto bypassIcon = juce::Drawable::createFromSVG(*lowBypassIcon);
|
auto bypassIcon = juce::Drawable::createFromSVG(*lowBypassIcon);
|
||||||
auto cutIcon = juce::Drawable::createFromSVG(*lowCutIcon);
|
auto cutIcon = juce::Drawable::createFromSVG(*lowCutIcon);
|
||||||
auto bellIcon = juce::Drawable::createFromSVG(*lowBellIcon);
|
auto bellIcon = juce::Drawable::createFromSVG(*lowBellIcon);
|
||||||
auto shelfIcon = juce::Drawable::createFromSVG(*lowShelfIcon);
|
auto shelfIcon = juce::Drawable::createFromSVG(*lowShelfIcon);
|
||||||
|
|
||||||
if (bypassIcon != nullptr && cutIcon != nullptr && bellIcon != nullptr && shelfIcon !=
|
if (bypassIcon != nullptr && cutIcon != nullptr && bellIcon != nullptr && shelfIcon != nullptr)
|
||||||
nullptr) {
|
{
|
||||||
|
|
||||||
juce::Colour colour;
|
juce::Colour colour;
|
||||||
if (!isEnabled) {
|
if (!isEnabled) {
|
||||||
colour = isToggled ? Colours::ACCENTWEAKCOLOUR : Colours::SURFACEBYPASS;
|
colour = isToggled ? Colours::ACCENTWEAKCOLOUR : Colours::SURFACEBYPASS;
|
||||||
} else if (isHovered) {
|
}
|
||||||
|
else if (isHovered) {
|
||||||
colour = isToggled ? Colours::ACCENTHOVER : Colours::SURFACEHOVER;
|
colour = isToggled ? Colours::ACCENTHOVER : Colours::SURFACEHOVER;
|
||||||
} else {
|
} else {
|
||||||
colour = isToggled
|
colour = isToggled
|
||||||
@ -701,25 +729,32 @@ namespace AXIOM {
|
|||||||
: Colours::SURFACECOLOUR;
|
: Colours::SURFACECOLOUR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Icon zeichnen
|
||||||
if (button.getName() == "LowBypass") {
|
if (button.getName() == "LowBypass") {
|
||||||
bypassIcon->replaceColour(juce::Colours::black, colour);
|
bypassIcon->replaceColour(juce::Colours::black, colour);
|
||||||
bypassIcon->drawWithin(g, iconBounds,
|
bypassIcon->drawWithin(g, iconBounds,
|
||||||
juce::RectanglePlacement::centred, bypassOpacity);
|
juce::RectanglePlacement::centred, bypassOpacity);
|
||||||
} else if (button.getName() == "LowCut") {
|
}
|
||||||
|
else if (button.getName() == "LowCut") {
|
||||||
cutIcon->replaceColour(juce::Colours::black, colour);
|
cutIcon->replaceColour(juce::Colours::black, colour);
|
||||||
cutIcon->drawWithin(g, iconBounds,
|
cutIcon->drawWithin(g, iconBounds,
|
||||||
juce::RectanglePlacement::centred, bypassOpacity);
|
juce::RectanglePlacement::centred, bypassOpacity);
|
||||||
} else if (button.getName() == "LowBell") {
|
}
|
||||||
|
else if (button.getName() == "LowBell") {
|
||||||
bellIcon->replaceColour(juce::Colours::black, colour);
|
bellIcon->replaceColour(juce::Colours::black, colour);
|
||||||
bellIcon->drawWithin(g, iconBounds,
|
bellIcon->drawWithin(g, iconBounds,
|
||||||
juce::RectanglePlacement::centred, bypassOpacity);
|
juce::RectanglePlacement::centred, bypassOpacity);
|
||||||
} else if (button.getName() == "LowShelf") {
|
}
|
||||||
|
else if (button.getName() == "LowShelf") {
|
||||||
shelfIcon->replaceColour(juce::Colours::black, colour);
|
shelfIcon->replaceColour(juce::Colours::black, colour);
|
||||||
shelfIcon->drawWithin(g, iconBounds,
|
shelfIcon->drawWithin(g, iconBounds,
|
||||||
juce::RectanglePlacement::centred, bypassOpacity);
|
juce::RectanglePlacement::centred, bypassOpacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -731,17 +766,22 @@ namespace AXIOM {
|
|||||||
|
|
||||||
class highBandButtonLookAndFeel : public juce::LookAndFeel_V4 {
|
class highBandButtonLookAndFeel : public juce::LookAndFeel_V4 {
|
||||||
public:
|
public:
|
||||||
highBandButtonLookAndFeel() {
|
highBandButtonLookAndFeel()
|
||||||
|
{
|
||||||
highBypassIcon = juce::XmlDocument::parse(BinaryData::bypass_icon_svg);
|
highBypassIcon = juce::XmlDocument::parse(BinaryData::bypass_icon_svg);
|
||||||
highCutIcon = juce::XmlDocument::parse(BinaryData::high_cut_icon_svg);
|
highCutIcon = juce::XmlDocument::parse(BinaryData::high_cut_icon_svg);
|
||||||
highBellIcon = juce::XmlDocument::parse(BinaryData::bell_icon_svg);
|
highBellIcon = juce::XmlDocument::parse(BinaryData::bell_icon_svg);
|
||||||
highShelfIcon = juce::XmlDocument::parse(BinaryData::high_shelf_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 shouldDrawButtonAsHighlighted,
|
||||||
bool shouldDrawButtonAsDown) override {
|
bool shouldDrawButtonAsDown) override
|
||||||
|
{
|
||||||
|
|
||||||
bool isHovered = button.isMouseOverOrDragging();
|
bool isHovered = button.isMouseOverOrDragging();
|
||||||
bool isToggled = button.getToggleState();
|
bool isToggled = button.getToggleState();
|
||||||
bool isEnabled = button.isEnabled();
|
bool isEnabled = button.isEnabled();
|
||||||
@ -754,19 +794,21 @@ namespace AXIOM {
|
|||||||
|
|
||||||
float bypassOpacity = 1.0f;
|
float bypassOpacity = 1.0f;
|
||||||
|
|
||||||
if (highBypassIcon != nullptr && highCutIcon != nullptr && highBellIcon != nullptr && highShelfIcon
|
if (highBypassIcon != nullptr && highCutIcon != nullptr && highBellIcon != nullptr && highShelfIcon != nullptr) {
|
||||||
!= nullptr) {
|
// WICHTIG: Erstelle für jeden Frame ein NEUES Drawable!
|
||||||
auto bypassIcon = juce::Drawable::createFromSVG(*highBypassIcon);
|
auto bypassIcon = juce::Drawable::createFromSVG(*highBypassIcon);
|
||||||
auto cutIcon = juce::Drawable::createFromSVG(*highCutIcon);
|
auto cutIcon = juce::Drawable::createFromSVG(*highCutIcon);
|
||||||
auto bellIcon = juce::Drawable::createFromSVG(*highBellIcon);
|
auto bellIcon = juce::Drawable::createFromSVG(*highBellIcon);
|
||||||
auto shelfIcon = juce::Drawable::createFromSVG(*highShelfIcon);
|
auto shelfIcon = juce::Drawable::createFromSVG(*highShelfIcon);
|
||||||
|
|
||||||
if (bypassIcon != nullptr && cutIcon != nullptr && bellIcon != nullptr && shelfIcon !=
|
if (bypassIcon != nullptr && cutIcon != nullptr && bellIcon != nullptr && shelfIcon != nullptr)
|
||||||
nullptr) {
|
{
|
||||||
|
|
||||||
juce::Colour colour;
|
juce::Colour colour;
|
||||||
if (!isEnabled) {
|
if (!isEnabled) {
|
||||||
colour = isToggled ? Colours::ACCENTWEAKCOLOUR : Colours::SURFACEBYPASS;
|
colour = isToggled ? Colours::ACCENTWEAKCOLOUR : Colours::SURFACEBYPASS;
|
||||||
} else if (isHovered) {
|
}
|
||||||
|
else if (isHovered) {
|
||||||
colour = isToggled ? Colours::ACCENTHOVER : Colours::SURFACEHOVER;
|
colour = isToggled ? Colours::ACCENTHOVER : Colours::SURFACEHOVER;
|
||||||
} else {
|
} else {
|
||||||
colour = isToggled
|
colour = isToggled
|
||||||
@ -774,25 +816,31 @@ namespace AXIOM {
|
|||||||
: Colours::SURFACECOLOUR;
|
: Colours::SURFACECOLOUR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Icon zeichnen
|
||||||
if (button.getName() == "HighBypass") {
|
if (button.getName() == "HighBypass") {
|
||||||
bypassIcon->replaceColour(juce::Colours::black, colour);
|
bypassIcon->replaceColour(juce::Colours::black, colour);
|
||||||
bypassIcon->drawWithin(g, iconBounds,
|
bypassIcon->drawWithin(g, iconBounds,
|
||||||
juce::RectanglePlacement::centred, bypassOpacity);
|
juce::RectanglePlacement::centred, bypassOpacity);
|
||||||
} else if (button.getName() == "HighCut") {
|
}
|
||||||
|
else if (button.getName() == "HighCut") {
|
||||||
cutIcon->replaceColour(juce::Colours::black, colour);
|
cutIcon->replaceColour(juce::Colours::black, colour);
|
||||||
cutIcon->drawWithin(g, iconBounds,
|
cutIcon->drawWithin(g, iconBounds,
|
||||||
juce::RectanglePlacement::centred, bypassOpacity);
|
juce::RectanglePlacement::centred, bypassOpacity);
|
||||||
} else if (button.getName() == "HighBell") {
|
}
|
||||||
|
else if (button.getName() == "HighBell") {
|
||||||
bellIcon->replaceColour(juce::Colours::black, colour);
|
bellIcon->replaceColour(juce::Colours::black, colour);
|
||||||
bellIcon->drawWithin(g, iconBounds,
|
bellIcon->drawWithin(g, iconBounds,
|
||||||
juce::RectanglePlacement::centred, bypassOpacity);
|
juce::RectanglePlacement::centred, bypassOpacity);
|
||||||
} else if (button.getName() == "HighShelf") {
|
}
|
||||||
|
else if (button.getName() == "HighShelf") {
|
||||||
shelfIcon->replaceColour(juce::Colours::black, colour);
|
shelfIcon->replaceColour(juce::Colours::black, colour);
|
||||||
shelfIcon->drawWithin(g, iconBounds,
|
shelfIcon->drawWithin(g, iconBounds,
|
||||||
juce::RectanglePlacement::centred, bypassOpacity);
|
juce::RectanglePlacement::centred, bypassOpacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -807,9 +855,11 @@ namespace AXIOM {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class BaseSliderLookAndFeel : public juce::LookAndFeel_V4 {
|
class BaseSliderLookAndFeel : public juce::LookAndFeel_V4
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
juce::Label *createSliderTextBox(juce::Slider &slider) override {
|
juce::Label* createSliderTextBox(juce::Slider& slider) override
|
||||||
|
{
|
||||||
auto* label = juce::LookAndFeel_V4::createSliderTextBox(slider);
|
auto* label = juce::LookAndFeel_V4::createSliderTextBox(slider);
|
||||||
|
|
||||||
label->setColour(juce::Label::backgroundColourId, juce::Colours::transparentBlack);
|
label->setColour(juce::Label::backgroundColourId, juce::Colours::transparentBlack);
|
||||||
@ -820,8 +870,8 @@ namespace AXIOM {
|
|||||||
Typography::applyToLabel(*label, Typography::Style::Mono, 1.f);
|
Typography::applyToLabel(*label, Typography::Style::Mono, 1.f);
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
juce::Slider::SliderLayout getSliderLayout (juce::Slider& slider) override
|
||||||
juce::Slider::SliderLayout getSliderLayout(juce::Slider &slider) override {
|
{
|
||||||
juce::Slider::SliderLayout layout;
|
juce::Slider::SliderLayout layout;
|
||||||
if (slider.getName() == "LowBand Slope" || slider.getName() == "HighBand Slope") {
|
if (slider.getName() == "LowBand Slope" || slider.getName() == "HighBand Slope") {
|
||||||
layout.textBoxBounds = {};
|
layout.textBoxBounds = {};
|
||||||
@ -845,15 +895,19 @@ namespace AXIOM {
|
|||||||
|
|
||||||
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,
|
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 radius = juce::jmin(width / 2, height / 2) - 4.0f;
|
||||||
auto centreX = x + width * 0.5f;
|
auto centreX = x + width * 0.5f;
|
||||||
auto centreY = y + height * 0.5f;
|
auto centreY = y + height * 0.5f;
|
||||||
auto angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
|
auto angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
|
||||||
|
|
||||||
|
// Outer ring
|
||||||
g.setColour(Colours::BACKGROUNDCOLOUR);
|
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);
|
||||||
|
|
||||||
|
// Indicator
|
||||||
juce::Path p;
|
juce::Path p;
|
||||||
auto pointerLength = radius * 0.6f;
|
auto pointerLength = radius * 0.6f;
|
||||||
auto pointerThickness = 2.0f;
|
auto pointerThickness = 2.0f;
|
||||||
@ -864,12 +918,13 @@ namespace AXIOM {
|
|||||||
g.fillPath(p);
|
g.fillPath(p);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
class GainSliderLookAndFeel : public BaseSliderLookAndFeel
|
||||||
class GainSliderLookAndFeel : public BaseSliderLookAndFeel {
|
{
|
||||||
public:
|
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,
|
float sliderPos, float rotaryStartAngle, float rotaryEndAngle,
|
||||||
juce::Slider &slider) override {
|
juce::Slider& slider) override
|
||||||
|
{
|
||||||
bool isHovered = slider.isMouseOverOrDragging();
|
bool isHovered = slider.isMouseOverOrDragging();
|
||||||
auto isEnabled = slider.isEnabled();
|
auto isEnabled = slider.isEnabled();
|
||||||
float hoverFactor = 1.0f;
|
float hoverFactor = 1.0f;
|
||||||
@ -892,6 +947,7 @@ namespace AXIOM {
|
|||||||
auto mid = (rotaryEndAngle - rotaryStartAngle) / 2 + rotaryStartAngle;
|
auto mid = (rotaryEndAngle - rotaryStartAngle) / 2 + rotaryStartAngle;
|
||||||
const float arcPathWidth = 3.0f;
|
const float arcPathWidth = 3.0f;
|
||||||
|
|
||||||
|
// Background
|
||||||
g.setColour(Colours::BACKGROUNDCOLOUR);
|
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);
|
||||||
|
|
||||||
@ -899,6 +955,7 @@ namespace AXIOM {
|
|||||||
g.drawEllipse(centreX - radius, centreY - radius, radius * 2.0f, radius * 2.0f, arcPathWidth);
|
g.drawEllipse(centreX - radius, centreY - radius, radius * 2.0f, radius * 2.0f, arcPathWidth);
|
||||||
|
|
||||||
|
|
||||||
|
// Arc für Gain-Anzeige
|
||||||
juce::Path valueArc;
|
juce::Path valueArc;
|
||||||
valueArc.addCentredArc(centreX, centreY, radius, radius,
|
valueArc.addCentredArc(centreX, centreY, radius, radius,
|
||||||
0.0f, mid, angle, true);
|
0.0f, mid, angle, true);
|
||||||
@ -906,19 +963,22 @@ namespace AXIOM {
|
|||||||
g.setColour(accentCol);
|
g.setColour(accentCol);
|
||||||
g.strokePath(valueArc, juce::PathStrokeType(arcPathWidth));
|
g.strokePath(valueArc, juce::PathStrokeType(arcPathWidth));
|
||||||
|
|
||||||
|
// Pointer
|
||||||
juce::Path p;
|
juce::Path p;
|
||||||
p.addRectangle(-arcPathWidth / 2, (-radius - arcPathWidth) * hoverFactor, arcPathWidth,
|
p.addRectangle(-arcPathWidth / 2, (-radius - arcPathWidth) * hoverFactor, arcPathWidth, radius * 0.5f * hoverFactor);
|
||||||
radius * 0.5f * hoverFactor);
|
|
||||||
p.applyTransform(juce::AffineTransform::rotation(angle).translated(centreX, centreY));
|
p.applyTransform(juce::AffineTransform::rotation(angle).translated(centreX, centreY));
|
||||||
g.fillPath(p);
|
g.fillPath(p);
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class FreqQSliderLookAndFeel : public BaseSliderLookAndFeel {
|
class FreqQSliderLookAndFeel : public BaseSliderLookAndFeel
|
||||||
|
{
|
||||||
public:
|
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,
|
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 radius = juce::jmin(width / 2, height / 2) - 4.0f;
|
||||||
auto centreX = x + width * 0.5f;
|
auto centreX = x + width * 0.5f;
|
||||||
auto centreY = y + height * 0.5f;
|
auto centreY = y + height * 0.5f;
|
||||||
@ -939,6 +999,7 @@ namespace AXIOM {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Einfacher Ring
|
||||||
g.setColour(surfaceCol);
|
g.setColour(surfaceCol);
|
||||||
g.drawEllipse(centreX - radius, centreY - radius, radius * 2.0f, radius * 2.0f, 2.0f);
|
g.drawEllipse(centreX - radius, centreY - radius, radius * 2.0f, radius * 2.0f, 2.0f);
|
||||||
|
|
||||||
@ -948,10 +1009,9 @@ namespace AXIOM {
|
|||||||
|
|
||||||
g.setColour(accentCol);
|
g.setColour(accentCol);
|
||||||
g.strokePath(valueArc, juce::PathStrokeType(arcPathWidth));
|
g.strokePath(valueArc, juce::PathStrokeType(arcPathWidth));
|
||||||
|
// Dünner Pointer
|
||||||
juce::Path p;
|
juce::Path p;
|
||||||
p.addRectangle(-1.0f, (-radius - arcPathWidth) * hoverFactor, arcPathWidth,
|
p.addRectangle(-1.0f, (-radius - arcPathWidth) * hoverFactor, arcPathWidth, radius * 0.4f * hoverFactor);
|
||||||
radius * 0.4f * hoverFactor);
|
|
||||||
p.applyTransform(juce::AffineTransform::rotation(angle).translated(centreX, centreY));
|
p.applyTransform(juce::AffineTransform::rotation(angle).translated(centreX, centreY));
|
||||||
|
|
||||||
g.setColour(accentCol);
|
g.setColour(accentCol);
|
||||||
@ -963,10 +1023,12 @@ namespace AXIOM {
|
|||||||
public:
|
public:
|
||||||
static constexpr float labelPadding = 20.0f;
|
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;
|
juce::Slider::SliderLayout layout;
|
||||||
auto bounds = slider.getLocalBounds();
|
auto bounds = slider.getLocalBounds();
|
||||||
|
|
||||||
|
// TextBox in der Mitte (wie bei BaseSliderLookAndFeel)
|
||||||
layout.textBoxBounds = juce::Rectangle<int>(
|
layout.textBoxBounds = juce::Rectangle<int>(
|
||||||
bounds.getCentreX() - bounds.getWidth() / 2,
|
bounds.getCentreX() - bounds.getWidth() / 2,
|
||||||
bounds.getCentreY() - bounds.getHeight() / 2,
|
bounds.getCentreY() - bounds.getHeight() / 2,
|
||||||
@ -974,6 +1036,8 @@ namespace AXIOM {
|
|||||||
bounds.getHeight()
|
bounds.getHeight()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// HIER IST DER TRICK: Knob-Bereich kleiner als Slider-Bounds!
|
||||||
|
// So bleibt Platz für die Labels außerhalb
|
||||||
layout.sliderBounds = bounds.reduced(labelPadding);
|
layout.sliderBounds = bounds.reduced(labelPadding);
|
||||||
|
|
||||||
return layout;
|
return layout;
|
||||||
@ -981,18 +1045,23 @@ namespace AXIOM {
|
|||||||
|
|
||||||
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,
|
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 radius = juce::jmin(width / 2, height / 2) - 4.0f;
|
||||||
auto centreX = x + width * 0.5f;
|
auto centreX = x + width * 0.5f;
|
||||||
auto centreY = y + height * 0.5f;
|
auto centreY = y + height * 0.5f;
|
||||||
auto angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
|
auto angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
|
||||||
bool isEnabled = slider.isEnabled();
|
bool isEnabled = slider.isEnabled();
|
||||||
|
bool isHovered = slider.isMouseOverOrDragging();
|
||||||
|
|
||||||
|
// Outer ring
|
||||||
g.setColour(Colours::BACKGROUNDCOLOUR);
|
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);
|
||||||
|
|
||||||
juce::Colour accentCol = isEnabled ? Colours::ACCENTCOLOUR : Colours::ACCENTWEAKCOLOUR;
|
juce::Colour accentCol = isEnabled ? Colours::ACCENTCOLOUR : Colours::ACCENTWEAKCOLOUR;
|
||||||
|
|
||||||
|
// Indicator
|
||||||
juce::Path p;
|
juce::Path p;
|
||||||
auto pointerLength = radius * 0.6f;
|
auto pointerLength = radius * 0.6f;
|
||||||
auto pointerThickness = 2.0f;
|
auto pointerThickness = 2.0f;
|
||||||
@ -1003,6 +1072,7 @@ namespace AXIOM {
|
|||||||
g.fillPath(p);
|
g.fillPath(p);
|
||||||
|
|
||||||
|
|
||||||
|
// Dann zeichne die Labels
|
||||||
const auto bounds = juce::Rectangle<int>(x, y, width, height);
|
const auto bounds = juce::Rectangle<int>(x, y, width, height);
|
||||||
const auto centre = bounds.getCentre().toFloat();
|
const auto centre = bounds.getCentre().toFloat();
|
||||||
const float textRadius = std::min(width, height) * 0.5f + 5.0f;
|
const float textRadius = std::min(width, height) * 0.5f + 5.0f;
|
||||||
@ -1012,15 +1082,16 @@ namespace AXIOM {
|
|||||||
g.setFont(12.0f);
|
g.setFont(12.0f);
|
||||||
auto value = slider.getValue();
|
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
|
const bool isMatch = value == i; // Toleranz: 0.5
|
||||||
|
|
||||||
juce::Colour colour;
|
juce::Colour colour;
|
||||||
if (!isEnabled) {
|
if (!isEnabled) {
|
||||||
colour = isMatch
|
colour = isMatch ? Colours::ACCENTWEAKCOLOUR : Colours::FOREGROUNDCOLOUR.withMultipliedAlpha (0.4f);
|
||||||
? Colours::ACCENTWEAKCOLOUR
|
}
|
||||||
: Colours::FOREGROUNDCOLOUR.withMultipliedAlpha(0.4f);
|
else {
|
||||||
} else {
|
|
||||||
colour = isMatch
|
colour = isMatch
|
||||||
? Colours::ACCENTCOLOUR
|
? Colours::ACCENTCOLOUR
|
||||||
: Colours::FOREGROUNDCOLOUR;
|
: Colours::FOREGROUNDCOLOUR;
|
||||||
@ -1041,14 +1112,17 @@ namespace AXIOM {
|
|||||||
|
|
||||||
g.drawText(labels[i], textRect, juce::Justification::centred);
|
g.drawText(labels[i], textRect, juce::Justification::centred);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class GlobalSliderLookAndFeel : public BaseSliderLookAndFeel {
|
class GlobalSliderLookAndFeel : public BaseSliderLookAndFeel
|
||||||
|
{
|
||||||
public:
|
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,
|
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 radius = juce::jmin(width / 2, height / 2) - 4.0f;
|
||||||
auto centreX = x + width * 0.5f;
|
auto centreX = x + width * 0.5f;
|
||||||
auto centreY = y + height * 0.5f;
|
auto centreY = y + height * 0.5f;
|
||||||
@ -1073,6 +1147,7 @@ namespace AXIOM {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Einfacher Ring
|
||||||
g.setColour(surfaceCol);
|
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);
|
||||||
|
|
||||||
@ -1085,10 +1160,9 @@ namespace AXIOM {
|
|||||||
|
|
||||||
g.setColour(accentCol);
|
g.setColour(accentCol);
|
||||||
g.strokePath(valueArc, juce::PathStrokeType(arcPathWidth));
|
g.strokePath(valueArc, juce::PathStrokeType(arcPathWidth));
|
||||||
|
// Dünner Pointer
|
||||||
juce::Path p;
|
juce::Path p;
|
||||||
p.addRectangle(-1.0f, (-radius - arcPathWidth) * hoverFactor, arcPathWidth,
|
p.addRectangle(-1.0f, (-radius - arcPathWidth) * hoverFactor, arcPathWidth, radius * 0.4f * hoverFactor);
|
||||||
radius * 0.4f * hoverFactor);
|
|
||||||
p.applyTransform(juce::AffineTransform::rotation(angle).translated(centreX, centreY));
|
p.applyTransform(juce::AffineTransform::rotation(angle).translated(centreX, centreY));
|
||||||
|
|
||||||
g.setColour(accentCol);
|
g.setColour(accentCol);
|
||||||
@ -1106,7 +1180,6 @@ namespace AXIOM {
|
|||||||
Global,
|
Global,
|
||||||
Mix
|
Mix
|
||||||
};
|
};
|
||||||
|
|
||||||
static float getSliderSizeMod(SizeMode mode) {
|
static float getSliderSizeMod(SizeMode mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case SizeMode::Gain: return 1.25f;
|
case SizeMode::Gain: return 1.25f;
|
||||||
@ -1118,6 +1191,7 @@ namespace AXIOM {
|
|||||||
default: return 1.0f;
|
default: return 1.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1135,6 +1209,10 @@ namespace AXIOM {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Layout {
|
struct Layout {
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @param mode Spacing mode -- e.g. Spacing::SizeMode::XS
|
||||||
|
/// @return Gap size in px as int
|
||||||
static int gap(Spacing::SizeMode mode) {
|
static int gap(Spacing::SizeMode mode) {
|
||||||
return juce::roundToInt(Spacing::scale.space(mode));
|
return juce::roundToInt(Spacing::scale.space(mode));
|
||||||
}
|
}
|
||||||
@ -1155,6 +1233,7 @@ namespace AXIOM {
|
|||||||
float flexShrink = 1.f,
|
float flexShrink = 1.f,
|
||||||
float basisPx = -1.f,
|
float basisPx = -1.f,
|
||||||
Spacing::SizeMode margin = Spacing::SizeMode::XS) {
|
Spacing::SizeMode margin = Spacing::SizeMode::XS) {
|
||||||
|
|
||||||
juce::FlexItem item{ component };
|
juce::FlexItem item{ component };
|
||||||
item.flexGrow = flexGrow;
|
item.flexGrow = flexGrow;
|
||||||
item.flexShrink = flexShrink;
|
item.flexShrink = flexShrink;
|
||||||
@ -1184,6 +1263,7 @@ namespace AXIOM {
|
|||||||
fb.items.addArray(items);
|
fb.items.addArray(items);
|
||||||
|
|
||||||
fb.performLayout(content(bounds, pad));
|
fb.performLayout(content(bounds, pad));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flexColumn(juce::Rectangle<int> bounds,
|
static void flexColumn(juce::Rectangle<int> bounds,
|
||||||
@ -1228,9 +1308,11 @@ namespace AXIOM {
|
|||||||
|
|
||||||
static juce::GridItem area(juce::Component& c,
|
static juce::GridItem area(juce::Component& c,
|
||||||
int rowStart, int colStart,
|
int rowStart, int colStart,
|
||||||
int rowEnd, int colEnd) {
|
int rowEnd, int colEnd)
|
||||||
|
{
|
||||||
return juce::GridItem(c)
|
return juce::GridItem(c)
|
||||||
.withArea(rowStart, colStart, rowEnd, colEnd);
|
.withArea(rowStart, colStart, rowEnd, colEnd);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void grid(juce::Rectangle<int> bounds,
|
static void grid(juce::Rectangle<int> bounds,
|
||||||
@ -1266,12 +1348,11 @@ namespace AXIOM {
|
|||||||
addAndMakeVisible(*saveButton);
|
addAndMakeVisible(*saveButton);
|
||||||
addAndMakeVisible(*deleteButton);
|
addAndMakeVisible(*deleteButton);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
};
|
||||||
class PresetMenuLookAndFeel : public juce::LookAndFeel_V4 {
|
class PresetMenuLookAndFeel : public juce::LookAndFeel_V4 {
|
||||||
public:
|
public:
|
||||||
void drawCallOutBoxBackground(juce::CallOutBox &callOutBox, juce::Graphics &g, const juce::Path &path,
|
void drawCallOutBoxBackground(juce::CallOutBox &callOutBox, juce::Graphics &g, const juce::Path &path, juce::Image &image) override {
|
||||||
juce::Image &image) override {
|
|
||||||
g.setColour(Colours::SURFACECOLOUR);
|
g.setColour(Colours::SURFACECOLOUR);
|
||||||
g.fillPath(path);
|
g.fillPath(path);
|
||||||
|
|
||||||
@ -1280,19 +1361,22 @@ namespace AXIOM {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int getCallOutBoxBorderSize(const juce::CallOutBox &) override {
|
int getCallOutBoxBorderSize (const juce::CallOutBox&) override
|
||||||
|
{
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PresetButtonsLookAndFeel : public juce::LookAndFeel_V4 {
|
class PresetButtonsLookAndFeel : public juce::LookAndFeel_V4 {
|
||||||
public:
|
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();
|
auto bounds = button.getLocalBounds();
|
||||||
|
|
||||||
|
// Text holen
|
||||||
auto text = button.getButtonText();
|
auto text = button.getButtonText();
|
||||||
|
|
||||||
|
// Farbe wählen
|
||||||
auto isHovered = button.isMouseOver();
|
auto isHovered = button.isMouseOver();
|
||||||
bool isEnabled = button.isEnabled();
|
bool isEnabled = button.isEnabled();
|
||||||
juce::Colour colour = isHovered ? Colours::FOREGROUNDHOVER : Colours::FOREGROUNDCOLOUR;
|
juce::Colour colour = isHovered ? Colours::FOREGROUNDHOVER : Colours::FOREGROUNDCOLOUR;
|
||||||
@ -1302,19 +1386,21 @@ namespace AXIOM {
|
|||||||
|
|
||||||
g.setColour(colour);
|
g.setColour(colour);
|
||||||
|
|
||||||
|
// Font einstellen
|
||||||
auto font = Typography::getFont(Typography::Style::Button, 1.0f);
|
auto font = Typography::getFont(Typography::Style::Button, 1.0f);
|
||||||
g.setFont(font);
|
g.setFont(font);
|
||||||
|
|
||||||
|
// Text zeichnen
|
||||||
g.drawFittedText(text,
|
g.drawFittedText(text,
|
||||||
bounds.reduced(4),
|
bounds.reduced(4),
|
||||||
juce::Justification::centred,
|
juce::Justification::centred,
|
||||||
1);
|
1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawButtonBackground(juce::Graphics& g, juce::Button& button,
|
void drawButtonBackground(juce::Graphics& g, juce::Button& button,
|
||||||
const juce::Colour& backgroundColour,
|
const juce::Colour& backgroundColour,
|
||||||
bool shouldDrawButtonAsHighlighted,
|
bool shouldDrawButtonAsHighlighted,
|
||||||
bool shouldDrawButtonAsDown) override {
|
bool shouldDrawButtonAsDown) override
|
||||||
|
{
|
||||||
auto bounds = button.getLocalBounds().toFloat();
|
auto bounds = button.getLocalBounds().toFloat();
|
||||||
|
|
||||||
bool isHovered = button.isMouseOver();
|
bool isHovered = button.isMouseOver();
|
||||||
@ -1328,203 +1414,47 @@ namespace AXIOM {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ClickableTextEditor : public juce::TextEditor {
|
class PresetComboBoxLookAndFeel : public juce::LookAndFeel_V4 {
|
||||||
public:
|
public:
|
||||||
std::function<void()> onMouseDown;
|
juce::PopupMenu::Options getOptionsForComboBoxPopupMenu(juce::ComboBox& box,
|
||||||
|
juce::Label& label) override
|
||||||
|
{
|
||||||
|
// Basis-Options holen
|
||||||
|
auto options = juce::LookAndFeel_V4::getOptionsForComboBoxPopupMenu(box, label);
|
||||||
|
|
||||||
void mouseDown(const juce::MouseEvent &event) override {
|
// Anzahl der sichtbaren Einträge
|
||||||
juce::TextEditor::mouseDown(event);
|
const int visibleRows = 5;
|
||||||
if (onMouseDown)
|
|
||||||
onMouseDown();
|
// 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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PresetInputLookAndFeel : public juce::LookAndFeel_V4 {
|
|
||||||
public:
|
|
||||||
void fillTextEditorBackground(juce::Graphics &g, int width, int height,
|
|
||||||
juce::TextEditor &textEditor) override {
|
|
||||||
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 {
|
|
||||||
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)) {
|
|
||||||
outlineColour = Colours::ACCENTCOLOUR;
|
|
||||||
} else if (textEditor.isMouseOver()) {
|
|
||||||
outlineColour = Colours::FOREGROUNDHOVER.withAlpha(0.5f);
|
|
||||||
} else {
|
|
||||||
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:
|
private:
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.15)
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
project(CrystalizerEQ VERSION 1.0.0)
|
project(CrystalizerEQ VERSION 0.1.0)
|
||||||
|
|
||||||
# JUCE einbinden (lokaler Pfad zu JUCE, z. B. als Submodul oder manuell kopiert)
|
# JUCE einbinden (lokaler Pfad zu JUCE, z. B. als Submodul oder manuell kopiert)
|
||||||
add_subdirectory(juce) # <-- Pfad zu deinem JUCE-Ordner relativ zum Projekt
|
add_subdirectory(juce) # <-- Pfad zu deinem JUCE-Ordner relativ zum Projekt
|
||||||
|
|||||||
@ -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"
|
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 32\">\n"
|
||||||
" <g id=\"Ebene_6\" data-name=\"Ebene 6\">\n"
|
" <g id=\"Ebene_6\" data-name=\"Ebene 6\">\n"
|
||||||
" <rect x=\"0\" y=\"0\" width=\"64\" height=\"32\" fill=\"#171a1a\"/>\n"
|
" <rect x=\"0\" y=\"0\" width=\"64\" height=\"32\" fill=\"#171a1a\"/>\n"
|
||||||
" <polygon points=\"64 0 62 2 32 16 2 30 0 32 0 0 64 0\" fill=\"#262b2b\"/>\n"
|
" <polygon points=\"0 32 2 30 32 16 62 2 64 0 64 32 0 32\" fill=\"#262b2b\"/>\n"
|
||||||
" </g>\n"
|
" </g>\n"
|
||||||
" <g id=\"Ebene_2\" data-name=\"Ebene 2\">\n"
|
" <g id=\"Ebene_2\" data-name=\"Ebene 2\">\n"
|
||||||
" <rect x=\"2\" y=\"2\" width=\"60\" height=\"28\" fill=\"#3db7b7\"/>\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>\n"
|
" </g>\n"
|
||||||
" <g id=\"Ebene_3_Kopie\" data-name=\"Ebene 3 Kopie\">\n"
|
" <g id=\"Ebene_3_Kopie\" data-name=\"Ebene 3 Kopie\">\n"
|
||||||
" <rect x=\"8\" y=\"8\" width=\"48\" height=\"16\" fill=\"#fffcfc\" opacity=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\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=\".17\"/>\n"
|
" <polygon points=\"62 8 62 2 59 5 56 8 62 8\" fill=\"#d1d1d1\" opacity=\".21\"/>\n"
|
||||||
" </g>\n"
|
" </g>\n"
|
||||||
"</svg>";
|
"</svg>";
|
||||||
|
|
||||||
@ -11692,7 +11692,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes)
|
|||||||
case 0x31532e06: numBytes = 353; return low_cut_icon_svg;
|
case 0x31532e06: numBytes = 353; return low_cut_icon_svg;
|
||||||
case 0x7e8ca05e: numBytes = 410; return low_shelf_icon_svg;
|
case 0x7e8ca05e: numBytes = 410; return low_shelf_icon_svg;
|
||||||
case 0x4df4bf1e: numBytes = 350; return preset_menu_icon_svg;
|
case 0x4df4bf1e: numBytes = 350; return preset_menu_icon_svg;
|
||||||
case 0xd842aaab: numBytes = 6341; return crystalize_button_active_icon_svg;
|
case 0xd842aaab: numBytes = 6343; return crystalize_button_active_icon_svg;
|
||||||
case 0x885a7642: numBytes = 6279; return crystalize_button_passive_icon_svg;
|
case 0x885a7642: numBytes = 6279; return crystalize_button_passive_icon_svg;
|
||||||
case 0xe49e0f15: numBytes = 406; return bypass_icon_svg;
|
case 0xe49e0f15: numBytes = 406; return bypass_icon_svg;
|
||||||
default: break;
|
default: break;
|
||||||
|
|||||||
@ -51,7 +51,7 @@ namespace BinaryData
|
|||||||
const int preset_menu_icon_svgSize = 350;
|
const int preset_menu_icon_svgSize = 350;
|
||||||
|
|
||||||
extern const char* crystalize_button_active_icon_svg;
|
extern const char* crystalize_button_active_icon_svg;
|
||||||
const int crystalize_button_active_icon_svgSize = 6341;
|
const int crystalize_button_active_icon_svgSize = 6343;
|
||||||
|
|
||||||
extern const char* crystalize_button_passive_icon_svg;
|
extern const char* crystalize_button_passive_icon_svg;
|
||||||
const int crystalize_button_passive_icon_svgSize = 6279;
|
const int crystalize_button_passive_icon_svgSize = 6279;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -19,11 +19,9 @@
|
|||||||
using AXIOM::DesignSystem;
|
using AXIOM::DesignSystem;
|
||||||
using Components = DesignSystem::Components;
|
using Components = DesignSystem::Components;
|
||||||
using SliderStyles = Components::SliderStyles;
|
using SliderStyles = Components::SliderStyles;
|
||||||
|
|
||||||
class SpectrumAnalyzer {
|
class SpectrumAnalyzer {
|
||||||
public:
|
public:
|
||||||
SpectrumAnalyzer(AudioFIFO &fifoRef, CrystalizerEQAudioProcessor &processor) : audioFIFO(fifoRef),
|
SpectrumAnalyzer(AudioFIFO& fifoRef, CrystalizerEQAudioProcessor& processor) : audioFIFO(fifoRef), audioProcessor(processor) {
|
||||||
audioProcessor(processor) {
|
|
||||||
fftData.resize(2 * FFTSIZE);
|
fftData.resize(2 * FFTSIZE);
|
||||||
magnitudes.resize(BINS);
|
magnitudes.resize(BINS);
|
||||||
magnitudesDb.resize(BINS);
|
magnitudesDb.resize(BINS);
|
||||||
@ -35,8 +33,9 @@ public:
|
|||||||
peakHoldMagnitudesDb.resize(BINS);
|
peakHoldMagnitudesDb.resize(BINS);
|
||||||
DELTAT = static_cast<float>(HOPSIZE) / static_cast<float>(sampleRate);
|
DELTAT = static_cast<float>(HOPSIZE) / static_cast<float>(sampleRate);
|
||||||
renderValuesDb.resize(BINS);
|
renderValuesDb.resize(BINS);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
~SpectrumAnalyzer() = default;
|
~SpectrumAnalyzer() = default;
|
||||||
|
|
||||||
|
|
||||||
@ -53,7 +52,7 @@ public:
|
|||||||
juce::Array<float> fftFrame;
|
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
|
//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.5f;
|
float smoothingFactor = 0.3f;
|
||||||
|
|
||||||
|
|
||||||
void processSamples();
|
void processSamples();
|
||||||
@ -77,6 +76,7 @@ public:
|
|||||||
std::vector<float> fftData;
|
std::vector<float> fftData;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const float MINDB = -90.f;
|
const float MINDB = -90.f;
|
||||||
const float MAXDB = 0.f;
|
const float MAXDB = 0.f;
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ public:
|
|||||||
std::vector<double> freqPerBin;
|
std::vector<double> freqPerBin;
|
||||||
|
|
||||||
//CHANGE FOR FASTER FALLOFF -- VALUE IS IN DB/S
|
//CHANGE FOR FASTER FALLOFF -- VALUE IS IN DB/S
|
||||||
const float FALLOFFRATE = 240.f;
|
const float FALLOFFRATE = 120.f;
|
||||||
|
|
||||||
float DELTAT = 0.f;
|
float DELTAT = 0.f;
|
||||||
|
|
||||||
@ -114,27 +114,23 @@ public:
|
|||||||
const float MAXFREQ = static_cast<float>(sampleRate) / 2;
|
const float MAXFREQ = static_cast<float>(sampleRate) / 2;
|
||||||
|
|
||||||
void fillFftDataFromFrame(std::vector<float> &windowedFrame);
|
void fillFftDataFromFrame(std::vector<float> &windowedFrame);
|
||||||
|
|
||||||
void buildMagnitudeSpectrum();
|
void buildMagnitudeSpectrum();
|
||||||
|
|
||||||
void convertToDb();
|
void convertToDb();
|
||||||
|
|
||||||
void applySmoothing();
|
void applySmoothing();
|
||||||
|
|
||||||
void applyEMA();
|
void applyEMA();
|
||||||
|
|
||||||
void applyFreqSmoothing();
|
void applyFreqSmoothing();
|
||||||
|
|
||||||
void applyPeakHoldAndFalloff();
|
void applyPeakHoldAndFalloff();
|
||||||
|
|
||||||
std::vector<float> getRenderValues();
|
std::vector<float> getRenderValues();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class CrystalizerEQAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::Timer, private juce::AudioProcessorValueTreeState::Listener {
|
class CrystalizerEQAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::Timer
|
||||||
public:
|
|
||||||
CrystalizerEQAudioProcessorEditor(CrystalizerEQAudioProcessor &);
|
|
||||||
|
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
CrystalizerEQAudioProcessorEditor (CrystalizerEQAudioProcessor&);
|
||||||
~CrystalizerEQAudioProcessorEditor() override;
|
~CrystalizerEQAudioProcessorEditor() override;
|
||||||
|
|
||||||
void paintAnalyzer(juce::Graphics &g);
|
void paintAnalyzer(juce::Graphics &g);
|
||||||
@ -145,12 +141,10 @@ public:
|
|||||||
|
|
||||||
//===================================================================
|
//===================================================================
|
||||||
void timerCallback();
|
void timerCallback();
|
||||||
|
|
||||||
void paint (juce::Graphics&) override;
|
void paint (juce::Graphics&) override;
|
||||||
|
|
||||||
|
|
||||||
void resized() override;
|
void resized() override;
|
||||||
|
|
||||||
void resetAllCheckboxes();
|
void resetAllCheckboxes();
|
||||||
|
|
||||||
using SliderAttach = juce::AudioProcessorValueTreeState::SliderAttachment;
|
using SliderAttach = juce::AudioProcessorValueTreeState::SliderAttachment;
|
||||||
@ -159,7 +153,7 @@ public:
|
|||||||
|
|
||||||
using ComboBoxAttach = juce::AudioProcessorValueTreeState::ComboBoxAttachment;
|
using ComboBoxAttach = juce::AudioProcessorValueTreeState::ComboBoxAttachment;
|
||||||
|
|
||||||
juce::Slider
|
juce::Slider testNoiseSlider,
|
||||||
lowBandFreqSlider, lowBandSlopeSlider, lowBandGainSlider, lowBandQSlider,
|
lowBandFreqSlider, lowBandSlopeSlider, lowBandGainSlider, lowBandQSlider,
|
||||||
peak1FreqSlider, peak1GainSlider, peak1QSlider,
|
peak1FreqSlider, peak1GainSlider, peak1QSlider,
|
||||||
peak2FreqSlider, peak2GainSlider, peak2QSlider,
|
peak2FreqSlider, peak2GainSlider, peak2QSlider,
|
||||||
@ -176,7 +170,7 @@ public:
|
|||||||
&inputSlider, &outputSlider
|
&inputSlider, &outputSlider
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<SliderAttach>
|
std::unique_ptr<SliderAttach> testNoiseAttach,
|
||||||
lowBandFreqAttach, lowBandSlopeAttach, lowBandGainAttach, lowBandQAttach,
|
lowBandFreqAttach, lowBandSlopeAttach, lowBandGainAttach, lowBandQAttach,
|
||||||
peak1FreqAttach, peak1GainAttach, peak1QAttach,
|
peak1FreqAttach, peak1GainAttach, peak1QAttach,
|
||||||
peak2FreqAttach, peak2GainAttach, peak2QAttach,
|
peak2FreqAttach, peak2GainAttach, peak2QAttach,
|
||||||
@ -184,11 +178,7 @@ public:
|
|||||||
highBandFreqAttach, highBandSlopeAttach, highBandGainAttach, highBandQAttach,
|
highBandFreqAttach, highBandSlopeAttach, highBandGainAttach, highBandQAttach,
|
||||||
inputAttach, outputAttach;
|
inputAttach, outputAttach;
|
||||||
|
|
||||||
std::unique_ptr<ButtonAttach>
|
juce::Label titleLabel, testNoiseLabel,
|
||||||
peak1BypassAttach, peak2BypassAttach, peak3BypassAttach,
|
|
||||||
crystalizeAttach, masterBypassAttach;
|
|
||||||
|
|
||||||
juce::Label titleLabel,
|
|
||||||
lowBandFreqLabel, lowBandSlopeLabel, lowBandGainLabel, lowBandQLabel, lowBandModeLabel,
|
lowBandFreqLabel, lowBandSlopeLabel, lowBandGainLabel, lowBandQLabel, lowBandModeLabel,
|
||||||
low12, low24, low36, low48, lowdBOctLabel,
|
low12, low24, low36, low48, lowdBOctLabel,
|
||||||
peak1FreqLabel, peak1GainLabel, peak1QLabel,
|
peak1FreqLabel, peak1GainLabel, peak1QLabel,
|
||||||
@ -204,8 +194,7 @@ public:
|
|||||||
&peak1FreqLabel, &peak1GainLabel, &peak1QLabel,
|
&peak1FreqLabel, &peak1GainLabel, &peak1QLabel,
|
||||||
&peak2FreqLabel, &peak2GainLabel, &peak2QLabel,
|
&peak2FreqLabel, &peak2GainLabel, &peak2QLabel,
|
||||||
&peak3FreqLabel, &peak3GainLabel, &peak3QLabel,
|
&peak3FreqLabel, &peak3GainLabel, &peak3QLabel,
|
||||||
&highBandFreqLabel, &highBandSlopeLabel, &highBandGainLabel, &highBandQLabel, &highBandModeLabel,
|
&highBandFreqLabel, &highBandSlopeLabel, &highBandGainLabel, &highBandQLabel, &highBandModeLabel, &highdBOctLabel,
|
||||||
&highdBOctLabel,
|
|
||||||
&inputLabel, &outputLabel
|
&inputLabel, &outputLabel
|
||||||
};
|
};
|
||||||
const juce::Array<juce::Label*> slopeLabels = {
|
const juce::Array<juce::Label*> slopeLabels = {
|
||||||
@ -214,14 +203,12 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
juce::TextButton resetButton, savePresetButton, deletePresetButton;
|
|
||||||
|
|
||||||
juce::ToggleButton masterBypassButton, crystalizeButton, peak1BypassButton, peak2BypassButton, peak3BypassButton,
|
juce::TextButton testNoiseButton, resetButton, savePresetButton, deletePresetButton;
|
||||||
presetMenuButton;
|
|
||||||
|
|
||||||
const juce::Array<juce::ToggleButton *> peakBypassButtons = {
|
juce::ToggleButton masterBypassButton, crystalizeButton, peak1BypassButton, peak2BypassButton, peak3BypassButton, presetMenuButton;
|
||||||
&peak1BypassButton, &peak2BypassButton, &peak3BypassButton
|
|
||||||
};
|
const juce::Array<juce::ToggleButton*> peakBypassButtons = {&peak1BypassButton, &peak2BypassButton, &peak3BypassButton};
|
||||||
|
|
||||||
juce::ComboBox presetBox;
|
juce::ComboBox presetBox;
|
||||||
|
|
||||||
@ -235,14 +222,18 @@ public:
|
|||||||
juce::ToggleButton lowBypass, lowCut, lowBell, lowShelf,
|
juce::ToggleButton lowBypass, lowCut, lowBell, lowShelf,
|
||||||
highBypass, highCut, highBell, highShelf;
|
highBypass, highCut, highBell, highShelf;
|
||||||
|
|
||||||
DesignSystem::ClickableTextEditor presetNameInput;
|
juce::TextEditor presetNameInput;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// This reference is provided as a quick way for your editor to
|
// This reference is provided as a quick way for your editor to
|
||||||
// access the processor object that created it.
|
// access the processor object that created it.
|
||||||
CrystalizerEQAudioProcessor& audioProcessor;
|
CrystalizerEQAudioProcessor& audioProcessor;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void setKnobVisibility();
|
void setKnobVisibility();
|
||||||
|
|
||||||
void animateCrystalizeButton();
|
void animateCrystalizeButton();
|
||||||
@ -262,13 +253,9 @@ private:
|
|||||||
void setupToggleButtons();
|
void setupToggleButtons();
|
||||||
|
|
||||||
void disableLowBand(float target);
|
void disableLowBand(float target);
|
||||||
|
|
||||||
void disableLowMidBand(float target);
|
void disableLowMidBand(float target);
|
||||||
|
|
||||||
void disableMidBand(float target);
|
void disableMidBand(float target);
|
||||||
|
|
||||||
void disableHighMidBand(float target);
|
void disableHighMidBand(float target);
|
||||||
|
|
||||||
void disableHighBand(float target);
|
void disableHighBand(float target);
|
||||||
|
|
||||||
void disableEverything(float target);
|
void disableEverything(float target);
|
||||||
@ -283,10 +270,6 @@ private:
|
|||||||
|
|
||||||
void initPresetSystem();
|
void initPresetSystem();
|
||||||
|
|
||||||
void updateFrequencyRanges();
|
|
||||||
|
|
||||||
void updateModeButtons();
|
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<AXIOM::DesignSystem::Components::BaseSliderLookAndFeel> baseLookAndFeel;
|
std::unique_ptr<AXIOM::DesignSystem::Components::BaseSliderLookAndFeel> baseLookAndFeel;
|
||||||
std::unique_ptr<DesignSystem::Components::GainSliderLookAndFeel> gainLookAndFeel;
|
std::unique_ptr<DesignSystem::Components::GainSliderLookAndFeel> gainLookAndFeel;
|
||||||
@ -301,7 +284,6 @@ private:
|
|||||||
std::unique_ptr<DesignSystem::PresetMenuLookAndFeel> presetMenuLookAndFeel;
|
std::unique_ptr<DesignSystem::PresetMenuLookAndFeel> presetMenuLookAndFeel;
|
||||||
std::unique_ptr<DesignSystem::PresetButtonsLookAndFeel> presetButtonLookAndFeel;
|
std::unique_ptr<DesignSystem::PresetButtonsLookAndFeel> presetButtonLookAndFeel;
|
||||||
std::unique_ptr<DesignSystem::PresetComboBoxLookAndFeel> presetComboBoxLookAndFeel;
|
std::unique_ptr<DesignSystem::PresetComboBoxLookAndFeel> presetComboBoxLookAndFeel;
|
||||||
std::unique_ptr<DesignSystem::PresetInputLookAndFeel> presetInputLookAndFeel;
|
|
||||||
|
|
||||||
|
|
||||||
//SPECRTRUM ANALYZER
|
//SPECRTRUM ANALYZER
|
||||||
@ -333,24 +315,18 @@ private:
|
|||||||
Component globalControlArea;
|
Component globalControlArea;
|
||||||
|
|
||||||
|
|
||||||
void scalePluginWindow(juce::Rectangle<int> area);
|
|
||||||
|
|
||||||
|
void scalePluginWindow(juce::Rectangle<int> area);
|
||||||
void setupMainGrid(juce::Rectangle<int> area);
|
void setupMainGrid(juce::Rectangle<int> area);
|
||||||
|
|
||||||
void setupLowBandLayout();
|
void setupLowBandLayout();
|
||||||
|
|
||||||
void setupLowMidBandLayout();
|
void setupLowMidBandLayout();
|
||||||
|
|
||||||
void setupMidBandLayout();
|
void setupMidBandLayout();
|
||||||
|
|
||||||
void setupHighMidBandLayout();
|
void setupHighMidBandLayout();
|
||||||
|
|
||||||
void setupHighBandLayout();
|
void setupHighBandLayout();
|
||||||
|
|
||||||
void setupHeader();
|
void setupHeader();
|
||||||
|
|
||||||
void setupBody();
|
void setupBody();
|
||||||
|
|
||||||
void setupFooter();
|
void setupFooter();
|
||||||
|
|
||||||
juce::Array<float> getReferenceCell();
|
juce::Array<float> getReferenceCell();
|
||||||
@ -368,19 +344,13 @@ private:
|
|||||||
|
|
||||||
std::unique_ptr<juce::Drawable> logoDrawable;
|
std::unique_ptr<juce::Drawable> logoDrawable;
|
||||||
|
|
||||||
|
DesignSystem::PresetMenu* test;
|
||||||
juce::Component::SafePointer<DesignSystem::PresetMenu> presetMenuSafePtr;
|
juce::Component::SafePointer<DesignSystem::PresetMenu> presetMenuSafePtr;
|
||||||
|
|
||||||
bool inputFocused = false;
|
|
||||||
|
|
||||||
float mapFrequencyToX(float freq, float minFreq, float maxFreq, float width);
|
float mapFrequencyToX(float freq, float minFreq, float maxFreq, float width);
|
||||||
|
|
||||||
int getClosestBinForFrequency(float freq);
|
int getClosestBinForFrequency(float freq);
|
||||||
|
|
||||||
void drawFrequencyGrid(juce::Graphics& g, const float dbRange);
|
void drawFrequencyGrid(juce::Graphics& g, const float dbRange);
|
||||||
|
|
||||||
float getInterpolatedDb(float exactBin);
|
float getInterpolatedDb(float exactBin);
|
||||||
|
|
||||||
void parameterChanged(const juce::String& parameterID, float newValue) override;
|
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CrystalizerEQAudioProcessorEditor)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CrystalizerEQAudioProcessorEditor)
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,24 +9,25 @@
|
|||||||
#include "PluginProcessor.h"
|
#include "PluginProcessor.h"
|
||||||
#include "PluginEditor.h"
|
#include "PluginEditor.h"
|
||||||
|
|
||||||
|
// ==================== Parameter-Layout ====================
|
||||||
juce::AudioProcessorValueTreeState::ParameterLayout
|
juce::AudioProcessorValueTreeState::ParameterLayout
|
||||||
CrystalizerEQAudioProcessor::createParameterLayout() {
|
CrystalizerEQAudioProcessor::createParameterLayout() {
|
||||||
std::vector<std::unique_ptr<juce::RangedAudioParameter>> params;
|
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
|
//LOW-BAND
|
||||||
|
|
||||||
params.push_back (std::make_unique<juce::AudioParameterFloat>(
|
params.push_back (std::make_unique<juce::AudioParameterFloat>(
|
||||||
"LowBandFreq", "LowBand Freq",
|
"LowBandFreq", "LowBand Freq",
|
||||||
juce::NormalisableRange<float>(20.f, 20000.f, 1.f, 0.5f), 30.f));
|
juce::NormalisableRange<float>(20.f, 20000.f, 1.f, 0.5f), 30.f));
|
||||||
|
|
||||||
params.push_back(std::make_unique<juce::AudioParameterFloat>("LowBandGain", "LowBand Gain",
|
params.push_back (std::make_unique<juce::AudioParameterFloat>("LowBandGain", "LowBand Gain", juce::NormalisableRange<float>(-48.f, 48.f, 0.1f), 0.f));
|
||||||
juce::NormalisableRange<float>(-48.f, 48.f, 0.1f),
|
|
||||||
0.f));
|
|
||||||
|
|
||||||
params.push_back(std::make_unique<juce::AudioParameterFloat>("LowBandQ", "LowBand Q",
|
params.push_back (std::make_unique<juce::AudioParameterFloat>("LowBandQ", "LowBand Q", juce::NormalisableRange<float>(0.1f, 10.f, 0.01f), 1.f));
|
||||||
juce::NormalisableRange<float>(0.1f, 10.f, 0.01f),
|
|
||||||
1.f));
|
|
||||||
|
|
||||||
params.push_back (std::make_unique<juce::AudioParameterChoice>(
|
params.push_back (std::make_unique<juce::AudioParameterChoice>(
|
||||||
"LowBandSlope", "LowBand Slope", // Anzeigename
|
"LowBandSlope", "LowBand Slope", // Anzeigename
|
||||||
@ -95,13 +96,9 @@ CrystalizerEQAudioProcessor::createParameterLayout() {
|
|||||||
"HighBandFreq", "HighBand Freq",
|
"HighBandFreq", "HighBand Freq",
|
||||||
juce::NormalisableRange<float>(20.f, 20000.f, 1.f, 0.5f), 17000.f));
|
juce::NormalisableRange<float>(20.f, 20000.f, 1.f, 0.5f), 17000.f));
|
||||||
|
|
||||||
params.push_back(std::make_unique<juce::AudioParameterFloat>("HighBandGain", "HighBand Gain",
|
params.push_back (std::make_unique<juce::AudioParameterFloat>("HighBandGain", "HighBand Gain", juce::NormalisableRange<float>(-48.f, 48.f, 0.1f), 0.f));
|
||||||
juce::NormalisableRange<float>(-48.f, 48.f, 0.1f),
|
|
||||||
0.f));
|
|
||||||
|
|
||||||
params.push_back(std::make_unique<juce::AudioParameterFloat>("HighBandQ", "HighBand Q",
|
params.push_back (std::make_unique<juce::AudioParameterFloat>("HighBandQ", "HighBand Q", juce::NormalisableRange<float>(0.1f, 10.f, 0.01f), 1.f));
|
||||||
juce::NormalisableRange<float>(0.1f, 10.f, 0.01f),
|
|
||||||
1.f));
|
|
||||||
|
|
||||||
params.push_back (std::make_unique<juce::AudioParameterChoice>(
|
params.push_back (std::make_unique<juce::AudioParameterChoice>(
|
||||||
"HighBandSlope", "HighBand Slope", // Anzeigename
|
"HighBandSlope", "HighBand Slope", // Anzeigename
|
||||||
@ -113,18 +110,16 @@ CrystalizerEQAudioProcessor::createParameterLayout() {
|
|||||||
juce::StringArray { "Off", "Cut", "Shelf", "Bell" }, // Einträge
|
juce::StringArray { "Off", "Cut", "Shelf", "Bell" }, // Einträge
|
||||||
2));
|
2));
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
params.push_back(std::make_unique<juce::AudioParameterFloat>("InputGain", "Input Gain",
|
params.push_back (std::make_unique<juce::AudioParameterFloat>("InputGain", "Input Gain", juce::NormalisableRange<float>(-30.f, 30.0f, 0.1f), 0.0f));
|
||||||
juce::NormalisableRange<float>(-30.f, 30.0f, 0.1f),
|
|
||||||
0.0f));
|
|
||||||
|
|
||||||
params.push_back(std::make_unique<juce::AudioParameterFloat>("OutputGain", "Output Gain",
|
params.push_back (std::make_unique<juce::AudioParameterFloat>("OutputGain", "Output Gain", juce::NormalisableRange<float>(-30.f, 30.0f, 0.1f), 0.0f));
|
||||||
juce::NormalisableRange<float>(-30.f, 30.0f, 0.1f),
|
|
||||||
0.0f));
|
|
||||||
|
|
||||||
params.push_back (std::make_unique<juce::AudioParameterBool>("CrystalizeButton", "Crystalize Button", false));
|
params.push_back (std::make_unique<juce::AudioParameterBool>("CrystalizeButton", "Crystalize Button", false));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
params.push_back (std::make_unique<juce::AudioParameterBool>("MasterBypass", "MasterBypass", false));
|
params.push_back (std::make_unique<juce::AudioParameterBool>("MasterBypass", "MasterBypass", false));
|
||||||
|
|
||||||
return { params.begin(), params.end() };
|
return { params.begin(), params.end() };
|
||||||
@ -144,17 +139,20 @@ CrystalizerEQAudioProcessor::CrystalizerEQAudioProcessor()
|
|||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CrystalizerEQAudioProcessor::~CrystalizerEQAudioProcessor() = default;
|
CrystalizerEQAudioProcessor::~CrystalizerEQAudioProcessor() = default;
|
||||||
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
const juce::String CrystalizerEQAudioProcessor::getName() const {
|
const juce::String CrystalizerEQAudioProcessor::getName() const
|
||||||
|
{
|
||||||
return JucePlugin_Name;
|
return JucePlugin_Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CrystalizerEQAudioProcessor::acceptsMidi() const {
|
bool CrystalizerEQAudioProcessor::acceptsMidi() const
|
||||||
|
{
|
||||||
#if JucePlugin_WantsMidiInput
|
#if JucePlugin_WantsMidiInput
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
@ -162,7 +160,8 @@ bool CrystalizerEQAudioProcessor::acceptsMidi() const {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CrystalizerEQAudioProcessor::producesMidi() const {
|
bool CrystalizerEQAudioProcessor::producesMidi() const
|
||||||
|
{
|
||||||
#if JucePlugin_ProducesMidiOutput
|
#if JucePlugin_ProducesMidiOutput
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
@ -170,7 +169,8 @@ bool CrystalizerEQAudioProcessor::producesMidi() const {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CrystalizerEQAudioProcessor::isMidiEffect() const {
|
bool CrystalizerEQAudioProcessor::isMidiEffect() const
|
||||||
|
{
|
||||||
#if JucePlugin_IsMidiEffect
|
#if JucePlugin_IsMidiEffect
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
@ -178,38 +178,49 @@ bool CrystalizerEQAudioProcessor::isMidiEffect() const {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
double CrystalizerEQAudioProcessor::getTailLengthSeconds() const {
|
double CrystalizerEQAudioProcessor::getTailLengthSeconds() const
|
||||||
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CrystalizerEQAudioProcessor::getNumPrograms() {
|
int CrystalizerEQAudioProcessor::getNumPrograms()
|
||||||
|
{
|
||||||
return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs,
|
return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs,
|
||||||
// so this should be at least 1, even if you're not really implementing programs.
|
// so this should be at least 1, even if you're not really implementing programs.
|
||||||
}
|
}
|
||||||
|
|
||||||
int CrystalizerEQAudioProcessor::getCurrentProgram() {
|
int CrystalizerEQAudioProcessor::getCurrentProgram()
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrystalizerEQAudioProcessor::setCurrentProgram(int index) {
|
void CrystalizerEQAudioProcessor::setCurrentProgram (int index)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const juce::String CrystalizerEQAudioProcessor::getProgramName(int index) {
|
const juce::String CrystalizerEQAudioProcessor::getProgramName (int index)
|
||||||
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrystalizerEQAudioProcessor::changeProgramName(int index, const juce::String &newName) {
|
void CrystalizerEQAudioProcessor::changeProgramName (int index, const juce::String& newName)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioFIFO::AudioFIFO(){
|
AudioFIFO::AudioFIFO(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioFIFO::~AudioFIFO() {
|
AudioFIFO::~AudioFIFO() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void CrystalizerEQAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) {
|
void CrystalizerEQAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
|
||||||
|
{
|
||||||
// Use this method as the place to do any pre-playback
|
// Use this method as the place to do any pre-playback
|
||||||
// initialisation that you need..
|
// initialisation that you need..
|
||||||
|
|
||||||
@ -219,55 +230,41 @@ void CrystalizerEQAudioProcessor::prepareToPlay(double sampleRate, int samplesPe
|
|||||||
spec.numChannels = static_cast<juce::uint32> (getTotalNumOutputChannels());
|
spec.numChannels = static_cast<juce::uint32> (getTotalNumOutputChannels());
|
||||||
|
|
||||||
|
|
||||||
mbLowpassL.prepare(spec);
|
mbLowpass.prepare(spec);
|
||||||
mbLowpassR.prepare(spec);
|
mbHighpass.prepare(spec);
|
||||||
|
mbLowpass.reset();
|
||||||
|
mbHighpass.reset();
|
||||||
|
|
||||||
mbHighpassL.prepare(spec);
|
mbHighPeak.prepare(spec);
|
||||||
mbHighpassR.prepare(spec);
|
mbHighPeak.reset();
|
||||||
|
|
||||||
mbLowpassL.reset();
|
saturator.prepare(spec);
|
||||||
mbLowpassR.reset();
|
saturator.functionToUse = [] (float x) {
|
||||||
|
|
||||||
mbHighpassL.reset();
|
|
||||||
mbHighpassR.reset();
|
|
||||||
|
|
||||||
mbHighPeakL.prepare(spec);
|
|
||||||
mbHighPeakR.prepare(spec);
|
|
||||||
mbHighPeakL.reset();
|
|
||||||
mbHighPeakR.reset();
|
|
||||||
|
|
||||||
|
|
||||||
saturatorL.prepare(spec);
|
|
||||||
|
|
||||||
|
|
||||||
saturatorL.functionToUse = [](float x) {
|
|
||||||
return std::tanh(x);
|
return std::tanh(x);
|
||||||
};
|
};
|
||||||
saturatorL.reset();
|
saturator.reset();
|
||||||
|
|
||||||
saturatorR.prepare(spec);
|
|
||||||
saturatorR.functionToUse = [](float x) {
|
|
||||||
return std::tanh(x);
|
|
||||||
};
|
|
||||||
saturatorR.reset();
|
|
||||||
|
|
||||||
spec.numChannels = static_cast<juce::uint32>(getTotalNumOutputChannels());
|
|
||||||
leftChain.prepare (spec);
|
leftChain.prepare (spec);
|
||||||
rightChain.prepare (spec);
|
rightChain.prepare (spec);
|
||||||
|
|
||||||
leftChain.reset();
|
leftChain.reset();
|
||||||
rightChain.reset();
|
rightChain.reset();
|
||||||
|
|
||||||
updateFilters();
|
updateFilters(); // initiale Koeffizienten
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setCoeffs(juce::dsp::IIR::Filter<float>& f,
|
static void setCoeffs(juce::dsp::IIR::Filter<float>& f,
|
||||||
juce::dsp::IIR::Coefficients<float>::Ptr c) {
|
juce::dsp::IIR::Coefficients<float>::Ptr c)
|
||||||
f.coefficients = c;
|
{
|
||||||
|
f.coefficients = c; // ok
|
||||||
|
// oder: *f.coefficients = *c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CrystalizerEQAudioProcessor::updateFilters() {
|
|
||||||
|
void CrystalizerEQAudioProcessor::updateFilters()
|
||||||
|
{
|
||||||
|
|
||||||
const auto sr = getSampleRate();
|
const auto sr = getSampleRate();
|
||||||
|
|
||||||
const auto lowFreq = apvts.getRawParameterValue("LowBandFreq")->load();
|
const auto lowFreq = apvts.getRawParameterValue("LowBandFreq")->load();
|
||||||
@ -315,12 +312,21 @@ void CrystalizerEQAudioProcessor::updateFilters() {
|
|||||||
const auto crystalized = static_cast<int>(apvts.getRawParameterValue("CrystalizeButton")->load());
|
const auto crystalized = static_cast<int>(apvts.getRawParameterValue("CrystalizeButton")->load());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
juce::dsp::IIR::Coefficients<float>::Ptr lowBand;
|
juce::dsp::IIR::Coefficients<float>::Ptr lowBand;
|
||||||
juce::dsp::IIR::Coefficients<float>::Ptr highBand;
|
juce::dsp::IIR::Coefficients<float>::Ptr highBand;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// links
|
||||||
leftChain.get<0>().setGainDecibels (inputGdB);
|
leftChain.get<0>().setGainDecibels (inputGdB);
|
||||||
rightChain.get<0>().setGainDecibels (inputGdB);
|
rightChain.get<0>().setGainDecibels (inputGdB);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setCoeffs (leftChain.get<5>(), peak1);
|
setCoeffs (leftChain.get<5>(), peak1);
|
||||||
setCoeffs (rightChain.get<5>(), peak1);
|
setCoeffs (rightChain.get<5>(), peak1);
|
||||||
setCoeffs (leftChain.get<6>(), peak2);
|
setCoeffs (leftChain.get<6>(), peak2);
|
||||||
@ -328,13 +334,11 @@ void CrystalizerEQAudioProcessor::updateFilters() {
|
|||||||
setCoeffs (leftChain.get<7>(), peak3);
|
setCoeffs (leftChain.get<7>(), peak3);
|
||||||
setCoeffs (rightChain.get<7>(), peak3);
|
setCoeffs (rightChain.get<7>(), peak3);
|
||||||
|
|
||||||
const auto crystalizedShelf = juce::dsp::IIR::Coefficients<float>::makeHighShelf(
|
const auto crystalizedShelf = juce::dsp::IIR::Coefficients<float>::makeHighShelf(sr, 12000.0f, 1.0f, juce::Decibels::decibelsToGain(4.0f));
|
||||||
sr, 12000.0f, 1.0f, juce::Decibels::decibelsToGain(4.0f));
|
|
||||||
setCoeffs(leftChain.get<12>(), crystalizedShelf);
|
setCoeffs(leftChain.get<12>(), crystalizedShelf);
|
||||||
setCoeffs(rightChain.get<12>(), crystalizedShelf);
|
setCoeffs(rightChain.get<12>(), crystalizedShelf);
|
||||||
|
|
||||||
const auto crystalizedBell = juce::dsp::IIR::Coefficients<float>::makePeakFilter(
|
const auto crystalizedBell = juce::dsp::IIR::Coefficients<float>::makePeakFilter(sr, 10000.0f, 1.0f, juce::Decibels::decibelsToGain(2.0f));
|
||||||
sr, 10000.0f, 1.0f, juce::Decibels::decibelsToGain(2.0f));
|
|
||||||
setCoeffs(leftChain.get<13>(), crystalizedBell);
|
setCoeffs(leftChain.get<13>(), crystalizedBell);
|
||||||
setCoeffs(rightChain.get<13>(), crystalizedBell);
|
setCoeffs(rightChain.get<13>(), crystalizedBell);
|
||||||
|
|
||||||
@ -342,6 +346,8 @@ void CrystalizerEQAudioProcessor::updateFilters() {
|
|||||||
rightChain.get<14>().setGainDecibels (outputGdB);
|
rightChain.get<14>().setGainDecibels (outputGdB);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (peak1Bypass) {
|
if (peak1Bypass) {
|
||||||
leftChain.setBypassed<5>(true);
|
leftChain.setBypassed<5>(true);
|
||||||
rightChain.setBypassed<5>(true);
|
rightChain.setBypassed<5>(true);
|
||||||
@ -398,6 +404,7 @@ void CrystalizerEQAudioProcessor::updateFilters() {
|
|||||||
setCoeffs(rightChain.get<4>(), lowBand);
|
setCoeffs(rightChain.get<4>(), lowBand);
|
||||||
|
|
||||||
|
|
||||||
|
//HIER SLOPE IMPLEMENTIEREN
|
||||||
leftChain .setBypassed<2>(lowSlope < 2);
|
leftChain .setBypassed<2>(lowSlope < 2);
|
||||||
rightChain.setBypassed<2>(lowSlope < 2);
|
rightChain.setBypassed<2>(lowSlope < 2);
|
||||||
leftChain .setBypassed<3>(lowSlope < 3);
|
leftChain .setBypassed<3>(lowSlope < 3);
|
||||||
@ -408,6 +415,7 @@ void CrystalizerEQAudioProcessor::updateFilters() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
|
// Q steuert die „Güte“/Steilheit des Übergangs
|
||||||
lowBand = juce::dsp::IIR::Coefficients<float>::makeLowShelf(sr, lowFreq, lowQ, lowGainLin);
|
lowBand = juce::dsp::IIR::Coefficients<float>::makeLowShelf(sr, lowFreq, lowQ, lowGainLin);
|
||||||
setCoeffs(leftChain .get<1>(), lowBand);
|
setCoeffs(leftChain .get<1>(), lowBand);
|
||||||
setCoeffs(rightChain.get<1>(), lowBand);
|
setCoeffs(rightChain.get<1>(), lowBand);
|
||||||
@ -415,15 +423,18 @@ void CrystalizerEQAudioProcessor::updateFilters() {
|
|||||||
rightChain.setBypassed<1>(false);
|
rightChain.setBypassed<1>(false);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3: // Bell (Glocke – optional, falls du das Low-Band als Bell nutzen willst)
|
||||||
lowBand = juce::dsp::IIR::Coefficients<float>::makePeakFilter(sr, lowFreq, lowQ, lowGainLin);
|
lowBand = juce::dsp::IIR::Coefficients<float>::makePeakFilter(sr, lowFreq, lowQ, lowGainLin);
|
||||||
setCoeffs(leftChain .get<1>(), lowBand);
|
setCoeffs(leftChain .get<1>(), lowBand);
|
||||||
setCoeffs(rightChain.get<1>(), lowBand);
|
setCoeffs(rightChain.get<1>(), lowBand);
|
||||||
leftChain .setBypassed<1>(false);
|
leftChain .setBypassed<1>(false);
|
||||||
rightChain.setBypassed<1>(false);
|
rightChain.setBypassed<1>(false);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//HIGH-BAND
|
//HIGH-BAND
|
||||||
const float highGainHin = juce::Decibels::decibelsToGain(highGdB);
|
const float highGainHin = juce::Decibels::decibelsToGain(highGdB);
|
||||||
|
|
||||||
@ -456,6 +467,7 @@ void CrystalizerEQAudioProcessor::updateFilters() {
|
|||||||
setCoeffs(rightChain.get<11>(), highBand);
|
setCoeffs(rightChain.get<11>(), highBand);
|
||||||
|
|
||||||
|
|
||||||
|
//HIER SLOPE IMPLEMENTIEREN
|
||||||
leftChain .setBypassed<9>(highSlope < 2);
|
leftChain .setBypassed<9>(highSlope < 2);
|
||||||
rightChain.setBypassed<9>(highSlope < 2);
|
rightChain.setBypassed<9>(highSlope < 2);
|
||||||
leftChain .setBypassed<10>(highSlope < 3);
|
leftChain .setBypassed<10>(highSlope < 3);
|
||||||
@ -466,6 +478,7 @@ void CrystalizerEQAudioProcessor::updateFilters() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
|
// Q steuert die „Güte“/Steilheit des Übergangs
|
||||||
highBand = juce::dsp::IIR::Coefficients<float>::makeHighShelf(sr, highFreq, highQ, highGainHin);
|
highBand = juce::dsp::IIR::Coefficients<float>::makeHighShelf(sr, highFreq, highQ, highGainHin);
|
||||||
setCoeffs(leftChain .get<8>(), highBand);
|
setCoeffs(leftChain .get<8>(), highBand);
|
||||||
setCoeffs(rightChain.get<8>(), highBand);
|
setCoeffs(rightChain.get<8>(), highBand);
|
||||||
@ -473,7 +486,7 @@ void CrystalizerEQAudioProcessor::updateFilters() {
|
|||||||
rightChain.setBypassed<8>(false);
|
rightChain.setBypassed<8>(false);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3: // Bell (Glocke – optional, falls du das Low-Band als Bell nutzen willst)
|
||||||
highBand = juce::dsp::IIR::Coefficients<float>::makePeakFilter(sr, highFreq, highQ, highGainHin);
|
highBand = juce::dsp::IIR::Coefficients<float>::makePeakFilter(sr, highFreq, highQ, highGainHin);
|
||||||
setCoeffs(leftChain .get<8>(), highBand);
|
setCoeffs(leftChain .get<8>(), highBand);
|
||||||
setCoeffs(rightChain.get<8>(), highBand);
|
setCoeffs(rightChain.get<8>(), highBand);
|
||||||
@ -481,6 +494,7 @@ void CrystalizerEQAudioProcessor::updateFilters() {
|
|||||||
rightChain.setBypassed<8>(false);
|
rightChain.setBypassed<8>(false);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!crystalized) {
|
if (!crystalized) {
|
||||||
@ -495,21 +509,24 @@ void CrystalizerEQAudioProcessor::updateFilters() {
|
|||||||
rightChain.setBypassed<13>(false);
|
rightChain.setBypassed<13>(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
lowCutActive = (lowBandModes == 1);
|
|
||||||
highCutActive = (highBandModes == 1);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
juce::String CrystalizerEQAudioProcessor::savePresetToFile() const {
|
juce::String CrystalizerEQAudioProcessor::savePresetToFile() const {
|
||||||
const auto nameInput = getPresetName();
|
const auto nameInput = getPresetName();
|
||||||
|
|
||||||
auto appData = juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory);
|
|
||||||
|
|
||||||
auto presetFolder = appData.getChildFile("AXIOM")
|
auto desktop = juce::File::getSpecialLocation(juce::File::userDesktopDirectory);
|
||||||
.getChildFile("CrystalizerEQ")
|
|
||||||
.getChildFile("Presets");
|
|
||||||
|
|
||||||
|
// Unterordner auf dem Desktop anlegen
|
||||||
|
auto presetFolder = desktop.getChildFile("CrystalizerEQ_Presets");
|
||||||
presetFolder.createDirectory();
|
presetFolder.createDirectory();
|
||||||
|
|
||||||
|
// Datei vorbereiten
|
||||||
auto file = presetFolder.getNonexistentChildFile(nameInput, ".xml");
|
auto file = presetFolder.getNonexistentChildFile(nameInput, ".xml");
|
||||||
|
|
||||||
juce::ValueTree preset ("Preset");
|
juce::ValueTree preset ("Preset");
|
||||||
@ -518,8 +535,10 @@ juce::String CrystalizerEQAudioProcessor::savePresetToFile() const {
|
|||||||
for (auto* p : getParameters()) {
|
for (auto* p : getParameters()) {
|
||||||
if (p == nullptr) continue;
|
if (p == nullptr) continue;
|
||||||
|
|
||||||
if (auto *ranged = dynamic_cast<juce::RangedAudioParameter *>(p)) {
|
if (auto* ranged = dynamic_cast<juce::RangedAudioParameter*>(p))
|
||||||
if (ranged->getParameterID() == "MasterBypass") { continue; }
|
{
|
||||||
|
if (ranged->getParameterID() == "MasterBypass")
|
||||||
|
{continue;}
|
||||||
|
|
||||||
juce::ValueTree param ("Param");
|
juce::ValueTree param ("Param");
|
||||||
param.setProperty("id", ranged->getParameterID(), nullptr);
|
param.setProperty("id", ranged->getParameterID(), nullptr);
|
||||||
@ -536,12 +555,16 @@ juce::String CrystalizerEQAudioProcessor::savePresetToFile() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CrystalizerEQAudioProcessor::loadPreset(const juce::String &preset){
|
void CrystalizerEQAudioProcessor::loadPreset(const juce::String &preset){
|
||||||
auto appData = juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory);
|
|
||||||
auto presetFolder = appData.getChildFile("AXIOM")
|
|
||||||
.getChildFile("CrystalizerEQ")
|
|
||||||
.getChildFile("Presets");
|
|
||||||
|
|
||||||
auto files = presetFolder.findChildFiles(juce::File::findFiles, false, "*.xml");
|
auto desktop = juce::File::getSpecialLocation(juce::File::userDesktopDirectory);
|
||||||
|
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
for (const auto& f : files) {
|
for (const auto& f : files) {
|
||||||
if (f.getFileName() != preset) {
|
if (f.getFileName() != preset) {
|
||||||
@ -556,8 +579,10 @@ void CrystalizerEQAudioProcessor::loadPreset(const juce::String &preset) {
|
|||||||
if (p == nullptr) continue;
|
if (p == nullptr) continue;
|
||||||
|
|
||||||
if (auto* ranged = dynamic_cast<juce::RangedAudioParameter*>(p)) {
|
if (auto* ranged = dynamic_cast<juce::RangedAudioParameter*>(p)) {
|
||||||
if (auto *child = xml->getFirstChildElement()) {
|
if (auto* child = xml->getFirstChildElement())
|
||||||
while (child != nullptr) {
|
{
|
||||||
|
while (child != nullptr)
|
||||||
|
{
|
||||||
juce::String id = child->getStringAttribute("id");
|
juce::String id = child->getStringAttribute("id");
|
||||||
|
|
||||||
if (id == ranged->getParameterID()) {
|
if (id == ranged->getParameterID()) {
|
||||||
@ -576,15 +601,15 @@ void CrystalizerEQAudioProcessor::loadPreset(const juce::String &preset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CrystalizerEQAudioProcessor::deletePreset(const juce::String &preset) const{
|
void CrystalizerEQAudioProcessor::deletePreset(const juce::String &preset) const{
|
||||||
auto appData = juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory);
|
auto desktop = juce::File::getSpecialLocation(juce::File::userDesktopDirectory);
|
||||||
auto presetFolder = appData.getChildFile("AXIOM")
|
|
||||||
.getChildFile("CrystalizerEQ")
|
// Unterordner auf dem Desktop anlegen
|
||||||
.getChildFile("Presets");
|
auto presetFolder = desktop.getChildFile("CrystalizerEQ_Presets");
|
||||||
|
|
||||||
juce::Array<juce::File> files = presetFolder.findChildFiles(
|
juce::Array<juce::File> files = presetFolder.findChildFiles(
|
||||||
juce::File::findFiles,
|
juce::File::findFiles, // nur Dateien (nicht Ordner)
|
||||||
false,
|
false, // nicht rekursiv (kein Durchsuchen von Unterordnern)
|
||||||
"*.xml"
|
"*.xml" // Pattern: alle Dateien
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const auto& f : files) {
|
for (const auto& f : files) {
|
||||||
@ -599,29 +624,35 @@ void CrystalizerEQAudioProcessor::resetAllParameters() const {
|
|||||||
for (auto* p : getParameters()) {
|
for (auto* p : getParameters()) {
|
||||||
if (p == nullptr) continue;
|
if (p == nullptr) continue;
|
||||||
|
|
||||||
if (auto *ranged = dynamic_cast<juce::RangedAudioParameter *>(p)) {
|
if (auto* ranged = dynamic_cast<juce::RangedAudioParameter*>(p))
|
||||||
const float def = ranged->getDefaultValue();
|
{
|
||||||
|
const float def = ranged->getDefaultValue(); // normalisiert [0..1]
|
||||||
ranged->beginChangeGesture();
|
ranged->beginChangeGesture();
|
||||||
ranged->setValueNotifyingHost(def);
|
ranged->setValueNotifyingHost(def);
|
||||||
ranged->endChangeGesture();
|
ranged->endChangeGesture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrystalizerEQAudioProcessor::parameterChanged(const juce::String &id, float v) {
|
void CrystalizerEQAudioProcessor::parameterChanged (const juce::String& id, float v)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
juce::StringArray CrystalizerEQAudioProcessor::getPresetNamesArray() const{
|
juce::StringArray CrystalizerEQAudioProcessor::getPresetNamesArray() const{
|
||||||
|
|
||||||
juce::StringArray presetNames = {"Init"};
|
juce::StringArray presetNames = {"Init"};
|
||||||
auto appData = juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory);
|
auto desktop = juce::File::getSpecialLocation(juce::File::userDesktopDirectory);
|
||||||
auto presetFolder = appData.getChildFile("AXIOM")
|
|
||||||
.getChildFile("CrystalizerEQ")
|
// Unterordner auf dem Desktop anlegen
|
||||||
.getChildFile("Presets");
|
auto presetFolder = desktop.getChildFile("CrystalizerEQ_Presets");
|
||||||
|
|
||||||
juce::Array<juce::File> files = presetFolder.findChildFiles(
|
juce::Array<juce::File> files = presetFolder.findChildFiles(
|
||||||
juce::File::findFiles,
|
juce::File::findFiles, // nur Dateien (nicht Ordner)
|
||||||
false,
|
false, // nicht rekursiv (kein Durchsuchen von Unterordnern)
|
||||||
"*.xml"
|
"*.xml" // Pattern: alle Dateien
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const auto& f : files) {
|
for (const auto& f : files) {
|
||||||
@ -632,13 +663,15 @@ juce::StringArray CrystalizerEQAudioProcessor::getPresetNamesArray() const {
|
|||||||
return presetNames;
|
return presetNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrystalizerEQAudioProcessor::releaseResources() {
|
void CrystalizerEQAudioProcessor::releaseResources()
|
||||||
|
{
|
||||||
// When playback stops, you can use this as an opportunity to free up any
|
// When playback stops, you can use this as an opportunity to free up any
|
||||||
// spare memory, etc.
|
// spare memory, etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef JucePlugin_PreferredChannelConfigurations
|
#ifndef JucePlugin_PreferredChannelConfigurations
|
||||||
bool CrystalizerEQAudioProcessor::isBusesLayoutSupported(const BusesLayout &layouts) const {
|
bool CrystalizerEQAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
|
||||||
|
{
|
||||||
#if JucePlugin_IsMidiEffect
|
#if JucePlugin_IsMidiEffect
|
||||||
juce::ignoreUnused (layouts);
|
juce::ignoreUnused (layouts);
|
||||||
return true;
|
return true;
|
||||||
@ -662,17 +695,66 @@ bool CrystalizerEQAudioProcessor::isBusesLayoutSupported(const BusesLayout &layo
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void CrystalizerEQAudioProcessor::processBlock(juce::AudioBuffer<float> &buffer, juce::MidiBuffer &midiMessages) {
|
void CrystalizerEQAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
juce::ignoreUnused (midiMessages);
|
juce::ignoreUnused (midiMessages);
|
||||||
juce::ScopedNoDenormals noDenormals;
|
juce::ScopedNoDenormals noDenormals;
|
||||||
auto totalNumInputChannels = getTotalNumInputChannels();
|
auto totalNumInputChannels = getTotalNumInputChannels();
|
||||||
auto totalNumOutputChannels = getTotalNumOutputChannels();
|
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)
|
for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
|
||||||
buffer.clear (i, 0, buffer.getNumSamples());
|
buffer.clear (i, 0, buffer.getNumSamples());
|
||||||
|
|
||||||
juce::AudioBuffer<float> lowBuf, highBuf;
|
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;
|
const bool masterBypassed = apvts.getRawParameterValue("MasterBypass")->load() > 0.5f;
|
||||||
if (masterBypassed)
|
if (masterBypassed)
|
||||||
return;
|
return;
|
||||||
@ -686,16 +768,18 @@ void CrystalizerEQAudioProcessor::processBlock(juce::AudioBuffer<float> &buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
updateFilters();
|
updateFilters();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
juce::dsp::AudioBlock<float> block (buffer);
|
juce::dsp::AudioBlock<float> block (buffer);
|
||||||
|
|
||||||
|
|
||||||
auto leftBlock = block.getSingleChannelBlock (0);
|
auto leftBlock = block.getSingleChannelBlock (0);
|
||||||
auto rightBlock = block.getSingleChannelBlock (1);
|
auto rightBlock = block.getSingleChannelBlock (1);
|
||||||
|
|
||||||
|
|
||||||
juce::dsp::ProcessContextReplacing<float> leftCtx (leftBlock);
|
juce::dsp::ProcessContextReplacing<float> leftCtx (leftBlock);
|
||||||
juce::dsp::ProcessContextReplacing<float> rightCtx(rightBlock);
|
juce::dsp::ProcessContextReplacing<float> rightCtx(rightBlock);
|
||||||
|
|
||||||
@ -703,11 +787,12 @@ void CrystalizerEQAudioProcessor::processBlock(juce::AudioBuffer<float> &buffer,
|
|||||||
rightChain.process (rightCtx);
|
rightChain.process (rightCtx);
|
||||||
|
|
||||||
audioFIFO.loadSamplesToFIFO(buffer);
|
audioFIFO.loadSamplesToFIFO(buffer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
juce::AudioBuffer<float> CrystalizerEQAudioProcessor::processMultiBand(juce::AudioBuffer<float> &lowBuf,
|
juce::AudioBuffer<float> CrystalizerEQAudioProcessor::processMultiBand(juce::AudioBuffer<float>& lowBuf, juce::AudioBuffer<float>& highBuf) {
|
||||||
juce::AudioBuffer<float> &highBuf) {
|
|
||||||
const auto sr = getSampleRate();
|
const auto sr = getSampleRate();
|
||||||
float fc = 10000.0f;
|
float fc = 10000.0f;
|
||||||
fc = juce::jlimit(20.0f, 0.49f * (float)sr, fc);
|
fc = juce::jlimit(20.0f, 0.49f * (float)sr, fc);
|
||||||
@ -716,15 +801,12 @@ juce::AudioBuffer<float> CrystalizerEQAudioProcessor::processMultiBand(juce::Aud
|
|||||||
auto lp = Coeff::makeLowPass (sr, fc, 0.7071f);
|
auto lp = Coeff::makeLowPass (sr, fc, 0.7071f);
|
||||||
auto hp = Coeff::makeHighPass(sr, fc, 0.7071f);
|
auto hp = Coeff::makeHighPass(sr, fc, 0.7071f);
|
||||||
|
|
||||||
mbLowpassL.setType(juce::dsp::LinkwitzRileyFilterType::lowpass);
|
mbLowpass.setType(juce::dsp::LinkwitzRileyFilterType::lowpass);
|
||||||
mbLowpassL.setCutoffFrequency(fc);
|
mbLowpass.setCutoffFrequency(fc);
|
||||||
mbLowpassR.setType(juce::dsp::LinkwitzRileyFilterType::lowpass);
|
|
||||||
mbLowpassR.setCutoffFrequency(fc);
|
mbHighpass.setType(juce::dsp::LinkwitzRileyFilterType::highpass);
|
||||||
|
mbHighpass.setCutoffFrequency(fc);
|
||||||
|
|
||||||
mbHighpassL.setType(juce::dsp::LinkwitzRileyFilterType::highpass);
|
|
||||||
mbHighpassL.setCutoffFrequency(fc);
|
|
||||||
mbHighpassR.setType(juce::dsp::LinkwitzRileyFilterType::highpass);
|
|
||||||
mbHighpassR.setCutoffFrequency(fc);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
juce::dsp::AudioBlock<float> lowBlock(lowBuf);
|
juce::dsp::AudioBlock<float> lowBlock(lowBuf);
|
||||||
@ -733,10 +815,11 @@ juce::AudioBuffer<float> CrystalizerEQAudioProcessor::processMultiBand(juce::Aud
|
|||||||
juce::dsp::ProcessContextReplacing<float> leftLowCtx(leftLowBlock);
|
juce::dsp::ProcessContextReplacing<float> leftLowCtx(leftLowBlock);
|
||||||
juce::dsp::ProcessContextReplacing<float> rightLowCtx(rightLowBlock);
|
juce::dsp::ProcessContextReplacing<float> rightLowCtx(rightLowBlock);
|
||||||
|
|
||||||
mbLowpassL.process(leftLowCtx);
|
mbLowpass.process(leftLowCtx);
|
||||||
mbLowpassR.process(rightLowCtx);
|
mbLowpass.process(rightLowCtx);
|
||||||
|
}
|
||||||
|
|
||||||
} {
|
{
|
||||||
//HIGH-BAND PROCESSING
|
//HIGH-BAND PROCESSING
|
||||||
juce::dsp::AudioBlock<float> highBlock(highBuf);
|
juce::dsp::AudioBlock<float> highBlock(highBuf);
|
||||||
auto leftHighBlock = highBlock.getSingleChannelBlock (0);
|
auto leftHighBlock = highBlock.getSingleChannelBlock (0);
|
||||||
@ -744,8 +827,8 @@ juce::AudioBuffer<float> CrystalizerEQAudioProcessor::processMultiBand(juce::Aud
|
|||||||
juce::dsp::ProcessContextReplacing<float> leftHighCtx(leftHighBlock);
|
juce::dsp::ProcessContextReplacing<float> leftHighCtx(leftHighBlock);
|
||||||
juce::dsp::ProcessContextReplacing<float> rightHighCtx(rightHighBlock);
|
juce::dsp::ProcessContextReplacing<float> rightHighCtx(rightHighBlock);
|
||||||
|
|
||||||
mbHighpassL.process(leftHighCtx);
|
mbHighpass.process(leftHighCtx);
|
||||||
mbHighpassR.process(rightHighCtx);
|
mbHighpass.process(rightHighCtx);
|
||||||
|
|
||||||
|
|
||||||
//WHITE NOISE ON HIGH-BAND
|
//WHITE NOISE ON HIGH-BAND
|
||||||
@ -753,27 +836,25 @@ juce::AudioBuffer<float> CrystalizerEQAudioProcessor::processMultiBand(juce::Aud
|
|||||||
const int numSamples = highBuf.getNumSamples();
|
const int numSamples = highBuf.getNumSamples();
|
||||||
const int numChannels = highBuf.getNumChannels();
|
const int numChannels = highBuf.getNumChannels();
|
||||||
|
|
||||||
const float rmsL = highBuf.getRMSLevel(0, 0, numSamples);
|
const float rms = highBuf.getRMSLevel(0, 0, numSamples); // oder Mittelwert über beide Kanäle
|
||||||
const float rmsR = highBuf.getRMSLevel(1, 0, numSamples);
|
const float dyn = juce::jlimit(0.0f, 1.0f, rms * 2.0f); // einfacher Kompressor
|
||||||
const float rms = (rmsL + rmsR) * 0.5f;
|
const float gain = dyn * juce::Decibels::decibelsToGain(.5f);
|
||||||
|
|
||||||
const float dyn = juce::jlimit(0.0f, 1.0f, rms * 2.0f);
|
|
||||||
const float gain = dyn * juce::Decibels::decibelsToGain(-3.0f);
|
|
||||||
|
|
||||||
|
|
||||||
for (int ch = 0; ch < numChannels; ++ch) {
|
for (int ch = 0; ch < numChannels; ++ch) {
|
||||||
auto* write = highBuf.getWritePointer (ch);
|
auto* write = highBuf.getWritePointer (ch);
|
||||||
auto& rng = (ch == 0 ? noiseRandL : noiseRandR);
|
auto& rng = (ch == 0 ? noiseRandL : noiseRandR);
|
||||||
|
|
||||||
for (int n = 0; n < numSamples; ++n) {
|
for (int n = 0; n < numSamples; ++n)
|
||||||
|
{
|
||||||
// rng.nextFloat() ∈ [0,1) → in [-1,1)
|
// rng.nextFloat() ∈ [0,1) → in [-1,1)
|
||||||
const float white = 2.0f * rng.nextFloat() - 1.0f;
|
const float white = 2.0f * rng.nextFloat() - 1.0f;
|
||||||
write[n] += white * gain; // ERSETZEN des Host-Inputs
|
write[n] += white * gain; // ERSETZEN des Host-Inputs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saturatorL.process(leftHighCtx);
|
saturator.process(leftHighCtx);
|
||||||
saturatorR.process(rightHighCtx);
|
saturator.process(rightHighCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -782,47 +863,57 @@ juce::AudioBuffer<float> CrystalizerEQAudioProcessor::processMultiBand(juce::Aud
|
|||||||
|
|
||||||
const int numCh = out.getNumChannels();
|
const int numCh = out.getNumChannels();
|
||||||
const int numSm = out.getNumSamples();
|
const int numSm = out.getNumSamples();
|
||||||
const float highBandGain = juce::Decibels::decibelsToGain(3.0f);
|
|
||||||
for (int ch = 0; ch < numCh; ++ch)
|
for (int ch = 0; ch < numCh; ++ch)
|
||||||
out.addFrom(ch, 0, highBuf, ch, 0, numSm, highBandGain);
|
out.addFrom(ch, 0, highBuf, ch, 0, numSm, 1.0f);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CrystalizerEQAudioProcessor::setPresetName(const juce::String &name) {
|
|
||||||
|
void CrystalizerEQAudioProcessor::setPresetName (const juce::String& name)
|
||||||
|
{
|
||||||
presetName = name;
|
presetName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
bool CrystalizerEQAudioProcessor::hasEditor() const {
|
bool CrystalizerEQAudioProcessor::hasEditor() const
|
||||||
|
{
|
||||||
return true; // (change this to false if you choose to not supply an editor)
|
return true; // (change this to false if you choose to not supply an editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
juce::AudioProcessorEditor *CrystalizerEQAudioProcessor::createEditor() {
|
juce::AudioProcessorEditor* CrystalizerEQAudioProcessor::createEditor()
|
||||||
|
{
|
||||||
return new CrystalizerEQAudioProcessorEditor (*this);
|
return new CrystalizerEQAudioProcessorEditor (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void CrystalizerEQAudioProcessor::getStateInformation(juce::MemoryBlock &destData) {
|
void CrystalizerEQAudioProcessor::getStateInformation (juce::MemoryBlock& destData)
|
||||||
|
{
|
||||||
// You should use this method to store your parameters in the memory block.
|
// You should use this method to store your parameters in the memory block.
|
||||||
// You could do that either as raw data, or use the XML or ValueTree classes
|
// You could do that either as raw data, or use the XML or ValueTree classes
|
||||||
// as intermediaries to make it easy to save and load complex data.
|
// as intermediaries to make it easy to save and load complex data.
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrystalizerEQAudioProcessor::setStateInformation(const void *data, int sizeInBytes) {
|
void CrystalizerEQAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
|
||||||
|
{
|
||||||
// You should use this method to restore your parameters from this memory block,
|
// You should use this method to restore your parameters from this memory block,
|
||||||
// whose contents will have been created by the getStateInformation() call.
|
// whose contents will have been created by the getStateInformation() call.
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
// This creates new instances of the plugin..
|
// This creates new instances of the plugin..
|
||||||
juce::AudioProcessor * JUCE_CALLTYPE createPluginFilter() {
|
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter()
|
||||||
|
{
|
||||||
return new CrystalizerEQAudioProcessor();
|
return new CrystalizerEQAudioProcessor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AudioFIFO::loadSamplesToFIFO(const juce::AudioBuffer<float> &samples) {
|
void AudioFIFO::loadSamplesToFIFO(const juce::AudioBuffer<float> &samples) {
|
||||||
const int numSamples = samples.getNumSamples();
|
const int numSamples = samples.getNumSamples();
|
||||||
|
|
||||||
@ -831,16 +922,20 @@ void AudioFIFO::loadSamplesToFIFO(const juce::AudioBuffer<float> &samples) {
|
|||||||
const juce::SpinLock::ScopedLockType guard(lock); // <— NEU
|
const juce::SpinLock::ScopedLockType guard(lock); // <— NEU
|
||||||
sampleStack.ensureStorageAllocated(sampleStack.size() + numSamples);
|
sampleStack.ensureStorageAllocated(sampleStack.size() + numSamples);
|
||||||
|
|
||||||
for (int i = 0; i < numSamples; ++i) {
|
for (int i = 0; i < numSamples; ++i)
|
||||||
|
{
|
||||||
sampleStack.add(channelData[i]);
|
sampleStack.add(channelData[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
juce::Array<float> AudioFIFO::sendSamplesToEditor(){
|
juce::Array<float> AudioFIFO::sendSamplesToEditor(){
|
||||||
|
|
||||||
const juce::SpinLock::ScopedLockType guard(lock);
|
const juce::SpinLock::ScopedLockType guard(lock);
|
||||||
juce::Array<float> copiedSamples = sampleStack;
|
juce::Array<float> copiedSamples = sampleStack;
|
||||||
sampleStack.clear();
|
sampleStack.clear();
|
||||||
|
|
||||||
return copiedSamples;
|
return copiedSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,33 +18,29 @@
|
|||||||
class AudioFIFO {
|
class AudioFIFO {
|
||||||
public:
|
public:
|
||||||
AudioFIFO();
|
AudioFIFO();
|
||||||
|
|
||||||
~AudioFIFO();
|
~AudioFIFO();
|
||||||
|
|
||||||
juce::Array<float> sampleStack;
|
juce::Array<float> sampleStack;
|
||||||
|
|
||||||
void loadSamplesToFIFO(const juce::AudioBuffer<float> &samples);
|
void loadSamplesToFIFO(const juce::AudioBuffer<float> &samples);
|
||||||
|
|
||||||
juce::Array<float> sendSamplesToEditor();
|
juce::Array<float> sendSamplesToEditor();
|
||||||
|
|
||||||
juce::SpinLock lock;
|
juce::SpinLock lock;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CrystalizerEQAudioProcessor : public juce::AudioProcessor, public juce::AudioProcessorValueTreeState::Listener {
|
class CrystalizerEQAudioProcessor : public juce::AudioProcessor , public juce::AudioProcessorValueTreeState::Listener
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
CrystalizerEQAudioProcessor();
|
CrystalizerEQAudioProcessor();
|
||||||
|
|
||||||
~CrystalizerEQAudioProcessor() override;
|
~CrystalizerEQAudioProcessor() override;
|
||||||
|
|
||||||
void parameterChanged (const juce::String& id, float newValue) override;
|
void parameterChanged (const juce::String& id, float newValue) override;
|
||||||
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void prepareToPlay (double sampleRate, int samplesPerBlock) override;
|
void prepareToPlay (double sampleRate, int samplesPerBlock) override;
|
||||||
|
|
||||||
void releaseResources() override;
|
void releaseResources() override;
|
||||||
|
|
||||||
#ifndef JucePlugin_PreferredChannelConfigurations
|
#ifndef JucePlugin_PreferredChannelConfigurations
|
||||||
@ -55,44 +51,33 @@ public:
|
|||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
juce::AudioProcessorEditor* createEditor() override;
|
juce::AudioProcessorEditor* createEditor() override;
|
||||||
|
|
||||||
bool hasEditor() const override;
|
bool hasEditor() const override;
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
const juce::String getName() const override;
|
const juce::String getName() const override;
|
||||||
|
|
||||||
bool acceptsMidi() const override;
|
bool acceptsMidi() const override;
|
||||||
|
|
||||||
bool producesMidi() const override;
|
bool producesMidi() const override;
|
||||||
|
|
||||||
bool isMidiEffect() const override;
|
bool isMidiEffect() const override;
|
||||||
|
|
||||||
double getTailLengthSeconds() const override;
|
double getTailLengthSeconds() const override;
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
int getNumPrograms() override;
|
int getNumPrograms() override;
|
||||||
|
|
||||||
int getCurrentProgram() override;
|
int getCurrentProgram() override;
|
||||||
|
|
||||||
void setCurrentProgram (int index) override;
|
void setCurrentProgram (int index) override;
|
||||||
|
|
||||||
const juce::String getProgramName (int index) override;
|
const juce::String getProgramName (int index) override;
|
||||||
|
|
||||||
void changeProgramName (int index, const juce::String& newName) override;
|
void changeProgramName (int index, const juce::String& newName) override;
|
||||||
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void getStateInformation (juce::MemoryBlock& destData) override;
|
void getStateInformation (juce::MemoryBlock& destData) override;
|
||||||
|
|
||||||
void setStateInformation (const void* data, int sizeInBytes) override;
|
void setStateInformation (const void* data, int sizeInBytes) override;
|
||||||
|
|
||||||
// --------- Parameter (APVTS) ----------
|
// --------- Parameter (APVTS) ----------
|
||||||
static juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
|
static juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
|
||||||
|
|
||||||
juce::AudioProcessorValueTreeState apvts { *this, nullptr, "PARAMS", createParameterLayout() };
|
juce::AudioProcessorValueTreeState apvts { *this, nullptr, "PARAMS", createParameterLayout() };
|
||||||
|
|
||||||
void setPresetName (const juce::String& s);
|
void setPresetName (const juce::String& s);
|
||||||
|
|
||||||
juce::String getPresetName() const noexcept { return presetName; }
|
juce::String getPresetName() const noexcept { return presetName; }
|
||||||
|
|
||||||
juce::StringArray getPresetNamesArray() const;
|
juce::StringArray getPresetNamesArray() const;
|
||||||
@ -105,21 +90,22 @@ public:
|
|||||||
|
|
||||||
void resetAllParameters() const;
|
void resetAllParameters() const;
|
||||||
|
|
||||||
bool lowCutActive = false;
|
|
||||||
bool highCutActive = false;
|
|
||||||
|
|
||||||
AudioFIFO audioFIFO;
|
AudioFIFO audioFIFO;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// --------- EQ-Kette ----------
|
||||||
using Gain = juce::dsp::Gain<float>;
|
using Gain = juce::dsp::Gain<float>;
|
||||||
using Filter = juce::dsp::IIR::Filter<float>;
|
using Filter = juce::dsp::IIR::Filter<float>;
|
||||||
using Chain = juce::dsp::ProcessorChain<Gain, Filter, Filter, Filter, Filter, Filter, Filter, Filter, Filter, Filter
|
using Chain = juce::dsp::ProcessorChain<Gain, Filter, Filter, Filter, Filter, Filter, Filter, Filter, Filter, Filter, Filter, Filter, Filter, Filter, Gain>; // 0: LowCut (HP), 1: Peak, 2: HighCut (LP)
|
||||||
, Filter, Filter, Filter, Filter, Gain>; // 0: LowCut (HP), 1: Peak, 2: HighCut (LP)
|
|
||||||
juce::Random noiseRandL, noiseRandR;
|
juce::Random noiseRandL, noiseRandR;
|
||||||
Chain leftChain, rightChain;
|
Chain leftChain, rightChain;
|
||||||
|
|
||||||
|
|
||||||
void updateFilters();
|
void updateFilters(); // Koeffizienten aus Parametern berechnen
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
juce::AudioBuffer<float> processMultiBand(juce::AudioBuffer<float>& lowBuf, juce::AudioBuffer<float>& highBuf);
|
juce::AudioBuffer<float> processMultiBand(juce::AudioBuffer<float>& lowBuf, juce::AudioBuffer<float>& highBuf);
|
||||||
@ -127,13 +113,10 @@ private:
|
|||||||
|
|
||||||
using Coeff = juce::dsp::IIR::Coefficients<float>;
|
using Coeff = juce::dsp::IIR::Coefficients<float>;
|
||||||
|
|
||||||
|
juce::dsp::LinkwitzRileyFilter<float> mbLowpass;
|
||||||
juce::dsp::IIR::Filter<float> mbHighPeakL;
|
juce::dsp::LinkwitzRileyFilter<float> mbHighpass;
|
||||||
juce::dsp::IIR::Filter<float> mbHighPeakR;
|
juce::dsp::IIR::Filter<float> mbHighPeak;
|
||||||
|
juce::dsp::WaveShaper<float> saturator;
|
||||||
juce::dsp::LinkwitzRileyFilter<float> mbLowpassL, mbLowpassR;
|
|
||||||
juce::dsp::LinkwitzRileyFilter<float> mbHighpassL, mbHighpassR;
|
|
||||||
juce::dsp::WaveShaper<float> saturatorL, saturatorR;
|
|
||||||
|
|
||||||
|
|
||||||
juce::String presetName { "Init" };
|
juce::String presetName { "Init" };
|
||||||
@ -141,3 +124,5 @@ private:
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CrystalizerEQAudioProcessor)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CrystalizerEQAudioProcessor)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user