diff --git a/kn0ck0ut.ttl b/kn0ck0ut.ttl index 25cf8c7..b0a73f6 100644 --- a/kn0ck0ut.ttl +++ b/kn0ck0ut.ttl @@ -6,7 +6,7 @@ @prefix ev: . @prefix ll: . - a lv2:Plugin ; + a lv2:Plugin ; doap:name "Kn0ck0ut Vocal Remover" ; lv2:binary ; doap:developer [ @@ -33,12 +33,18 @@ a lv2:AudioPort ; a lv2:OutputPort ; lv2:index 2 ; - lv2:symbol "out" ; - lv2:name "Output" ; + lv2:symbol "outl" ; + lv2:name "Output Left" ; + ],[ + a lv2:AudioPort ; + a lv2:OutputPort ; + lv2:index 3 ; + lv2:symbol "outr" ; + lv2:name "Output Right" ; ],[ a lv2:InputPort; a lv2:ControlPort; - lv2:index 3; + lv2:index 4; lv2:symbol "mode"; lv2:name "Mode"; lv2:portProperty lv2:enumeration; @@ -48,7 +54,7 @@ ],[ a lv2:InputPort; a lv2:ControlPort; - lv2:index 4; + lv2:index 5; lv2:symbol "lowcut"; lv2:name "Low Frequency Cut"; lv2:default 0; @@ -57,7 +63,7 @@ ],[ a lv2:InputPort; a lv2:ControlPort; - lv2:index 5; + lv2:index 6; lv2:symbol "highcut"; lv2:name "High Frequency Cut"; lv2:default 0; @@ -66,7 +72,7 @@ ],[ a lv2:InputPort; a lv2:ControlPort; - lv2:index 6; + lv2:index 7; lv2:symbol "decay"; lv2:name "Decay"; lv2:default 0; @@ -75,7 +81,7 @@ ],[ a lv2:InputPort; a lv2:ControlPort; - lv2:index 7; + lv2:index 8; lv2:symbol "blur"; lv2:name "Blur"; lv2:default 0; @@ -84,7 +90,7 @@ ],[ a lv2:InputPort; a lv2:ControlPort; - lv2:index 8; + lv2:index 9; lv2:symbol "windowsize"; lv2:name "Window Size"; lv2:default 8192; @@ -93,7 +99,7 @@ ],[ a lv2:InputPort; a lv2:ControlPort; - lv2:index 9; + lv2:index 10; lv2:symbol "overlapf"; lv2:name "Overlap Factor"; lv2:default 2; @@ -102,14 +108,14 @@ ],[ a lv2:InputPort; a lv2:ControlPort; - lv2:index 10; + lv2:index 11; lv2:symbol "phase"; lv2:name "Phase Compensation"; lv2:portProperty lv2:toggled; ],[ a lv2:OutputPort; a lv2:ControlPort; - lv2:index 11; + lv2:index 12; lv2:symbol "latency"; lv2:name "Latency"; lv2:portProperty lv2:reportsLatency; diff --git a/kn0ck0ut6.cpp b/kn0ck0ut6.cpp index d10ac6d..ea852c0 100644 --- a/kn0ck0ut6.cpp +++ b/kn0ck0ut6.cpp @@ -72,37 +72,42 @@ void AKnockout::AllocateNewBuffers(unsigned int fftSize) { gInFIFO = new float [fftSize]; FFTRealBuffer=(float*)fftwf_malloc(sizeof(float)*fftSize); gFFTworksp = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize2); - gOutputAccum = new float [fftSize]; + gOutputAccum = new float [fftSize]; + gOutputAccum2 = new float [fftSize]; gAnaPhase1 = new float [fftSize2]; gAnaPhase2 = new float [fftSize2]; gAnaMagn = new float [fftSize2]; gInFIFO2 = new float [fftSize]; gFFTworksp2 = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize2); gAnaMagn2 = new float [fftSize2]; - gDecay = new float [fftSize2]; + gDecay = new float [fftSize2]; + gDecay2 = new float [fftSize2]; window = new float [fftSize]; forward_sp1= fftwf_plan_dft_r2c_1d(fftSize, FFTRealBuffer , gFFTworksp, FFTW_ESTIMATE); forward_sp2= fftwf_plan_dft_r2c_1d(fftSize,FFTRealBuffer, gFFTworksp2, FFTW_ESTIMATE); - backwards=fftwf_plan_dft_c2r_1d(fftSize, gFFTworksp, FFTRealBuffer, + backward_sp1=fftwf_plan_dft_c2r_1d(fftSize, gFFTworksp, FFTRealBuffer, FFTW_ESTIMATE); - + backward_sp2=fftwf_plan_dft_c2r_1d(fftSize, gFFTworksp2, FFTRealBuffer, + FFTW_ESTIMATE); makelookup(fftSize); } void AKnockout::FreeOldBuffers() { delete[] gInFIFO; fftwf_free(FFTRealBuffer); fftwf_free(gFFTworksp); - delete[] gOutputAccum; + delete[] gOutputAccum; + delete[] gOutputAccum2; delete[] gAnaPhase1; delete[] gAnaPhase2; delete[] gAnaMagn; delete[] gAnaMagn2; delete[] gInFIFO2; fftwf_free(gFFTworksp2); - delete[] gDecay; + delete[] gDecay; + delete[] gDecay2; delete[] window; } @@ -114,7 +119,8 @@ void AKnockout::clearBuffers() unsigned int fftSize2=fftSize/2+1; memset(gInFIFO, 0, fftSize*sizeof(float)); memset(gFFTworksp, 0, fftSize2*sizeof(fftwf_complex)); - memset(gOutputAccum, 0, fftSize*sizeof(float)); + memset(gOutputAccum, 0, fftSize*sizeof(float)); + memset(gOutputAccum2, 0, fftSize*sizeof(float)); memset(gAnaPhase1, 0, fftSize2*sizeof(float)); memset(gAnaPhase2, 0, fftSize2*sizeof(float)); memset(gAnaMagn, 0, fftSize2*sizeof(float)); @@ -122,6 +128,7 @@ void AKnockout::clearBuffers() memset(gFFTworksp2, 0, fftSize2*sizeof(fftwf_complex)); memset(gAnaMagn2, 0, fftSize2*sizeof(float)); memset(gDecay,0,fftSize2*sizeof(float)); + memset(gDecay2,0,fftSize2*sizeof(float)); long stepSize=fftSize/goverlap; gRover=0; @@ -208,7 +215,7 @@ void AKnockout::run(uint32_t sampleFrames) bool consider_phase = *p(p_phase)>0; // arguments are number of samples to process, fft window size, sample overlap (4-32), input buffer, output buffer, init flag, gain, R input gain, decay, l cut, hi cut - do_rebuild(sampleFrames, gfftSize, goverlap, sampleRate, p(p_left), p(p_right), p(p_out), fDecay, iBlur, loCut, hiCut, centre, consider_phase); + do_rebuild(sampleFrames, gfftSize, goverlap, sampleRate, p(p_left), p(p_right), p(p_outl), p(p_outr), fDecay, iBlur, loCut, hiCut, centre, consider_phase); } #define DEFINE_CIRC_COPY(NAME, OUTBUFFER, INBUFFER) \ static inline int NAME(int circularsize,\ @@ -262,21 +269,101 @@ float AKnockout::phaseToFrequency(float phase, int k,float dOversampbytwopi, flo phase-=PI; return ((double)k + phase*dOversampbytwopi); -} +} + +inline void AKnockout::knockout(float origmag,float origphase, fftwf_complex * __restrict workspace, float* __restrict magnbuff, float* __restrict decaybuff, float coef, int k, float fDecayRate, int iBlur) { + /* decay control */ + if (magnbuff[k]>decaybuff[k]) { + decaybuff[k]=magnbuff[k]; + } else { + decaybuff[k]=(decaybuff[k]-fDecayRate); + decaybuff[k]=decaybuff[k]*(decaybuff[k]>1); + } + + if (fDecayRate==0) { + decaybuff[k]=magnbuff[k];/* if decay is off, set this value to right channel magn*/ + } + /* spectral blur control */ + + for (long m=-iBlur; mdecaybuff[k]) { + decaybuff[k]=magnbuff[k+m]; + } + } + + /* this is the 'knockout' process */ + + origmag -= coef* decaybuff[k]; /* subtract right channel magnitudes from left, with decay*/ + origmag*= (origmag>0); /* zero -ve partials*/ + /* get real and imag part and re-interleave */ + myQT.QuickSinCos(origphase,workspace[k],workspace[k]+1); + workspace[k][0] *=origmag; + workspace[k][1] *=origmag; +} + +inline void AKnockout::sumIntoCircularBuffer(float* __restrict outaccum,float dOutfactor,long outAccumIndex,long stepSize,long fftFrameSize){ + long inindex=0; + /* do windowing and add to output accumulator */ + + /* + * For this step, we observe that tOutputAccum is a circular buffer + * of size fftFrameSize. The previous stepSize frames of data we + * can discard, since it was just written out. However, the remaining + * Data we want to accumulate to. Thus, we add to the next fftFrameSize - stepSize + * frames of data, and overwrite the last stepSize frames. However, + * This is a little more complicated because we have to wrap around the circular buffers. + */ + long lastind=outAccumIndex-stepSize; + if(lastind<0) { + lastind+=fftFrameSize; + //Fill up the part which we are still adding to. + for(long k=outAccumIndex; k < lastind; k++) { + outaccum[k] += window[inindex]*FFTRealBuffer[inindex]/(dOutfactor); + inindex++; + } + //start to overwrite the old data at the end of the buffer. + for(long k=lastind; k=samples_needed_in_buffer) { @@ -329,13 +418,17 @@ void AKnockout::do_rebuild(long numSampsToProcess, long fftFrameSize, long osamp // lo cut for (long k = 0; k <= loCut+iBlur; k++) { gFFTworksp[k][0]=0; - gFFTworksp[k][1]=0; + gFFTworksp[k][1]=0; + gFFTworksp2[k][0]=0; + gFFTworksp2[k][1]=0; } // hi cut for (long k = fftFrameSize2-HiCut-iBlur; k <= fftFrameSize2; k++) { gFFTworksp[k][0]=0; - gFFTworksp[k][1]=0; + gFFTworksp[k][1]=0; + gFFTworksp2[k][0]=0; + gFFTworksp2[k][1]=0; } /* get R input magnitudes */ @@ -345,108 +438,29 @@ void AKnockout::do_rebuild(long numSampsToProcess, long fftFrameSize, long osamp float imag=gFFTworksp2[k][1]; tAnaMagn2[k]=(2.*sqrt(real*real+imag*imag)); tAnaPhase2[k]=atan2(imag,real); - } - - - for (long k = loCut+iBlur; k <= fftFrameSize2-HiCut-iBlur; k++) { - - - /* decay control */ - - if (tAnaMagn2[k]>tDecay[k]) { - tDecay[k]=tAnaMagn2[k]; - } else { - tDecay[k]=(tDecay[k]-fDecayRate); - tDecay[k]=tDecay[k]*(tDecay[k]>1); - } - if (fDecayRate==0) { - tDecay[k]=tAnaMagn2[k]; // if decay is off, set this value to right channel magn - } - /* spectral blur control */ - - for (long m=-iBlur; mtDecay[k]) { - tDecay[k]=tAnaMagn2[k+m]; - } - } - //we subtract out the part of the right channel *parallel to* the left + } + + for (long k = loCut+iBlur; k <= fftFrameSize2-HiCut-iBlur; k++) { + /*we subtract out the part of the right channel *parallel to* the left*/ float diff=fabs(tAnaPhase1[k]-tAnaPhase2[k]); diff*=consider_phase; float coef=cosf(diff); if(coef<0) { coef=0; - } - /* this is the 'knockout' process */ - - tAnaMagn[k] = tAnaMagn[k] - coef* tDecay[k]; // subtract right channel magnitudes from left, with decay - tAnaMagn[k] = tAnaMagn[k] * (tAnaMagn[k]>0); // zero -ve partials - - //(Note by Jeremy): The phase has not been modified at all. - //This exactly undoes the transformation of the phase of the left - //channel which we did during the analysis phase. - - /* correct the frequency - sm sprenger method - double tmp = tAnaFreq[k]; - tmp -= (double)k*freqPerBin; - tmp *= dFreqfactor; - tmp += (double)k*expct; */ - - /* get real and imag part and re-interleave */ - myQT.QuickSinCos(tAnaPhase1[k],gFFTworksp[k],gFFTworksp[k]+1); - gFFTworksp[k][0] *=tAnaMagn[k]; - gFFTworksp[k][1] *=tAnaMagn[k]; - - } - - /* do inverse transform */ - fftwf_execute(backwards); - - long inindex=0; - /* do windowing and add to output accumulator */ - - /* - * For this step, we observe that tOutputAccum is a circular buffer - * of size fftFrameSize. The previous stepSize frames of data we - * can discard, since it was just written out. However, the remaining - * Data we want to accumulate to. Thus, we add to the next fftFrameSize - stepSize - * frames of data, and overwrite the last stepSize frames. However, - * This is a little more complicated because we have to wrap around the circular buffers. - */ - long lastind=outAccumIndex-stepSize; - if(lastind<0) { - lastind+=fftFrameSize; - //Fill up the part which we are still adding to. - for(long k=outAccumIndex; k < lastind; k++) { - tOutputAccum[k] += twindow[inindex]*tFFTRealBuffer[inindex]/(dOutfactor); - inindex++; } - //start to overwrite the old data at the end of the buffer. - for(long k=lastind; k { unsigned int goverlap; unsigned int gfftSize; double sampleRate; - - void do_rebuild(long numSampsToProcess, long fftFrameSize, long osamp, float sampleRate, float *indata, float *indata2, float *outdata, float fDecayRate, int iBlur, int loCut, int HiCut, int centreExtract, bool consider_phase); + inline void knockout(float origmag,float origphase, fftwf_complex * __restrict workspace, float* __restrict magnbuff, float* __restrict decaybuff, float coef, int k, float fDecayRate, int iBlur); + void do_rebuild(long numSampsToProcess, long fftFrameSize, long osamp, float sampleRate, float *indata, float *indata2, float *outdata1,float *outdata2, float fDecayRate, int iBlur, int loCut, int HiCut, int centreExtract, bool consider_phase); + inline void sumIntoCircularBuffer(float* __restrict outaccum,float dOutFactor,long outAccumIndex,long stepSize,long fftFrameSize); void makelookup(int fftFrameSize); inline float phaseToFrequency(float phase, int k,float dOversampbytwopi, float expct); - float* __restrict gInFIFO ; + float* __restrict gInFIFO; + float* __restrict gInFIFO2; float* __restrict gOutputAccum; + float* __restrict gOutputAccum2; float* __restrict FFTRealBuffer; float* __restrict gAnaPhase1; float* __restrict gAnaPhase2; float* __restrict gAnaMagn; - float* __restrict gInFIFO2; float* __restrict gAnaMagn2; - float* __restrict gDecay; + float* __restrict gDecay; + float* __restrict gDecay2; float* __restrict window; long gRover; @@ -76,7 +79,8 @@ class AKnockout:public Plugin { fftwf_complex * gFFTworksp; fftwf_plan forward_sp1; fftwf_plan forward_sp2; - fftwf_plan backwards; + fftwf_plan backward_sp1; + fftwf_plan backward_sp2; }; diff --git a/manifest.ttl b/manifest.ttl index 686362f..d9573f2 100644 --- a/manifest.ttl +++ b/manifest.ttl @@ -1,6 +1,6 @@ @prefix lv2: . @prefix rdfs: . - + a lv2:Plugin; rdfs:seeAlso . diff --git a/readme.txt b/readme.txt index 0e8ae10..872840d 100644 --- a/readme.txt +++ b/readme.txt @@ -1,4 +1,4 @@ -kn0ck0ut-LV2 version 1.0 by Jeremy Salwen (jeremysalwen@gmail.com). +kn0ck0ut-LV2 version 1.1 by Jeremy Salwen (jeremysalwen@gmail.com). An LV2 port of kn0ck0ut (http://www.freewebs.com/st3pan0va/) @@ -22,53 +22,54 @@ In addition to the features of the original Kn0ck0ut, Kn0ck0ut-LV2 features: * Experimental "Phase Compensation" option, which will perhaps preserve additional fidelity in certain cases. * Restored Low-cut filter which was removed in later releases. +* Stereo output for center removal. Below Reads the Original Readme ==================================================================== -Kn0ck0ut v0.5 - ---++/* by St3pan0va */++-- - - -Notes on the source codes: - -the code is a mess. sorry. im no programmer. - -any newbies out there - don't use this as an example. - -any VST wizards - plz feel free to develop (mend ;) - -so long as yr source + plugin are freely available. - -no commercial use. no use without acknowledgement. - -written/compiled on codewarrior 4.04 for windows - -.mcp file included is the codewarrior project file. - -you will need vst SDK from steinberg website. - -contact st3pan0va [at] netscape [dot] net. - - - ----- - -Acknowledgements / Licence - -Kn0ck0ut is freeware and beta. No warranty, no - -support. The plugin may be redistributed but only for free, - -and only with this readme file. - -Made using the VST SDK and adapts (with thanks) code from S.M.Sprenger - -available under the Wide Open Licence at www.dspdimension.com - -Uses the QuickTrig class by Robin Davies at www.musicdsp.com - -Thanks to TimG, FondueMeltdown, brainy & the ppl of *GYBO*. - +Kn0ck0ut v0.5 + +--++/* by St3pan0va */++-- + + +Notes on the source codes: + +the code is a mess. sorry. im no programmer. + +any newbies out there - don't use this as an example. + +any VST wizards - plz feel free to develop (mend ;) + +so long as yr source + plugin are freely available. + +no commercial use. no use without acknowledgement. + +written/compiled on codewarrior 4.04 for windows + +.mcp file included is the codewarrior project file. + +you will need vst SDK from steinberg website. + +contact st3pan0va [at] netscape [dot] net. + + + +---- + +Acknowledgements / Licence + +Kn0ck0ut is freeware and beta. No warranty, no + +support. The plugin may be redistributed but only for free, + +and only with this readme file. + +Made using the VST SDK and adapts (with thanks) code from S.M.Sprenger + +available under the Wide Open Licence at www.dspdimension.com + +Uses the QuickTrig class by Robin Davies at www.musicdsp.com + +Thanks to TimG, FondueMeltdown, brainy & the ppl of *GYBO*. +