Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // PluginEditor.h
- #pragma once
- #include "../JuceLibraryCode/JuceHeader.h"
- #include "PluginProcessor.h"
- class SpectrogramComponent : public Component,
- private Timer
- {
- public:
- SpectrogramComponent()
- : forwardFFT(fftOrder),
- spectrogramImage(Image::RGB, 400, 300, true),
- fifoIndex(0),
- nextFFTBlockReady(false)
- {
- setOpaque(true);
- startTimerHz(60);
- }
- ~SpectrogramComponent()
- {
- stopTimer();
- }
- //==============================================================================
- void processAudioBlock(const AudioBuffer<float>& buffer)
- {
- if (buffer.getNumChannels() > 0)
- {
- const float* channelData = buffer.getReadPointer(0);
- for (int i = 0; i < buffer.getNumSamples(); ++i)
- pushNextSampleIntoFifo(channelData[i]);
- }
- }
- //==============================================================================
- void paint(Graphics& g) override
- {
- g.fillAll(Colours::grey);
- g.setOpacity(1.0f);
- g.drawImage(spectrogramImage, getLocalBounds().toFloat());
- }
- void timerCallback() override
- {
- if (nextFFTBlockReady)
- {
- drawNextLineOfSpectrogram();
- nextFFTBlockReady = false;
- repaint();
- }
- }
- void pushNextSampleIntoFifo(float sample) noexcept
- {
- // if the fifo contains enough data, set a flag to say
- // that the next line should now be rendered..
- if (fifoIndex == fftSize)
- {
- if (!nextFFTBlockReady)
- {
- zeromem(fftData, sizeof(fftData));
- memcpy(fftData, fifo, sizeof(fifo));
- nextFFTBlockReady = true;
- }
- fifoIndex = 0;
- }
- fifo[fifoIndex++] = sample;
- }
- void drawNextLineOfSpectrogram()
- {
- const int rightHandEdge = spectrogramImage.getWidth() - 1;
- const int imageHeight = spectrogramImage.getHeight();
- // first, shuffle our image leftwards by 1 pixel..
- spectrogramImage.moveImageSection(0, 0, 1, 0, rightHandEdge, imageHeight);
- // then render our FFT data..
- forwardFFT.performFrequencyOnlyForwardTransform(fftData);
- // find the range of values produced, so we can scale our rendering to
- // show up the detail clearly
- Range<float> maxLevel = FloatVectorOperations::findMinAndMax(fftData, fftSize / 2);
- if (maxLevel.getEnd() == 0.0f)
- maxLevel.setEnd(0.00001);
- for (int y = 1; y < imageHeight; ++y)
- {
- const float skewedProportionY = 1.0f - std::exp(std::log(y / (float)imageHeight) * 0.2f);
- const int fftDataIndex = jlimit(0, fftSize / 2, (int)(skewedProportionY * fftSize / 2));
- const float level = jmap(fftData[fftDataIndex], 0.0f, maxLevel.getEnd(), 0.0f, 1.0f);
- spectrogramImage.setPixelAt(rightHandEdge, y, Colour::fromHSV(level, 1.0f, level, 1.0f));
- }
- }
- enum
- {
- fftOrder = 10,
- fftSize = 1 << fftOrder
- };
- private:
- dsp::FFT forwardFFT;
- Image spectrogramImage;
- float fifo[fftSize];
- float fftData[2 * fftSize];
- int fifoIndex;
- bool nextFFTBlockReady;
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SpectrogramComponent)
- };
- //==============================================================================
- /**
- */
- class SpectrogramPluginAudioProcessorEditor : public AudioProcessorEditor
- {
- public:
- SpectrogramPluginAudioProcessorEditor (SpectrogramPluginAudioProcessor&);
- ~SpectrogramPluginAudioProcessorEditor();
- //==============================================================================
- void paint (Graphics&) override;
- void resized() override;
- SpectrogramComponent m_SpectroGramComp;
- private:
- // This reference is provided as a quick way for your editor to
- // access the processor object that created it.
- SpectrogramPluginAudioProcessor& processor;
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SpectrogramPluginAudioProcessorEditor)
- };
- // PluginEditor.cpp
- /*
- ==============================================================================
- This file was auto-generated!
- It contains the basic framework code for a JUCE plugin editor.
- ==============================================================================
- */
- #include "PluginProcessor.h"
- #include "PluginEditor.h"
- //==============================================================================
- SpectrogramPluginAudioProcessorEditor::SpectrogramPluginAudioProcessorEditor (SpectrogramPluginAudioProcessor& p)
- : AudioProcessorEditor (&p), processor (p)
- {
- // Make sure that before the constructor has finished, you've set the
- // editor's size to whatever you need it to be.
- addAndMakeVisible(&m_SpectroGramComp);
- setSize (400, 300);
- }
- SpectrogramPluginAudioProcessorEditor::~SpectrogramPluginAudioProcessorEditor()
- {
- }
- //==============================================================================
- void SpectrogramPluginAudioProcessorEditor::paint (Graphics& g)
- {
- // (Our component is opaque, so we must completely fill the background with a solid colour)
- g.fillAll (Colours::green);
- }
- void SpectrogramPluginAudioProcessorEditor::resized()
- {
- m_SpectroGramComp.setBounds(0, 0, getWidth(), getHeight());
- }
- // PluginProcessor.cpp
- /*
- ==============================================================================
- This file was auto-generated!
- It contains the basic framework code for a JUCE plugin processor.
- ==============================================================================
- */
- #include "PluginProcessor.h"
- #include "PluginEditor.h"
- //==============================================================================
- SpectrogramPluginAudioProcessor::SpectrogramPluginAudioProcessor()
- #ifndef JucePlugin_PreferredChannelConfigurations
- : AudioProcessor (BusesProperties()
- #if ! JucePlugin_IsMidiEffect
- #if ! JucePlugin_IsSynth
- .withInput ("Input", AudioChannelSet::stereo(), true)
- #endif
- .withOutput ("Output", AudioChannelSet::stereo(), true)
- #endif
- )
- #endif
- {
- }
- SpectrogramPluginAudioProcessor::~SpectrogramPluginAudioProcessor()
- {
- }
- //==============================================================================
- const String SpectrogramPluginAudioProcessor::getName() const
- {
- return JucePlugin_Name;
- }
- bool SpectrogramPluginAudioProcessor::acceptsMidi() const
- {
- #if JucePlugin_WantsMidiInput
- return true;
- #else
- return false;
- #endif
- }
- bool SpectrogramPluginAudioProcessor::producesMidi() const
- {
- #if JucePlugin_ProducesMidiOutput
- return true;
- #else
- return false;
- #endif
- }
- double SpectrogramPluginAudioProcessor::getTailLengthSeconds() const
- {
- return 0.0;
- }
- int SpectrogramPluginAudioProcessor::getNumPrograms()
- {
- return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs,
- // so this should be at least 1, even if you're not really implementing programs.
- }
- int SpectrogramPluginAudioProcessor::getCurrentProgram()
- {
- return 0;
- }
- void SpectrogramPluginAudioProcessor::setCurrentProgram (int index)
- {
- }
- const String SpectrogramPluginAudioProcessor::getProgramName (int index)
- {
- return {};
- }
- void SpectrogramPluginAudioProcessor::changeProgramName (int index, const String& newName)
- {
- }
- //==============================================================================
- void SpectrogramPluginAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
- {
- // Use this method as the place to do any pre-playback
- // initialisation that you need..
- }
- void SpectrogramPluginAudioProcessor::releaseResources()
- {
- // When playback stops, you can use this as an opportunity to free up any
- // spare memory, etc.
- }
- #ifndef JucePlugin_PreferredChannelConfigurations
- bool SpectrogramPluginAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
- {
- #if JucePlugin_IsMidiEffect
- ignoreUnused (layouts);
- return true;
- #else
- // This is the place where you check if the layout is supported.
- // In this template code we only support mono or stereo.
- if (layouts.getMainOutputChannelSet() != AudioChannelSet::mono()
- && layouts.getMainOutputChannelSet() != AudioChannelSet::stereo())
- return false;
- // This checks if the input layout matches the output layout
- #if ! JucePlugin_IsSynth
- if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
- return false;
- #endif
- return true;
- #endif
- }
- #endif
- void SpectrogramPluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
- {
- const int totalNumInputChannels = getTotalNumInputChannels();
- const int totalNumOutputChannels = getTotalNumOutputChannels();
- // In case we have more outputs than inputs, this code clears any output
- // channels that didn't contain input data, (because these aren't
- // guaranteed to be empty - they may contain garbage).
- // This is here to avoid people getting screaming feedback
- // when they first compile a plugin, but obviously you don't need to keep
- // this code if your algorithm always overwrites all the output channels.
- for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
- buffer.clear (i, 0, buffer.getNumSamples());
- auto myeditor = dynamic_cast<SpectrogramPluginAudioProcessorEditor*>(getActiveEditor());
- if (myeditor != nullptr)
- {
- myeditor->m_SpectroGramComp.processAudioBlock(buffer);
- }
- // This is the place where you'd normally do the guts of your plugin's
- // audio processing...
- for (int channel = 0; channel < totalNumInputChannels; ++channel)
- {
- float* channelData = buffer.getWritePointer (channel);
- // ..do something to the data...
- }
- }
- //==============================================================================
- bool SpectrogramPluginAudioProcessor::hasEditor() const
- {
- return true; // (change this to false if you choose to not supply an editor)
- }
- AudioProcessorEditor* SpectrogramPluginAudioProcessor::createEditor()
- {
- return new SpectrogramPluginAudioProcessorEditor (*this);
- }
- //==============================================================================
- void SpectrogramPluginAudioProcessor::getStateInformation (MemoryBlock& destData)
- {
- // You should use this method to store your parameters in the memory block.
- // You could do that either as raw data, or use the XML or ValueTree classes
- // as intermediaries to make it easy to save and load complex data.
- }
- void SpectrogramPluginAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
- {
- // You should use this method to restore your parameters from this memory block,
- // whose contents will have been created by the getStateInformation() call.
- }
- //==============================================================================
- // This creates new instances of the plugin..
- AudioProcessor* JUCE_CALLTYPE createPluginFilter()
- {
- return new SpectrogramPluginAudioProcessor();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement