From 28f83fdb2651eb43edf7cc17171774a6b29b19f7 Mon Sep 17 00:00:00 2001 From: Yifeng Yu Date: Wed, 22 May 2024 16:23:08 -0400 Subject: [PATCH] update spectrum --- Fire.jucer | 4 + Source/Panels/SpectrogramPanel/Multiband.cpp | 2 +- .../SpectrogramPanel/SpectrumBackground.cpp | 62 +++++++++ .../SpectrogramPanel/SpectrumBackground.h | 36 ++++++ .../SpectrogramPanel/SpectrumComponent.cpp | 122 ++++++++---------- .../SpectrogramPanel/SpectrumComponent.h | 9 +- Source/PluginEditor.cpp | 38 ++++-- Source/PluginEditor.h | 5 +- Source/PluginProcessor.cpp | 37 ++++-- Source/PluginProcessor.h | 9 +- 10 files changed, 226 insertions(+), 98 deletions(-) create mode 100644 Source/Panels/SpectrogramPanel/SpectrumBackground.cpp create mode 100644 Source/Panels/SpectrogramPanel/SpectrumBackground.h diff --git a/Fire.jucer b/Fire.jucer index 87d2333..78354b6 100644 --- a/Fire.jucer +++ b/Fire.jucer @@ -33,6 +33,10 @@ + + lineNumLimit && focusIndex == index) { - juce::ColourGradient grad (COLOUR5.withAlpha (0.2f), 0, 0, COLOUR1.withAlpha (0.2f), getLocalBounds().getWidth(), 0, false); + juce::ColourGradient grad(COLOUR5.withAlpha(0.2f), 0, getLocalBounds().getHeight(), COLOUR1.withAlpha(0.0f), 0, getLocalBounds().getHeight() / 10.0f * 9.0f, false); g.setGradientFill (grad); g.fillRect (x, y, width, height); } diff --git a/Source/Panels/SpectrogramPanel/SpectrumBackground.cpp b/Source/Panels/SpectrogramPanel/SpectrumBackground.cpp new file mode 100644 index 0000000..4c74685 --- /dev/null +++ b/Source/Panels/SpectrogramPanel/SpectrumBackground.cpp @@ -0,0 +1,62 @@ +/* + ============================================================================== + + SpectrumBackground.cpp + Created: 22 May 2024 3:13:06pm + Author: 羽翼深蓝Wings + + ============================================================================== +*/ + +#include "SpectrumBackground.h" +#include "SpectrumComponent.h" + +const int SpectrumBackground::frequenciesForLines[] = { 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000 }; +const int SpectrumBackground::numberOfLines = 28; +//============================================================================== +SpectrumBackground::SpectrumBackground() : numberOfBins (1024), mBinWidth (44100 / (float) 2048) +{ +} + +SpectrumBackground::~SpectrumBackground() +{ +} + +void SpectrumBackground::paint (juce::Graphics& g) +{ + // paint background + g.setColour (COLOUR6); + g.fillAll(); + + // paint horizontal lines and frequency numbers + g.setColour (juce::Colours::lightgrey.withAlpha (0.2f)); + g.drawLine (0, getHeight() / 5, getWidth(), getHeight() / 5, 1); + + for (int i = 0; i < numberOfLines; ++i) + { + const double proportion = frequenciesForLines[i] / 20000.0; + int xPos = SpectrumComponent::transformToLog (proportion * 20000) * (getWidth()); + g.drawVerticalLine (xPos, getHeight() / 5, getHeight()); + if (frequenciesForLines[i] == 10 || frequenciesForLines[i] == 100 || frequenciesForLines[i] == 200) + g.drawFittedText (static_cast (frequenciesForLines[i]), xPos - 30, 0, 60, getHeight() / 5, juce::Justification::centred, 2); + else if (frequenciesForLines[i] == 1000 || frequenciesForLines[i] == 10000 || frequenciesForLines[i] == 2000) + g.drawFittedText (static_cast (frequenciesForLines[i] / 1000) + "k", xPos - 30, 0, 60, getHeight() / 5, juce::Justification::centred, 2); + else if (frequenciesForLines[i] == 20) + g.drawFittedText (static_cast (frequenciesForLines[i]), xPos - 30, 0, 60, getHeight() / 5, juce::Justification::right, 2); + else if (frequenciesForLines[i] == 20000) + g.drawFittedText (static_cast (frequenciesForLines[i] / 1000) + "k", xPos - 30, 0, 60, getHeight() / 5, juce::Justification::left, 2); + } + + // paint vertical db numbers + // float fontWidth = 50; + // float fontHeight = getHeight() / 5; + // float centerAlign = fontHeight / 2; + // g.drawFittedText("-20 db", 0, getHeight() / 6 * 2 - centerAlign, fontWidth, fontHeight, juce::Justification::centred, 2); + // g.drawFittedText("-40 db", 0, getHeight() / 6 * 3 - centerAlign, fontWidth, fontHeight, juce::Justification::centred, 2); + // g.drawFittedText("-60 db", 0, getHeight() / 6 * 4 - centerAlign, fontWidth, fontHeight, juce::Justification::centred, 2); + // g.drawFittedText("-80 db", 0, getHeight() / 6 * 5 - centerAlign, fontWidth, fontHeight, juce::Justification::centred, 2); +} + +void SpectrumBackground::resized() +{ +} diff --git a/Source/Panels/SpectrogramPanel/SpectrumBackground.h b/Source/Panels/SpectrogramPanel/SpectrumBackground.h new file mode 100644 index 0000000..74a382a --- /dev/null +++ b/Source/Panels/SpectrogramPanel/SpectrumBackground.h @@ -0,0 +1,36 @@ +/* + ============================================================================== + + SpectrumBackground.h + Created: 22 May 2024 3:13:06pm + Author: 羽翼深蓝Wings + + ============================================================================== +*/ + +#pragma once + +#include +#include "../../GUI/LookAndFeel.h" + +//============================================================================== +/* +*/ +class SpectrumBackground : public juce::Component +{ +public: + SpectrumBackground(); + ~SpectrumBackground(); + + void paint (juce::Graphics& g) override; + void resized() override; + +private: + int numberOfBins; + + static const int frequenciesForLines[]; + static const int numberOfLines; + float mBinWidth; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SpectrumBackground) +}; diff --git a/Source/Panels/SpectrogramPanel/SpectrumComponent.cpp b/Source/Panels/SpectrogramPanel/SpectrumComponent.cpp index 0c3d7ec..2f38fca 100644 --- a/Source/Panels/SpectrogramPanel/SpectrumComponent.cpp +++ b/Source/Panels/SpectrogramPanel/SpectrumComponent.cpp @@ -11,51 +11,23 @@ #include #include "SpectrumComponent.h" -const int SpectrumComponent::frequenciesForLines[] = { 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000 }; -const int SpectrumComponent::numberOfLines = 28; //============================================================================== -SpectrumComponent::SpectrumComponent() : numberOfBins (1024), mBinWidth (44100 / (float) 2048) +SpectrumComponent::SpectrumComponent() : mStyle(1), mDrawPeak(true), numberOfBins (1024), mBinWidth (44100 / (float) 2048) { } +SpectrumComponent::SpectrumComponent(int style, bool drawPeak) : numberOfBins (1024), mBinWidth (44100 / (float) 2048) +{ + mStyle = style; + mDrawPeak = drawPeak; +} + SpectrumComponent::~SpectrumComponent() { } void SpectrumComponent::paint (juce::Graphics& g) { - // paint background - g.setColour (COLOUR6); - g.fillAll(); - - // paint horizontal lines and frequency numbers - g.setColour (juce::Colours::lightgrey.withAlpha (0.2f)); - g.drawLine (0, getHeight() / 5, getWidth(), getHeight() / 5, 1); - - for (int i = 0; i < numberOfLines; ++i) - { - const double proportion = frequenciesForLines[i] / 20000.0; - int xPos = transformToLog (proportion * 20000) * (getWidth()); - g.drawVerticalLine (xPos, getHeight() / 5, getHeight()); - if (frequenciesForLines[i] == 10 || frequenciesForLines[i] == 100 || frequenciesForLines[i] == 200) - g.drawFittedText (static_cast (frequenciesForLines[i]), xPos - 30, 0, 60, getHeight() / 5, juce::Justification::centred, 2); - else if (frequenciesForLines[i] == 1000 || frequenciesForLines[i] == 10000 || frequenciesForLines[i] == 2000) - g.drawFittedText (static_cast (frequenciesForLines[i] / 1000) + "k", xPos - 30, 0, 60, getHeight() / 5, juce::Justification::centred, 2); - else if (frequenciesForLines[i] == 20) - g.drawFittedText (static_cast (frequenciesForLines[i]), xPos - 30, 0, 60, getHeight() / 5, juce::Justification::right, 2); - else if (frequenciesForLines[i] == 20000) - g.drawFittedText (static_cast (frequenciesForLines[i] / 1000) + "k", xPos - 30, 0, 60, getHeight() / 5, juce::Justification::left, 2); - } - - // paint vertical db numbers - // float fontWidth = 50; - // float fontHeight = getHeight() / 5; - // float centerAlign = fontHeight / 2; - // g.drawFittedText("-20 db", 0, getHeight() / 6 * 2 - centerAlign, fontWidth, fontHeight, juce::Justification::centred, 2); - // g.drawFittedText("-40 db", 0, getHeight() / 6 * 3 - centerAlign, fontWidth, fontHeight, juce::Justification::centred, 2); - // g.drawFittedText("-60 db", 0, getHeight() / 6 * 4 - centerAlign, fontWidth, fontHeight, juce::Justification::centred, 2); - // g.drawFittedText("-80 db", 0, getHeight() / 6 * 5 - centerAlign, fontWidth, fontHeight, juce::Justification::centred, 2); - // paint current spectrum g.setColour (juce::Colours::white); paintSpectrum(); @@ -63,41 +35,45 @@ void SpectrumComponent::paint (juce::Graphics& g) currentSpectrumImage.moveImageSection (0, 10, 0, 0, currentSpectrumImage.getWidth(), currentSpectrumImage.getHeight()); g.drawImageAt (currentSpectrumImage, 0, 0); - // paint peak spectrum - maxSpectrumImage.multiplyAllAlphas (0.5); - g.drawImageAt (maxSpectrumImage, 0, 0); + if (mDrawPeak) + { + // paint peak spectrum + maxSpectrumImage.multiplyAllAlphas (0.5); + g.drawImageAt (maxSpectrumImage, 0, 0); - // paint peak text - float mouseX = getMouseXYRelative().getX(); - float mouseY = getMouseXYRelative().getY(); + // paint peak text + float mouseX = getMouseXYRelative().getX(); + float mouseY = getMouseXYRelative().getY(); - if (mouseX > 0 && mouseX < getWidth() - && mouseY > 0 && mouseY < getHeight()) - { - mouseOver = true; - } - else - { - mouseOver = false; - } + if (mouseX > 0 && mouseX < getWidth() + && mouseY > 0 && mouseY < getHeight()) + { + mouseOver = true; + } + else + { + mouseOver = false; + } - if (maxDecibelValue >= -99.9f && mouseOver) - { - float boxWidth = 100.0f; - g.setColour (juce::Colours::lightgrey); - g.drawText (juce::String (maxDecibelValue, 1) + " db", maxDecibelPoint.getX() - boxWidth / 2.0f, maxDecibelPoint.getY() - boxWidth / 4.0f, boxWidth, boxWidth, juce::Justification::centred); - g.drawText (juce::String (static_cast (maxFreq)) + " Hz", maxDecibelPoint.getX() - boxWidth / 2.0f, maxDecibelPoint.getY(), boxWidth, boxWidth, juce::Justification::centred); - } - else - { - maxDecibelValue = -100.0f; - maxFreq = 0.0f; - maxDecibelPoint.setXY (-10.0f, -10.0f); - for (int i = 0; i < 1024; i++) + if (maxDecibelValue >= -99.9f && mouseOver) + { + float boxWidth = 100.0f; + g.setColour (juce::Colours::lightgrey); + g.drawText (juce::String (maxDecibelValue, 1) + " db", maxDecibelPoint.getX() - boxWidth / 2.0f, maxDecibelPoint.getY() - boxWidth / 4.0f, boxWidth, boxWidth, juce::Justification::centred); + g.drawText (juce::String (static_cast (maxFreq)) + " Hz", maxDecibelPoint.getX() - boxWidth / 2.0f, maxDecibelPoint.getY(), boxWidth, boxWidth, juce::Justification::centred); + } + else { - maxData[i] = 0; + maxDecibelValue = -100.0f; + maxFreq = 0.0f; + maxDecibelPoint.setXY (-10.0f, -10.0f); + for (int i = 0; i < 1024; i++) + { + maxData[i] = 0; + } } } + } void SpectrumComponent::resized() @@ -187,8 +163,20 @@ void SpectrumComponent::paintSpectrum() // roundedMaxPath.closeSubPath(); gCurrent.setColour (COLOUR1); + + juce::ColourGradient grad; - juce::ColourGradient grad (juce::Colours::red.withAlpha (0.8f), 0, 0, COLOUR1.withAlpha (0.8f), 0, getLocalBounds().getHeight(), false); + if (mStyle == 1) + { + grad = juce::ColourGradient(juce::Colours::red.withAlpha(specAlpha), 0, 0, COLOUR1.withAlpha(specAlpha), 0, getLocalBounds().getHeight(), false); + } + else + { + grad = juce::ColourGradient(juce::Colours::white.withAlpha(0.2f), 0, 0, juce::Colours::grey.withAlpha(0.2f), 0, getLocalBounds().getHeight(), false); + } + + gCurrent.setGradientFill(grad); + gCurrent.setGradientFill (grad); gCurrent.fillPath (roundedCurrentPath); @@ -209,6 +197,10 @@ void SpectrumComponent::prepareToPaintSpectrum (int numBins, float* data, float mBinWidth = binWidth; } +void SpectrumComponent::setSpecAlpha (const float alp) { + specAlpha = alp; +} + float SpectrumComponent::transformToLog (double valueToTransform) // freq to x { // input: 20-20000 diff --git a/Source/Panels/SpectrogramPanel/SpectrumComponent.h b/Source/Panels/SpectrogramPanel/SpectrumComponent.h index c13b8f5..f736d3e 100644 --- a/Source/Panels/SpectrogramPanel/SpectrumComponent.h +++ b/Source/Panels/SpectrogramPanel/SpectrumComponent.h @@ -20,16 +20,20 @@ class SpectrumComponent : public juce::Component { public: SpectrumComponent(); + SpectrumComponent(int style, bool drawPeak); ~SpectrumComponent(); void paint (juce::Graphics& g) override; void prepareToPaintSpectrum (int numberOfBins, float* spectrumData, float binWidth); + void setSpecAlpha(const float alp); static float transformToLog (double valueToTransform); static float transformFromLog (double between0and1); void resized() override; void paintSpectrum(); private: + int mStyle; + bool mDrawPeak; int numberOfBins; float spectrumData[1024] = { 0 }; float maxData[1024] = { 0 }; @@ -41,8 +45,9 @@ class SpectrumComponent : public juce::Component juce::Image currentSpectrumImage = juce::Image (juce::Image::ARGB, 1000, 300, true); juce::Image maxSpectrumImage = juce::Image (juce::Image::ARGB, 1000, 300, true); - static const int frequenciesForLines[]; - static const int numberOfLines; float mBinWidth; + float specAlpha = 0.8f; + + juce::ColourGradient specGrad; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SpectrumComponent) }; diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index d601984..2dce5e2 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -36,7 +36,9 @@ FireAudioProcessorEditor::FireAudioProcessorEditor (FireAudioProcessor& p) addAndMakeVisible (globalPanel); // Spectrum - addAndMakeVisible(spectrum); + addAndMakeVisible(specBackground); + addAndMakeVisible(processedSpectrum); + addAndMakeVisible(originalSpectrum); addAndMakeVisible(multiband); multiband.addMouseListener(this, false); updateWhenChangingFocus(); @@ -49,8 +51,9 @@ FireAudioProcessorEditor::FireAudioProcessorEditor (FireAudioProcessor& p) bandPanel.getWidthButton (i).addListener (this); } - spectrum.setInterceptsMouseClicks (false, false); - spectrum.prepareToPaintSpectrum (processor.getNumBins(), processor.getFFTData(), processor.getSampleRate() / (float) processor.getFFTSize()); + processedSpectrum.setInterceptsMouseClicks (false, false); + processedSpectrum.prepareToPaintSpectrum (processor.getNumBins(), processor.getFFTData(1), processor.getSampleRate() / (float) processor.getFFTSize()); + originalSpectrum.prepareToPaintSpectrum (processor.getNumBins(), processor.getFFTData(0), processor.getSampleRate() / (float) processor.getFFTSize()); // presets addAndMakeVisible (stateComponent); @@ -283,14 +286,18 @@ void FireAudioProcessorEditor::resized() if (zoomButton.getToggleState()) { juce::Rectangle spectrumArea = area; - spectrum.setBounds (spectrumArea); + specBackground.setBounds (spectrumArea); + processedSpectrum.setBounds (spectrumArea); + originalSpectrum.setBounds (spectrumArea); multiband.setBounds (spectrumArea); filterControl.setBounds (spectrumArea); } else { juce::Rectangle spectrumArea = area.removeFromTop (SPEC_HEIGHT); - spectrum.setBounds (spectrumArea); + specBackground.setBounds (spectrumArea); + processedSpectrum.setBounds (spectrumArea); + originalSpectrum.setBounds (spectrumArea); multiband.setBounds (spectrumArea); filterControl.setBounds (spectrumArea); @@ -360,15 +367,24 @@ void FireAudioProcessorEditor::timerCallback() //(1<<11) // create a temp ddtData because sometimes pushNextSampleIntoFifo will replace the original // fftData after doingProcess and before painting. - float tempFFTData[2 * 2048] = { 0 }; - memmove (tempFFTData, processor.getFFTData(), sizeof (tempFFTData)); - // doing process, fifo data to fft data - processor.processFFT (tempFFTData); + + float tempFFTDataProcessed[2 * 2048] = { 0 }; + memmove(tempFFTDataProcessed, processor.getFFTData(1), sizeof(tempFFTDataProcessed)); + processor.processFFT(tempFFTDataProcessed, 1); + float tempFFTDataOriginal[2 * 2048] = { 0 }; + memmove(tempFFTDataOriginal, processor.getFFTData(0), sizeof(tempFFTDataOriginal)); + processor.processFFT(tempFFTDataOriginal, 0); + // prepare to paint the spectrum - spectrum.prepareToPaintSpectrum (processor.getNumBins(), tempFFTData, processor.getSampleRate() / (float) processor.getFFTSize()); + float specAlpha = static_cast (*processor.treeState.getRawParameterValue (MIX_ID)); + processedSpectrum.setSpecAlpha(specAlpha); + originalSpectrum.setSpecAlpha(specAlpha); + processedSpectrum.prepareToPaintSpectrum (processor.getNumBins(), tempFFTDataProcessed, processor.getSampleRate() / (float) processor.getFFTSize()); + originalSpectrum.prepareToPaintSpectrum (processor.getNumBins(), tempFFTDataOriginal, processor.getSampleRate() / (float) processor.getFFTSize()); graphPanel.repaint(); - spectrum.repaint(); + processedSpectrum.repaint(); + originalSpectrum.repaint(); multiband.repaint(); bandPanel.repaint(); globalPanel.repaint(); diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index 11b1b4f..ddc769d 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -22,6 +22,7 @@ #include "Panels/SpectrogramPanel/Multiband.h" #include "Panels/SpectrogramPanel/FilterControl.h" #include "GUI/InterfaceDefines.h" +#include "Panels/SpectrogramPanel/SpectrumBackground.h" //============================================================================== /** @@ -73,7 +74,9 @@ class FireAudioProcessorEditor : public juce::AudioProcessorEditor, FilterControl filterControl { processor, globalPanel }; // Spectrum - SpectrumComponent spectrum; + SpectrumComponent processedSpectrum{1, true}; + SpectrumComponent originalSpectrum{0, false}; + SpectrumBackground specBackground; // Labels juce::Label hqLabel; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 23dbd11..d48efec 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -715,7 +715,8 @@ void FireAudioProcessor::processBlock (juce::AudioBuffer& buffer, juce::M // Spectrum mWetBuffer.makeCopyOf (buffer); - pushDataToFFT(); + pushDataToFFT(mWetBuffer, processedSpecProcessor); + pushDataToFFT(mDryBuffer, originalSpecProcessor); // VU output meter setLeftRightMeterRMSValues (buffer, mOutputLeftSmoothedGlobal, mOutputRightSmoothedGlobal); @@ -983,41 +984,49 @@ juce::Array FireAudioProcessor::getHistoryArrayR() return historyArrayR; } -float* FireAudioProcessor::getFFTData() +float* FireAudioProcessor::getFFTData(int dataIndex) { - return spectrum_processor.fftData; + if (dataIndex == 0) + { + return originalSpecProcessor.fftData; + } + else + { + return processedSpecProcessor.fftData; + } } int FireAudioProcessor::getNumBins() { - return spectrum_processor.numBins; + return processedSpecProcessor.numBins; } int FireAudioProcessor::getFFTSize() { - return spectrum_processor.fftSize; + return processedSpecProcessor.fftSize; } bool FireAudioProcessor::isFFTBlockReady() { - return spectrum_processor.nextFFTBlockReady; + return processedSpecProcessor.nextFFTBlockReady; } -void FireAudioProcessor::pushDataToFFT() +void FireAudioProcessor::pushDataToFFT(juce::AudioBuffer& buffer, SpectrumProcessor& specProcessor) { - if (mWetBuffer.getNumChannels() > 0) + if (buffer.getNumChannels() > 0) { - auto* channelData = mWetBuffer.getReadPointer (0); + auto* channelData = buffer.getReadPointer(0); - for (auto i = 0; i < mWetBuffer.getNumSamples(); ++i) - spectrum_processor.pushNextSampleIntoFifo (channelData[i]); + for (auto i = 0; i < buffer.getNumSamples(); ++i) + specProcessor.pushNextSampleIntoFifo(channelData[i]); } } -void FireAudioProcessor::processFFT (float* tempFFTData) +void FireAudioProcessor::processFFT(float* tempFFTData, int dataIndex) { - spectrum_processor.doProcessing (tempFFTData); - spectrum_processor.nextFFTBlockReady = false; + SpectrumProcessor& specProcessor = (dataIndex == 0) ? originalSpecProcessor : processedSpecProcessor; + specProcessor.doProcessing(tempFFTData); + specProcessor.nextFFTBlockReady = false; } float FireAudioProcessor::safeMode (float drive, juce::AudioBuffer& buffer, juce::String safeID) diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index fa1f1f6..43c1c64 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -83,12 +83,12 @@ class FireAudioProcessor : public juce::AudioProcessor state::StatePresets statePresets; // FFT - float* getFFTData(); + float* getFFTData(int dataIndex); int getNumBins(); int getFFTSize(); bool isFFTBlockReady(); - void pushDataToFFT(); - void processFFT (float* tempFFTData); + void pushDataToFFT(juce::AudioBuffer& buffer, SpectrumProcessor& specProcessor); + void processFFT (float* tempFFTData, int dataIndex); // save size void setSavedWidth (const int width); @@ -129,7 +129,8 @@ class FireAudioProcessor : public juce::AudioProcessor int historyLength = 400; // Spectrum - SpectrumProcessor spectrum_processor; + SpectrumProcessor processedSpecProcessor; + SpectrumProcessor originalSpecProcessor; // dry audio buffer juce::AudioBuffer mDryBuffer;