Compare commits

...

2 Commits

Author SHA1 Message Date
Legaeli
0eb6325e2e Added analyzer. Fixed some bugs. 2025-11-20 22:24:11 +01:00
Legaeli
da00962842 Finished all sliders. Added logo. 2025-11-13 16:51:12 +01:00
9 changed files with 717 additions and 254 deletions

View File

@ -585,7 +585,7 @@ namespace AXIOM {
std::unique_ptr<juce::XmlElement> svgXml; std::unique_ptr<juce::XmlElement> svgXml;
}; };
class PresetMenuButtonLookAndFeel : public juce::LookAndFeel_V4 { class PresetMenuButtonLookAndFeel : public juce::LookAndFeel_V4 {
public: public:
PresetMenuButtonLookAndFeel() PresetMenuButtonLookAndFeel()
{ {
@ -605,10 +605,7 @@ class PresetMenuButtonLookAndFeel : public juce::LookAndFeel_V4 {
auto hoverFactor = isHovered ? 1.05f : 1.0f; auto hoverFactor = isHovered ? 1.05f : 1.0f;
auto iconBounds = juce::Rectangle<float>(iconSize * hoverFactor, iconSize * hoverFactor) auto iconBounds = juce::Rectangle<float>(iconSize * hoverFactor, iconSize * hoverFactor)
.withCentre(bounds.getCentre()) .withCentre(bounds.getCentre());
.withX(bounds.getX());
// ganz links im Button starten
;
float bypassOpacity = 1.0f; float bypassOpacity = 1.0f;
@ -755,10 +752,6 @@ class PresetMenuButtonLookAndFeel : public juce::LookAndFeel_V4 {
juce::RectanglePlacement::centred, bypassOpacity); juce::RectanglePlacement::centred, bypassOpacity);
} }
} }
} }
@ -880,6 +873,10 @@ class PresetMenuButtonLookAndFeel : public juce::LookAndFeel_V4 {
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") {
layout.textBoxBounds = {};
return layout;
}
auto r = slider.getLocalBounds(); auto r = slider.getLocalBounds();
@ -1025,6 +1022,7 @@ class PresetMenuButtonLookAndFeel : public juce::LookAndFeel_V4 {
class SlopeSliderLookAndFeel : public BaseSliderLookAndFeel { class SlopeSliderLookAndFeel : public BaseSliderLookAndFeel {
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;
@ -1136,20 +1134,25 @@ class PresetMenuButtonLookAndFeel : public juce::LookAndFeel_V4 {
float hoverFactor = 1.0f; float hoverFactor = 1.0f;
auto surfaceCol = Colours::SURFACECOLOUR; auto surfaceCol = Colours::SURFACECOLOUR;
auto accentCol = Colours::ACCENTCOLOUR; auto accentCol = Colours::ACCENTCOLOUR;
auto ringCol = Colours::SURFACEHOVER;
if (isEnabled) { if (isEnabled) {
surfaceCol = isHovered ? Colours::SURFACEBYPASS : Colours::SURFACECOLOUR; surfaceCol = isHovered ? Colours::SURFACEHOVER : Colours::SURFACECOLOUR;
accentCol = isHovered ? Colours::ACCENTHOVER : Colours::ACCENTCOLOUR; accentCol = isHovered ? Colours::ACCENTHOVER : Colours::ACCENTCOLOUR;
ringCol = isHovered ? Colours::SURFACECOLOUR : Colours::SURFACEHOVER;
hoverFactor = isHovered ? 1.05f : 1.0f; hoverFactor = isHovered ? 1.05f : 1.0f;
} else { } else {
surfaceCol = Colours::SURFACEBYPASS; surfaceCol = Colours::SURFACEBYPASS;
accentCol = Colours::ACCENTWEAKCOLOUR; accentCol = Colours::ACCENTWEAKCOLOUR;
ringCol = Colours::SURFACEHOVER;
} }
// Einfacher Ring // 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);
//g.drawEllipse(centreX - radius, centreY - radius, radius * 2.0f, radius * 2.0f, 2.0f);
g.setColour(ringCol);
g.drawEllipse(centreX - radius, centreY - radius, radius * 2.0f, radius * 2.0f, arcPathWidth);
juce::Path valueArc; juce::Path valueArc;
valueArc.addCentredArc(centreX, centreY, radius, radius, valueArc.addCentredArc(centreX, centreY, radius, radius,
@ -1183,7 +1186,7 @@ class PresetMenuButtonLookAndFeel : public juce::LookAndFeel_V4 {
case SizeMode::Freq: return 0.8f; case SizeMode::Freq: return 0.8f;
case SizeMode::Q: return 0.8f; case SizeMode::Q: return 0.8f;
case SizeMode::Slope: return 0.7f; case SizeMode::Slope: return 0.7f;
case SizeMode::Global: return 1.0f; case SizeMode::Global: return 0.8f;
case SizeMode::Mix: return 0.8f; case SizeMode::Mix: return 0.8f;
default: return 1.0f; default: return 1.0f;
} }
@ -1336,6 +1339,118 @@ class PresetMenuButtonLookAndFeel : public juce::LookAndFeel_V4 {
} }
}; };
class PresetMenu : public juce::Component {
public:
PresetMenu(juce::TextEditor* inputField,
juce::TextButton* saveButton,
juce::TextButton* deleteButton) {
addAndMakeVisible(*inputField);
addAndMakeVisible(*saveButton);
addAndMakeVisible(*deleteButton);
}
};
class PresetMenuLookAndFeel : public juce::LookAndFeel_V4 {
public:
void drawCallOutBoxBackground(juce::CallOutBox &callOutBox, juce::Graphics &g, const juce::Path &path, juce::Image &image) override {
g.setColour(Colours::SURFACECOLOUR);
g.fillPath(path);
g.setColour (Colours::FOREGROUNDCOLOUR.withAlpha(0.3f));
g.strokePath (path, juce::PathStrokeType (1.0f));
};
int getCallOutBoxBorderSize (const juce::CallOutBox&) override
{
return 4;
}
};
class PresetButtonsLookAndFeel : public juce::LookAndFeel_V4 {
public:
void drawButtonText(juce::Graphics &g, juce::TextButton &button, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override {
auto bounds = button.getLocalBounds();
// Text holen
auto text = button.getButtonText();
// Farbe wählen
auto isHovered = button.isMouseOver();
bool isEnabled = button.isEnabled();
juce::Colour colour = isHovered ? Colours::FOREGROUNDHOVER : Colours::FOREGROUNDCOLOUR;
if (!isEnabled) colour = colour.withMultipliedAlpha(0.6f);
g.setColour(colour);
// Font einstellen
auto font = Typography::getFont(Typography::Style::Button, 1.0f);
g.setFont(font);
// Text zeichnen
g.drawFittedText(text,
bounds.reduced(4),
juce::Justification::centred,
1);
}
void drawButtonBackground(juce::Graphics& g, juce::Button& button,
const juce::Colour& backgroundColour,
bool shouldDrawButtonAsHighlighted,
bool shouldDrawButtonAsDown) override
{
auto bounds = button.getLocalBounds().toFloat();
bool isHovered = button.isMouseOver();
bool isEnabled = button.isEnabled();
auto colour = isHovered ? Colours::BACKGROUNDHOVER : Colours::BACKGROUNDCOLOUR;
if (!isEnabled) colour = colour.withMultipliedAlpha(0.6f);
g.setColour(colour);
g.fillRoundedRectangle(bounds.reduced(1.0f), 4.0f);
}
};
class PresetComboBoxLookAndFeel : public juce::LookAndFeel_V4 {
public:
juce::PopupMenu::Options getOptionsForComboBoxPopupMenu(juce::ComboBox& box,
juce::Label& label) override
{
// Basis-Options holen
auto options = juce::LookAndFeel_V4::getOptionsForComboBoxPopupMenu(box, label);
// Anzahl der sichtbaren Einträge
const int visibleRows = 5;
// Höhe einer Zeile
auto font = getComboBoxFont(box);
int rowHeight = (int)std::ceil(font.getHeight() * 1.6f);
// Maximale Höhe des Popups
int maxPopupHeight = visibleRows * rowHeight;
// Screen-Bounds der ComboBox
auto boxScreen = box.getScreenBounds();
// Wichtig: Ein sehr breiter aber in der Höhe begrenzter Bereich
// JUCE wird das Popup darin zentrieren
juce::Rectangle<int> constrainedArea(
0, // X: ganze Screen-Breite
boxScreen.getBottom(), // Y: direkt unter der Box
juce::Desktop::getInstance().getDisplays()
.getPrimaryDisplay()->totalArea.getWidth(),
maxPopupHeight // Höhe: nur unsere gewünschten Zeilen
);
options = options.withTargetScreenArea(constrainedArea)
.withStandardItemHeight(rowHeight);
return options;
}
};

View File

@ -164,6 +164,7 @@
<None Include="..\..\Resources\Fonts\Orbitron-Bold.ttf"/> <None Include="..\..\Resources\Fonts\Orbitron-Bold.ttf"/>
<None Include="..\..\Resources\Fonts\Orbitron-Regular.ttf"/> <None Include="..\..\Resources\Fonts\Orbitron-Regular.ttf"/>
<None Include="..\..\Resources\Fonts\Roboto-Regular.ttf"/> <None Include="..\..\Resources\Fonts\Roboto-Regular.ttf"/>
<None Include="..\..\Resources\Icons\logo_icon.svg"/>
<None Include="..\..\Resources\Icons\bell_icon.svg"/> <None Include="..\..\Resources\Icons\bell_icon.svg"/>
<None Include="..\..\Resources\Icons\high_cut_icon.svg"/> <None Include="..\..\Resources\Icons\high_cut_icon.svg"/>
<None Include="..\..\Resources\Icons\high_shelf_icon.svg"/> <None Include="..\..\Resources\Icons\high_shelf_icon.svg"/>

View File

@ -74,6 +74,9 @@
<None Include="..\..\Resources\Fonts\Roboto-Regular.ttf"> <None Include="..\..\Resources\Fonts\Roboto-Regular.ttf">
<Filter>CrystalizerEQ\Resources\Fonts</Filter> <Filter>CrystalizerEQ\Resources\Fonts</Filter>
</None> </None>
<None Include="..\..\Resources\Icons\logo_icon.svg">
<Filter>CrystalizerEQ\Resources\Icons</Filter>
</None>
<None Include="..\..\Resources\Icons\bell_icon.svg"> <None Include="..\..\Resources\Icons\bell_icon.svg">
<Filter>CrystalizerEQ\Resources\Icons</Filter> <Filter>CrystalizerEQ\Resources\Icons</Filter>
</None> </None>

View File

@ -21,6 +21,7 @@
file="Resources/Fonts/Roboto-Regular.ttf"/> file="Resources/Fonts/Roboto-Regular.ttf"/>
</GROUP> </GROUP>
<GROUP id="{3DCFA257-AECE-2625-016F-D02D71FFA24B}" name="Icons"> <GROUP id="{3DCFA257-AECE-2625-016F-D02D71FFA24B}" name="Icons">
<FILE id="RCNwIt" name="logo_icon.svg" compile="0" resource="1" file="Resources/Icons/logo_icon.svg"/>
<FILE id="waE621" name="bell_icon.svg" compile="0" resource="1" file="Resources/Icons/bell_icon.svg"/> <FILE id="waE621" name="bell_icon.svg" compile="0" resource="1" file="Resources/Icons/bell_icon.svg"/>
<FILE id="KOfMYl" name="high_cut_icon.svg" compile="0" resource="1" <FILE id="KOfMYl" name="high_cut_icon.svg" compile="0" resource="1"
file="Resources/Icons/high_cut_icon.svg"/> file="Resources/Icons/high_cut_icon.svg"/>

View File

@ -11413,63 +11413,88 @@ static const unsigned char temp_binary_data_6[] =
const char* RobotoRegular_ttf = (const char*) temp_binary_data_6; const char* RobotoRegular_ttf = (const char*) temp_binary_data_6;
//================== bell_icon.svg ================== //================== logo_icon.svg ==================
static const unsigned char temp_binary_data_7[] = static const unsigned char temp_binary_data_7[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 3100 3100\">\n"
" <g id=\"Ebene_2\" data-name=\"Ebene 2\">\n"
" <circle cx=\"1550.48\" cy=\"1550\" r=\"64\" fill=\"#333\"/>\n"
" </g>\n"
" <g id=\"Ebene_3\" data-name=\"Ebene 3\">\n"
" <path d=\"M1512.64,1563.07c4.53,0,8.47-4.21,9.59-8.78.37-1.57.45-2.93.45-4.86,0-1.36,0-2.5-.3-3.71-.89-4.64-4.46-8.85-9.22-8.85-6.1,0-10.26,5.78-10.26,13.64,0,6.57,3.49,12.57,9.74,12.57ZM1523.38,1559.03c-2.38,4.14-6.65,9.03-12.38,9.03-8.55,0-14.7"
"2-6.85-14.72-17.35,0-11.28,7.73-18.78,16.06-18.78,11.02,0,11.04,9.03,11.04,9.03l1.81-9.03h7.23l-5.27,18.1,5.27,18.03h-7.23\" fill=\"#fcfaf9\"/>\n"
" <path d=\"M1604.67,1546.39c0-9.91-6.59-14.45-18.06-14.45-11.68.09-18.06,4.49-18.06,14.45,0,8.11,9.03,12.65,9.03,12.65l-9.03,1.76v7.23l13.55-3.96v-5.02c-4.11-2.29-8.85-5.06-8.85-10.84,0-7.24,4.4-9.76,13.37-9.69,9.1,0,13.37,2.53,13.37,9.69,0,5.74-4"
".73,8.53-8.85,10.84v5.04l13.55,3.95v-7.23l-9.03-1.76s9.03-4.55,9.03-12.65Z\" fill=\"#fcfaf9\"/>\n"
" <polygon points=\"1534.67 1572.58 1543.71 1550 1536.93 1527.42 1496.29 1527.42 1496.29 1522.9 1541.45 1522.9 1550.48 1540.97 1559.51 1522.9 1604.67 1522.9 1604.67 1527.42 1564.03 1527.42 1557.25 1550 1566.29 1572.58 1604.67 1572.58 1604.67 1577.1"
" 1561.77 1577.1 1550.48 1554.52 1539.19 1577.1 1496.29 1577.1 1496.29 1572.58 1534.67 1572.58\" fill=\"#56feff\"/>\n"
" </g>\n"
" <g id=\"Ebene_5\" data-name=\"Ebene 5\">\n"
" <rect x=\"1582.09\" y=\"1554.52\" width=\"9.03\" height=\"13.55\" fill=\"#333\"/>\n"
" <rect x=\"1581.53\" y=\"1565.63\" width=\"11.31\" height=\"4.42\" fill=\"#333\"/>\n"
" <rect x=\"1585.12\" y=\"1564.25\" width=\"11.31\" height=\"4.42\" transform=\"translate(1131.12 -618.28) rotate(33.56)\" fill=\"#333\"/>\n"
" <polygon points=\"1587.05 1561.29 1584.91 1557.43 1592.17 1553.63 1591.89 1558.6 1587.05 1561.29\" fill=\"#333\"/>\n"
" </g>\n"
"</svg>";
const char* logo_icon_svg = (const char*) temp_binary_data_7;
//================== bell_icon.svg ==================
static const unsigned char temp_binary_data_8[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<svg id=\"Ebene_1\" data-name=\"Ebene 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 28 12.02\">\n" "<svg id=\"Ebene_1\" data-name=\"Ebene 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 28 12.02\">\n"
" <path fill=\"black\" d=\"M0,8.02h4.82c.75,0,1.45-.34,1.92-.92L11.42,1.24c1.32-1.65,3.84-1.65,5.16,0l4.68,5.86c.47.58,1.17.92,1.92.92h4.82v4h-4.82c-.75,0-1.45-.34-1.92-.92l-5.73-7.16c-.79-.98-2.28-.98-3.07,0l-5.73,7.16c-.47.58-1.17.92-1.92.92H0s0-4," " <path fill=\"black\" d=\"M0,8.02h4.82c.75,0,1.45-.34,1.92-.92L11.42,1.24c1.32-1.65,3.84-1.65,5.16,0l4.68,5.86c.47.58,1.17.92,1.92.92h4.82v4h-4.82c-.75,0-1.45-.34-1.92-.92l-5.73-7.16c-.79-.98-2.28-.98-3.07,0l-5.73,7.16c-.47.58-1.17.92-1.92.92H0s0-4,"
"0-4Z\"/>\n" "0-4Z\"/>\n"
"</svg>"; "</svg>";
const char* bell_icon_svg = (const char*) temp_binary_data_7; const char* bell_icon_svg = (const char*) temp_binary_data_8;
//================== high_cut_icon.svg ================== //================== high_cut_icon.svg ==================
static const unsigned char temp_binary_data_8[] = static const unsigned char temp_binary_data_9[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<svg id=\"Ebene_1\" data-name=\"Ebene 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n" "<svg id=\"Ebene_2\" data-name=\"Ebene 2\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 29.49 36.9\">\n"
" <path fill=\"black\" d=\"M24,23.02V4C24,1.79,22.21,0,20,0H.98C.44,0,0,.44,0,.98v2.03c0,.54.44.98.98.98h17.02c1.2,0,2,.8,2,2v17.02c0,.54.44.98.98.98h2.05c.54,0,.98-.44.98-.98Z\"/>\n" " <path d=\"M4.68,17.31v-.81c0-.33.27-.59.59-.59h17.58c1.08,0,2.03.72,2.32,1.76l4.3,15.48c.11.38-.18.75-.57.75h-.78c-.26,0-.49-.17-.57-.42l-4.34-13.89c-.31-1.01-1.24-1.69-2.3-1.69H5.27c-.33,0-.59-.27-.59-.59Z\"/>\n"
"</svg>"; "</svg>";
const char* high_cut_icon_svg = (const char*) temp_binary_data_8; const char* high_cut_icon_svg = (const char*) temp_binary_data_9;
//================== high_shelf_icon.svg ================== //================== high_shelf_icon.svg ==================
static const unsigned char temp_binary_data_9[] = static const unsigned char temp_binary_data_10[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<svg id=\"Ebene_1\" data-name=\"Ebene 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 28 12\">\n" "<svg id=\"Ebene_1\" data-name=\"Ebene 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 28 12\">\n"
" <path fill=\"black\" d=\"M11.23,6.39l5.62-4.77c1.23-1.04,2.79-1.61,4.4-1.61h6.04c.4,0,.72.32.72.72v2.56c0,.4-.32.72-.72.72h-6.08c-1.62,0-3.18.58-4.41,1.63l-5.56,4.75c-1.23,1.05-2.79,1.63-4.41,1.63H.72c-.4,0-.72-.32-.72-.72v-2.56c0-.4.32-.72.72-.72h" " <path fill=\"black\" d=\"M11.23,6.39l5.62-4.77c1.23-1.04,2.79-1.61,4.4-1.61h6.04c.4,0,.72.32.72.72v2.56c0,.4-.32.72-.72.72h-6.08c-1.62,0-3.18.58-4.41,1.63l-5.56,4.75c-1.23,1.05-2.79,1.63-4.41,1.63H.72c-.4,0-.72-.32-.72-.72v-2.56c0-.4.32-.72.72-.72h"
"6.12c1.61,0,3.17-.57,4.4-1.61Z\"/>\n" "6.12c1.61,0,3.17-.57,4.4-1.61Z\"/>\n"
"</svg>"; "</svg>";
const char* high_shelf_icon_svg = (const char*) temp_binary_data_9; const char* high_shelf_icon_svg = (const char*) temp_binary_data_10;
//================== low_cut_icon.svg ================== //================== low_cut_icon.svg ==================
static const unsigned char temp_binary_data_10[] = static const unsigned char temp_binary_data_11[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<svg id=\"Ebene_1\" data-name=\"Ebene 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n" "<svg id=\"Ebene_2\" data-name=\"Ebene 2\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 29.49 36.9\">\n"
" <path fill=\"black\" d=\"M0,23.02V4C0,1.79,1.79,0,4,0h19.02c.54,0,.98.44.98.98v2.03c0,.54-.44.98-.98.98H6c-1.2,0-2,.8-2,2v17.02c0,.54-.44.98-.98.98H.98c-.54,0-.98-.44-.98-.98Z\"/>\n" " <path d=\"M29.49,17.31v-.81c0-.33-.27-.59-.59-.59H11.32c-1.08,0-2.03.72-2.32,1.76l-4.3,15.48c-.11.38.18.75.57.75h.78c.26,0,.49-.17.57-.42l4.34-13.89c.31-1.01,1.24-1.69,2.3-1.69h15.64c.33,0,.59-.27.59-.59Z\"/>\n"
"</svg>"; "</svg>";
const char* low_cut_icon_svg = (const char*) temp_binary_data_10; const char* low_cut_icon_svg = (const char*) temp_binary_data_11;
//================== low_shelf_icon.svg ================== //================== low_shelf_icon.svg ==================
static const unsigned char temp_binary_data_11[] = static const unsigned char temp_binary_data_12[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<svg id=\"Ebene_1\" data-name=\"Ebene 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 28 12\">\n" "<svg id=\"Ebene_1\" data-name=\"Ebene 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 28 12\">\n"
" <path fill=\"black\" d=\"M16.77,6.39L11.15,1.61C9.92.57,8.36,0,6.75,0H.72C.32,0,0,.32,0,.72v2.56c0,.4.32.72.72.72h6.08c1.62,0,3.18.58,4.41,1.63l5.56,4.75c1.23,1.05,2.79,1.63,4.41,1.63h6.11c.4,0,.72-.32.72-.72v-2.56c0-.4-.32-.72-.72-.72h-6.12c-1.61," " <path fill=\"black\" d=\"M16.77,6.39L11.15,1.61C9.92.57,8.36,0,6.75,0H.72C.32,0,0,.32,0,.72v2.56c0,.4.32.72.72.72h6.08c1.62,0,3.18.58,4.41,1.63l5.56,4.75c1.23,1.05,2.79,1.63,4.41,1.63h6.11c.4,0,.72-.32.72-.72v-2.56c0-.4-.32-.72-.72-.72h-6.12c-1.61,"
"0-3.17-.57-4.4-1.61Z\"/>\n" "0-3.17-.57-4.4-1.61Z\"/>\n"
"</svg>"; "</svg>";
const char* low_shelf_icon_svg = (const char*) temp_binary_data_11; const char* low_shelf_icon_svg = (const char*) temp_binary_data_12;
//================== preset_menu_icon.svg ================== //================== preset_menu_icon.svg ==================
static const unsigned char temp_binary_data_12[] = static const unsigned char temp_binary_data_13[] =
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 30 30\" width=\"60px\" height=\"60px\"><path d=\"M 3 7 A 1.0001 1.0001 0 1 0 3 9 L 27 9 A 1.0001 1.0001 0 1 0 27 7 L 3 7 z M 3 14 A 1.0001 1.0001 0 1 0 3 16 L 27 16 A 1.0001 1.0001 0 1 0 27 14 " "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 30 30\" width=\"60px\" height=\"60px\"><path d=\"M 3 7 A 1.0001 1.0001 0 1 0 3 9 L 27 9 A 1.0001 1.0001 0 1 0 27 7 L 3 7 z M 3 14 A 1.0001 1.0001 0 1 0 3 16 L 27 16 A 1.0001 1.0001 0 1 0 27 14 "
"L 3 14 z M 3 21 A 1.0001 1.0001 0 1 0 3 23 L 27 23 A 1.0001 1.0001 0 1 0 27 21 L 3 21 z\" fill=\"black\"/></svg>"; "L 3 14 z M 3 21 A 1.0001 1.0001 0 1 0 3 23 L 27 23 A 1.0001 1.0001 0 1 0 27 21 L 3 21 z\" fill=\"black\"/></svg>";
const char* preset_menu_icon_svg = (const char*) temp_binary_data_12; const char* preset_menu_icon_svg = (const char*) temp_binary_data_13;
//================== crystalize_button_active_icon.svg ================== //================== crystalize_button_active_icon.svg ==================
static const unsigned char temp_binary_data_13[] = static const unsigned char temp_binary_data_14[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<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"
@ -11548,10 +11573,10 @@ static const unsigned char temp_binary_data_13[] =
" </g>\n" " </g>\n"
"</svg>"; "</svg>";
const char* crystalize_button_active_icon_svg = (const char*) temp_binary_data_13; const char* crystalize_button_active_icon_svg = (const char*) temp_binary_data_14;
//================== crystalize_button_passive_icon.svg ================== //================== crystalize_button_passive_icon.svg ==================
static const unsigned char temp_binary_data_14[] = static const unsigned char temp_binary_data_15[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<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"
@ -11629,17 +11654,17 @@ static const unsigned char temp_binary_data_14[] =
" </g>\n" " </g>\n"
"</svg>"; "</svg>";
const char* crystalize_button_passive_icon_svg = (const char*) temp_binary_data_14; const char* crystalize_button_passive_icon_svg = (const char*) temp_binary_data_15;
//================== bypass_icon.svg ================== //================== bypass_icon.svg ==================
static const unsigned char temp_binary_data_15[] = static const unsigned char temp_binary_data_16[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<svg id=\"Ebene_1\" data-name=\"Ebene 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 22 23\">\n" "<svg id=\"Ebene_1\" data-name=\"Ebene 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 22 23\">\n"
" <rect x=\"10\" width=\"2\" height=\"12\"/>\n" " <rect x=\"10\" width=\"2\" height=\"12\"/>\n"
" <path d=\"M13,1.19v1.87c4.1.91,7.17,4.57,7.17,8.94,0,5.06-4.1,9.17-9.17,9.17S1.83,17.06,1.83,12C1.83,7.63,4.9,3.97,9,3.06v-1.87C3.88,2.13,0,6.61,0,12c0,6.08,4.92,11,11,11s11-4.92,11-11c0-5.39-3.88-9.87-9-10.81Z\" fill=\"black\"/>\n" " <path d=\"M13,1.19v1.87c4.1.91,7.17,4.57,7.17,8.94,0,5.06-4.1,9.17-9.17,9.17S1.83,17.06,1.83,12C1.83,7.63,4.9,3.97,9,3.06v-1.87C3.88,2.13,0,6.61,0,12c0,6.08,4.92,11,11,11s11-4.92,11-11c0-5.39-3.88-9.87-9-10.81Z\" fill=\"black\"/>\n"
"</svg>"; "</svg>";
const char* bypass_icon_svg = (const char*) temp_binary_data_15; const char* bypass_icon_svg = (const char*) temp_binary_data_16;
const char* getNamedResource (const char* resourceNameUTF8, int& numBytes); const char* getNamedResource (const char* resourceNameUTF8, int& numBytes);
@ -11660,10 +11685,11 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes)
case 0xcbceafb3: numBytes = 24668; return OrbitronBold_ttf; case 0xcbceafb3: numBytes = 24668; return OrbitronBold_ttf;
case 0x9c8232dc: numBytes = 24716; return OrbitronRegular_ttf; case 0x9c8232dc: numBytes = 24716; return OrbitronRegular_ttf;
case 0x93fe9a1e: numBytes = 146004; return RobotoRegular_ttf; case 0x93fe9a1e: numBytes = 146004; return RobotoRegular_ttf;
case 0xa297e1b2: numBytes = 1793; return logo_icon_svg;
case 0x1024555a: numBytes = 397; return bell_icon_svg; case 0x1024555a: numBytes = 397; return bell_icon_svg;
case 0x46c5a278: numBytes = 316; return high_cut_icon_svg; case 0x46c5a278: numBytes = 355; return high_cut_icon_svg;
case 0x0133c050: numBytes = 420; return high_shelf_icon_svg; case 0x0133c050: numBytes = 420; return high_shelf_icon_svg;
case 0x31532e06: numBytes = 317; 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 = 6343; return crystalize_button_active_icon_svg; case 0xd842aaab: numBytes = 6343; return crystalize_button_active_icon_svg;
@ -11685,6 +11711,7 @@ const char* namedResourceList[] =
"OrbitronBold_ttf", "OrbitronBold_ttf",
"OrbitronRegular_ttf", "OrbitronRegular_ttf",
"RobotoRegular_ttf", "RobotoRegular_ttf",
"logo_icon_svg",
"bell_icon_svg", "bell_icon_svg",
"high_cut_icon_svg", "high_cut_icon_svg",
"high_shelf_icon_svg", "high_shelf_icon_svg",
@ -11705,6 +11732,7 @@ const char* originalFilenames[] =
"Orbitron-Bold.ttf", "Orbitron-Bold.ttf",
"Orbitron-Regular.ttf", "Orbitron-Regular.ttf",
"Roboto-Regular.ttf", "Roboto-Regular.ttf",
"logo_icon.svg",
"bell_icon.svg", "bell_icon.svg",
"high_cut_icon.svg", "high_cut_icon.svg",
"high_shelf_icon.svg", "high_shelf_icon.svg",

View File

@ -29,17 +29,20 @@ namespace BinaryData
extern const char* RobotoRegular_ttf; extern const char* RobotoRegular_ttf;
const int RobotoRegular_ttfSize = 146004; const int RobotoRegular_ttfSize = 146004;
extern const char* logo_icon_svg;
const int logo_icon_svgSize = 1793;
extern const char* bell_icon_svg; extern const char* bell_icon_svg;
const int bell_icon_svgSize = 397; const int bell_icon_svgSize = 397;
extern const char* high_cut_icon_svg; extern const char* high_cut_icon_svg;
const int high_cut_icon_svgSize = 316; const int high_cut_icon_svgSize = 355;
extern const char* high_shelf_icon_svg; extern const char* high_shelf_icon_svg;
const int high_shelf_icon_svgSize = 420; const int high_shelf_icon_svgSize = 420;
extern const char* low_cut_icon_svg; extern const char* low_cut_icon_svg;
const int low_cut_icon_svgSize = 317; const int low_cut_icon_svgSize = 353;
extern const char* low_shelf_icon_svg; extern const char* low_shelf_icon_svg;
const int low_shelf_icon_svgSize = 410; const int low_shelf_icon_svgSize = 410;
@ -57,7 +60,7 @@ namespace BinaryData
const int bypass_icon_svgSize = 406; const int bypass_icon_svgSize = 406;
// Number of elements in the namedResourceList and originalFileNames arrays. // Number of elements in the namedResourceList and originalFileNames arrays.
const int namedResourceListSize = 16; const int namedResourceListSize = 17;
// Points to the start of a list of resource names. // Points to the start of a list of resource names.
extern const char* namedResourceList[]; extern const char* namedResourceList[];

View File

@ -52,6 +52,9 @@ void CrystalizerEQAudioProcessorEditor::setupSliders() {
&peak3FreqSlider, &peak3QSlider, &highBandFreqSlider, &highBandQSlider}) { &peak3FreqSlider, &peak3QSlider, &highBandFreqSlider, &highBandQSlider}) {
s->setLookAndFeel(freqQLookAndFeel.get()); s->setLookAndFeel(freqQLookAndFeel.get());
} }
lowBandSlopeSlider.setTextBoxStyle(juce::Slider::NoTextBox, true, 0, 0);
highBandSlopeSlider.setTextBoxStyle(juce::Slider::NoTextBox, true, 0, 0);
} }
//endregion setupSliders //endregion setupSliders
@ -130,7 +133,7 @@ void CrystalizerEQAudioProcessorEditor::setupDisplayNames() {
testNoiseSlider.setTextValueSuffix(" Gain"); testNoiseSlider.setTextValueSuffix(" Gain");
//lowBandFreqSlider.setTextValueSuffix ("\nHz"); //lowBandFreqSlider.setTextValueSuffix ("\nHz");
lowBandSlopeSlider.setTextValueSuffix ("\ndB/Oct"); //lowBandSlopeSlider.setTextValueSuffix ("\ndB/Oct");
lowBandGainSlider.setTextValueSuffix("\ndB"); lowBandGainSlider.setTextValueSuffix("\ndB");
//lowBandQSlider.setTextValueSuffix ("\nQ"); //lowBandQSlider.setTextValueSuffix ("\nQ");
@ -151,7 +154,7 @@ void CrystalizerEQAudioProcessorEditor::setupDisplayNames() {
//highBandFreqSlider.setTextValueSuffix ("\nHz"); //highBandFreqSlider.setTextValueSuffix ("\nHz");
highBandSlopeSlider.setTextValueSuffix ("\ndB/Oct"); //highBandSlopeSlider.setTextValueSuffix ("\ndB/Oct");
highBandGainSlider.setTextValueSuffix("\ndB"); highBandGainSlider.setTextValueSuffix("\ndB");
// highBandQSlider.setTextValueSuffix ("\nQ"); // highBandQSlider.setTextValueSuffix ("\nQ");
@ -329,17 +332,30 @@ void CrystalizerEQAudioProcessorEditor::disableHighBand(const float target) {
//region disableEverything //region disableEverything
void CrystalizerEQAudioProcessorEditor::disableEverything(const float target) { void CrystalizerEQAudioProcessorEditor::disableEverything(const float target) {
bool isToggled = target <= 0.5f; bool isToggled = target <= 0.5f;
for (auto* s : sliders) { for (auto* s : sliders) {
s->setEnabled(isToggled); s->setEnabled(isToggled);
} }
for (auto* l : sliderLabels) { for (auto* l : sliderLabels) {
l->setEnabled(isToggled); l->setEnabled(isToggled);
} }
//TODO: If band bypass is active prior to master bypass, upon reactivating master the bypassed band is getting active.
peak1BypassButton.setEnabled(isToggled); for (auto*b : peakBypassButtons) {
peak2BypassButton.setEnabled(isToggled); b->setEnabled(isToggled);
peak3BypassButton.setEnabled(isToggled); const auto bypassTarget = b->getToggleState() ? 1.0f : 0.0f;
if (b == &peak1BypassButton && isToggled) {
disableLowMidBand(bypassTarget);
}
else if (b == &peak2BypassButton && isToggled) {
disableMidBand(bypassTarget);
}
else if (b == &peak3BypassButton && isToggled) {
disableHighMidBand(bypassTarget);
}
}
resetButton.setEnabled(isToggled); resetButton.setEnabled(isToggled);
crystalizeButton.setEnabled(isToggled); crystalizeButton.setEnabled(isToggled);
lowBandModeBox.setEnabled(isToggled); lowBandModeBox.setEnabled(isToggled);
highBandModeBox.setEnabled(isToggled); highBandModeBox.setEnabled(isToggled);
@ -379,11 +395,7 @@ void CrystalizerEQAudioProcessorEditor::addComponentsToLayout() {
presetArea.addAndMakeVisible(presetMenuButton); presetArea.addAndMakeVisible(presetMenuButton);
headerBar.addAndMakeVisible(presetMenu); headerBar.addAndMakeVisible(presetMenu);
presetMenu.addAndMakeVisible(presetNameInput);
presetMenu.addAndMakeVisible(savePresetButton);
presetMenu.addAndMakeVisible(deletePresetButton);
presetMenu.toFront(true);
presetMenu.setVisible(false);
addAndMakeVisible(mainPanel); addAndMakeVisible(mainPanel);
@ -403,8 +415,8 @@ void CrystalizerEQAudioProcessorEditor::addComponentsToLayout() {
lowBandModeBox.addAndMakeVisible(lowBell); lowBandModeBox.addAndMakeVisible(lowBell);
lowBandModeBox.addAndMakeVisible(lowShelf); lowBandModeBox.addAndMakeVisible(lowShelf);
lowFilterArea.addAndMakeVisible(lowBandModeBox); lowFilterArea.addAndMakeVisible(lowBandModeBox);
lowBandModeButtons.add(&lowBypass, &lowCut, &lowBell, &lowShelf); lowBandModeButtons.add(&lowBypass, &lowCut, &lowShelf, &lowBell);
lowBandBools = {false, false, false, true}; lowBandBools = {false, false, true, false};
lowFilterArea.addAndMakeVisible(lowBandSlopeLabel); lowFilterArea.addAndMakeVisible(lowBandSlopeLabel);
@ -416,7 +428,9 @@ void CrystalizerEQAudioProcessorEditor::addComponentsToLayout() {
lowBandSlopeSlider.addAndMakeVisible(low24); lowBandSlopeSlider.addAndMakeVisible(low24);
lowBandSlopeSlider.addAndMakeVisible(low36); lowBandSlopeSlider.addAndMakeVisible(low36);
lowBandSlopeSlider.addAndMakeVisible(low48); lowBandSlopeSlider.addAndMakeVisible(low48);
lowFilterArea.addAndMakeVisible(lowBandSlopeSlider); lowFilterArea.addAndMakeVisible(lowBandSlopeSlider);
lowFilterArea.addAndMakeVisible(lowdBOctLabel);
lowFilterArea.addAndMakeVisible(lowBandGainSlider); lowFilterArea.addAndMakeVisible(lowBandGainSlider);
lowFilterArea.addAndMakeVisible(lowBandQSlider); lowFilterArea.addAndMakeVisible(lowBandQSlider);
@ -465,8 +479,8 @@ void CrystalizerEQAudioProcessorEditor::addComponentsToLayout() {
highBandModeBox.addAndMakeVisible(highBell); highBandModeBox.addAndMakeVisible(highBell);
highBandModeBox.addAndMakeVisible(highShelf); highBandModeBox.addAndMakeVisible(highShelf);
highFilterArea.addAndMakeVisible(highBandModeBox); highFilterArea.addAndMakeVisible(highBandModeBox);
highBandModeButtons.add(&highBypass, &highCut, &highBell, &highShelf); highBandModeButtons.add(&highBypass, &highCut, &highShelf, &highBell);
highBandBools = {false, false, false, true}; highBandBools = {false, false, true, false};
highFilterArea.addAndMakeVisible(highBandSlopeLabel); highFilterArea.addAndMakeVisible(highBandSlopeLabel);
highFilterArea.addAndMakeVisible(highBandGainLabel); highFilterArea.addAndMakeVisible(highBandGainLabel);
@ -478,6 +492,8 @@ void CrystalizerEQAudioProcessorEditor::addComponentsToLayout() {
highBandSlopeSlider.addAndMakeVisible(high36); highBandSlopeSlider.addAndMakeVisible(high36);
highBandSlopeSlider.addAndMakeVisible(high48); highBandSlopeSlider.addAndMakeVisible(high48);
highFilterArea.addAndMakeVisible(highBandSlopeSlider); highFilterArea.addAndMakeVisible(highBandSlopeSlider);
highFilterArea.addAndMakeVisible(highdBOctLabel);
highFilterArea.addAndMakeVisible(highBandGainSlider); highFilterArea.addAndMakeVisible(highBandGainSlider);
highFilterArea.addAndMakeVisible(highBandQSlider); highFilterArea.addAndMakeVisible(highBandQSlider);
@ -486,13 +502,12 @@ void CrystalizerEQAudioProcessorEditor::addComponentsToLayout() {
} }
addAndMakeVisible(footerBar);
footerBar.addAndMakeVisible(globalControlArea);
globalControlArea.addAndMakeVisible(inputLabel);
globalControlArea.addAndMakeVisible(outputLabel);
globalControlArea.addAndMakeVisible(inputSlider); globalControlArea.addAndMakeVisible(inputSlider);
globalControlArea.addAndMakeVisible(outputSlider); globalControlArea.addAndMakeVisible(outputSlider);
globalControlArea.addAndMakeVisible(masterBypassButton); globalControlArea.addAndMakeVisible(masterBypassButton);
footerBar.addAndMakeVisible(globalControlArea);
addAndMakeVisible(footerBar);
} }
//endregion addComponentsToLayout //endregion addComponentsToLayout
@ -518,6 +533,7 @@ void CrystalizerEQAudioProcessorEditor::setupLabels() {
setupLabel(low24, "24"); setupLabel(low24, "24");
setupLabel(low36, "36"); setupLabel(low36, "36");
setupLabel(low48, "48"); setupLabel(low48, "48");
setupLabel(lowdBOctLabel, "dB/Oct");
//PEAK 1 //PEAK 1
setupLabel (peak1FreqLabel,"Low-Mid\nHz"); setupLabel (peak1FreqLabel,"Low-Mid\nHz");
@ -544,6 +560,8 @@ void CrystalizerEQAudioProcessorEditor::setupLabels() {
setupLabel(high24, "24"); setupLabel(high24, "24");
setupLabel(high36, "36"); setupLabel(high36, "36");
setupLabel(high48, "48"); setupLabel(high48, "48");
setupLabel(highdBOctLabel, "dB/Oct");
setupLabel(presetBoxLabel, "Presets"); setupLabel(presetBoxLabel, "Presets");
@ -557,6 +575,9 @@ void CrystalizerEQAudioProcessorEditor::setupFontsWithColours() {
Typography::applyToLabel(titleLabel, Typography::Style::Display, 1.f); Typography::applyToLabel(titleLabel, Typography::Style::Display, 1.f);
titleLabel.setColour(juce::Label::textColourId, Colours::ACCENTCOLOUR); titleLabel.setColour(juce::Label::textColourId, Colours::ACCENTCOLOUR);
Typography::applyToLabel(presetBoxLabel, Typography::Style::H3, 1.f);
presetBoxLabel.setColour(juce::Label::textColourId, Colours::FOREGROUNDCOLOUR);
for (auto* l : sliderLabels) { for (auto* l : sliderLabels) {
l->setColour(juce::Label::textColourId, Colours::FOREGROUNDCOLOUR); l->setColour(juce::Label::textColourId, Colours::FOREGROUNDCOLOUR);
Typography::applyToLabel(*l, Typography::Style::Mono, 1.f); Typography::applyToLabel(*l, Typography::Style::Mono, 1.f);
@ -595,7 +616,6 @@ void CrystalizerEQAudioProcessorEditor::handleLowBandModes() {
lowBandModeButtons[j]->setToggleState(false, juce::dontSendNotification); lowBandModeButtons[j]->setToggleState(false, juce::dontSendNotification);
} }
} }
// Aktuellen aktivieren // Aktuellen aktivieren
lowBandBools[i] = true; lowBandBools[i] = true;
param->setValueNotifyingHost(param->convertTo0to1((float)i)); param->setValueNotifyingHost(param->convertTo0to1((float)i));
@ -649,8 +669,26 @@ void CrystalizerEQAudioProcessorEditor::handleHighBandModes() {
//region setupEventListeners //region setupEventListeners
void CrystalizerEQAudioProcessorEditor::setupEventListeners() { void CrystalizerEQAudioProcessorEditor::setupEventListeners() {
presetMenuButton.onClick = [this]() { presetMenuButton.onClick = [this]() {
bool menuOpened = presetMenuButton.getToggleState();
presetMenu.setVisible(menuOpened); auto* menu = new DesignSystem::PresetMenu(&presetNameInput, &savePresetButton, &deletePresetButton);
const auto presetMenuBounds = presetMenu.getLocalBounds();
menu->setBounds(presetMenuBounds);
presetMenuLookAndFeel = std::make_unique<DesignSystem::PresetMenuLookAndFeel>();
juce::Rectangle<int> areaToPointTo = presetMenuButton.getScreenBounds();
auto* menuRaw = menu;
presetMenuSafePtr = menuRaw;
auto& box = juce::CallOutBox::launchAsynchronously(
std::unique_ptr<juce::Component>(menu),
areaToPointTo,
nullptr
);
box.setLookAndFeel(presetMenuLookAndFeel.get());
}; };
savePresetButton.onClick = [this]() { savePresetButton.onClick = [this]() {
@ -705,8 +743,21 @@ void CrystalizerEQAudioProcessorEditor::setupEventListeners() {
resetButton.onClick = [this]() resetButton.onClick = [this]()
{ {
audioProcessor.resetAllParameters(); audioProcessor.resetAllParameters();
if (crystalizeButton.getToggleState()) {
isAnimatingCrystalize = true;
isFadingToActive = (svgToggleButtonLookAndFeel->activeIconOpacity < 1.0f);
}
resetAllCheckboxes(); resetAllCheckboxes();
for (auto* s : sliders) {
s->setEnabled(true);
}
for (auto* l : sliderLabels) {
l->setEnabled(true);
}
presetBox.setSelectedId(1, juce::dontSendNotification); presetBox.setSelectedId(1, juce::dontSendNotification);
}; };
handleLowBandModes(); handleLowBandModes();
@ -724,6 +775,7 @@ void CrystalizerEQAudioProcessorEditor::initPresetSystem() {
presetBox.addItemList(presets, 1); presetBox.addItemList(presets, 1);
presetBox.setSelectedId(1, juce::dontSendNotification); presetBox.setSelectedId(1, juce::dontSendNotification);
presetMenuButton.setName("PresetMenuButton"); presetMenuButton.setName("PresetMenuButton");
presetMenuButton.setColour (juce::ToggleButton::textColourId, juce::Colours::black); presetMenuButton.setColour (juce::ToggleButton::textColourId, juce::Colours::black);
presetMenuButton.setColour(juce::ToggleButton::tickColourId, juce::Colours::black); presetMenuButton.setColour(juce::ToggleButton::tickColourId, juce::Colours::black);
@ -733,6 +785,14 @@ void CrystalizerEQAudioProcessorEditor::initPresetSystem() {
presetNameInput.setJustification(juce::Justification::centred); presetNameInput.setJustification(juce::Justification::centred);
presetNameInput.setColour(juce::TextEditor::backgroundColourId, juce::Colours::black); presetNameInput.setColour(juce::TextEditor::backgroundColourId, juce::Colours::black);
presetNameInput.setColour(juce::TextEditor::textColourId, juce::Colours::white); presetNameInput.setColour(juce::TextEditor::textColourId, juce::Colours::white);
presetButtonLookAndFeel = std::make_unique<DesignSystem::PresetButtonsLookAndFeel>();
presetComboBoxLookAndFeel = std::make_unique<DesignSystem::PresetComboBoxLookAndFeel>();
savePresetButton.setLookAndFeel(presetButtonLookAndFeel.get());
deletePresetButton.setLookAndFeel(presetButtonLookAndFeel.get());
resetButton.setLookAndFeel(presetButtonLookAndFeel.get());
// TODO: presetBox.setLookAndFeel(presetComboBoxLookAndFeel.get());
} }
//endregion initPresetSystem //endregion initPresetSystem
@ -754,6 +814,12 @@ CrystalizerEQAudioProcessorEditor::CrystalizerEQAudioProcessorEditor (Crystalize
setupSliders(); setupSliders();
initPresetSystem(); initPresetSystem();
auto logoIcon = juce::XmlDocument::parse (BinaryData::logo_icon_svg);
if (logoIcon != nullptr)
logoDrawable = juce::Drawable::createFromSVG (*logoIcon);
addAndMakeVisible (testNoiseButton); addAndMakeVisible (testNoiseButton);
testNoiseButton.onClick = [this]() { testNoiseButton.onClick = [this]() {
@ -790,6 +856,7 @@ CrystalizerEQAudioProcessorEditor::~CrystalizerEQAudioProcessorEditor() {
crystalizeButton.setLookAndFeel(nullptr); crystalizeButton.setLookAndFeel(nullptr);
presetMenuButton.setLookAndFeel(nullptr); presetMenuButton.setLookAndFeel(nullptr);
for (auto* b : lowBandModeButtons) { for (auto* b : lowBandModeButtons) {
b->setLookAndFeel(nullptr); b->setLookAndFeel(nullptr);
} }
@ -798,6 +865,37 @@ CrystalizerEQAudioProcessorEditor::~CrystalizerEQAudioProcessorEditor() {
} }
}; };
float CrystalizerEQAudioProcessorEditor::getInterpolatedDb(float exactBin) {
int bin0 = static_cast<int>(std::floor(exactBin)) - 1;
int bin1 = static_cast<int>(std::floor(exactBin));
int bin2 = static_cast<int>(std::ceil(exactBin));
int bin3 = static_cast<int>(std::ceil(exactBin)) + 1;
const int maxBin = static_cast<int>(spectrumAnalyzer.renderValuesDb.size()) - 1;
bin0 = juce::jlimit(0, maxBin, bin0);
bin1 = juce::jlimit(0, maxBin, bin1);
bin2 = juce::jlimit(0, maxBin, bin2);
bin3 = juce::jlimit(0, maxBin, bin3);
float y0 = spectrumAnalyzer.renderValuesDb[bin0];
float y1 = spectrumAnalyzer.renderValuesDb[bin1];
float y2 = spectrumAnalyzer.renderValuesDb[bin2];
float y3 = spectrumAnalyzer.renderValuesDb[bin3];
float fraction = exactBin - bin1;
// Catmull-Rom Spline Interpolation
float a0 = -0.5f * y0 + 1.5f * y1 - 1.5f * y2 + 0.5f * y3;
float a1 = y0 - 2.5f * y1 + 2.0f * y2 - 0.5f * y3;
float a2 = -0.5f * y0 + 0.5f * y2;
float a3 = y1;
return a0 * fraction * fraction * fraction +
a1 * fraction * fraction +
a2 * fraction +
a3;
}
//region paintAnalyzer //region paintAnalyzer
void CrystalizerEQAudioProcessorEditor::paintAnalyzer(juce::Graphics &g) { void CrystalizerEQAudioProcessorEditor::paintAnalyzer(juce::Graphics &g) {
analyzerRect = getLocalArea(&analyzerArea, analyzerArea.getLocalBounds()); analyzerRect = getLocalArea(&analyzerArea, analyzerArea.getLocalBounds());
@ -806,14 +904,156 @@ void CrystalizerEQAudioProcessorEditor::paintAnalyzer(juce::Graphics &g) {
auto r = analyzerRect.toFloat(); auto r = analyzerRect.toFloat();
// Hintergrund des Analyzer-Bereichs // Hintergrund
g.setColour(juce::Colours::black); g.setColour(juce::Colours::black);
g.fillRect(r); g.fillRect(r);
// Rahmen (optional) // Rahmen
g.setColour(juce::Colours::grey); g.setColour(juce::Colours::grey);
g.drawRect(analyzerRect); g.drawRect(analyzerRect);
// === Spektrum zeichnen ===
g.setColour(Colours::ACCENTCOLOUR);
const float analyzerWidth = analyzerRect.getWidth();
const float analyzerHeight = analyzerRect.getHeight();
const float analyzerBottom = analyzerRect.getBottom();
const float minDb = spectrumAnalyzer.MINDB;
const float maxDb = spectrumAnalyzer.MAXDB;
const float dbRange = maxDb - minDb; // = 96 dB
const float zeroDbY = analyzerBottom - (analyzerHeight * (0.0f - minDb) / dbRange); // Position von 0dB
const float minFreq = spectrumAnalyzer.MINFREQ; // 20 Hz
const float maxFreq = spectrumAnalyzer.MAXFREQ; // 20 kHz
float sampleRate = spectrumAnalyzer.sampleRate;
float deltaF = spectrumAnalyzer.deltaF;
// Zeichne für jede X-Position
juce::Path spectrumPath;
bool pathStarted = false;
// Erhöhe die Auflösung - zeichne mehr Punkte als Pixel
const int resolutionMultiplier = 4; // 4x mehr Punkte
const int numPoints = static_cast<int>(analyzerWidth) * resolutionMultiplier;
for (int i = 0; i < numPoints; ++i) {
// Berechne X-Position
float x = (i / static_cast<float>(numPoints)) * analyzerWidth;
// Berechne Frequenz (logarithmisch)
float normalizedX = i / static_cast<float>(numPoints);
float logMin = std::log10(minFreq);
float logMax = std::log10(maxFreq);
float logFreq = logMin + normalizedX * (logMax - logMin);
float freq = std::pow(10.0f, logFreq);
// Finde Bin und interpoliere
float exactBin = freq / deltaF;
float dB = getInterpolatedDb(exactBin);
// Normalisiere
float normalized = (dB - minDb) / dbRange;
normalized = juce::jlimit(0.0f, 1.0f, normalized);
// Berechne Y-Position
float pixelHeight = normalized * analyzerHeight;
float y = analyzerBottom - pixelHeight;
// Füge zum Path hinzu
if (!pathStarted) {
spectrumPath.startNewSubPath(x + analyzerRect.getX(), y);
pathStarted = true;
} else {
spectrumPath.lineTo(x + analyzerRect.getX(), y);
}
}
// Zeichne die Linie mit Anti-Aliasing
if (pathStarted) {
juce::PathStrokeType stroke(2.0f);
stroke.setJointStyle(juce::PathStrokeType::curved); // Runde Ecken
g.strokePath(spectrumPath, stroke);
spectrumPath.lineTo(analyzerRect.getRight(), analyzerBottom);
spectrumPath.lineTo(analyzerRect.getX(), analyzerBottom);
spectrumPath.closeSubPath();
g.setColour(Colours::ACCENTCOLOUR.withAlpha(0.3f));
g.fillPath(spectrumPath);
}
// Optional: Zeichne Frequenz-Grid-Linien
drawFrequencyGrid(g, dbRange);
} }
float CrystalizerEQAudioProcessorEditor::mapFrequencyToX(float freq, float minFreq, float maxFreq, float width) {
// Logarithmische Skalierung: log(freq) zwischen log(minFreq) und log(maxFreq)
float logMin = std::log10(minFreq);
float logMax = std::log10(maxFreq);
float logFreq = std::log10(freq);
float normalized = (logFreq - logMin) / (logMax - logMin);
return normalized * width;
}
void CrystalizerEQAudioProcessorEditor::drawFrequencyGrid(juce::Graphics& g, const float dbRange) {
g.setColour(Colours::FOREGROUNDCOLOUR.withAlpha(0.3f));
const float minFreq = spectrumAnalyzer.MINFREQ;
const float maxFreq = spectrumAnalyzer.MAXFREQ;
const float analyzerWidth = analyzerRect.getWidth();
const float minDB = spectrumAnalyzer.MINDB;
const float maxDB = spectrumAnalyzer.MAXDB;
const float analyzerHeight = analyzerRect.getHeight();
const float analyzerBottom = analyzerRect.getBottom();
std::vector<float> gridFreqs = {0, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000};
std::vector<float> gridDB = {0, -12, -24, -36, -48, -60, -72};
for (int i = 0; i < gridDB.size(); ++i) {
float db = gridDB[i];
// 1: dB normalisieren (wie bei der Kurve)
float normalized = (db - minDB) / dbRange;
normalized = juce::jlimit(0.0f, 1.0f, normalized);
// 2: Y-Position wie beim Spektrum berechnen
float pixelHeight = normalized * analyzerHeight;
float y = analyzerBottom - pixelHeight;
g.drawHorizontalLine(static_cast<int>(y), static_cast<float>(analyzerRect.getX()), static_cast<float>(analyzerRect.getRight()));
g.setFont(Typography::getFont(Typography::Style::Mono, 1.0f));
juce::String label = juce::String(gridDB[i]);
g.drawText(label, analyzerRect.getX(), y, 30, 15,
juce::Justification::centred);
}
for (float freq : gridFreqs) {
float x = mapFrequencyToX(freq, minFreq, maxFreq, analyzerWidth);
x += analyzerRect.getX();
g.drawVerticalLine(static_cast<int>(x),
static_cast<float>(analyzerRect.getY()),
static_cast<float>(analyzerRect.getBottom()));
// Optional: Frequenz-Label zeichnen
if (freq == 20) continue;
g.setFont(Typography::getFont(Typography::Style::Mono, 1.0f));
juce::String label = (freq >= 1000) ? juce::String(freq / 1000) + "k" : juce::String(freq);
g.drawText(label, static_cast<int>(x) - 15, analyzerRect.getY(), 30, 15,
juce::Justification::centred);
}
}
//endregion paintAnalyzer //endregion paintAnalyzer
void CrystalizerEQAudioProcessorEditor::paintModeBoxBorders(juce::Graphics &g) { void CrystalizerEQAudioProcessorEditor::paintModeBoxBorders(juce::Graphics &g) {
@ -861,8 +1101,11 @@ void CrystalizerEQAudioProcessorEditor::paint (juce::Graphics& g)
auto hBH = hB.getHeight(); auto hBH = hB.getHeight();
auto hBPad = ((hBY + mPY) - hBH) / 2; auto hBPad = ((hBY + mPY) - hBH) / 2;
g.fillRect(hBX, hBY, hBW, mPY - hBPad); g.fillRect(hBX, hBY, hBW, mPY - hBPad);
//paintBorderLines(g);
const auto logoArea = hB.toFloat().reduced(hBPad);
logoDrawable->drawWithin(g, logoArea,
juce::RectanglePlacement::xRight, // oder xLeft, yTop etc.
1.0f);
g.setColour(Colours::SURFACECOLOUR); g.setColour(Colours::SURFACECOLOUR);
const auto pA = getLocalArea(&presetArea, presetArea.getLocalBounds()); const auto pA = getLocalArea(&presetArea, presetArea.getLocalBounds());
@ -871,7 +1114,10 @@ void CrystalizerEQAudioProcessorEditor::paint (juce::Graphics& g)
auto pAWidth = pA.getWidth(); auto pAWidth = pA.getWidth();
auto pAHeight = pA.getHeight(); auto pAHeight = pA.getHeight();
g.fillRoundedRectangle(pAX, pAY - 10.f, pAWidth, pAHeight + 10.f, 10.0f); g.fillRoundedRectangle(pAX, pAY - 10.f, pAWidth, pAHeight + 10.f, 10.0f);
//paintBorderLines(g);
const auto fA = getLocalArea(&filterArea, filterArea.getLocalBounds()); const auto fA = getLocalArea(&filterArea, filterArea.getLocalBounds());
const int fABorderWidth = 3; const int fABorderWidth = 3;
@ -888,13 +1134,13 @@ void CrystalizerEQAudioProcessorEditor::paint (juce::Graphics& g)
g.setColour(Colours::BACKGROUNDBYPASS); g.setColour(Colours::BACKGROUNDBYPASS);
g.fillRect(fA); g.fillRect(fA);
paintBorderLines(g);
//paintModeBoxBorders(g); //paintModeBoxBorders(g);
g.setColour(Colours::SURFACEBYPASS); g.setColour(Colours::SURFACEBYPASS);
const auto fB = getLocalArea(&footerBar, footerBar.getLocalBounds()); const auto fB = getLocalArea(&footerBar, footerBar.getLocalBounds());
g.fillRect(fB); g.fillRect(fB);
paintBorderLines(g);
if constexpr (false) // -> auf false setzen, wenn nicht gebraucht if constexpr (false) // -> auf false setzen, wenn nicht gebraucht
@ -1054,6 +1300,25 @@ void CrystalizerEQAudioProcessorEditor::paintBorderLines(juce::Graphics &g) {
g.drawVerticalLine(x,center - halfLen, center + halfLen); g.drawVerticalLine(x,center - halfLen, center + halfLen);
} }
g.setColour(DesignSystem::Colours::SURFACECOLOUR);
auto prevRightGlobal = (float) globalControlArea.getRight();
for (auto* c : globalControlArea.getChildren()) {
if (c == &inputSlider) continue;
if (c == &masterBypassButton) continue;
const auto area = getLocalArea(c, c->getLocalBounds());
const float xAvg = ((float) area.getX() - prevRightGlobal) / 2;
const int x = area.getX() - xAvg;
prevRightGlobal = (float) c->getRight();
const auto top = (float) area.getY();
const auto bot = (float) area.getBottom();
const float center = (top + bot) * 0.5f;
const float halfLen = (bot - top) * 0.375f;
g.drawVerticalLine(x,center - halfLen, center + halfLen);
}
} }
//endregion paintBorderLines //endregion paintBorderLines
@ -1073,6 +1338,7 @@ void CrystalizerEQAudioProcessorEditor::setKnobVisibility() {
lowBandFreqLabel.setEnabled (lowMode >= 1); lowBandFreqLabel.setEnabled (lowMode >= 1);
lowBandSlopeSlider.setEnabled (lowMode == 1); lowBandSlopeSlider.setEnabled (lowMode == 1);
lowBandSlopeLabel.setEnabled (lowMode == 1); lowBandSlopeLabel.setEnabled (lowMode == 1);
lowdBOctLabel.setEnabled (lowMode == 1);
lowBandGainSlider.setEnabled(lowMode >= 2); lowBandGainSlider.setEnabled(lowMode >= 2);
lowBandGainLabel .setEnabled(lowMode >= 2); lowBandGainLabel .setEnabled(lowMode >= 2);
lowBandQSlider .setEnabled(lowMode >= 1); lowBandQSlider .setEnabled(lowMode >= 1);
@ -1090,6 +1356,7 @@ void CrystalizerEQAudioProcessorEditor::setKnobVisibility() {
highBandFreqLabel.setEnabled (highMode >= 1); highBandFreqLabel.setEnabled (highMode >= 1);
highBandSlopeSlider.setEnabled (highMode == 1); highBandSlopeSlider.setEnabled (highMode == 1);
highBandSlopeLabel.setEnabled (highMode == 1); highBandSlopeLabel.setEnabled (highMode == 1);
highdBOctLabel.setEnabled (highMode == 1);
highBandGainSlider.setEnabled(highMode >= 2); highBandGainSlider.setEnabled(highMode >= 2);
highBandGainLabel .setEnabled(highMode >= 2); highBandGainLabel .setEnabled(highMode >= 2);
highBandQSlider .setEnabled(highMode >= 1); highBandQSlider .setEnabled(highMode >= 1);
@ -1140,6 +1407,11 @@ void CrystalizerEQAudioProcessorEditor::timerCallback()
repaint(analyzerRect); repaint(analyzerRect);
resized(); resized();
animateCrystalizeButton(); animateCrystalizeButton();
if (presetMenuSafePtr == nullptr)
{
presetMenuButton.setToggleState(false, juce::dontSendNotification);
}
} }
//endregion timerCallback //endregion timerCallback
@ -1157,6 +1429,7 @@ void CrystalizerEQAudioProcessorEditor::resized()
const auto testBounds = mainPanel.getLocalBounds(); const auto testBounds = mainPanel.getLocalBounds();
const auto testWidth = testBounds.getWidth(); const auto testWidth = testBounds.getWidth();
const auto testHeight = testBounds.getHeight(); const auto testHeight = testBounds.getHeight();
@ -1220,6 +1493,8 @@ void CrystalizerEQAudioProcessorEditor::setupHeader() {
const float presetAreaWidth = static_cast<float>(bounds.getWidth()) * 0.5f; const float presetAreaWidth = static_cast<float>(bounds.getWidth()) * 0.5f;
const auto titleWidthCentre = titleLabel.getFont().getStringWidth("Crystalizer") / 4;
Layout::GridSpec headerSpec{ Layout::GridSpec headerSpec{
/* cols */ { Layout::fr(1), Layout::pxTrack(presetAreaWidth), Layout::fr(1) }, /* cols */ { Layout::fr(1), Layout::pxTrack(presetAreaWidth), Layout::fr(1) },
/* rows */ { Layout::fr(1) }, /* rows */ { Layout::fr(1) },
@ -1228,8 +1503,9 @@ void CrystalizerEQAudioProcessorEditor::setupHeader() {
/* pad */ Layout::padding(Spacing::SizeMode::XS) /* pad */ Layout::padding(Spacing::SizeMode::XS)
}; };
Layout::grid(bounds, headerSpec, { Layout::grid(bounds, headerSpec, {
Layout::area(titleLabel, 1, 1, 2, 2),
Layout::area(presetArea, 1, 2, 2, 3), Layout::area(presetArea, 1, 2, 2, 3),
Layout::area(titleLabel, 1, 1, 2, 2)
.withMargin(juce::GridItem::Margin(0, 0, 0, titleWidthCentre)),
Layout::area(presetMenu, 1, 3, 2, 4), Layout::area(presetMenu, 1, 3, 2, 4),
}); });
@ -1251,11 +1527,12 @@ void CrystalizerEQAudioProcessorEditor::setupHeader() {
const auto presetAreaBounds = presetArea.getLocalBounds(); const auto presetAreaBounds = presetArea.getLocalBounds();
const auto presetBoxWidth = static_cast<float>(presetArea.getWidth()); const auto presetBoxWidth = static_cast<float>(presetArea.getWidth());
const auto presetBoxHeight = static_cast<float>(presetArea.getHeight()); const auto presetBoxHeight = static_cast<float>(presetArea.getHeight());
const float rowHeight = presetBoxHeight * 0.25f;
const float iconSize = rowHeight;
Layout::GridSpec presetSpec{ Layout::GridSpec presetSpec{
/* cols */ { Layout::fr(1), Layout::pxTrack(presetBoxWidth * 0.5f), Layout::fr(1)}, /* cols */ { Layout::fr(1), Layout::pxTrack(presetBoxWidth * 0.5f), Layout::fr(1)},
/* rows */ { Layout::pxTrack(presetBoxHeight * 0.25f), Layout::pxTrack(presetBoxHeight * 0.25f)}, /* rows */ { Layout::pxTrack(rowHeight), Layout::pxTrack(rowHeight)},
/* colGap */ Spacing::SizeMode::XS, /* colGap */ Spacing::SizeMode::XS,
/* rowGap */ Spacing::SizeMode::XS, /* rowGap */ Spacing::SizeMode::XS,
/* pad */ Layout::padding(Spacing::SizeMode::S) /* pad */ Layout::padding(Spacing::SizeMode::S)
@ -1268,7 +1545,8 @@ void CrystalizerEQAudioProcessorEditor::setupHeader() {
Layout::area(resetButton, 2, 1, 2, 2), Layout::area(resetButton, 2, 1, 2, 2),
// Menütaste unten rechts (row2, col2) // Menütaste unten rechts (row2, col2)
Layout::area(presetMenuButton, 2, 3, 3, 4) Layout::area(presetMenuButton, 2, 3, 3, 4)
, .withWidth(iconSize)
.withHeight(iconSize)
}); });
@ -1394,6 +1672,10 @@ void CrystalizerEQAudioProcessorEditor::setupLowBandLayout() {
Layout::area(lowBandSlopeLabel, 3, 1, 4, 2) Layout::area(lowBandSlopeLabel, 3, 1, 4, 2)
.withMargin(juce::GridItem::Margin(-offSetToGainTop / 1.5f, 0, 0, 0)), .withMargin(juce::GridItem::Margin(-offSetToGainTop / 1.5f, 0, 0, 0)),
Layout::area(lowdBOctLabel, 3, 1, 4, 2)
.withAlignSelf(juce::GridItem::AlignSelf::center)
.withJustifySelf(juce::GridItem::JustifySelf::center),
}); });
@ -1630,6 +1912,10 @@ void CrystalizerEQAudioProcessorEditor::setupHighBandLayout() {
Layout::area(highBandSlopeLabel, 3, 3, 4, 4) Layout::area(highBandSlopeLabel, 3, 3, 4, 4)
.withMargin(juce::GridItem::Margin(-offSetToGainTop / 1.5f, 0, 0, 0)), .withMargin(juce::GridItem::Margin(-offSetToGainTop / 1.5f, 0, 0, 0)),
Layout::area(highdBOctLabel, 3, 3, 4, 4)
.withAlignSelf(juce::GridItem::AlignSelf::center)
.withJustifySelf(juce::GridItem::JustifySelf::center),
}); });
const auto modeBoxBounds = lowBandModeBox.getLocalBounds(); const auto modeBoxBounds = lowBandModeBox.getLocalBounds();
@ -1668,7 +1954,7 @@ void CrystalizerEQAudioProcessorEditor::setupFooter() {
const auto refH = getReferenceCell()[1]; const auto refH = getReferenceCell()[1];
Layout::GridSpec footerSpec{ Layout::GridSpec footerSpec{
/* cols */ { Layout::fr(1), Layout::fr(1), Layout::pxTrack(footerWidth / 3.0f) }, /* cols */ { Layout::fr(1), Layout::fr(1), Layout::fr(1) },
/* rows */ { Layout::fr(1) }, /* rows */ { Layout::fr(1) },
/* colGap */ Spacing::SizeMode::XS, /* colGap */ Spacing::SizeMode::XS,
/* rowGap */ Spacing::SizeMode::XS, /* rowGap */ Spacing::SizeMode::XS,
@ -1682,10 +1968,12 @@ void CrystalizerEQAudioProcessorEditor::setupFooter() {
const auto globalControlAreaWidth = static_cast<float>(globalControlArea.getWidth()); const auto globalControlAreaWidth = static_cast<float>(globalControlArea.getWidth());
const auto globalControlAreaHeight = static_cast<float>(globalControlArea.getHeight()); const auto globalControlAreaHeight = static_cast<float>(globalControlArea.getHeight());
const auto globalControlColWidth = globalControlAreaWidth / 3.0f; const auto globalControlColWidth = globalControlAreaWidth / 3.0f;
const auto sliderRadius = outputSlider.getWidth() / 2.0f;
const auto sliderWidth = outputSlider.getWidth();
Layout::GridSpec globalControlAreaSpec{ Layout::GridSpec globalControlAreaSpec{
/* cols */ { Layout::fr(1), Layout::pxTrack(globalControlColWidth), Layout::fr(1) }, /* cols */ { Layout::fr(1), Layout::fr(1), Layout::fr(1) },
/* rows */ { Layout::fr(1)}, /* rows */ { Layout::fr(1)},
/* colGap */ Spacing::SizeMode::XS, /* colGap */ Spacing::SizeMode::XS,
/* rowGap */ Spacing::SizeMode::XS, /* rowGap */ Spacing::SizeMode::XS,
@ -1694,19 +1982,26 @@ void CrystalizerEQAudioProcessorEditor::setupFooter() {
Layout::grid(globalControlAreaBounds, globalControlAreaSpec, { Layout::grid(globalControlAreaBounds, globalControlAreaSpec, {
//TODO: Bring components closer together //TODO: Bring components closer together
Layout::area(inputSlider, 1, 2, 3, 3)
.withWidth(refW * globalMod * 0.8f) Layout::area(outputSlider, 1, 2, 3, 3)
.withHeight(refH * globalMod * 0.8f) .withWidth(refW * globalMod )
.withHeight(refH * globalMod )
.withMargin(juce::GridItem::Margin(0, 0, 0, sliderRadius * 6))
.withAlignSelf(juce::GridItem::AlignSelf::center) .withAlignSelf(juce::GridItem::AlignSelf::center)
.withJustifySelf(juce::GridItem::JustifySelf::center), .withJustifySelf(juce::GridItem::JustifySelf::center),
Layout::area(outputSlider, 1, 3, 3, 4)
.withWidth(refW * globalMod * 0.8f) Layout::area(inputSlider, 1, 1, 3, 2)
.withHeight(refH * globalMod * 0.8f) .withWidth(refW * globalMod )
.withHeight(refH * globalMod )
.withMargin(juce::GridItem::Margin(0, 0, 0, sliderRadius * 10))
.withAlignSelf(juce::GridItem::AlignSelf::center) .withAlignSelf(juce::GridItem::AlignSelf::center)
.withJustifySelf(juce::GridItem::JustifySelf::center), .withJustifySelf(juce::GridItem::JustifySelf::center),
Layout::area(masterBypassButton, 1, 1, 3, 2), Layout::area(masterBypassButton, 1, 3, 3, 4)
.withWidth(sliderWidth)
.withMargin(juce::GridItem::Margin(0, 0, 0, sliderRadius * 2)),
}); });
} }
@ -1774,7 +2069,9 @@ void SpectrumAnalyzer::applyWindowOnFftFrame(std::vector<float> &fullFrame) {
void SpectrumAnalyzer::processWindowedFrame(std::vector<float> &windowedFrame) { void SpectrumAnalyzer::processWindowedFrame(std::vector<float> &windowedFrame) {
if (windowedFrame.size() != FFTSIZE || fftData.size() != FFTSIZE * 2) return; if (windowedFrame.size() != FFTSIZE || fftData.size() != FFTSIZE * 2) return;
fillFftDataFromFrame(windowedFrame); fillFftDataFromFrame(windowedFrame);
fft.performRealOnlyForwardTransform(fftData.data()); // fft.performRealOnlyForwardTransform(fftData.data());
fft.performFrequencyOnlyForwardTransform(fftData.data(), true);
buildMagnitudeSpectrum(); buildMagnitudeSpectrum();
convertToDb(); convertToDb();
applySmoothing(); applySmoothing();
@ -1786,8 +2083,9 @@ void SpectrumAnalyzer::processWindowedFrame(std::vector<float> &windowedFrame) {
//region fillFftDataFromFrame //region fillFftDataFromFrame
void SpectrumAnalyzer::fillFftDataFromFrame(std::vector<float> &windowedFrame) { void SpectrumAnalyzer::fillFftDataFromFrame(std::vector<float> &windowedFrame) {
for (int n = 0; n < FFTSIZE; ++n) { for (int n = 0; n < FFTSIZE; ++n) {
fftData[2*n] = windowedFrame[n]; /*fftData[2*n] = windowedFrame[n];
fftData[2*n + 1] = 0.0f; fftData[2*n + 1] = 0.0f;*/
fftData[n] = windowedFrame[n];
} }
} }
//endregion fillFftDataFromFrame //endregion fillFftDataFromFrame
@ -1795,17 +2093,9 @@ void SpectrumAnalyzer::fillFftDataFromFrame(std::vector<float> &windowedFrame) {
//region buildMagnitudeSpectrum //region buildMagnitudeSpectrum
void SpectrumAnalyzer::buildMagnitudeSpectrum() { void SpectrumAnalyzer::buildMagnitudeSpectrum() {
for (int k = 0; k < BINS; ++k) { for (int k = 0; k < BINS; ++k) {
float re = 0.f; float mag = fftData[k];
float im = 0.f;
if (k < BINS / 2) {
re = fftData[k];
} else {
im = fftData[k];
}
float mag = sqrt(re * re + im * im);
mag /= (FFTSIZE * 0.5f); mag /= (FFTSIZE * 0.5f);
mag = std::max(mag, 1e-12f); mag = std::max(mag, 1e-24f);
magnitudes[k] = mag; magnitudes[k] = mag;
} }
} }
@ -1813,9 +2103,14 @@ void SpectrumAnalyzer::buildMagnitudeSpectrum() {
//region convertToDb //region convertToDb
void SpectrumAnalyzer::convertToDb() { void SpectrumAnalyzer::convertToDb() {
for (int k = 0; k < magnitudes.size(); ++k) { for (int k = 0; k < magnitudes.size(); ++k) {
float mag = magnitudes[k]; float mag = magnitudes[k];
float dB = juce::Decibels::gainToDecibels(mag); float dB = juce::Decibels::gainToDecibels(mag);
dB = juce::jlimit(MINDB, MAXDB, dB); dB = juce::jlimit(MINDB, MAXDB, dB);
magnitudesDb[k] = dB; magnitudesDb[k] = dB;
} }
@ -1867,6 +2162,7 @@ void SpectrumAnalyzer::applyFreqSmoothing() {
float avg = sum / static_cast<float>(highestBin - lowestBin + 1); float avg = sum / static_cast<float>(highestBin - lowestBin + 1);
freqSmoothedMagnitudesDb[k] = avg; freqSmoothedMagnitudesDb[k] = avg;
} }
} }
//endregion applyFreqSmoothing //endregion applyFreqSmoothing
@ -1877,7 +2173,9 @@ void SpectrumAnalyzer::applyPeakHoldAndFalloff() {
for (int k = 0; k < BINS; ++k) { for (int k = 0; k < BINS; ++k) {
float current = freqSmoothedMagnitudesDb[k]; float current = freqSmoothedMagnitudesDb[k];
float prev = prevPeak[k]; float prev = prevPeak[k];
peakHoldMagnitudesDb[k] = std::max(current, prev - FALLOFFRATE * DELTAT); peakHoldMagnitudesDb[k] = std::max(current, prev - FALLOFFRATE * DELTAT);
} }
} }
//endregion applyPeakHoldAndFalloff //endregion applyPeakHoldAndFalloff

View File

@ -77,8 +77,8 @@ class SpectrumAnalyzer {
const float MINDB = -120.f; const float MINDB = -90.f;
const float MAXDB = 96.f; const float MAXDB = 0.f;
std::vector<float> magnitudes; std::vector<float> magnitudes;
@ -180,21 +180,21 @@ public:
juce::Label titleLabel, testNoiseLabel, juce::Label titleLabel, testNoiseLabel,
lowBandFreqLabel, lowBandSlopeLabel, lowBandGainLabel, lowBandQLabel, lowBandModeLabel, lowBandFreqLabel, lowBandSlopeLabel, lowBandGainLabel, lowBandQLabel, lowBandModeLabel,
low12, low24, low36, low48, low12, low24, low36, low48, lowdBOctLabel,
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,
high12, high24, high36, high48, high12, high24, high36, high48, highdBOctLabel,
inputLabel, outputLabel, inputLabel, outputLabel,
presetBoxLabel; presetBoxLabel;
const juce::Array<juce::Label*> sliderLabels = { const juce::Array<juce::Label*> sliderLabels = {
&lowBandFreqLabel, &lowBandSlopeLabel, &lowBandGainLabel, &lowBandQLabel, &lowBandModeLabel, &lowBandFreqLabel, &lowBandSlopeLabel, &lowBandGainLabel, &lowBandQLabel, &lowBandModeLabel, &lowdBOctLabel,
&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,
&inputLabel, &outputLabel &inputLabel, &outputLabel
}; };
const juce::Array<juce::Label*> slopeLabels = { const juce::Array<juce::Label*> slopeLabels = {
@ -202,10 +202,14 @@ public:
&high12, &high24, &high36, &high48 &high12, &high24, &high36, &high48
}; };
juce::TextButton testNoiseButton, resetButton, savePresetButton, deletePresetButton; juce::TextButton testNoiseButton, resetButton, savePresetButton, deletePresetButton;
juce::ToggleButton masterBypassButton, crystalizeButton, peak1BypassButton, peak2BypassButton, peak3BypassButton, presetMenuButton; juce::ToggleButton masterBypassButton, crystalizeButton, peak1BypassButton, peak2BypassButton, peak3BypassButton, presetMenuButton;
const juce::Array<juce::ToggleButton*> peakBypassButtons = {&peak1BypassButton, &peak2BypassButton, &peak3BypassButton};
juce::ComboBox presetBox; juce::ComboBox presetBox;
juce::Component lowBandModeBox, highBandModeBox; juce::Component lowBandModeBox, highBandModeBox;
@ -276,10 +280,10 @@ private:
std::unique_ptr<Components::PresetMenuButtonLookAndFeel> presetMenuButtonLookAndFeel; std::unique_ptr<Components::PresetMenuButtonLookAndFeel> presetMenuButtonLookAndFeel;
std::unique_ptr<Components::lowBandButtonLookAndFeel> lowBandButtonLookAndFeel; std::unique_ptr<Components::lowBandButtonLookAndFeel> lowBandButtonLookAndFeel;
std::unique_ptr<Components::highBandButtonLookAndFeel> highBandButtonLookAndFeel; std::unique_ptr<Components::highBandButtonLookAndFeel> highBandButtonLookAndFeel;
std::unique_ptr<Components::SvgToggleButtonLookAndFeel> svgToggleButtonLookAndFeel; std::unique_ptr<Components::SvgToggleButtonLookAndFeel> svgToggleButtonLookAndFeel;
std::unique_ptr<DesignSystem::PresetMenuLookAndFeel> presetMenuLookAndFeel;
std::unique_ptr<DesignSystem::PresetButtonsLookAndFeel> presetButtonLookAndFeel;
std::unique_ptr<DesignSystem::PresetComboBoxLookAndFeel> presetComboBoxLookAndFeel;
//SPECRTRUM ANALYZER //SPECRTRUM ANALYZER
@ -338,5 +342,15 @@ private:
bool isAnimatingCrystalize = false; bool isAnimatingCrystalize = false;
bool isFadingToActive = false; bool isFadingToActive = false;
std::unique_ptr<juce::Drawable> logoDrawable;
DesignSystem::PresetMenu* test;
juce::Component::SafePointer<DesignSystem::PresetMenu> presetMenuSafePtr;
float mapFrequencyToX(float freq, float minFreq, float maxFreq, float width);
int getClosestBinForFrequency(float freq);
void drawFrequencyGrid(juce::Graphics& g, const float dbRange);
float getInterpolatedDb(float exactBin);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CrystalizerEQAudioProcessorEditor) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CrystalizerEQAudioProcessorEditor)
}; };

View File

@ -17,7 +17,7 @@ CrystalizerEQAudioProcessor::createParameterLayout() {
params.push_back (std::make_unique<juce::AudioParameterBool>( params.push_back (std::make_unique<juce::AudioParameterBool>(
"TestNoiseEnabled", "Test Noise Enabled", false)); "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), -18.f)); 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
@ -25,7 +25,7 @@ CrystalizerEQAudioProcessor::createParameterLayout() {
"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", juce::NormalisableRange<float>(-24.f, 24.f, 0.1f), 0.f)); params.push_back (std::make_unique<juce::AudioParameterFloat>("LowBandGain", "LowBand Gain", juce::NormalisableRange<float>(-48.f, 48.f, 0.1f), 0.f));
params.push_back (std::make_unique<juce::AudioParameterFloat>("LowBandQ", "LowBand Q", juce::NormalisableRange<float>(0.1f, 10.f, 0.01f), 1.f)); params.push_back (std::make_unique<juce::AudioParameterFloat>("LowBandQ", "LowBand Q", juce::NormalisableRange<float>(0.1f, 10.f, 0.01f), 1.f));
@ -47,7 +47,7 @@ CrystalizerEQAudioProcessor::createParameterLayout() {
params.push_back (std::make_unique<juce::AudioParameterFloat>( params.push_back (std::make_unique<juce::AudioParameterFloat>(
"Peak1Gain", "Peak1 Gain (dB)", "Peak1Gain", "Peak1 Gain (dB)",
juce::NormalisableRange<float>(-24.f, 24.f, 0.1f), 0.f)); juce::NormalisableRange<float>(-48.f, 48.f, 0.1f), 0.f));
params.push_back (std::make_unique<juce::AudioParameterFloat>( params.push_back (std::make_unique<juce::AudioParameterFloat>(
"Peak1Q", "Peak1 Q", "Peak1Q", "Peak1 Q",
@ -64,7 +64,7 @@ CrystalizerEQAudioProcessor::createParameterLayout() {
params.push_back (std::make_unique<juce::AudioParameterFloat>( params.push_back (std::make_unique<juce::AudioParameterFloat>(
"Peak2Gain", "Peak2 Gain (dB)", "Peak2Gain", "Peak2 Gain (dB)",
juce::NormalisableRange<float>(-24.f, 24.f, 0.1f), 0.f)); juce::NormalisableRange<float>(-48.f, 48.f, 0.1f), 0.f));
params.push_back (std::make_unique<juce::AudioParameterFloat>( params.push_back (std::make_unique<juce::AudioParameterFloat>(
"Peak2Q", "Peak2 Q", "Peak2Q", "Peak2 Q",
@ -81,7 +81,7 @@ CrystalizerEQAudioProcessor::createParameterLayout() {
params.push_back (std::make_unique<juce::AudioParameterFloat>( params.push_back (std::make_unique<juce::AudioParameterFloat>(
"Peak3Gain", "Peak3 Gain (dB)", "Peak3Gain", "Peak3 Gain (dB)",
juce::NormalisableRange<float>(-24.f, 24.f, 0.1f), 0.f)); juce::NormalisableRange<float>(-48.f, 48.f, 0.1f), 0.f));
params.push_back (std::make_unique<juce::AudioParameterFloat>( params.push_back (std::make_unique<juce::AudioParameterFloat>(
"Peak3Q", "Peak3 Q", "Peak3Q", "Peak3 Q",
@ -96,7 +96,7 @@ 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", juce::NormalisableRange<float>(-24.f, 24.f, 0.1f), 0.f)); params.push_back (std::make_unique<juce::AudioParameterFloat>("HighBandGain", "HighBand Gain", juce::NormalisableRange<float>(-48.f, 48.f, 0.1f), 0.f));
params.push_back (std::make_unique<juce::AudioParameterFloat>("HighBandQ", "HighBand Q", juce::NormalisableRange<float>(0.1f, 10.f, 0.01f), 1.f)); params.push_back (std::make_unique<juce::AudioParameterFloat>("HighBandQ", "HighBand Q", juce::NormalisableRange<float>(0.1f, 10.f, 0.01f), 1.f));