From 52d3326de64062b17b97d6d97e455db34e52eef4 Mon Sep 17 00:00:00 2001 From: essej Date: Tue, 12 Apr 2022 18:46:50 -0400 Subject: [PATCH] added accelerate vdsp FFT support and use it on iOS --- Source/PS_Source/ProcessedStretch.h | 4 +- Source/PS_Source/Stretch.cpp | 172 ++++++++++++++++++++++++---- Source/PS_Source/Stretch.h | 37 +++++- Source/power.svg | 71 ++++++++++++ Source/power_sel.svg | 72 ++++++++++++ paulstretchplugin_ios.jucer | 69 +++++------ 6 files changed, 364 insertions(+), 61 deletions(-) create mode 100644 Source/power.svg create mode 100644 Source/power_sel.svg diff --git a/Source/PS_Source/ProcessedStretch.h b/Source/PS_Source/ProcessedStretch.h index 0e3980c..13dd9b8 100644 --- a/Source/PS_Source/ProcessedStretch.h +++ b/Source/PS_Source/ProcessedStretch.h @@ -179,7 +179,9 @@ inline REALTYPE profile(REALTYPE fi, REALTYPE bwi) { inline void spectrum_copy(int nfreq, REALTYPE* freq1, REALTYPE* freq2) { - for (int i = 0; i +//#include +#endif + #include "Stretch.h" #include #include + FFT::FFT(int nsamples_, bool no_inverse) { nsamples=nsamples_; @@ -41,6 +48,19 @@ FFT::FFT(int nsamples_, bool no_inverse) data.resize(nsamples,true); bool allow_long_planning = false; // g_propsfile->getBoolValue("fftw_allow_long_planning", false); //double t0 = Time::getMillisecondCounterHiRes(); +#if PS_USE_VDSP_FFT + int maxlog2N = 1; + while ((1 << maxlog2N) < nsamples) + ++maxlog2N; + log2N = maxlog2N; + planfft = vDSP_create_fftsetup(maxlog2N, kFFTRadix2); + + m_workReal.resize(nsamples,false); + m_workImag.resize(nsamples,false); + + //Logger::writeToLog("fftsize: " + String(nsamples) + " log2N: " + String(log2N)); + +#else if (allow_long_planning) { //fftwf_plan_with_nthreads(2); @@ -55,6 +75,8 @@ FFT::FFT(int nsamples_, bool no_inverse) if (no_inverse == false) planifftw=fftwf_plan_r2r_1d(nsamples,data.data(),data.data(),FFTW_HC2R,FFTW_ESTIMATE); } +#endif + //double t1 = Time::getMillisecondCounterHiRes(); //Logger::writeToLog("Creating FFTW3 plans took "+String(t1-t0)+ "ms"); static int seed = 0; @@ -64,46 +86,123 @@ FFT::FFT(int nsamples_, bool no_inverse) FFT::~FFT() { - fftwf_destroy_plan(planfftw); +#if PS_USE_VDSP_FFT + vDSP_destroy_fftsetup((FFTSetup)planfft); +#else + fftwf_destroy_plan(planfftw); if (planifftw!=nullptr) fftwf_destroy_plan(planifftw); +#endif }; void FFT::smp2freq() { +#if PS_USE_VDSP_FFT - for (int i=0;imBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize); + + // forward fft + vDSP_fft_zrip((FFTSetup)planfft, &A, 1, log2N, FFT_FORWARD); + + // result is in split packed complex A.realp[0] is DC, A.imagp[0] is NY, so we zero NY before doing mag^2 + A.imagp[0] = 0.0f; + + //DebugLogC("post fft: %g %g\n", A.realp[fftFrameSize/4], A.imagp[fftFrameSize/4 + 1]); + + // Absolute square (equivalent to mag^2) + vDSP_zvmags(&A, 1, freq.data(), 1, halfsamples); + + // take square root + //vvsqrtf(freq.data(), freq.data(), &halfsamples); + + for (int i=1; i < halfsamples;i++) + { + freq[i]=sqrt(freq[i]); + } + + freq[0] = 0.0; + +#else + + for (int i=0;ismp.data(), old_smps.data(), bufsize); + FloatVectorOperations::copy(infft->smp.data()+bufsize, smps, bufsize); + FloatVectorOperations::copy(old_freq.data(), infft->freq.data(), bufsize); + /* + for (int i=0;ismp[i]=old_smps[i]; infft->smp[i+bufsize]=smps[i]; old_freq[i]=infft->freq[i]; }; + */ + infft->applywindow(window_type); infft->smp2freq(); }; void Stretch::do_next_inbuf_smps(REALTYPE *smps){ - for (int i=0;i 0); REALTYPE onset=0.0; if (bypass){ - for (int i=0;i=bufsize) start_pos=bufsize-1; + + FloatVectorOperations::copy(fft->smp.data(), very_old_smps.data() + start_pos, bufsize-start_pos); + FloatVectorOperations::copy(fft->smp.data() + (bufsize - start_pos), old_smps.data() , bufsize); + FloatVectorOperations::copy(fft->smp.data() + (2*bufsize - start_pos), new_smps.data() , start_pos); + + /* for (int i=0;ismp[i]=very_old_smps[i+start_pos]; for (int i=0;ismp[i+bufsize-start_pos]=old_smps[i]; for (int i=0;ismp[i+2*bufsize-start_pos]=new_smps[i]; + */ + //compute the output spectrum fft->applywindow(window_type); fft->smp2freq(); - for (int i=0;ifreq[i]=fft->freq[i]; - + + //for (int i=0;ifreq[i]=fft->freq[i]; + FloatVectorOperations::copy(outfft->freq.data(), fft->freq.data(), bufsize); + //for (int i=0;ifreq[i]=infft->freq[i]*remained_samples+old_freq[i]*(1.0-remained_samples); @@ -310,7 +435,8 @@ REALTYPE Stretch::process(REALTYPE *smps,int nsmps) }; //copy the current output buffer to old buffer - for (int i=0;ismp[i]; + //for (int i=0;ismp[i]; + FloatVectorOperations::copy(old_out_smps.data(), outfft->smp.data(), 2*bufsize); }; diff --git a/Source/PS_Source/Stretch.h b/Source/PS_Source/Stretch.h index fb89b4c..5e1c2a8 100644 --- a/Source/PS_Source/Stretch.h +++ b/Source/PS_Source/Stretch.h @@ -22,13 +22,20 @@ #include "globals.h" -#include "fftw3.h" +#ifndef PS_USE_VDSP_FFT +#define PS_USE_VDSP_FFT 0 +#endif +#if PS_USE_VDSP_FFT +#else +#include "fftw3.h" +#endif #include "../JuceLibraryCode/JuceHeader.h" #include #include + template class FFTWBuffer { @@ -94,19 +101,34 @@ private: int m_size = 0; void mallocimpl(T*& buf,int size) { +#if PS_USE_VDSP_FFT + // malloc aligns properly on vdsp platforms + if constexpr (std::is_same::value) + buf = (float*)malloc(size*sizeof(float)); + else + buf = (double*)malloc(size * sizeof(double)); +#else if constexpr (std::is_same::value) buf = (float*)fftwf_malloc(size*sizeof(float)); else buf = (double*)fftw_malloc(size * sizeof(double)); +#endif } void freeimpl(T*& buf) { if (buf!=nullptr) { +#if PS_USE_VDSP_FFT if constexpr (std::is_same::value) - fftwf_free(buf); + free(buf); else - fftw_free(buf); + free(buf); +#else + if constexpr (std::is_same::value) + fftwf_free(buf); + else + fftw_free(buf); +#endif buf = nullptr; } } @@ -132,7 +154,14 @@ class FFT private: - fftwf_plan planfftw,planifftw; +#if PS_USE_VDSP_FFT + void * planfft; + int log2N; + FFTWBuffer m_workReal; + FFTWBuffer m_workImag; +#else + fftwf_plan planfftw,planifftw; +#endif FFTWBuffer data; struct{ diff --git a/Source/power.svg b/Source/power.svg new file mode 100644 index 0000000..1779b0d --- /dev/null +++ b/Source/power.svg @@ -0,0 +1,71 @@ + +Benjamin J Sperryimage/svg+xml diff --git a/Source/power_sel.svg b/Source/power_sel.svg new file mode 100644 index 0000000..f2b198b --- /dev/null +++ b/Source/power_sel.svg @@ -0,0 +1,72 @@ + +Benjamin J Sperryimage/svg+xml diff --git a/paulstretchplugin_ios.jucer b/paulstretchplugin_ios.jucer index 767ae18..6672c9a 100644 --- a/paulstretchplugin_ios.jucer +++ b/paulstretchplugin_ios.jucer @@ -15,28 +15,6 @@ jucerFormatVersion="1" useAppConfig="0" defines="JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP=1"> - - - - - - - - - - - - - - + + + + + + + + + + + + - - + + + + + + + - + UIFileSharingEnabled="1" UISupportsDocumentBrowser="1" extraDefs="PS_USE_VDSP_FFT=1">