Allow FFT object to be constructed without inverse FFT. Added SpectralVisualizer component that does an extremely inefficient visualization of the spectral processing stages.
This commit is contained in:
		@@ -20,7 +20,7 @@
 | 
				
			|||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <math.h>
 | 
					#include <math.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FFT::FFT(int nsamples_)
 | 
					FFT::FFT(int nsamples_, bool no_inverse)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    nsamples=nsamples_;
 | 
					    nsamples=nsamples_;
 | 
				
			||||||
	if (nsamples%2!=0) {
 | 
						if (nsamples%2!=0) {
 | 
				
			||||||
@@ -43,12 +43,14 @@ FFT::FFT(int nsamples_)
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        //fftwf_plan_with_nthreads(2);
 | 
					        //fftwf_plan_with_nthreads(2);
 | 
				
			||||||
        planfftw=fftwf_plan_r2r_1d(nsamples,data.data(),data.data(),FFTW_R2HC,FFTW_MEASURE);
 | 
					        planfftw=fftwf_plan_r2r_1d(nsamples,data.data(),data.data(),FFTW_R2HC,FFTW_MEASURE);
 | 
				
			||||||
 | 
					        if (no_inverse == false)
 | 
				
			||||||
			planifftw=fftwf_plan_r2r_1d(nsamples,data.data(),data.data(),FFTW_HC2R,FFTW_MEASURE);
 | 
								planifftw=fftwf_plan_r2r_1d(nsamples,data.data(),data.data(),FFTW_HC2R,FFTW_MEASURE);
 | 
				
			||||||
    } else
 | 
					    } else
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        //fftwf_plan_with_nthreads(2);
 | 
					        //fftwf_plan_with_nthreads(2);
 | 
				
			||||||
        planfftw=fftwf_plan_r2r_1d(nsamples,data.data(),data.data(),FFTW_R2HC,FFTW_ESTIMATE);
 | 
					        planfftw=fftwf_plan_r2r_1d(nsamples,data.data(),data.data(),FFTW_R2HC,FFTW_ESTIMATE);
 | 
				
			||||||
        //fftwf_plan_with_nthreads(2);
 | 
					        //fftwf_plan_with_nthreads(2);
 | 
				
			||||||
 | 
					        if (no_inverse == false)
 | 
				
			||||||
			planifftw=fftwf_plan_r2r_1d(nsamples,data.data(),data.data(),FFTW_HC2R,FFTW_ESTIMATE);
 | 
								planifftw=fftwf_plan_r2r_1d(nsamples,data.data(),data.data(),FFTW_HC2R,FFTW_ESTIMATE);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    //double t1 = Time::getMillisecondCounterHiRes();
 | 
					    //double t1 = Time::getMillisecondCounterHiRes();
 | 
				
			||||||
@@ -64,6 +66,7 @@ FFT::FFT(int nsamples_)
 | 
				
			|||||||
FFT::~FFT()
 | 
					FFT::~FFT()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	fftwf_destroy_plan(planfftw);
 | 
						fftwf_destroy_plan(planfftw);
 | 
				
			||||||
 | 
						if (planifftw!=nullptr)
 | 
				
			||||||
		fftwf_destroy_plan(planifftw);
 | 
							fftwf_destroy_plan(planifftw);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -122,7 +122,7 @@ enum FFTWindow{W_RECTANGULAR,W_HAMMING,W_HANN,W_BLACKMAN,W_BLACKMAN_HARRIS};
 | 
				
			|||||||
