| @@ -173,21 +173,6 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau | |||
| }; | |||
| m_spec_order_ed.ModuleOrderOrEnabledChangedCallback = [this]() | |||
| { | |||
| /* | |||
| const auto& specord = processor.getStretchSource()->getSpectrumProcessOrder(); | |||
| for (int i = 0; i < specord.size(); ++i) | |||
| { | |||
| int grtofind = specord[i].m_index; | |||
| for (int j = 0; j < m_parcomps.size(); ++j) | |||
| { | |||
| int gid = m_parcomps[j]->m_group_id; | |||
| if (gid == grtofind) | |||
| { | |||
| m_parcomps[j]->setEnabled(specord[i].m_enabled); | |||
| } | |||
| } | |||
| } | |||
| */ | |||
| processor.setDirty(); | |||
| }; | |||
| @@ -244,8 +229,9 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau | |||
| m_wavefilter_tab.addTab("Waveform", Colours::white, m_wave_container, true); | |||
| m_wavefilter_tab.addTab("Ratio mixer", Colours::white, &m_ratiomixeditor, false); | |||
| m_wavefilter_tab.addTab("Free filter", Colours::white, &m_free_filter_component, false); | |||
| addAndMakeVisible(&m_wavefilter_tab); | |||
| m_wavefilter_tab.addTab("Spectrum", Colours::white, &m_sonogram, false); | |||
| addAndMakeVisible(&m_wavefilter_tab); | |||
| setSize (1200, 320+14*25); | |||
| startTimer(1, 100); | |||
| startTimer(2, 1000); | |||
| @@ -265,6 +265,122 @@ private: | |||
| }; | |||
| class SimpleFFTComponent : public Component, | |||
| private Timer | |||
| { | |||
| public: | |||
| SimpleFFTComponent() : | |||
| forwardFFT(fftOrder), | |||
| spectrogramImage(Image::RGB, 512, 512, true) | |||
| { | |||
| setOpaque(true); | |||
| startTimerHz(60); | |||
| } | |||
| ~SimpleFFTComponent() | |||
| { | |||
| } | |||
| void addAudioBlock(const AudioBuffer<float>& bufferToFill) | |||
| { | |||
| if (bufferToFill.getNumChannels() > 0) | |||
| { | |||
| const auto* channelData = bufferToFill.getReadPointer(0); | |||
| for (auto i = 0; i < bufferToFill.getNumSamples(); ++i) | |||
| pushNextSampleIntoFifo(channelData[i]); | |||
| } | |||
| } | |||
| void resized() override | |||
| { | |||
| spectrogramImage = Image(Image::RGB, getWidth(), getHeight(), true); | |||
| } | |||
| void paint(Graphics& g) override | |||
| { | |||
| g.fillAll(Colours::black); | |||
| 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() | |||
| { | |||
| auto rightHandEdge = spectrogramImage.getWidth() - 1; | |||
| auto 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 | |||
| auto maxLevel = FloatVectorOperations::findMinAndMax(fftData, fftSize / 2); | |||
| for (auto y = 1; y < imageHeight; ++y) | |||
| { | |||
| auto skewedProportionY = 1.0f - std::exp(std::log(y / (float)imageHeight) * 0.2f); | |||
| auto fftDataIndex = jlimit(0, fftSize / 2, (int)(skewedProportionY * fftSize / 2)); | |||
| auto level = jmap(fftData[fftDataIndex], 0.0f, jmax(maxLevel.getEnd(), 1e-5f), 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[8 * fftSize]; | |||
| int fifoIndex = 0; | |||
| bool nextFFTBlockReady = false; | |||
| }; | |||
| class AudioFilePreviewComponent : public FilePreviewComponent | |||
| { | |||
| public: | |||
| @@ -319,7 +435,7 @@ public: | |||
| void chooseFile(); | |||
| void showRenderDialog(); | |||
| void executeModalMenuAction(int menuid, int actionid); | |||
| SimpleFFTComponent m_sonogram; | |||
| private: | |||
| PaulstretchpluginAudioProcessor& processor; | |||
| uptrvec<ParameterComponent> m_parcomps; | |||
| @@ -337,6 +453,7 @@ private: | |||
| zoom_scrollbar m_zs; | |||
| RatioMixerEditor m_ratiomixeditor{ 8 }; | |||
| FreeFilterComponent m_free_filter_component; | |||
| MyTabComponent m_wavefilter_tab; | |||
| Component* m_wave_container=nullptr; | |||
| void showAbout(); | |||
| @@ -811,6 +811,11 @@ void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, M | |||
| { | |||
| buffer.clear(); | |||
| } | |||
| auto ed = dynamic_cast<PaulstretchpluginAudioProcessorEditor*>(getActiveEditor()); | |||
| if (ed != nullptr) | |||
| { | |||
| ed->m_sonogram.addAudioBlock(buffer); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| @@ -11,7 +11,7 @@ | |||
| pluginWantsMidiIn="0" pluginProducesMidiOut="0" pluginIsMidiEffectPlugin="0" | |||
| pluginEditorRequiresKeys="0" pluginAUExportPrefix="paulxstretchAU" | |||
| aaxIdentifier="com.yourcompany.paulstretchplugin" pluginAAXCategory="2" | |||
| jucerVersion="5.3.2" headerPath=" " pluginFormats="buildVST,buildVST3,buildAU,buildStandalone"> | |||
| jucerVersion="5.4.1" headerPath=" " pluginFormats="buildVST,buildVST3,buildAU,buildStandalone"> | |||
| <MAINGROUP id="nozXHl" name="PaulXStretch"> | |||
| <GROUP id="{03DA6B32-F666-FF60-F168-4385D0847058}" name="Source"> | |||
| <FILE id="RanaVV" name="RenderSettingsComponent.cpp" compile="1" resource="0" | |||
| @@ -50,8 +50,7 @@ | |||
| </GROUP> | |||
| </MAINGROUP> | |||
| <EXPORTFORMATS> | |||
| <XCODE_MAC targetFolder="Builds/MacOSX" extraLinkerFlags="/usr/local/Cellar/fftw/3.3.8/lib/libfftw3f.a " | |||
| vst3Folder=""> | |||
| <XCODE_MAC targetFolder="Builds/MacOSX" extraLinkerFlags="/usr/local/Cellar/fftw/3.3.8/lib/libfftw3f.a "> | |||
| <CONFIGURATIONS> | |||
| <CONFIGURATION name="Debug" enablePluginBinaryCopyStep="1" isDebug="1" optimisation="1" | |||
| linkTimeOptimisation="0" targetName="PaulXStretch" headerPath="Source/PS_Source Source/WDL /Users/teemu/codeprojects/JUCE/modules/vst2.x " | |||
| @@ -77,10 +76,11 @@ | |||
| <MODULEPATH id="juce_audio_processors" path="../JUCE/modules"/> | |||
| <MODULEPATH id="juce_audio_plugin_client" path="../JUCE/modules"/> | |||
| <MODULEPATH id="juce_audio_utils" path="../JUCE/modules"/> | |||
| <MODULEPATH id="juce_dsp" path="../gitrepos/JUCE/modules"/> | |||
| </MODULEPATHS> | |||
| </XCODE_MAC> | |||
| <VS2017 targetFolder="Builds/VisualStudio2017" externalLibraries="C:\ProgrammingProjects\fftw-3.3.6-pl2\fftw-3.3-libs\x64\Static-Release\libfftwf-3.3.lib" | |||
| extraDefs="" vst3Folder=""> | |||
| extraDefs=""> | |||
| <CONFIGURATIONS> | |||
| <CONFIGURATION name="Debug" winWarningLevel="4" generateManifest="1" winArchitecture="x64" | |||
| debugInformationFormat="ProgramDatabase" enablePluginBinaryCopyStep="1" | |||
| @@ -107,6 +107,7 @@ | |||
| <MODULEPATH id="juce_audio_processors" path="../JUCE/modules"/> | |||
| <MODULEPATH id="juce_audio_plugin_client" path="../JUCE/modules"/> | |||
| <MODULEPATH id="juce_audio_utils" path="../JUCE/modules"/> | |||
| <MODULEPATH id="juce_dsp" path="../gitrepos/JUCE/modules"/> | |||
| </MODULEPATHS> | |||
| </VS2017> | |||
| <LINUX_MAKE targetFolder="Builds/LinuxMakefile" extraDefs="JUCE_WEB_BROWSER=0 "> | |||
| @@ -130,6 +131,7 @@ | |||
| <MODULEPATH id="juce_audio_processors" path="../JUCE/modules"/> | |||
| <MODULEPATH id="juce_audio_plugin_client" path="../JUCE/modules"/> | |||
| <MODULEPATH id="juce_audio_utils" path="../JUCE/modules"/> | |||
| <MODULEPATH id="juce_dsp" path="../gitrepos/JUCE/modules"/> | |||
| </MODULEPATHS> | |||
| </LINUX_MAKE> | |||
| </EXPORTFORMATS> | |||
| @@ -144,6 +146,7 @@ | |||
| <MODULE id="juce_core" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/> | |||
| <MODULE id="juce_cryptography" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/> | |||
| <MODULE id="juce_data_structures" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/> | |||
| <MODULE id="juce_dsp" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/> | |||
| <MODULE id="juce_events" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/> | |||
| <MODULE id="juce_graphics" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/> | |||
| <MODULE id="juce_gui_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/> | |||