void FFT_next(FFT *unit, int wrongNumSamples) { float *in = IN(1); float *out = unit->m_inbuf + unit->m_pos + unit->m_shuntsize; int numSamples = unit->m_numSamples; // copy input memcpy(out, in, numSamples * sizeof(float)); unit->m_pos += numSamples; bool gate = ZIN0(4) > 0.f; // Buffer shunting continues, but no FFTing if (unit->m_pos != unit->m_hopsize || !unit->m_fftsndbuf->data || unit->m_fftsndbuf->samples != unit->m_fullbufsize) { if(unit->m_pos == unit->m_hopsize) unit->m_pos = 0; ZOUT0(0) = -1.f; } else { unit->m_pos = 0; if(gate){ scfft_dofft(unit->m_scfft); unit->m_fftsndbuf->coord = coord_Complex; ZOUT0(0) = unit->m_fftbufnum; } else { ZOUT0(0) = -1; } // Shunt input buf down memmove(unit->m_inbuf, unit->m_inbuf + unit->m_hopsize, unit->m_shuntsize * sizeof(float)); } }
//buffer preparation void PreparePartConv(World *world, struct SndBuf *buf, struct sc_msg_iter *msg) { // 'channels' not used- should just be mono, num frames= num samples float *data1 = buf->data; uint32 frombufnum = msg->geti(); int fftsize = msg->geti(); //output size must be frombuf->frames*2 if (frombufnum >= world->mNumSndBufs) frombufnum = 0; SndBuf* frombuf = world->mSndBufs + frombufnum; int frames2 = frombuf->frames; float *data2 = frombuf->data; //scfft int nover2= fftsize>>1; int numpartitions; if(frames2 % nover2 == 0){ numpartitions= frames2/nover2; }else{ numpartitions= (frames2/nover2)+1; } //printf("reality check numpartitions %d fftsize %d product %d numinputframes %d \n", numpartitions, fftsize, numpartitions*fftsize, frames2); float * inputbuf= (float*)RTAlloc(world, fftsize * sizeof(float)); float * spectrum= (float*)RTAlloc(world, fftsize * sizeof(float)); SCWorld_Allocator alloc(ft, world); scfft* m_scfft = scfft_create(fftsize, fftsize, kRectWindow, inputbuf, spectrum, kForward, alloc); memset(inputbuf, 0, sizeof(float)*fftsize); // for zero padding //run through input data buffer, taking nover2 chunks, zero padding each for (int i=0; i<numpartitions; ++i) { int indexnow= nover2*i; int indexout= fftsize*i; if(i<(numpartitions-1)){ memcpy(inputbuf, data2+indexnow, nover2 * sizeof(float)); }else{ int takenow = frames2 % nover2; if(takenow == 0){ takenow = nover2; } memcpy(inputbuf, data2+indexnow, takenow * sizeof(float)); if(takenow<nover2){ memset(inputbuf+takenow, 0, (nover2-takenow)*sizeof(float)); } } scfft_dofft(m_scfft); memcpy(data1+indexout, spectrum, fftsize * sizeof(float)); } //clean up RTFree(world, inputbuf); RTFree(world, spectrum); if(m_scfft) scfft_destroy(m_scfft, alloc); }
void Convolution2_next(Convolution2 *unit, int wrongNumSamples) { float *in1 = IN(0); //float *in2 = IN(1); float curtrig = ZIN0(2); float *out1 = unit->m_inbuf1 + unit->m_pos; // float *out2 = unit->m_inbuf2 + unit->m_pos; int numSamples = unit->mWorld->mFullRate.mBufLength; uint32 insize=unit->m_insize * sizeof(float); // copy input Copy(numSamples, out1, in1); unit->m_pos += numSamples; if (unit->m_prevtrig <= 0.f && curtrig > 0.f){ //float fbufnum = ZIN0(1); //int log2n2 = unit->m_log2n; //uint32 bufnum = (int)fbufnum; //printf("bufnum %i \n", bufnum); //World *world = unit->mWorld; //if (bufnum >= world->mNumSndBufs) bufnum = 0; //SndBuf *buf = world->mSndBufs + bufnum; SndBuf *buf = ConvGetBuffer(unit,(uint32)ZIN0(1), "Convolution2", numSamples); if (!buf) return; LOCK_SNDBUF_SHARED(buf); memcpy(unit->m_fftbuf2, buf->data, insize); memset(unit->m_fftbuf2+unit->m_insize, 0, insize); //rffts(unit->m_fftbuf2, log2n2, 1, cosTable[log2n2]); scfft_dofft(unit->m_scfft2); } if (unit->m_pos & unit->m_insize) { //have collected enough samples to transform next frame unit->m_pos = 0; //reset collection counter // copy to fftbuf //int log2n = unit->m_log2n; memcpy(unit->m_fftbuf1, unit->m_inbuf1, insize); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf1+unit->m_insize, 0, insize); //if (unit->m_prevtrig <= 0.f && curtrig > 0.f) scfft_dofft(unit->m_scfft1); //in place transform for now // rffts(unit->m_fftbuf1, log2n, 1, cosTable[log2n]); //complex multiply time int numbins = unit->m_fftsize >> 1; //unit->m_fftsize - 2 >> 1; float * p1= unit->m_fftbuf1; float * p2= unit->m_fftbuf2; p1[0] *= p2[0]; p1[1] *= p2[1]; //complex multiply for (int i=1; i<numbins; ++i) { float real,imag; int realind,imagind; realind= 2*i; imagind= realind+1; real= p1[realind]*p2[realind]- p1[imagind]*p2[imagind]; imag= p1[realind]*p2[imagind]+ p1[imagind]*p2[realind]; p1[realind] = real; //p2->bin[i]; p1[imagind]= imag; } //copy second part from before to overlap memcpy(unit->m_overlapbuf, unit->m_outbuf+unit->m_insize, insize); //inverse fft into outbuf memcpy(unit->m_outbuf, unit->m_fftbuf1, unit->m_fftsize * sizeof(float)); //in place //riffts(unit->m_outbuf, log2n, 1, cosTable[log2n]); scfft_doifft(unit->m_scfftR); // DoWindowing(log2n, unit->m_outbuf, unit->m_fftsize); }
void Convolution2_Ctor(Convolution2 *unit) { //require size N+M-1 to be a power of two unit->m_insize=(int)ZIN0(3); //could be input parameter // printf( "unit->m_insize %i\n", unit->m_insize ); // printf( "unit->mWorld->mFullRate.mBufLength %i\n", unit->mWorld->mFullRate.mBufLength ); //float fbufnum = ZIN0(1); uint32 bufnum = (int)ZIN0(1); //fbufnum; World *world = unit->mWorld; //before added check for LocalBuf //if (bufnum >= world->mNumSndBufs) bufnum = 0; // SndBuf *buf = world->mSndBufs + bufnum; SndBuf *buf = ConvGetBuffer(unit, bufnum, "Convolution2", 1); if(buf) { if ( unit->m_insize <= 0 ) // if smaller than zero, equal to size of buffer unit->m_insize=buf->frames; //could be input parameter unit->m_fftsize=2*(unit->m_insize); //printf("hello %i, %i\n", unit->m_insize, unit->m_fftsize); //just use memory for the input buffers and fft buffers int insize = unit->m_insize * sizeof(float); int fftsize = unit->m_fftsize * sizeof(float); // // unit->m_inbuf1 = (float*)RTAlloc(unit->mWorld, insize); //// unit->m_inbuf2 = (float*)RTAlloc(unit->mWorld, insize); // // unit->m_fftbuf1 = (float*)RTAlloc(unit->mWorld, fftsize); // unit->m_fftbuf2 = (float*)RTAlloc(unit->mWorld, fftsize); unit->m_inbuf1 = (float*)RTAlloc(world, insize); unit->m_fftbuf1 = (float*)RTAlloc(world, fftsize); unit->m_fftbuf2 = (float*)RTAlloc(world, fftsize); unit->m_outbuf = (float*)RTAlloc(world, fftsize); unit->m_overlapbuf = (float*)RTAlloc(world, insize); memset(unit->m_outbuf, 0, fftsize); memset(unit->m_overlapbuf, 0, insize); //unit->m_log2n = LOG2CEIL(unit->m_fftsize); unit->m_pos = 0; memset(unit->m_outbuf, 0, fftsize); memset(unit->m_overlapbuf, 0, insize); SCWorld_Allocator alloc(ft, unit->mWorld); unit->m_scfft1 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf1, unit->m_fftbuf1, kForward, alloc); unit->m_scfft2 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf2, unit->m_fftbuf2, kForward, alloc); unit->m_scfftR = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf1, unit->m_outbuf, kBackward, alloc); //calculate fft for kernel straight away memcpy(unit->m_fftbuf2, buf->data, insize); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf2+unit->m_insize, 0, insize); scfft_dofft(unit->m_scfft2); unit->m_pos = 0; // unit->m_log2n = LOG2CEIL(unit->m_fftsize); // // int log2n = unit->m_log2n; // // //test for full input buffer // //unit->m_mask = unit->m_insize; // // //in place transform for now // rffts(unit->m_fftbuf2, log2n, 1, cosTable[log2n]); unit->m_prevtrig = 0.f; unit->m_prevtrig = ZIN0(2); // printf( "unit->m_insize %i\n", unit->m_insize ); // printf( "world->mFullRate.mBufLength %i\n", world->mFullRate.mBufLength ); if ( unit->m_insize >= world->mFullRate.mBufLength ) { // printf( "insize bigger than blocksize\n" ); SETCALC(Convolution2_next); } else { printf( "Convolution2 framesize smaller than blocksize \n" ); SETCALC(*ClearUnitOutputs); unit->mDone = true; //SETCALC(Convolution2_next2); } } else { unit->m_scfft2 = unit->m_scfft1 = unit->m_scfftR = NULL; } }
void Convolution_next(Convolution *unit, int numSamples) { float *in1 = IN(0); float *in2 = IN(1); float *out1 = unit->m_inbuf1 + unit->m_pos; float *out2 = unit->m_inbuf2 + unit->m_pos; //int numSamples = unit->mWorld->mFullRate.mBufLength; // copy input Copy(numSamples, out1, in1); Copy(numSamples, out2, in2); unit->m_pos += numSamples; int insize= unit->m_insize; if (unit->m_pos & insize) { //have collected enough samples to transform next frame unit->m_pos = 0; //reset collection counter int memsize= insize*sizeof(float); // copy to fftbuf memcpy(unit->m_fftbuf1, unit->m_inbuf1, memsize); memcpy(unit->m_fftbuf2, unit->m_inbuf2, memsize); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf1+unit->m_insize, 0, memsize); memset(unit->m_fftbuf2+unit->m_insize, 0, memsize); // do fft //in place transform for now //old Green fft code, now replaced by scfft // int log2n = unit->m_log2n; // rffts(unit->m_fftbuf1, log2n, 1, cosTable[log2n]); // rffts(unit->m_fftbuf2, log2n, 1, cosTable[log2n]); scfft_dofft(unit->m_scfft1); scfft_dofft(unit->m_scfft2); //complex multiply time float * p1= unit->m_fftbuf1; float * p2= unit->m_fftbuf2; p1[0] *= p2[0]; p1[1] *= p2[1]; //complex multiply for (int i=1; i<insize; ++i) { float real,imag; int realind,imagind; realind= 2*i; imagind= realind+1; real= p1[realind]*p2[realind]- p1[imagind]*p2[imagind]; imag= p1[realind]*p2[imagind]+ p1[imagind]*p2[realind]; p1[realind] = real; p1[imagind]= imag; } //copy second part from before to overlap memcpy(unit->m_overlapbuf, unit->m_outbuf+unit->m_insize, memsize); //inverse fft into outbuf memcpy(unit->m_outbuf, unit->m_fftbuf1, unit->m_fftsize * sizeof(float)); //in place //riffts(unit->m_outbuf, log2n, 1, cosTable[log2n]); scfft_doifft(unit->m_scfftR); } //write out samples copied from outbuf, with overlap added in float *output = ZOUT(0); float *out= unit->m_outbuf+unit->m_pos; float *overlap= unit->m_overlapbuf+unit->m_pos; for (int i=0; i<numSamples; ++i) ZXP(output) = out[i] + overlap[i]; }
void PartConv_next( PartConv *unit, int inNumSamples ) { float *in = IN(0); float *out = OUT(0); int pos = unit->m_pos; //safety check if (!(unit->mWorld->mSndBufs + unit->m_specbufnumcheck)->data) { printf("PartConv Error: Spectral data buffer not allocated \n"); ClearUnitOutputs(unit, inNumSamples); SETCALC(*ClearUnitOutputs); unit->mDone = true; return; } float * input= unit->m_inputbuf; float * output= unit->m_output; int outputpos= unit->m_outputpos; //into input buffer memcpy(input+pos, in, inNumSamples * sizeof(float)); pos += inNumSamples; //if ready for new FFT int nover2 = unit->m_nover2; //assumes that blocksize perfectly divides windowsize if (pos == nover2) { //FFT this input, second half of input always zero //memset(input+unit->m_nover2, 0, sizeof(float)*unit->m_nover2); scfft_dofft(unit->m_scfft); //reset pos into input buffer pos=0; //reset outputpos outputpos= 0; float * spectrum = unit->m_spectrum; float * spectrum2 = unit->m_spectrum2; //multiply spectra and accumulate for all ir spectra across storage buffer int fftsize = unit->m_fftsize; int accumpos = unit->m_fd_accum_pos; float * accumbuffer = unit->m_fd_accumulate; float * irspectrum = unit->m_irspectra; int fullsize = unit->m_fullsize; //JUST DO FIRST ONE FOR NOW, AMORTISED FOR OTHERS //frames for (int i=0; i<1; ++i) { int irpos= (i*fftsize); int posnow= (accumpos+irpos)%fullsize; float * target= accumbuffer+posnow; float * ir= irspectrum+irpos; //real multiply for dc and nyquist target[0] += ir[0]*spectrum[0]; target[1] += ir[1]*spectrum[1]; //complex multiply for frequency bins for (int j=1; j<nover2; ++j) { int binposr= 2*j; int binposi= binposr+1; target[binposr] += (ir[binposr]*spectrum[binposr]) - (ir[binposi]*spectrum[binposi]); target[binposi] += (ir[binposi]*spectrum[binposr]) + (ir[binposr]*spectrum[binposi]); } } //IFFT this partition float * input2 = unit->m_inputbuf2; memcpy(input2, accumbuffer+accumpos, fftsize * sizeof(float)); scfft_doifft(unit->m_scifft); //shunt output data down and zero top bit memcpy(output, output+nover2, nover2 * sizeof(float)); memset(output+nover2, 0, nover2 * sizeof(float)); //sum into output for (int j=0; j<fftsize; ++j) output[j] += spectrum2[j]; //zero this partition memset(accumbuffer+accumpos, 0, fftsize * sizeof(float)); //ONLY DO AT END OF AMORTISATION???? no, amort code has extra -1 in indexing to cope //update partition counter accumpos= (accumpos+fftsize)%fullsize; unit->m_fd_accum_pos= accumpos; //set up for amortisation (calculate output for other partitions of impulse response) unit->m_amortcount=0; unit->m_partitionsdone=1; } else { //amortisation steps: //complex multiply of this new fft spectrum against existing irspectrums and sum to accumbuffer if (unit->m_amortcount>=0) { float * spectrum= unit->m_spectrum; //multiply spectra and accumulate for all ir spectra across storage buffer int fftsize= unit->m_fftsize; int nover2= unit->m_nover2; //int frames= unit->m_partitions; int accumpos= unit->m_fd_accum_pos; float * accumbuffer= unit->m_fd_accumulate; float * irspectrum= unit->m_irspectra; int fullsize= unit->m_fullsize; int starti, stopi; int number; if(unit->m_amortcount==(unit->m_spareblocks-1)) { number= unit->m_lastamort; }else{ number= unit->m_numamort; } starti= unit->m_partitionsdone-1; stopi= starti+number-1; //printf("amort check count %d starti %d stopi %d number %d framesdone %d \n",unit->m_amortcount, starti, stopi, number, unit->m_partitionsdone); unit->m_partitionsdone += number; ++unit->m_amortcount; for (int i=starti; i<=stopi; ++i) { int posnow= (accumpos+(i*fftsize))%fullsize; float * target= accumbuffer+posnow; int irpos= (i*fftsize); float * ir= irspectrum+irpos; //real multiply for dc and nyquist target[0]+= ir[0]*spectrum[0]; target[1]+= ir[1]*spectrum[1]; //complex multiply for frequency bins for (int j=1; j<nover2; ++j) { int binposr= 2*j; int binposi= binposr+1; target[binposr]+= (ir[binposr]*spectrum[binposr]) - (ir[binposi]*spectrum[binposi]); target[binposi]+= (ir[binposi]*spectrum[binposr]) + (ir[binposr]*spectrum[binposi]); } } } } //do this second! memcpy(out, output+outputpos, inNumSamples * sizeof(float)); //debugging tests: output values tend to be fftsize too big, probably due to complex multiply and also summation over all partitions // RGen& rgen = *unit->mParent->mRGen; // int testindex= rgen.irand(inNumSamples-1); // printf("inNumSamples %d testindex %d out %f output %f \n",inNumSamples, testindex, out[testindex], *(output+outputpos+testindex)); outputpos+=inNumSamples; unit->m_outputpos= outputpos; unit->m_pos= pos; }
void Convolution2_next(Convolution2 *unit, int wrongNumSamples) { float *in1 = IN(0); float curtrig = ZIN0(2); float *inbuf1writepos = unit->m_inbuf1 + unit->m_pos; int numSamples = unit->mWorld->mFullRate.mBufLength; uint32 framesize = unit->m_framesize; uint32 framesize_f = framesize * sizeof(float); // copy input Copy(numSamples, inbuf1writepos, in1); unit->m_pos += numSamples; if (unit->m_prevtrig <= 0.f && curtrig > 0.f){ SndBuf *kernelbuf = ConvGetBuffer(unit,(uint32)ZIN0(1), "Convolution2", numSamples); if (!kernelbuf) return; LOCK_SNDBUF_SHARED(kernelbuf); // we cannot use a kernel larger than the fft size, so truncate if needed. the kernel may be smaller though. size_t kernelcopysize = sc_min(kernelbuf->frames, framesize); memcpy(unit->m_fftbuf2, kernelbuf->data, kernelcopysize * sizeof(float)); memset(unit->m_fftbuf2 + kernelcopysize, 0, (2 * framesize - kernelcopysize) * sizeof(float)); scfft_dofft(unit->m_scfft2); } if (unit->m_pos >= framesize) { //have collected enough samples to transform next frame unit->m_pos = 0; //reset collection counter // copy to fftbuf memcpy(unit->m_fftbuf1, unit->m_inbuf1, framesize_f); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf1+unit->m_framesize, 0, framesize_f); scfft_dofft(unit->m_scfft1); //complex multiply time int numbins = unit->m_fftsize >> 1; float * p1= unit->m_fftbuf1; float * p2= unit->m_fftbuf2; p1[0] *= p2[0]; p1[1] *= p2[1]; //complex multiply for (int i=1; i<numbins; ++i) { float real,imag; int realind,imagind; realind= 2*i; imagind= realind+1; real= p1[realind]*p2[realind]- p1[imagind]*p2[imagind]; imag= p1[realind]*p2[imagind]+ p1[imagind]*p2[realind]; p1[realind] = real; p1[imagind]= imag; } //copy second part from before to overlap memcpy(unit->m_overlapbuf, unit->m_outbuf+unit->m_framesize, framesize_f); //inverse fft into outbuf scfft_doifft(unit->m_scfftR); }
void Convolution2_Ctor(Convolution2 *unit) { //require size N+M-1 to be a power of two unit->m_framesize=(int)ZIN0(3); uint32 kernelbufnum = (int)ZIN0(1); World *world = unit->mWorld; SndBuf *kernelbuf = ConvGetBuffer(unit, kernelbufnum, "Convolution2", 1); if(kernelbuf) { if ( unit->m_framesize <= 0 ){ // if smaller than zero, we use the size of the buffer unit->m_framesize=kernelbuf->frames; } unit->m_fftsize=2*(unit->m_framesize); if(unit->m_fftsize > SC_FFT_ABSOLUTE_MAXSIZE){ printf( "Convolution2: FFT size is larger than SC_FFT_ABSOLUTE_MAXSIZE, cannot run. We suggest PartConv instead.\n" ); SETCALC(*ClearUnitOutputs); } // allocate memory internally for the input buffers and fft buffers int framesize_f = unit->m_framesize * sizeof(float); int fftsize_f = unit->m_fftsize * sizeof(float); unit->m_inbuf1 = (float*)RTAlloc(world, framesize_f); unit->m_fftbuf1 = (float*)RTAlloc(world, fftsize_f); unit->m_fftbuf2 = (float*)RTAlloc(world, fftsize_f); unit->m_outbuf = (float*)RTAlloc(world, fftsize_f); memset(unit->m_outbuf, 0, fftsize_f); unit->m_overlapbuf = (float*)RTAlloc(world, framesize_f); memset(unit->m_overlapbuf, 0, framesize_f); unit->m_pos = 0; SCWorld_Allocator alloc(ft, unit->mWorld); unit->m_scfft1 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf1, unit->m_fftbuf1, kForward, alloc); unit->m_scfft2 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf2, unit->m_fftbuf2, kForward, alloc); unit->m_scfftR = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf1, unit->m_outbuf, kBackward, alloc); if(!unit->m_scfft1 || !unit->m_scfft2 || !unit->m_scfftR){ printf( "Could not create scfft.\n" ); SETCALC(*ClearUnitOutputs); unit->mDone = true; return; } //calculate fft for kernel straight away // we cannot use a kernel larger than the fft size, so truncate if needed. the kernel may be smaller though. uint32 framesize = unit->m_framesize; size_t kernelcopysize = sc_min(kernelbuf->frames, framesize); memcpy(unit->m_fftbuf2, kernelbuf->data, kernelcopysize * sizeof(float)); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf2 + kernelcopysize, 0, (2 * framesize - kernelcopysize) * sizeof(float)); scfft_dofft(unit->m_scfft2); unit->m_pos = 0; unit->m_prevtrig = 0.f; unit->m_prevtrig = ZIN0(2); if ( unit->m_framesize >= world->mFullRate.mBufLength ) { SETCALC(Convolution2_next); } else { printf( "Convolution2 framesize smaller than blocksize \n" ); SETCALC(*ClearUnitOutputs); unit->mDone = true; } } else { unit->m_scfft2 = unit->m_scfft1 = unit->m_scfftR = NULL; printf("Convolution2_Ctor: can't get kernel buffer, giving up.\n"); SETCALC(*ClearUnitOutputs); } }