static void barkSpec_tilde_bang(t_barkSpec *x)
{
    int i, j, window, windowHalf, bangSample;
	t_atom *listOut;
	t_sample *signal_R, *signal_I;
	t_float *windowFuncPtr;
	double currentTime, timef = 0.0;
    
	window = x->window;
	windowHalf = window*0.5;
    
	// create local memory
	listOut = (t_atom *)t_getbytes_(x->numFilters*sizeof(t_atom));
	signal_R = (t_sample *)t_getbytes_(window*sizeof(t_sample));
	signal_I = (t_sample *)t_getbytes_((windowHalf+1)*sizeof(t_sample));
    
	//currentTime = clock_gettimesince(x->lastDspTime);
    clock_getftime(&timef);
    currentTime =  timef - x->lastDspTime;
    
	bangSample = (int)(((currentTime/1000.0)*x->sr)+0.5); // round
    
	if (bangSample < 0)
		bangSample = 0;
	else if ( bangSample >= x->n )
		bangSample = x->n - 1;
    
	// construct analysis window using bangSample as the end of the window
	for(i=0, j=bangSample; i<window; i++, j++)
		signal_R[i] = x->signal_R[j];
    
	// set window function
	windowFuncPtr = x->hann; //default case to get rid of compile warning
    
	switch(x->windowFunction)
	{
		case 0:
			break;
		case 1:
			windowFuncPtr = x->blackman;
			break;
		case 2:
			windowFuncPtr = x->cosine;
			break;
		case 3:
			windowFuncPtr = x->hamming;
			break;
		case 4:
			windowFuncPtr = x->hann;
			break;
		default:
			break;
	};
    
	// if windowFunction == 0, skip the windowing (rectangular)
	if(x->windowFunction>0)
		for(i=0; i<window; i++, windowFuncPtr++)
			signal_R[i] *= *windowFuncPtr;
    
	mayer_realfft(window, signal_R);
	tIDLib_realfftUnpack(window, windowHalf, signal_R, signal_I);
	tIDLib_power(windowHalf+1, signal_R, signal_I);
    
	// power spectrum sometimes generates lower scores than magnitude. make it optional.
	if(!x->powerSpectrum)
		tIDLib_mag(windowHalf+1, signal_R);
    
	tIDLib_filterbankMultiply(signal_R, x->normalize, x->filterAvg, x->x_filterbank, x->numFilters);
    
	for(i=0; i<x->numFilters; i++)
		SETFLOAT(listOut+i, signal_R[i]);
    
	outlet_list(x->x_featureList, 0, x->numFilters, listOut);
    
	// free local memory
	t_freebytes_(listOut, x->numFilters*sizeof(t_atom));
	t_freebytes_(signal_R, window*sizeof(t_sample));
	t_freebytes_(signal_I, (windowHalf+1)*sizeof(t_sample));    
    
}
Exemplo n.º 2
0
static void bark_analyze(t_bark *x, t_floatarg startTime, t_floatarg endTime)
{
    int i, j, window, windowHalf, hop, nFrames, frame, sampRange, startSamp, endSamp;
    t_float totalGrowth, totalVel, *windowFuncPtr;
	t_garray *a;

	if(!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
        pd_error(x, "%s: no such array", x->x_arrayname->s_name);
    else if(!garray_getfloatwords(a, &x->x_array_points, &x->x_vec))
    	pd_error(x, "%s: bad template for bark", x->x_arrayname->s_name);
	else
	{
		window = x->window;
		windowHalf = window*0.5;
		hop = x->hop;

		if(endTime)
		{
			startSamp = floor(startTime*x->sr);
			endSamp = floor(endTime*x->sr);

			if(startSamp>=0 && endSamp<x->x_array_points)
				sampRange = endSamp-startSamp+1;
			else
			{
				error("invalid time range");
				return;
			}
		}
		else
		{
			sampRange = x->x_array_points;
			startSamp = 0;
			endSamp = x->x_array_points-1;
		}

		nFrames = floor((sampRange-window)/hop);

		// init mask to zero
		for(i=0; i<x->numFilters; i++)
			x->mask[i] = 0.0;

		for(frame=0; frame<nFrames; frame++)
		{
			// fill buffer with <window> samples
			for(i=0, j=frame*hop+startSamp; i<window; i++, j++)
				x->signalBuf[i] = x->x_vec[j].w_float;

			totalGrowth = 0.0;
			totalVel = 0.0;

		    // set window function
		    windowFuncPtr = x->hann; //default case to get rid of compile warning

		    switch(x->windowFunction)
		    {
			    case 0:
				    break;
			    case 1:
				    windowFuncPtr = x->blackman;
				    break;
			    case 2:
				    windowFuncPtr = x->cosine;
				    break;
			    case 3:
				    windowFuncPtr = x->hamming;
				    break;
			    case 4:
				    windowFuncPtr = x->hann;
				    break;
			    default:
				    break;
		    };

		    // if windowFunction == 0, skip the windowing (rectangular)
		    if(x->windowFunction>0)
			    for(i=0; i<window; i++, windowFuncPtr++)
				    x->analysisBuf[i] = x->signalBuf[i] * *windowFuncPtr;
		    else
			    for(i=0; i<window; i++, windowFuncPtr++)
				    x->analysisBuf[i] = x->signalBuf[i];

			mayer_realfft(window, x->analysisBuf);

			// calculate the power spectrum in place. we'll overwrite the first N/2+1 points in x->analysisBuf with the magnitude spectrum, as this is all that's used below in filterbank_multiply()
			x->analysisBuf[0] = x->analysisBuf[0] * x->analysisBuf[0];  // DC
			x->analysisBuf[windowHalf] = x->analysisBuf[windowHalf] * x->analysisBuf[windowHalf];  // Nyquist

			for(i=(window-1), j=1; i>windowHalf; i--, j++)
				x->analysisBuf[j] = (x->analysisBuf[j]*x->analysisBuf[j]) + (x->analysisBuf[i]*x->analysisBuf[i]);

			// optional use of power/magnitude spectrum
			if(!x->powerSpectrum)
				for(i=0; i<=windowHalf; i++)
					x->analysisBuf[i] = sqrt(x->analysisBuf[i]);

			tIDLib_filterbankMultiply(x->analysisBuf, x->normalize, x->filterAvg, x->x_filterbank, x->numFilters);

			// optional loudness weighting
			if(x->useWeights)
				for(i=0; i<x->numFilters; i++)
					x->analysisBuf[i] *= x->loudWeights[i];

			for(i=0; i<x->numFilters; i++)
				totalVel += x->analysisBuf[i];

			// init growth list to zero
			for(i=0; i<x->numFilters; i++)
				x->growth[i] = 0.0;

			for(i=0; i<x->numFilters; i++)
			{
				// from p.3 of Puckette/Apel/Zicarelli, 1998
				// salt divisor with + 1.0e-15 in case previous power was zero
				if(x->analysisBuf[i] > x->mask[i])
					x->growth[i] = x->analysisBuf[i]/(x->mask[i] + 1.0e-15) - 1.0;

				if(i>=x->loBin && i<=x->hiBin && x->growth[i]>0)
					totalGrowth += x->growth[i];

				SETFLOAT(x->growthList+i, x->growth[i]);
			}

			if(frame*hop+startSamp >= x->debounceActive)
			    x->debounceActive = -1;

			if(totalVel >= x->minvel && totalGrowth > x->hiThresh && !x->haveHit && x->debounceActive < 0)
			{
				if(x->debug)
					post("peak: %f", totalGrowth);

				x->haveHit = 1;
				x->debounceActive = frame*hop+startSamp + x->debounceSamp;
			}
			else if(x->haveHit && x->loThresh>0 && totalGrowth < x->loThresh) // if loThresh is an actual value (not -1), then wait until growth drops below that value before reporting attack
			{
				if(x->debug)
					post("drop: %f", totalGrowth);

				x->haveHit = 0;

				// don't output data if spew will do it anyway below
				if(!x->spew)
				{
					outlet_list(x->x_outputList, 0, x->numFilters, x->growthList);
					outlet_float(x->x_growthOut, totalGrowth);
				}

				// add half a window of samples as a fudge factor. note that since this NRT and we can look into the future, all attack reports will be roughly a half window EARLY.  in RT, everything is a half window LATE because the point of reference is the END of the window.  here, it's the BEGINNING of the window.
				outlet_float(x->x_timeOut, (frame*hop+startSamp + windowHalf)/x->sr);
			}
			else if(x->haveHit && x->loThresh<0 && totalGrowth < x->prevTotalGrowth) // if loThresh == -1, report attack as soon as growth shows any decay at all
			{
				if(x->debug)
					post("drop: %f", totalGrowth);

				x->haveHit = 0;

				// don't output data if spew will do it anyway below
				if(!x->spew)
				{
					outlet_list(x->x_outputList, 0, x->numFilters, x->growthList);
					outlet_float(x->x_growthOut, totalGrowth);
				}

				// add half a window of samples as a fudge factor. note that since this NRT and we can look into the future, all attack reports will be roughly a half window EARLY.  in RT, everything is a half window LATE because the point of reference is the END of the window.  here, it's the BEGINNING of the window.
				outlet_float(x->x_timeOut, (frame*hop+startSamp + windowHalf)/x->sr);
			}

			if(x->spew)
			{
				outlet_list(x->x_outputList, 0, x->numFilters, x->growthList);
				outlet_float(x->x_growthOut, totalGrowth);
			}

			// update mask
			for(i=0; i<x->numFilters; i++)
			{
				if(x->analysisBuf[i] > x->mask[i])
				{
					x->mask[i] = x->analysisBuf[i];
					x->numPeriods[i] = 0;
				}
				else
					if(++x->numPeriods[i] >= x->maskPeriods)
						x->mask[i] *= x->maskDecay;
			}

			x->prevTotalGrowth = totalGrowth;
		}
	}

	post("analyzed %i frames", nFrames);
}