Beispiel #1
0
static void vftom_perform(t_vftom *x, t_symbol *s, int argc, t_atom *argv)
{
	int i;
	t_atom *ap,*app;
    ap = (t_atom *)getbytes(sizeof(t_atom)*argc);
	app=ap;

	for (i = 0; i < argc; i++)
	{
		SETFLOAT(app, ftom(atom_getfloat(argv++)));
		app++;
	}
	outlet_list(x->x_obj.ob_outlet,gensym("list"),argc,ap);
    freebytes(ap,argc);
}
Beispiel #2
0
// This is the actual Fiddle~ code
void pitch_getit(t_pitch *x)
{
    t_int i, j, k;
    t_peak *pk1; // peaks found
    t_peakout *pk2; // peaks to output
    t_histopeak *hp1;
    t_float power_spec = 0.0f, total_power = 0.0f, total_loudness = 0.0f, total_db = 0.0f;
    t_float *fp1, *fp2;
    t_float *spec = x->BufFFT, *powSpec = x->BufPower, threshold, mult;
    t_int n = x->FFTSize/2;
    t_int npitch, newphase, oldphase, npeak = 0;
    t_int logn = pitch_ilog2(n);
    t_float maxbin = BINPEROCT * (logn-2);
    t_float hzperbin = x->x_Fs/x->FFTSize;
    t_float coeff = x->FFTSize/(t_float)x->BufSize;
    t_float *histogram = x->histBuf + BINGUARD;
    t_int npeaktot = (x->x_npeakout > x->x_npeakanal ? x->x_npeakout : x->x_npeakanal);
    t_pitchhist *phist;
    
    // Circular buffer for History
    oldphase = x->x_histphase;
    newphase = x->x_histphase + 1;
    if (newphase == HISTORY) newphase = 0;
    x->x_histphase = newphase;

	// Get spectrum power
	for (i=0; i<n; i++)
		power_spec += powSpec[i];
			    
	total_power = 4.0f * power_spec; // Compensate for fiddle~ power estimation (difference of 6 dB)

    if (total_power > POWERTHRES) {
		total_db = (FIDDLEDB_REF-DBFUDGE) + LOGTODB*flog(total_power/n); // dB power estimation of fiddle~
		total_loudness = fsqrt(fsqrt(power_spec)); // Use the actual real estimation rather than fiddle~'s
		if (total_db < 0) total_db = 0.0f;
    } else {
    	total_db = total_loudness = 0.0f;
    }
    
	// Store new db in history vector
    x->x_dbs[newphase] = total_db;

	// Not enough power to find anything
    if (total_db < x->x_amplo) goto nopow;

	// search for peaks
	pk1 = x->x_peaklist;
		
    for (i=MINBIN, fp1=spec+2*MINBIN, fp2=powSpec+MINBIN; (i<n-3) && (npeak<npeaktot); i++, fp1+=2, fp2++) {    	 
    	 
		t_float height = fp2[0], h1 = fp2[-1], h2 = fp2[1]; // Bin power and adjacents
		t_float totalfreq, pfreq, f1, f2, m, var, stdev;
	
		if (height<h1 || height<h2 || h1*coeff<POWERTHRES*total_power || h2*coeff<POWERTHRES*total_power) continue; // Go to next

    	// Use an informal phase vocoder to estimate the frequency
		pfreq = ((fp1[-4] - fp1[4]) * (2.0f * fp1[0] - fp1[4] - fp1[-4]) +
				 (fp1[-3] - fp1[5]) * (2.0f * fp1[1] - fp1[5] - fp1[-3])) / (2.0f * height);
		    
    	// Do this for the two adjacent bins too
		f1 = ((fp1[-6] - fp1[2]) * (2.0f * fp1[-2] - fp1[2] - fp1[-6]) +
			  (fp1[-5] - fp1[3]) * (2.0f * fp1[-1] - fp1[3] - fp1[-5])) / (2.0f * h1) - 1;
		f2 = ((fp1[-2] - fp1[6]) * (2.0f * fp1[2] - fp1[6] - fp1[-2]) +
			  (fp1[-1] - fp1[7]) * (2.0f * fp1[3] - fp1[7] - fp1[-1])) / (2.0f * h2) + 1;

    	// get sample mean and variance of the three
		m = 0.333333f * (pfreq + f1 + f2);
		var = 0.5f * ((pfreq-m)*(pfreq-m) + (f1-m)*(f1-m) + (f2-m)*(f2-m));

		totalfreq = i + m;
		
		// BAD HACK TO BE CHANGE IN NEXT VERSION !!!!
		if (coeff > 1) {
			switch ((t_int)coeff) {
				case 2:
					mult = 0.005;
					break;
				case 4:
					mult = 0.125;
					break;
				case 8:
					mult = 0.2;
					break;
				case 16:
					mult = 0.25; // weird values found by trying to get npeak around 6-7
					break;
				default:
					mult = 0.25;
			}			
			threshold = KNOCKTHRESH * height * mult;
		} else {
			threshold = KNOCKTHRESH * height;
		}

		if ((var * total_power) > threshold || (var < 1e-30)) continue;

		stdev = fsqrt(var);
		if (totalfreq < 4) totalfreq = 4;
		
		// Store the peak info in the list of peaks
		pk1->p_width = stdev;
		pk1->p_pow = height;
		pk1->p_loudness = fsqrt(fsqrt(height));
		pk1->p_fp = fp1;
		pk1->p_freq = totalfreq;
	
		npeak++;
		pk1++;
    } // end for
		
    // prepare the raw peaks for output
    for (i=0, pk1=x->x_peaklist, pk2=x->peakBuf; i<npeak; i++, pk1++, pk2++) {
    	
    	t_float loudness = pk1->p_loudness;
    	if (i>=x->x_npeakout) break;
    	
    	pk2->po_freq = hzperbin * pk1->p_freq;
    	pk2->po_amp = (2.f/(t_float)n) * loudness * loudness * coeff;
    }
        
    // in case npeak < x->x_npeakout
    for (; i<x->x_npeakout; i++, pk2++) pk2->po_amp = pk2->po_freq = 0;

	// now, make a sort of "likelihood" spectrum. Proceeding in 48ths of an octave,  
	// from 2 to n/2 (in bins), the likelihood of each pitch range is contributed
	// to by every peak in peaklist that's an integer multiple of it in frequency

    if (npeak > x->x_npeakanal) npeak = x->x_npeakanal; // max # peaks to analyze
        
    // Initialize histogram buffer to 0
    for (i=0, fp1=histogram; i<maxbin; i++) *fp1++ = 0.0f;

    for (i=0, pk1=x->x_peaklist; i<npeak; i++, pk1++) {
    
		t_float pit = BPEROOVERLOG2 * flog(pk1->p_freq) - 96.0f;
		t_float binbandwidth = FACTORTOBINS * pk1->p_width/pk1->p_freq;
		t_float putbandwidth = (binbandwidth < 2 ? 2 : binbandwidth);
		t_float weightbandwidth = (binbandwidth < 1.0f ? 1.0f : binbandwidth);
		t_float weightamp = 4.0f * pk1->p_loudness / total_loudness;

		for (j=0, fp2=pitch_partialonset; j<NPARTIALONSET; j++, fp2++) {
	    	t_float bin = pit - *fp2;
	    	if (bin<maxbin) {
				t_float para, pphase, score = BINAMPCOEFF * weightamp / ((j+x->x_npartial) * weightbandwidth);
				t_int firstbin = bin + 0.5f - 0.5f * putbandwidth;
				t_int lastbin = bin + 0.5f + 0.5f * putbandwidth;
				t_int ibw = lastbin - firstbin;
				if (firstbin < -BINGUARD) break;
				para = 1.0f / (putbandwidth * putbandwidth);
				for (k=0, fp1=histogram+firstbin, pphase=firstbin-bin; k<=ibw; k++, fp1++, pphase+=1.0f)
		    		*fp1 += score * (1.0f - para * pphase * pphase);
	    	}
		} // end for
    } // end for
      
    //post("npeaks = %d, %f",npeak,mult); // For debugging weird hack!!!
   
    
	// Next we find up to NPITCH strongest peaks in the histogram.
	// If a peak is related to a stronger one via an interval in
	// the pitch_partialonset array, we suppress it.

    for (npitch=0; npitch<x->x_npitch; npitch++) {
		t_int index;
		t_float best;
		if (npitch) {
	    	for (best=0, index=-1, j=1; j<maxbin-1; j++) {
				if ((histogram[j]>best) && (histogram[j]>histogram[j-1]) && (histogram[j]>histogram[j+1])) {
		    		for (k=0; k<npitch; k++)
						if (x->x_histvec[k].h_index == j) goto peaknogood;
		    		for (k=0; k<NPARTIALONSET; k++) {
						if ((j-pitch_intpartialonset[k]) < 0) break;
						if (histogram[j-pitch_intpartialonset[k]] > histogram[j]) goto peaknogood;
					}
		    		for (k=0; k<NPARTIALONSET; k++) {
						if (j+ pitch_intpartialonset[k] >= maxbin) break;
						if (histogram[j+pitch_intpartialonset[k]] > histogram[j]) goto peaknogood;
		    		}
		    		index = j;
		    		best = histogram[j];
				}
	    		peaknogood: ;
	    	}
		} else {
			best = 0; 
			index = -1;
	    	for (j=0; j<maxbin; j++)
				if (histogram[j] > best) {
		    		index = j; 
		    		best = histogram[j];
		    	}
		}

		if (index < 0) break;
	
		x->x_histvec[npitch].h_value = best;
		x->x_histvec[npitch].h_index = index;
    }
       
	// for each histogram peak, we now search back through the
	// FFT peaks.  A peak is a pitch if either there are several
	// harmonics that match it, or else if (a) the fundamental is
	// present, and (b) the sum of the powers of the contributing peaks
	// is at least 1/100 of the total power.
	//
	// A peak is a contributor if its frequency is within 25 cents of
	// a partial from 1 to 16.
	//
	// Finally, we have to be at least 5 bins in frequency, which
	// corresponds to 2-1/5 periods fitting in the analysis window.

    for (i=0; i<npitch; i++) {
    	t_float cumpow=0, cumstrength=0, freqnum=0, freqden=0;
		t_int npartials=0,  nbelow8=0;
	    // guessed-at frequency in bins
		t_float putfreq = fexp((1.0f / BPEROOVERLOG2) * (x->x_histvec[i].h_index + 96.0f));
	
		for (j=0; j<npeak; j++) {
	    	t_float fpnum = x->x_peaklist[j].p_freq/putfreq;
	    	t_int pnum = fpnum + 0.5f;
	    	t_float fipnum = pnum;
	    	t_float deviation;
	    
	    	if ((pnum>16) || (pnum<1)) continue;
	    
	    	deviation = 1.0f - fpnum/fipnum;
	   		if ((deviation > -PARTIALDEVIANCE) && (deviation < PARTIALDEVIANCE)) {
		 	// we figure this is a partial since it's within 1/4 of
		 	// a halftone of a multiple of the putative frequency.
				t_float stdev, weight;
				npartials++;
				if (pnum<8) nbelow8++;
				cumpow += x->x_peaklist[j].p_pow;
				cumstrength += fsqrt(fsqrt(x->x_peaklist[j].p_pow));
				stdev = (x->x_peaklist[j].p_width > MINBW ? x->x_peaklist[j].p_width : MINBW);
				weight = 1.0f / ((stdev*fipnum) * (stdev*fipnum));
				freqden += weight;
				freqnum += weight * x->x_peaklist[j].p_freq/fipnum;		
	    	} // end if
		} // end for
	
		if (((nbelow8<4) || (npartials<DEFNPARTIAL)) && (cumpow < (0.01f * total_power))) {
			x->x_histvec[i].h_value = 0;
		} else {
	  	  	t_float pitchpow = (cumstrength * cumstrength * cumstrength * cumstrength);
			t_float freqinbins = freqnum/freqden;
		
			// check for minimum output frequency
			if (freqinbins < MINFREQINBINS) {
				x->x_histvec[i].h_value = 0;
			} else {
    		    // we passed all tests... save the values we got
	    		x->x_histvec[i].h_pitch = ftom(hzperbin * freqnum/freqden);
	    		x->x_histvec[i].h_loud = (FIDDLEDB_REF-DBFUDGE) + LOGTODB*flog(pitchpow*coeff/n);
	    	}	
		} // end else
    } // end for
    
	// Now try to find continuous pitch tracks that match the new pitches. 
	// First mark each peak unmatched.

    for (i=0, hp1=x->x_histvec; i<npitch; i++, hp1++)
		hp1->h_used = 0;

	// For each old pitch, try to match a new one to it.
    for (i=0, phist=x->x_hist; i<x->x_npitch; i++, phist++) {
		t_float thispitch = phist->h_pitches[oldphase];
		phist->h_pitch = 0;	    // no output, thanks...
		phist->h_wherefrom = 0;
		if (thispitch == 0.0f) continue;
		for (j=0, hp1=x->x_histvec; j<npitch; j++, hp1++)
	    	if ((hp1->h_value > 0) && (hp1->h_pitch > thispitch - GLISS) && (hp1->h_pitch < thispitch + GLISS)) {
	    		phist->h_wherefrom = hp1;
	    		hp1->h_used = 1;
			}
    }
    
    for (i=0, hp1=x->x_histvec; i<npitch; i++, hp1++)
		if ((hp1->h_value > 0) && !hp1->h_used) {
			for (j=0, phist=x->x_hist; j<x->x_npitch; j++, phist++)
	    		if (!phist->h_wherefrom) {
	    			phist->h_wherefrom = hp1;
					phist->h_age = 0;
					phist->h_noted = 0;
					hp1->h_used = 1;
					goto happy;
				}
				break;
    			happy: ;
    	} // end if
    	
	// Copy the pitch info into the history vector
    for (i=0, phist=x->x_hist; i<x->x_npitch; i++, phist++) {
		if (phist->h_wherefrom) {
			phist->h_amps[newphase] = phist->h_wherefrom->h_loud;
			phist->h_pitches[newphase] = phist->h_wherefrom->h_pitch;
			(phist->h_age)++;
		} else {
			phist->h_age = 0;
			phist->h_amps[newphase] = phist->h_pitches[newphase] = 0;
		}
    } // end for
    	
	// Look for envelope attacks
    x->x_attackvalue = 0;

    if (x->x_peaked) {
		if (total_db > x->x_amphi) {
			t_int binlook = newphase - x->x_attackbins;
	    	if (binlook < 0) binlook += HISTORY;
	    	if (total_db > x->x_dbs[binlook] + x->x_attackthresh) {
				x->x_attackvalue = 1;
				x->x_peaked = 0;
	    	}
		}
    } else {
		t_int binlook = newphase - x->x_attackbins;
		if (binlook < 0) binlook += HISTORY;
		if ((x->x_dbs[binlook] > x->x_amphi) && (x->x_dbs[binlook] > total_db))
	    	x->x_peaked = 1;
    }

	// For each current frequency track, test for a new note using a
	// stability criterion. Later perhaps we should also do as in
	// pitch~ and check for unstable notes a posteriori when
	// there's a new attack with no note found since the last onset;
	// but what's an attack &/or onset when we're polyphonic?

    for (i=0, phist=x->x_hist; i<x->x_npitch; i++, phist++) {
    	// if we've found a pitch but we've now strayed from it, turn it off
		if (phist->h_noted) {
	    	if (phist->h_pitches[newphase] > phist->h_noted + x->x_vibdepth
				|| phist->h_pitches[newphase] < phist->h_noted - x->x_vibdepth)
				phist->h_noted = 0;
		} else {
			if (phist->h_wherefrom && phist->h_age >= x->x_vibbins) {
				t_float centroid = 0;
				t_int not = 0;
				for (j=0, k=newphase; j<x->x_vibbins; j++) {
					centroid += phist->h_pitches[k];
					k--;
					if (k<0) k = HISTORY-1;
				}
				centroid /= x->x_vibbins;
				for (j=0, k=newphase; j<x->x_vibbins; j++) {
					// calculate deviation from norm
					t_float dev = centroid - phist->h_pitches[k];
					k--;
		    		if (k<0) k = HISTORY-1;
					if ((dev > x->x_vibdepth) || (-dev > x->x_vibdepth)) not = 1;
				}
				if (!not) {
		    		phist->h_pitch = phist->h_noted = centroid;
		    	}
	    	} // end if
	    } // end else
	}
    return;

	nopow:

    for (i=0; i<x->x_npitch; i++) {
		x->x_hist[i].h_pitch = 
		x->x_hist[i].h_noted =
	    x->x_hist[i].h_pitches[newphase] =
	    x->x_hist[i].h_amps[newphase] =
		x->x_hist[i].h_age = 0;
    }
    x->x_peaked = 1;
    x->x_dbage = 0;

	return;
}