class FFT
 | 
					class FFT
 | 
				
			||||||
{//FFT class that considers phases as random
 | 
					{//FFT class that considers phases as random
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		FFT(int nsamples_);//samples must be even
 | 
							FFT(int nsamples_, bool no_inverse=false);//samples must be even
 | 
				
			||||||
		~FFT();
 | 
							~FFT();
 | 
				
			||||||
		void smp2freq();//input is smp, output is freq (phases are discarded)
 | 
							void smp2freq();//input is smp, output is freq (phases are discarded)
 | 
				
			||||||
		void freq2smp();//input is freq,output is smp (phases are random)
 | 
							void freq2smp();//input is freq,output is smp (phases are random)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,7 +42,7 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor (Pa
 | 
				
			|||||||
	addAndMakeVisible(&m_rec_enable);
 | 
						addAndMakeVisible(&m_rec_enable);
 | 
				
			||||||
	m_rec_enable.setButtonText("Capture");
 | 
						m_rec_enable.setButtonText("Capture");
 | 
				
			||||||
	attachCallback(m_rec_enable, [this]() { processor.setRecordingEnabled(m_rec_enable.getToggleState()); });
 | 
						attachCallback(m_rec_enable, [this]() { processor.setRecordingEnabled(m_rec_enable.getToggleState()); });
 | 
				
			||||||
 | 
						addAndMakeVisible(&m_specvis);
 | 
				
			||||||
	setSize (700, 30+pars.size()*25+200);
 | 
						setSize (700, 30+pars.size()*25+200);
 | 
				
			||||||
	m_wavecomponent.TimeSelectionChangedCallback = [this](Range<double> range, int which)
 | 
						m_wavecomponent.TimeSelectionChangedCallback = [this](Range<double> range, int which)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -56,6 +56,7 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor (Pa
 | 
				
			|||||||
	m_wavecomponent.ShowFileCacheRange = true;
 | 
						m_wavecomponent.ShowFileCacheRange = true;
 | 
				
			||||||
	startTimer(1, 100);
 | 
						startTimer(1, 100);
 | 
				
			||||||
	startTimer(2, 1000);
 | 
						startTimer(2, 1000);
 | 
				
			||||||
 | 
						startTimer(3, 500);
 | 
				
			||||||
	m_wavecomponent.startTimer(100);
 | 
						m_wavecomponent.startTimer(100);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -82,7 +83,8 @@ void PaulstretchpluginAudioProcessorEditor::resized()
 | 
				
			|||||||
		m_parcomps[i]->setBounds(1, 30 + i * 25, getWidth()-2, 24);
 | 
							m_parcomps[i]->setBounds(1, 30 + i * 25, getWidth()-2, 24);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	int yoffs = m_parcomps.back()->getBottom() + 1;
 | 
						int yoffs = m_parcomps.back()->getBottom() + 1;
 | 
				
			||||||
	m_wavecomponent.setBounds(1, yoffs, getWidth()-2, getHeight()-1-yoffs);
 | 
						//m_wavecomponent.setBounds(1, yoffs, getWidth()-2, getHeight()-1-yoffs);
 | 
				
			||||||
 | 
						m_specvis.setBounds(1, yoffs, getWidth() - 2, getHeight() - 1 - yoffs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void PaulstretchpluginAudioProcessorEditor::timerCallback(int id)
 | 
					void PaulstretchpluginAudioProcessorEditor::timerCallback(int id)
 | 
				
			||||||
@@ -108,6 +110,12 @@ void PaulstretchpluginAudioProcessorEditor::timerCallback(int id)
 | 
				
			|||||||
			m_wavecomponent.setAudioFile(processor.getAudioFile());
 | 
								m_wavecomponent.setAudioFile(processor.getAudioFile());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		m_wavecomponent.setTimeSelection(processor.getTimeSelection());
 | 
							m_wavecomponent.setTimeSelection(processor.getTimeSelection());
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (id == 3)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_specvis.setState(processor.getStretchSource()->getProcessParameters(), processor.getStretchSource()->getFFTSize() / 2,
 | 
				
			||||||
 | 
								processor.getSampleRate());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -431,3 +439,55 @@ int WaveformComponent::getTimeSelectionEdge(int x, int y)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SpectralVisualizer::SpectralVisualizer()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_img = Image(Image::RGB, 500, 200, true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectralVisualizer::setState(ProcessParameters & pars, int nfreqs, double samplerate)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_img = Image(Image::RGB, getWidth(), getHeight(), true);
 | 
				
			||||||
 | 
						std::vector<REALTYPE> insamples(nfreqs*2);
 | 
				
			||||||
 | 
						std::vector<REALTYPE> freqs1(nfreqs*2);
 | 
				
			||||||
 | 
						std::vector<REALTYPE> freqs2(nfreqs*2);
 | 
				
			||||||
 | 
						std::vector<REALTYPE> freqs3(nfreqs*2);
 | 
				
			||||||
 | 
						double hz = 440.0;
 | 
				
			||||||
 | 
						int numharmonics = 40;
 | 
				
			||||||
 | 
						double scaler = 1.0 / numharmonics;
 | 
				
			||||||
 | 
						for (int i = 0; i < nfreqs; ++i)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							for (int j = 0; j < numharmonics; ++j)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								double oscgain = 1.0 - (1.0 / numharmonics)*j;
 | 
				
			||||||
 | 
								insamples[i] += scaler * oscgain * sin(2 * 3.141592653 / samplerate * i* (hz+hz*j));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						FFT fft(nfreqs*2);
 | 
				
			||||||
 | 
						for (int i = 0; i < nfreqs; ++i)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							fft.smp[i] = insamples[i];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fft.applywindow(W_HAMMING);
 | 
				
			||||||
 | 
						fft.smp2freq();
 | 
				
			||||||
 | 
						double ratio = pow(2.0f, pars.pitch_shift.cents / 1200.0f);
 | 
				
			||||||
 | 
						spectrum_do_pitch_shift(pars, nfreqs, fft.freq.data(), freqs2.data(), ratio);
 | 
				
			||||||
 | 
						spectrum_do_freq_shift(pars, nfreqs, samplerate, freqs2.data(), freqs1.data());
 | 
				
			||||||
 | 
						spectrum_do_compressor(pars, nfreqs, freqs1.data(), freqs2.data());
 | 
				
			||||||
 | 
						spectrum_spread(nfreqs, samplerate, freqs3, freqs2.data(), freqs1.data(), pars.spread.bandwidth);
 | 
				
			||||||
 | 
						Graphics g(m_img);
 | 
				
			||||||
 | 
						g.setColour(Colours::white);
 | 
				
			||||||
 | 
						for (int i = 0; i < nfreqs; ++i)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							double binfreq = (samplerate / 2 / nfreqs)*i;
 | 
				
			||||||
 | 
							double xcor = jmap<double>(binfreq, 0.0, samplerate / 2.0, 0.0, getWidth());
 | 
				
			||||||
 | 
							double ycor = getHeight()- jmap<double>(freqs1[i], 0.0, nfreqs/64, 0.0, getHeight());
 | 
				
			||||||
 | 
							ycor = jlimit<double>(0.0, getHeight(), ycor);
 | 
				
			||||||
 | 
							g.drawLine(xcor, getHeight(), xcor, ycor, 1.0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						repaint();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectralVisualizer::paint(Graphics & g)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						g.drawImage(m_img, 0, 0, getWidth(), getHeight(), 0, 0, m_img.getWidth(), m_img.getHeight());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,17 @@
 | 
				
			|||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SpectralVisualizer : public Component
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						SpectralVisualizer();
 | 
				
			||||||
 | 
						void setState(ProcessParameters& pars, int nfreqs, double samplerate);
 | 
				
			||||||
 | 
						void paint(Graphics& g) override;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						Image m_img;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void attachCallback(Button& button, std::function<void()> callback)
 | 
					inline void attachCallback(Button& button, std::function<void()> callback)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ButtonCallback : public Button::Listener,
 | 
						struct ButtonCallback : public Button::Listener,
 | 
				
			||||||
@@ -240,6 +251,7 @@ public:
 | 
				
			|||||||
private:
 | 
					private:
 | 
				
			||||||
    PaulstretchpluginAudioProcessor& processor;
 | 
					    PaulstretchpluginAudioProcessor& processor;
 | 
				
			||||||
	std::vector<std::shared_ptr<ParameterComponent>> m_parcomps;
 | 
						std::vector<std::shared_ptr<ParameterComponent>> m_parcomps;
 | 
				
			||||||
 | 
						SpectralVisualizer m_specvis;
 | 
				
			||||||
	ToggleButton m_rec_enable;
 | 
						ToggleButton m_rec_enable;
 | 
				
			||||||
	TextButton m_import_button;
 | 
						TextButton m_import_button;
 | 
				
			||||||
	Label m_info_label;
 | 
						Label m_info_label;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user