mirror of
https://codeberg.org/armin/chromaflock.git
synced 2026-09-01 04:10:47 +02:00
UI polish: amber theme, smooth spectrum, MIDI LED, VU tuning
- Rename section labels: COMPRESSOR → COMPRESSION, AUTO-PAN → PANNING - Replace spectrum analyzer bars with smooth gapless filled wave - Use gold (#c59c07) for wave/spectrum strokes and piano roll active keys - Amber CRT-style patch LCD with dark background and gold dot-matrix text - Add MIDI signal LED with glow between semi and scale controls - Reduce VU meter sensitivity (5x → 1.5x) and match amber gradient theme - Add subtle glow behind section and sub-section boxes - Fix Compressor.h class name and PluginProcessor include to match
This commit is contained in:
parent
efbad6c88e
commit
628e1e3cba
6 changed files with 120 additions and 41 deletions
|
|
@ -168,7 +168,7 @@ void VuMeter::paint(juce::Graphics& g) {
|
|||
clipPath.addRoundedRectangle(bounds, 9.0f);
|
||||
g.reduceClipRegion(clipPath);
|
||||
|
||||
juce::ColourGradient grad(juce::Colour(0xff00cc44).withAlpha(0.7f), 0.0f, bounds.getBottom(),
|
||||
juce::ColourGradient grad(juce::Colour(0xffc59c07).withAlpha(0.7f), 0.0f, bounds.getBottom(),
|
||||
juce::Colour(0xffcc2200).withAlpha(0.7f), 0.0f, bounds.getY(), false);
|
||||
g.setGradientFill(grad);
|
||||
g.fillRoundedRectangle(innerBar, 2.0f);
|
||||
|
|
@ -230,13 +230,13 @@ void WaveformDisplay::paint(juce::Graphics& g) {
|
|||
clipPath.addRoundedRectangle(bounds, 9.0f);
|
||||
g.reduceClipRegion(clipPath);
|
||||
|
||||
juce::ColourGradient waveGrad(juce::Colour(0xff00ff88).withAlpha(0.5f), 0.0f, bounds.getY(),
|
||||
juce::Colour(0xff005522).withAlpha(0.4f), 0.0f, bounds.getBottom(), false);
|
||||
juce::ColourGradient waveGrad(juce::Colour(0xffc59c07).withAlpha(0.5f), 0.0f, bounds.getY(),
|
||||
juce::Colour(0xff3d2e02).withAlpha(0.4f), 0.0f, bounds.getBottom(), false);
|
||||
g.setGradientFill(waveGrad);
|
||||
g.fillPath(filledPath);
|
||||
|
||||
g.setColour(juce::Colour(0xff00ff88).withAlpha(0.7f));
|
||||
g.strokePath(wavePath, juce::PathStrokeType(0.7f));
|
||||
g.setColour(juce::Colour(0xffc59c07).withAlpha(0.9f));
|
||||
g.strokePath(wavePath, juce::PathStrokeType(1.5f));
|
||||
}
|
||||
|
||||
g.setColour(juce::Colour(0xffccaa44));
|
||||
|
|
@ -272,23 +272,26 @@ void SpectrumAnalyzer::paint(juce::Graphics& g) {
|
|||
|
||||
fft->performFrequencyOnlyForwardTransform(fftData.data());
|
||||
|
||||
int numBars = 48;
|
||||
int numPoints = 128;
|
||||
float w = bounds.getWidth();
|
||||
float h = bounds.getHeight() - 22.0f;
|
||||
float barBottom = bounds.getBottom() - 2.0f;
|
||||
float barW = w / static_cast<float>(numBars);
|
||||
float bottom = bounds.getBottom() - 2.0f;
|
||||
int maxBin = fftSize / 4;
|
||||
float sampleRate = static_cast<float>(processor.getSampleRate());
|
||||
float binHz = sampleRate / static_cast<float>(fftSize);
|
||||
float lowCut = 80.0f;
|
||||
float lowPass = 250.0f;
|
||||
|
||||
juce::Graphics::ScopedSaveState savedClip(g);
|
||||
juce::Path clipPath;
|
||||
clipPath.addRoundedRectangle(bounds, 9.0f);
|
||||
g.reduceClipRegion(clipPath);
|
||||
|
||||
for (int bar = 0; bar < numBars; ++bar) {
|
||||
float t = static_cast<float>(bar) / static_cast<float>(numBars);
|
||||
float tNext = static_cast<float>(bar + 1) / static_cast<float>(numBars);
|
||||
std::vector<float> mags(numPoints + 1);
|
||||
for (int i = 0; i <= numPoints; ++i) {
|
||||
float t = static_cast<float>(i) / static_cast<float>(numPoints);
|
||||
int binStart = static_cast<int>(std::pow(t, 2.0f) * static_cast<float>(maxBin));
|
||||
int binEnd = static_cast<int>(std::pow(tNext, 2.0f) * static_cast<float>(maxBin));
|
||||
int binEnd = static_cast<int>(std::pow(t + 1.0f / static_cast<float>(numPoints), 2.0f) * static_cast<float>(maxBin));
|
||||
if (binEnd <= binStart) binEnd = binStart + 1;
|
||||
if (binEnd > maxBin) binEnd = maxBin;
|
||||
|
||||
|
|
@ -301,24 +304,43 @@ void SpectrumAnalyzer::paint(juce::Graphics& g) {
|
|||
mag = count > 0 ? mag / static_cast<float>(count) : 0.0f;
|
||||
mag = mag / static_cast<float>(fftSize);
|
||||
mag = std::sqrt(mag) * 6.0f;
|
||||
mag = juce::jlimit(0.0f, 1.0f, mag);
|
||||
|
||||
float barH = mag * h;
|
||||
float x = bounds.getX() + static_cast<float>(bar) * barW;
|
||||
float bw = barW - 2.0f;
|
||||
float bx = x + 1.0f;
|
||||
float by = barBottom - barH;
|
||||
|
||||
g.setColour(juce::Colour(0xff00ff88).withAlpha(0.4f));
|
||||
g.fillRect(bx, by, bw, barH);
|
||||
float centerHz = static_cast<float>((binStart + binEnd) / 2) * binHz;
|
||||
float rolloff = juce::jlimit(0.0f, 1.0f, (centerHz - lowCut) / (lowPass - lowCut));
|
||||
mag *= rolloff;
|
||||
mags[i] = juce::jlimit(0.0f, 1.0f, mag);
|
||||
}
|
||||
|
||||
juce::Path wavePath;
|
||||
wavePath.startNewSubPath(bounds.getX(), bottom);
|
||||
juce::Path strokePath;
|
||||
strokePath.startNewSubPath(bounds.getX(), bottom - mags[0] * h);
|
||||
|
||||
for (int i = 0; i <= numPoints; ++i) {
|
||||
float t = static_cast<float>(i) / static_cast<float>(numPoints);
|
||||
float x = bounds.getX() + t * w;
|
||||
float y = bottom - mags[i] * h;
|
||||
wavePath.lineTo(x, y);
|
||||
if (i > 0) strokePath.lineTo(x, y);
|
||||
}
|
||||
|
||||
wavePath.lineTo(bounds.getRight(), bottom);
|
||||
wavePath.closeSubPath();
|
||||
|
||||
juce::ColourGradient fillGrad(juce::Colour(0xffc59c07).withAlpha(0.35f), 0.0f, bottom,
|
||||
juce::Colour(0xffc59c07).withAlpha(0.02f), 0.0f, bottom - h, false);
|
||||
g.setGradientFill(fillGrad);
|
||||
g.fillPath(wavePath);
|
||||
|
||||
g.setColour(juce::Colour(0xffc59c07).withAlpha(0.9f));
|
||||
g.strokePath(strokePath, juce::PathStrokeType(1.5f));
|
||||
|
||||
g.setColour(juce::Colour(0xffccaa44));
|
||||
g.setFont(juce::Font(13.0f).boldened());
|
||||
g.drawText("SPECTRUM", bounds.withBottom(bounds.getY() + 22.0f).translated(0, 6), juce::Justification::centred);
|
||||
}
|
||||
|
||||
// --- Patch LCD (green dot-matrix) ---
|
||||
// --- Patch LCD (amber dot-matrix) ---
|
||||
namespace {
|
||||
struct Glyph { char c; unsigned char rows[7]; };
|
||||
// 5x7 font; each byte is a row, bits 4..0 are columns left->right.
|
||||
|
|
@ -374,16 +396,16 @@ void PatchLCD::paint(juce::Graphics& g) {
|
|||
auto b = getLocalBounds();
|
||||
|
||||
// Dark LCD panel
|
||||
g.setColour(juce::Colour(0xcc061206));
|
||||
g.setColour(juce::Colour(0xcc1a0e00));
|
||||
g.fillRoundedRectangle(b.toFloat(), 3.0f);
|
||||
g.setColour(juce::Colour(0xff114411));
|
||||
g.setColour(juce::Colour(0xff5a3a00));
|
||||
g.drawRoundedRectangle(b.toFloat(), 3.0f, 1.0f);
|
||||
|
||||
const int pitch = 3;
|
||||
const int glyphW = 5, glyphH = 7, glyphGap = 1;
|
||||
|
||||
// Faint "off" LED grid
|
||||
g.setColour(juce::Colour(0xff0a200a));
|
||||
g.setColour(juce::Colour(0xff1a1000));
|
||||
for (int y = pitch / 2; y < b.getHeight(); y += pitch)
|
||||
for (int x = pitch / 2; x < b.getWidth(); x += pitch)
|
||||
g.fillRect(static_cast<float>(x) - 0.5f, static_cast<float>(y) - 0.5f, 1.0f, 1.0f);
|
||||
|
|
@ -402,9 +424,9 @@ void PatchLCD::paint(juce::Graphics& g) {
|
|||
if (bits & (1 << (glyphW - 1 - col))) {
|
||||
float px = static_cast<float>(cx + col * pitch + pitch / 2);
|
||||
float py = static_cast<float>(cy + row * pitch + pitch / 2);
|
||||
g.setColour(juce::Colour(0xff1a330a));
|
||||
g.setColour(juce::Colour(0xff3a2000));
|
||||
g.fillEllipse(px - pitch * 0.5f, py - pitch * 0.5f, pitch, pitch);
|
||||
g.setColour(juce::Colour(0xff33ff66));
|
||||
g.setColour(juce::Colour(0xffc59c07));
|
||||
g.fillEllipse(px - pitch * 0.4f, py - pitch * 0.4f, pitch * 0.8f, pitch * 0.8f);
|
||||
}
|
||||
}
|
||||
|
|
@ -414,8 +436,32 @@ void PatchLCD::paint(juce::Graphics& g) {
|
|||
}
|
||||
}
|
||||
|
||||
// --- MIDI Signal LED ---
|
||||
void MidiLed::paint(juce::Graphics& g) {
|
||||
auto b = getLocalBounds().toFloat();
|
||||
auto centre = b.getCentre();
|
||||
float radius = juce::jmin(b.getWidth(), b.getHeight()) * 0.5f;
|
||||
|
||||
bool active = processor.isAnyNoteActive();
|
||||
|
||||
if (active) {
|
||||
g.setColour(juce::Colour(0xffc59c07).withAlpha(0.2f));
|
||||
g.fillEllipse(centre.x - radius * 1.8f, centre.y - radius * 1.8f, radius * 3.6f, radius * 3.6f);
|
||||
}
|
||||
|
||||
g.setColour(juce::Colour(0xff1a1200));
|
||||
g.fillEllipse(centre.x - radius, centre.y - radius, radius * 2.0f, radius * 2.0f);
|
||||
|
||||
if (active)
|
||||
g.setColour(juce::Colour(0xffc59c07));
|
||||
else
|
||||
g.setColour(juce::Colour(0xff3a2a06));
|
||||
|
||||
g.fillEllipse(centre.x - radius * 0.75f, centre.y - radius * 0.75f, radius * 1.5f, radius * 1.5f);
|
||||
}
|
||||
|
||||
MainContentComponent::MainContentComponent(ChromaFlockProcessor& p)
|
||||
: processorRef(p), vuMeter(p), waveformDisplay(p), spectrumAnalyzer(p), pianoRoll(p) {
|
||||
: processorRef(p), vuMeter(p), waveformDisplay(p), spectrumAnalyzer(p), pianoRoll(p), midiLed(p) {
|
||||
|
||||
auto setupParam = [&](juce::Slider& knob, std::unique_ptr<SliderAttachment>& attach,
|
||||
const juce::String& paramId, const juce::String& name) {
|
||||
|
|
@ -534,6 +580,7 @@ MainContentComponent::MainContentComponent(ChromaFlockProcessor& p)
|
|||
addAndMakeVisible(presetButton);
|
||||
|
||||
addAndMakeVisible(patchLCD);
|
||||
addAndMakeVisible(midiLed);
|
||||
patchLCD.onClick = [this]() { showFileMenu(); };
|
||||
|
||||
auto setupArrow = [&](juce::TextButton& btn) {
|
||||
|
|
@ -576,6 +623,12 @@ MainContentComponent::MainContentComponent(ChromaFlockProcessor& p)
|
|||
scaleLabel.setJustificationType(juce::Justification::centredRight);
|
||||
addAndMakeVisible(scaleLabel);
|
||||
|
||||
midiLabel.setText("MIDI IN", juce::dontSendNotification);
|
||||
midiLabel.setFont(juce::Font(9.0f));
|
||||
midiLabel.setColour(juce::Label::textColourId, juce::Colour(0xff888888));
|
||||
midiLabel.setJustificationType(juce::Justification::centredLeft);
|
||||
addAndMakeVisible(midiLabel);
|
||||
|
||||
auto setupTransposeLabel = [&](juce::Label& label, const juce::String& text) {
|
||||
label.setText(text, juce::dontSendNotification);
|
||||
label.setFont(juce::Font(9.0f));
|
||||
|
|
@ -916,6 +969,10 @@ void MainContentComponent::paint(juce::Graphics& g) {
|
|||
auto drawSection = [&](int x, int y, int w, int h) {
|
||||
auto rect = juce::Rectangle<float>(static_cast<float>(x), static_cast<float>(y),
|
||||
static_cast<float>(w), static_cast<float>(h));
|
||||
// Soft glow behind section
|
||||
auto glow = rect.expanded(6.0f);
|
||||
g.setColour(juce::Colour(0xff222222).withAlpha(0.25f));
|
||||
g.fillRoundedRectangle(glow, 12.0f);
|
||||
// 3D fill gradient: slight light top, dark bottom
|
||||
juce::ColourGradient fillGrad(juce::Colour(0xBB222222), rect.getCentreX(), rect.getY(),
|
||||
juce::Colour(0xBB111111), rect.getCentreX(), rect.getBottom(), false);
|
||||
|
|
@ -938,6 +995,9 @@ void MainContentComponent::paint(juce::Graphics& g) {
|
|||
auto drawSubSection = [&](int x, int y, int w, int h, const juce::String& title, int titlePadY = 2) {
|
||||
auto rect = juce::Rectangle<float>(static_cast<float>(x), static_cast<float>(y),
|
||||
static_cast<float>(w), static_cast<float>(h));
|
||||
auto glow = rect.expanded(6.0f);
|
||||
g.setColour(juce::Colour(0xff222222).withAlpha(0.25f));
|
||||
g.fillRoundedRectangle(glow, 12.0f);
|
||||
juce::ColourGradient fillGrad(juce::Colour(0xBB222222), rect.getCentreX(), rect.getY(),
|
||||
juce::Colour(0xBB111111), rect.getCentreX(), rect.getBottom(), false);
|
||||
g.setGradientFill(fillGrad);
|
||||
|
|
@ -950,8 +1010,8 @@ void MainContentComponent::paint(juce::Graphics& g) {
|
|||
};
|
||||
|
||||
drawSubSection(10, 508, 510, 140, "DISTORTION", 6);
|
||||
drawSubSection(528, 508, 468, 140, "COMPRESSOR", 6);
|
||||
drawSubSection(1004, 508, 268, 140, "AUTO-PAN", 6);
|
||||
drawSubSection(528, 508, 468, 140, "COMPRESSION", 6);
|
||||
drawSubSection(1004, 508, 268, 140, "PANNING", 6);
|
||||
drawSubSection(1280, 508, 370, 140, "LIMITER", 6);
|
||||
|
||||
// LFO sub-sections
|
||||
|
|
@ -1048,7 +1108,7 @@ void MainContentComponent::resized() {
|
|||
distToneKnob.setBounds(dx + (fxKnobSize + 6) * 2, fxKnobY, fxKnobSize, fxKnobSize);
|
||||
}
|
||||
|
||||
// Compressor sub-section (X=528, W=470)
|
||||
// Compression sub-section (X=528, W=470)
|
||||
{
|
||||
int rowW = 5 * fxKnobSize + 4 * 6;
|
||||
int sx = 528 + (470 - rowW) / 2;
|
||||
|
|
@ -1142,6 +1202,9 @@ void MainContentComponent::resized() {
|
|||
semitoneTransposeLabel.setBounds(1214, labelY2, 32, labelH2);
|
||||
semitoneTransposeBox.setBounds(1246, comboY2, 74, comboH2);
|
||||
|
||||
midiLabel.setBounds(1340, labelY2, 46, labelH2);
|
||||
midiLed.setBounds(1390, (headerH - 10) / 2, 10, 10);
|
||||
|
||||
scaleLabel.setBounds(1514, labelY2, 42, labelH2);
|
||||
uiScaleBox.setBounds(1560, comboY2, 80, comboH2);
|
||||
|
||||
|
|
@ -1324,7 +1387,7 @@ void PianoRollComponent::paint(juce::Graphics& g) {
|
|||
|
||||
bool pressed = processor.isNoteActive(note);
|
||||
if (pressed) {
|
||||
g.setColour(juce::Colour(0xffccaa44));
|
||||
g.setColour(juce::Colour(0xff996600));
|
||||
} else {
|
||||
juce::ColourGradient grad(juce::Colour(0xff444444), static_cast<float>(bx), 0.0f,
|
||||
juce::Colour(0xff222222), static_cast<float>(bx), static_cast<float>(blackKeyHeight), false);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue