Advertisement
Guest User

Untitled

a guest
Aug 7th, 2017
268
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.91 KB | None | 0 0
  1. // PluginEditor.h
  2.  
  3. #pragma once
  4.  
  5. #include "../JuceLibraryCode/JuceHeader.h"
  6. #include "PluginProcessor.h"
  7.  
  8. class SpectrogramComponent : public Component,
  9.     private Timer
  10. {
  11. public:
  12.     SpectrogramComponent()
  13.         : forwardFFT(fftOrder),
  14.         spectrogramImage(Image::RGB, 400, 300, true),
  15.         fifoIndex(0),
  16.         nextFFTBlockReady(false)
  17.     {
  18.         setOpaque(true);
  19.         startTimerHz(60);
  20.     }
  21.  
  22.     ~SpectrogramComponent()
  23.     {
  24.         stopTimer();
  25.     }
  26.  
  27.     //==============================================================================
  28.    
  29.     void processAudioBlock(const AudioBuffer<float>& buffer)
  30.     {
  31.         if (buffer.getNumChannels() > 0)
  32.         {
  33.             const float* channelData = buffer.getReadPointer(0);
  34.             for (int i = 0; i < buffer.getNumSamples(); ++i)
  35.                 pushNextSampleIntoFifo(channelData[i]);
  36.         }
  37.     }
  38.  
  39.     //==============================================================================
  40.     void paint(Graphics& g) override
  41.     {
  42.         g.fillAll(Colours::grey);
  43.  
  44.         g.setOpacity(1.0f);
  45.         g.drawImage(spectrogramImage, getLocalBounds().toFloat());
  46.     }
  47.  
  48.     void timerCallback() override
  49.     {
  50.         if (nextFFTBlockReady)
  51.         {
  52.             drawNextLineOfSpectrogram();
  53.             nextFFTBlockReady = false;
  54.             repaint();
  55.         }
  56.     }
  57.  
  58.     void pushNextSampleIntoFifo(float sample) noexcept
  59.     {
  60.         // if the fifo contains enough data, set a flag to say
  61.         // that the next line should now be rendered..
  62.         if (fifoIndex == fftSize)
  63.         {
  64.             if (!nextFFTBlockReady)
  65.             {
  66.                 zeromem(fftData, sizeof(fftData));
  67.                 memcpy(fftData, fifo, sizeof(fifo));
  68.                 nextFFTBlockReady = true;
  69.             }
  70.  
  71.             fifoIndex = 0;
  72.         }
  73.  
  74.         fifo[fifoIndex++] = sample;
  75.     }
  76.  
  77.     void drawNextLineOfSpectrogram()
  78.     {
  79.         const int rightHandEdge = spectrogramImage.getWidth() - 1;
  80.         const int imageHeight = spectrogramImage.getHeight();
  81.  
  82.         // first, shuffle our image leftwards by 1 pixel..
  83.         spectrogramImage.moveImageSection(0, 0, 1, 0, rightHandEdge, imageHeight);
  84.  
  85.         // then render our FFT data..
  86.         forwardFFT.performFrequencyOnlyForwardTransform(fftData);
  87.  
  88.         // find the range of values produced, so we can scale our rendering to
  89.         // show up the detail clearly
  90.         Range<float> maxLevel = FloatVectorOperations::findMinAndMax(fftData, fftSize / 2);
  91.         if (maxLevel.getEnd() == 0.0f)
  92.             maxLevel.setEnd(0.00001);
  93.         for (int y = 1; y < imageHeight; ++y)
  94.         {
  95.             const float skewedProportionY = 1.0f - std::exp(std::log(y / (float)imageHeight) * 0.2f);
  96.             const int fftDataIndex = jlimit(0, fftSize / 2, (int)(skewedProportionY * fftSize / 2));
  97.             const float level = jmap(fftData[fftDataIndex], 0.0f, maxLevel.getEnd(), 0.0f, 1.0f);
  98.  
  99.             spectrogramImage.setPixelAt(rightHandEdge, y, Colour::fromHSV(level, 1.0f, level, 1.0f));
  100.         }
  101.     }
  102.  
  103.     enum
  104.     {
  105.         fftOrder = 10,
  106.         fftSize = 1 << fftOrder
  107.     };
  108.  
  109. private:
  110.     dsp::FFT forwardFFT;
  111.     Image spectrogramImage;
  112.  
  113.     float fifo[fftSize];
  114.     float fftData[2 * fftSize];
  115.     int fifoIndex;
  116.     bool nextFFTBlockReady;
  117.  
  118.     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SpectrogramComponent)
  119. };
  120.  
  121.  
  122. //==============================================================================
  123. /**
  124. */
  125. class SpectrogramPluginAudioProcessorEditor  : public AudioProcessorEditor
  126. {
  127. public:
  128.     SpectrogramPluginAudioProcessorEditor (SpectrogramPluginAudioProcessor&);
  129.     ~SpectrogramPluginAudioProcessorEditor();
  130.  
  131.     //==============================================================================
  132.     void paint (Graphics&) override;
  133.     void resized() override;
  134.     SpectrogramComponent m_SpectroGramComp;
  135. private:
  136.     // This reference is provided as a quick way for your editor to
  137.     // access the processor object that created it.
  138.     SpectrogramPluginAudioProcessor& processor;
  139.    
  140.     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SpectrogramPluginAudioProcessorEditor)
  141. };
  142.  
  143. // PluginEditor.cpp
  144.  
  145. /*
  146.   ==============================================================================
  147.  
  148.     This file was auto-generated!
  149.  
  150.     It contains the basic framework code for a JUCE plugin editor.
  151.  
  152.   ==============================================================================
  153. */
  154.  
  155. #include "PluginProcessor.h"
  156. #include "PluginEditor.h"
  157.  
  158.  
  159. //==============================================================================
  160. SpectrogramPluginAudioProcessorEditor::SpectrogramPluginAudioProcessorEditor (SpectrogramPluginAudioProcessor& p)
  161.     : AudioProcessorEditor (&p), processor (p)
  162. {
  163.     // Make sure that before the constructor has finished, you've set the
  164.     // editor's size to whatever you need it to be.
  165.     addAndMakeVisible(&m_SpectroGramComp);
  166.     setSize (400, 300);
  167. }
  168.  
  169. SpectrogramPluginAudioProcessorEditor::~SpectrogramPluginAudioProcessorEditor()
  170. {
  171. }
  172.  
  173. //==============================================================================
  174. void SpectrogramPluginAudioProcessorEditor::paint (Graphics& g)
  175. {
  176.     // (Our component is opaque, so we must completely fill the background with a solid colour)
  177.     g.fillAll (Colours::green);
  178. }
  179.  
  180. void SpectrogramPluginAudioProcessorEditor::resized()
  181. {
  182.     m_SpectroGramComp.setBounds(0, 0, getWidth(), getHeight());
  183. }
  184.  
  185. // PluginProcessor.cpp
  186.  
  187. /*
  188.   ==============================================================================
  189.  
  190.     This file was auto-generated!
  191.  
  192.     It contains the basic framework code for a JUCE plugin processor.
  193.  
  194.   ==============================================================================
  195. */
  196.  
  197. #include "PluginProcessor.h"
  198. #include "PluginEditor.h"
  199.  
  200.  
  201. //==============================================================================
  202. SpectrogramPluginAudioProcessor::SpectrogramPluginAudioProcessor()
  203. #ifndef JucePlugin_PreferredChannelConfigurations
  204.      : AudioProcessor (BusesProperties()
  205.                      #if ! JucePlugin_IsMidiEffect
  206.                       #if ! JucePlugin_IsSynth
  207.                        .withInput  ("Input",  AudioChannelSet::stereo(), true)
  208.                       #endif
  209.                        .withOutput ("Output", AudioChannelSet::stereo(), true)
  210.                      #endif
  211.                        )
  212. #endif
  213. {
  214. }
  215.  
  216. SpectrogramPluginAudioProcessor::~SpectrogramPluginAudioProcessor()
  217. {
  218. }
  219.  
  220. //==============================================================================
  221. const String SpectrogramPluginAudioProcessor::getName() const
  222. {
  223.     return JucePlugin_Name;
  224. }
  225.  
  226. bool SpectrogramPluginAudioProcessor::acceptsMidi() const
  227. {
  228.    #if JucePlugin_WantsMidiInput
  229.     return true;
  230.    #else
  231.     return false;
  232.    #endif
  233. }
  234.  
  235. bool SpectrogramPluginAudioProcessor::producesMidi() const
  236. {
  237.    #if JucePlugin_ProducesMidiOutput
  238.     return true;
  239.    #else
  240.     return false;
  241.    #endif
  242. }
  243.  
  244. double SpectrogramPluginAudioProcessor::getTailLengthSeconds() const
  245. {
  246.     return 0.0;
  247. }
  248.  
  249. int SpectrogramPluginAudioProcessor::getNumPrograms()
  250. {
  251.     return 1;   // NB: some hosts don't cope very well if you tell them there are 0 programs,
  252.                 // so this should be at least 1, even if you're not really implementing programs.
  253. }
  254.  
  255. int SpectrogramPluginAudioProcessor::getCurrentProgram()
  256. {
  257.     return 0;
  258. }
  259.  
  260. void SpectrogramPluginAudioProcessor::setCurrentProgram (int index)
  261. {
  262. }
  263.  
  264. const String SpectrogramPluginAudioProcessor::getProgramName (int index)
  265. {
  266.     return {};
  267. }
  268.  
  269. void SpectrogramPluginAudioProcessor::changeProgramName (int index, const String& newName)
  270. {
  271. }
  272.  
  273. //==============================================================================
  274. void SpectrogramPluginAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
  275. {
  276.     // Use this method as the place to do any pre-playback
  277.     // initialisation that you need..
  278. }
  279.  
  280. void SpectrogramPluginAudioProcessor::releaseResources()
  281. {
  282.     // When playback stops, you can use this as an opportunity to free up any
  283.     // spare memory, etc.
  284. }
  285.  
  286. #ifndef JucePlugin_PreferredChannelConfigurations
  287. bool SpectrogramPluginAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
  288. {
  289.   #if JucePlugin_IsMidiEffect
  290.     ignoreUnused (layouts);
  291.     return true;
  292.   #else
  293.     // This is the place where you check if the layout is supported.
  294.     // In this template code we only support mono or stereo.
  295.     if (layouts.getMainOutputChannelSet() != AudioChannelSet::mono()
  296.      && layouts.getMainOutputChannelSet() != AudioChannelSet::stereo())
  297.         return false;
  298.  
  299.     // This checks if the input layout matches the output layout
  300.    #if ! JucePlugin_IsSynth
  301.     if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
  302.         return false;
  303.    #endif
  304.  
  305.     return true;
  306.   #endif
  307. }
  308. #endif
  309.  
  310. void SpectrogramPluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
  311. {
  312.     const int totalNumInputChannels  = getTotalNumInputChannels();
  313.     const int totalNumOutputChannels = getTotalNumOutputChannels();
  314.  
  315.     // In case we have more outputs than inputs, this code clears any output
  316.     // channels that didn't contain input data, (because these aren't
  317.     // guaranteed to be empty - they may contain garbage).
  318.     // This is here to avoid people getting screaming feedback
  319.     // when they first compile a plugin, but obviously you don't need to keep
  320.     // this code if your algorithm always overwrites all the output channels.
  321.     for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
  322.         buffer.clear (i, 0, buffer.getNumSamples());
  323.     auto myeditor = dynamic_cast<SpectrogramPluginAudioProcessorEditor*>(getActiveEditor());
  324.     if (myeditor != nullptr)
  325.     {
  326.         myeditor->m_SpectroGramComp.processAudioBlock(buffer);
  327.     }
  328.     // This is the place where you'd normally do the guts of your plugin's
  329.     // audio processing...
  330.     for (int channel = 0; channel < totalNumInputChannels; ++channel)
  331.     {
  332.         float* channelData = buffer.getWritePointer (channel);
  333.  
  334.         // ..do something to the data...
  335.     }
  336. }
  337.  
  338. //==============================================================================
  339. bool SpectrogramPluginAudioProcessor::hasEditor() const
  340. {
  341.     return true; // (change this to false if you choose to not supply an editor)
  342. }
  343.  
  344. AudioProcessorEditor* SpectrogramPluginAudioProcessor::createEditor()
  345. {
  346.     return new SpectrogramPluginAudioProcessorEditor (*this);
  347. }
  348.  
  349. //==============================================================================
  350. void SpectrogramPluginAudioProcessor::getStateInformation (MemoryBlock& destData)
  351. {
  352.     // You should use this method to store your parameters in the memory block.
  353.     // You could do that either as raw data, or use the XML or ValueTree classes
  354.     // as intermediaries to make it easy to save and load complex data.
  355. }
  356.  
  357. void SpectrogramPluginAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
  358. {
  359.     // You should use this method to restore your parameters from this memory block,
  360.     // whose contents will have been created by the getStateInformation() call.
  361. }
  362.  
  363. //==============================================================================
  364. // This creates new instances of the plugin..
  365. AudioProcessor* JUCE_CALLTYPE createPluginFilter()
  366. {
  367.     return new SpectrogramPluginAudioProcessor();
  368. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement