void IFFT_next(IFFT *unit, int wrongNumSamples){ float *out = OUT(0); // NB not ZOUT0 // Load state from struct into local scope int pos = unit->m_pos; int fullbufsize = unit->m_fullbufsize; int audiosize = unit->m_audiosize; // int numSamples = unit->mWorld->mFullRate.mBufLength; int numSamples = unit->m_numSamples; float *olabuf = unit->m_olabuf; float fbufnum = ZIN0(0); // Only run the IFFT if we're receiving a new block of input data - otherwise just output data already received if (fbufnum >= 0.f){ // Ensure it's in cartesian format, not polar ToComplexApx(unit->m_fftsndbuf); float* fftbuf = unit->m_fftsndbuf->data; scfft_doifft(unit->m_scfft); // Then shunt the "old" time-domain output down by one hop int hopsamps = pos; int shuntsamps = audiosize - hopsamps; if(hopsamps != audiosize){ // There's only copying to be done if the position isn't all the way to the end of the buffer memcpy(olabuf, olabuf+hopsamps, shuntsamps * sizeof(float)); } // Then mix the "new" time-domain data in - adding at first, then just setting (copying) where the "old" is supposed to be zero. #if SC_DARWIN vDSP_vadd(olabuf, 1, fftbuf, 1, olabuf, 1, shuntsamps); #else // NB we re-use the "pos" variable temporarily here for write rather than read for(pos = 0; pos < shuntsamps; ++pos){ olabuf[pos] += fftbuf[pos]; } #endif memcpy(olabuf + shuntsamps, fftbuf + shuntsamps, (hopsamps) * sizeof(float)); // Move the pointer back to zero, which is where playback will next begin pos = 0; } // End of has-the-chain-fired // Now we can output some stuff, as long as there is still data waiting to be output. // If there is NOT data waiting to be output, we output zero. (Either irregular/negative-overlap // FFT firing, or FFT has given up, or at very start of execution.) if(pos >= audiosize){ ClearUnitOutputs(unit, numSamples); }else{ memcpy(out, olabuf + pos, numSamples * sizeof(float)); pos += numSamples; } unit->m_pos = pos; }
void FFTPower_next(FFTPower *unit, int inNumSamples) { FFTAnalyser_GET_BUF float normfactor = unit->m_normfactor; bool square = unit->m_square; if(normfactor == 0.f){ if(square) unit->m_normfactor = normfactor = 1.f / powf(numbins + 2.f, 1.5f); else unit->m_normfactor = normfactor = 1.f / (numbins + 2.f); } SCComplexBuf *p = ToComplexApx(buf); // SCPolarBuf *p = ToPolarApx(buf); float total; if(square){ total = sc_abs(p->dc) * sc_abs(p->dc) + sc_abs(p->nyq) * sc_abs(p->nyq); for (int i=0; i<numbins; ++i) { float rabs = (p->bin[i].real); float iabs = (p->bin[i].imag); total += (rabs*rabs) + (iabs*iabs); } }else{ total = sc_abs(p->dc) + sc_abs(p->nyq); for (int i=0; i<numbins; ++i) { float rabs = (p->bin[i].real); float iabs = (p->bin[i].imag); total += sqrt((rabs*rabs) + (iabs*iabs)); } // for (int i=0; i<numbins; ++i) { // total += sc_abs(p->bin[i].mag); // } } // Store the val for output in future calls unit->outval = total * normfactor; ZOUT0(0) = unit->outval; }
void FFTSubbandPower_next(FFTSubbandPower *unit, int inNumSamples) { int numbands = unit->m_numbands; int numcutoffs = numbands - 1; // Multi-output equiv of FFTAnalyser_GET_BUF float fbufnum = ZIN0(0); if (fbufnum < 0.f) { for(int i=0; i<numbands; i++){ ZOUT0(i) = unit->m_outvals[i]; } return; } uint32 ibufnum = (uint32)fbufnum; World *world = unit->mWorld; SndBuf *buf; if (ibufnum >= world->mNumSndBufs) { int localBufNum = ibufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) { buf = parent->mLocalSndBufs + localBufNum; } else { buf = world->mSndBufs; } } else { buf = world->mSndBufs + ibufnum; } int numbins = (buf->samples - 2) >> 1; // End: Multi-output equiv of FFTAnalyser_GET_BUF int scalemode = unit->m_scalemode; float normfactor = unit->m_normfactor; bool square = unit->m_square; if(normfactor == 0.f){ if(square) unit->m_normfactor = normfactor = 1.f / powf(numbins + 2.f, 1.5f); else unit->m_normfactor = normfactor = 1.f / (numbins + 2.f); } // Now we create the integer lookup list, if it doesn't already exist int * cutoffs = unit->m_cutoffs; if(!unit->m_cutoff_inited){ float srate = world->mFullRate.mSampleRate; for(int i=0; i < numcutoffs; ++i) { cutoffs[i] = (int)(buf->samples * ZIN0(4 + i) / srate); //Print("Allocated bin cutoff #%d, at bin %d\n", i, cutoffs[i]); } unit->m_cutoff_inited = true; } SCComplexBuf *p = ToComplexApx(buf); // Now we can actually calculate the bandwise subtotals float total = sc_abs(p->dc); if(square){ total *= total; // square the DC val } int binaddcount = 1; // Counts how many bins contributed to the current band (1 because of the DC value) int curband = 0; float * outvals = unit->m_outvals; float magsq; for (int i=0; i<numbins; ++i) { if((curband != numbands) && (i >= cutoffs[curband])){ if(scalemode==1){ outvals[curband] = total * normfactor; }else{ if(square) outvals[curband] = total / powf((float)binaddcount, 1.5f); else outvals[curband] = total / binaddcount; } //Print("Finished off band %i while in bin %i\n", curband, i); ++curband; total = 0.f; binaddcount = 0; } float rabs = (p->bin[i].real); float iabs = (p->bin[i].imag); magsq = ((rabs*rabs) + (iabs*iabs)); if(square) total += magsq; else total += std::sqrt(magsq); ++binaddcount; } // Remember to output the very last (highest) band if(square) total += p->nyq * p->nyq; else total += sc_abs(p->nyq); // Pop the last one onto the end of the lovely list if(scalemode==1){ outvals[curband] = total * normfactor; }else{ if(square) outvals[curband] = total / powf((float)binaddcount + 1.f, 1.5f); // Plus one because of the nyq value else outvals[curband] = total / (binaddcount + 1); // Plus one because of the nyq value } // Now we can output the vals for(int i=0; i<numbands; i++) { ZOUT0(i) = outvals[i]; } }
////////////////////////////////////////////////////////////////////////////////////////////////// void SpecFlatness_Ctor(SpecFlatness *unit) { SETCALC(SpecFlatness_next); ZOUT0(0) = unit->outval = 0.; unit->m_oneovern = 0.; } void SpecFlatness_next(SpecFlatness *unit, int inNumSamples) { FFTAnalyser_GET_BUF if(unit->m_oneovern == 0.) unit->m_oneovern = 1./(numbins + 2); SCComplexBuf *p = ToComplexApx(buf); // Spectral Flatness Measure is geometric mean divided by arithmetic mean. // // In order to calculate geom mean without hitting the precision limit, // we use the trick of converting to log, taking the average, then converting back from log. double geommean = std::log(sc_abs(p->dc)) + std::log(sc_abs(p->nyq)); double mean = sc_abs(p->dc) + sc_abs(p->nyq); for (int i=0; i<numbins; ++i) { float rabs = (p->bin[i].real); float iabs = (p->bin[i].imag); float amp = std::sqrt((rabs*rabs) + (iabs*iabs)); if(amp != 0.f) { // zeroes lead to NaNs geommean += std::log(amp); mean += amp;
//calculation function once FFT data ready void KeyTrack_calculatekey(KeyTrack *unit, uint32 ibufnum) { World *world = unit->mWorld; SndBuf *buf; if (ibufnum >= world->mNumSndBufs) { int localBufNum = ibufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) { buf = parent->mLocalSndBufs + localBufNum; } else { buf = world->mSndBufs; if(unit->mWorld->mVerbosity > -1){ Print("KeyTrack error: Buffer number overrun: %i\n", ibufnum); } } } else { buf = world->mSndBufs + ibufnum; } LOCK_SNDBUF(buf); int numbins = buf->samples - 2 >> 1; //assumed in this representation SCComplexBuf *p = ToComplexApx(buf); const float * data= buf->data; //memcpy(unit->m_FFTBuf, data, NOVER2); //to hold powers float * fftbuf= unit->m_FFTBuf; //get powers for bins //don't need to calculate past half Nyquist, because no indices involved of harmonics above 10000 Hz or so (see index data at top of file) for (int i=0; i<NOVER2; i+=2) { //i>>1 is i/2 fftbuf[i>>1] = ((data[i] * data[i]) + (data[i+1] * data[i+1])); } float * chroma= unit->m_chroma; float sum; int indexbase, index; //experimental; added leaky integration on each note; also, only add to sum if harmonic, ie not a transient float * weights = unit->m_weights; int * bins = unit->m_bins; float chromaleak= ZIN0(2); //zero for new round (should add leaky integrator here! for (int i=0;i<12;++i) chroma[i] *= chromaleak; for (int i=0;i<60;++i) { int chromaindex = (i+9)%12; //starts at A1 up to G#6 sum=0.0; indexbase= 12*i; //6 partials, 2 of each //transient sum, setting up last values too float phasesum=0.0; for(int j=0;j<12;++j) { //12 if 144 data points index=indexbase+j; //experimental transient detection code, not reliable //int binindex= unit->m_bins[index]-1; //SCPolar binnow= p->bin[binindex].ToPolarApx(); //float phaseadvance= (binindex+1)*(TWOPI*0.5); //k * (512/44100) * (44100/1024) //convert bin number to frequency //float power= binnow.mag * binnow.mag; //(p->bin[binindex].real)*(p->bin[binindex].real) + (p->bin[binindex].imag)*(p->bin[binindex].imag); //(p->bin[binindex].mag); //power *= power; //int phaseindex= indexbase+j; //float phasenow= binnow.phase; //0.0; //(p->bin[binindex].phase); //float prevphase = fmod(unit->m_prevphase[index]+phaseadvance,TWOPI); //float a,b,tmp; //a=phasenow; b=prevphase; //b=phasenow; a=prevphase; //if(b<a) {b= b+TWOPI;} //float phasechange = sc_min(b-a,a+TWOPI-b); //more complicated, need mod 2pi and to know lower and upper //phasesum+= phasechange; //unit->m_prevphase[index]= phasenow; //((p->bin[index-1].mag) * (p->bin[index-1].mag)) //printf("comparison %f %f \n",fftbuf[g_bins2[index]], power); //sum+= (unit->m_weights[index])* power; sum+= (weights[index])* (fftbuf[bins[index]]); } //transient test here too? //if(phasesum>(5*PI)){sum=0.0;} //if((i>5) && (i<15)) //printf("test phasesum %f \n", phasesum); //unit->m_leaknote[i] = (0.8*unit->m_leaknote[i]) + sum; chroma[chromaindex]+= sum; //unit->m_leaknote[i]; //sum; } float* key = unit->m_key; //major for (int i=0;i<12;++i) { sum=0.0; for (int j=0;j<7;++j) { indexbase=g_major[j]; index=(i+indexbase)%12; //sum+=(chroma[index]*g_kkmajor[indexbase]); sum+=(chroma[index]*g_diatonicmajor[indexbase]); } key[i]=sum; //10*log10(sum+1); } //minor for (int i=0;i<12;++i) { sum=0.0; for (int j=0;j<7;++j) { indexbase=g_minor[j]; index=(i+indexbase)%12; //sum+=(chroma[index]*g_kkminor[indexbase]); sum+=(chroma[index]*g_diatonicminor[indexbase]); } key[12+i]=sum; } float keyleak= ZIN0(1); //fade parameter to 0.01 for histogram in seconds, convert to FFT frames //keyleak in seconds, convert to drop time in FFT hop frames (FRAMEPERIOD) keyleak= sc_max(0.001f,keyleak/unit->m_frameperiod); //FRAMEPERIOD; //now number of frames, actual leak param is decay exponent to reach 0.01 in x seconds, ie 0.01 = leakparam ** (x/ffthopsize) //0.01 is -40dB keyleak= pow(0.01f,(1.f/keyleak)); float * histogram= unit->m_histogram; int bestkey=0; float bestscore=0.0; for (int i=0;i<24;++i) { histogram[i]= (keyleak*histogram[i])+key[i]; if(histogram[i]>bestscore) { bestscore=histogram[i]; bestkey=i; } //printf("%f ",histogram[i]); } //should find secondbest and only swap if win by a margin //printf(" best %d \n\n",bestkey); //what is winning currently? find max in histogram unit->m_currentKey=bestkey; //about 5 times per second //if((unit->m_triggerid) && ((unit->m_frame%2==0))) SendTrigger(&unit->mParent->mNode, unit->m_triggerid, bestkey); }