Пример #1
0
void SPECTACLE2_BASE::update_bin_groups(
	int bin_groups[],
	const float minfreq,
	const float maxfreq,
	const int control_table_size,
	const char *type)		// to identify bin groups to user
{
	if (control_table_size == 0)				// no control table
		return;

	const int nbins = _half_fftlen + 1;		// including DC and Nyquist

	// The optional <_binmaptable> has <control_table_size> elements, each giving
	// the number of adjacent FFT bins controlled by that element in any of the
	// control tables (e.g., EQ).  Copy this information into the <bin_groups>
	// array, which is sized to <nbins>.  We ignore minfreq and maxfreq.

	if (_binmaptable != NULL) {
		int bidx = 0;
		for (int i = 0; i < control_table_size; i++) {
			int bincount = int(_binmaptable[i]);
			while (bincount-- > 0) {
				if (bidx == nbins)
					goto highcount;
				bin_groups[bidx++] = i;
			}
		}
highcount:
		if (bidx < nbins) {
			const int last = control_table_size - 1;
			while (bidx < nbins)
				bin_groups[bidx++] = last;
		}
	}

	// If there is no binmap table...
	// If freq. range is full bandwidth, and control table size is >= to the
	// number of bins, then use linear mapping of control table slots to bins,
	// as in SPECTACLE v1.  If table is larger than the number of bins, warn 
	// about ignoring the extra table slots.

	else if (minfreq == 0 && maxfreq == _nyquist
	                  && control_table_size >= _half_fftlen) {
		for (int i = 0; i < _half_fftlen; i++)
			bin_groups[i] = i;

		// Let last table element control last two bins (incl. Nyquist), so that
		// we can ask user to size arrays to fftlen/2, rather than fftlen/2 + 1.
		bin_groups[_half_fftlen] = _half_fftlen - 1;
		if (control_table_size > _half_fftlen) {
			const int ignorevals = control_table_size - _half_fftlen;
			if (ignorevals != _prev_bg_ignorevals) {
				warn(instname(), "Control table of size %d too large for "
			                    "frequency range...ignoring last %d values",
			                    control_table_size, ignorevals);
				_prev_bg_ignorevals = ignorevals;
			}
		}
	}

	// Otherwise, there is either a freq. range that is not full bandwidth, or
	// the control table size is less than the number of bins.  If the former,
	// we insure that the first array slot affects all bins whose frequencies
	// are below (and possibly a little above) the min. freq., and that the last
	// array slot affects all bins whose frequencies are above (and possibly a
	// little below) the max. freq.  If the control table is smaller than the
	// number of bins within the freq. range, then we construct a one-to-one or
	// one-to-many mapping of control table slots to bins, arranged so that we
	// can control lower frequencies with greater resolution.
	//
	// Depending on the difference between the control table size and the number
	// of FFT bins, we create a mapping that begins linearly and grows
	// arithmetically after a certain point.  The purpose is to get higher
	// resolution in the lower frequencies of the range, where it matters most.
	// So near the low end of the range, there is a one-to-one mapping of control
	// array slots to FFT bins.  Near the high end of the range, one control
	// array slot affects many FFT bins.  We attempt to transition smoothly
	// between these two extremes.  As an example, the number of FFT bins
	// controlled by each slot of a control table array might look like this:
	//
	//            number of bins spanned by each cntl slot
	// (lowshelf) 1 1 1 1 1 1 1 1 1 1 1 2 3 4 5 6 7 8 9 10 14 (highshelf)
	//
	// The scheme isn't perfect -- e.g., the penultimate slot might control more
	// than you would expect -- but it does guarantee that each control table
	// slot affects at least one FFT bin.

	else {
		const int lowshelfbin = closest_bin(minfreq);
		const int highshelfbin = closest_bin(maxfreq);
		int cntltablen = control_table_size;
		const float endflatrange = minfreq + (cntltablen * _fund_anal_freq);
		bool linear_map = true;
		if (endflatrange > maxfreq - _fund_anal_freq) {
			const int ignorevals = int((endflatrange - maxfreq)
			                                                 / _fund_anal_freq);
			if (ignorevals > 0) {
				cntltablen = control_table_size - ignorevals;
				if (ignorevals != _prev_bg_ignorevals) {
					warn(instname(), "Control table of size %d too large for "
			                       "frequency range...ignoring last %d values",
			                       control_table_size, ignorevals);
					_prev_bg_ignorevals = ignorevals;
				}
			}
		}
		else
			linear_map = false;
#ifdef DEBUG_BINGROUPS
		printf("lowbin=%d, highbin=%d, endflatrange=%f, map=%s\n",
					lowshelfbin, highshelfbin, endflatrange,
					linear_map ? "linear" : "nonlinear");
#endif

		// assign low shelf group
		int bidx = 0;
		while (bidx <= lowshelfbin)
			bin_groups[bidx++] = 0;

		// assign interior groups
		if (linear_map) {
			int bingroup = 1;
			while (bidx < highshelfbin) {
				bin_groups[bidx++] = bingroup;
				if (bingroup < cntltablen - 2)
					bingroup++;
			}
		}
		else {	// higher array slots control more and more bins
			const int extrabins = (highshelfbin - lowshelfbin) - cntltablen;
			assert(extrabins > 0);
			const int nsums = int(sqrt(2 * extrabins) + 2);

			// Compute the sum of integers for n in [nsums-2, nsums);
			// formula is the closed-form equation: x = n * (n + 1) / 2.
			const int an = nsums - 2;
			const int bn = nsums - 1;
			const int a = (an * (an + 1)) / 2;
			const int b = (bn * (bn + 1)) / 2;
			int cntlspan = 0, binspan = 0;
			if (a > extrabins) {
				cntlspan = an;
				binspan = a;
			}
			else if (b > extrabins) {
				cntlspan = bn;
				binspan = b;
			}
			else
				assert(0);  // this should never happen, but if it does, we'll know

#ifdef DEBUG_BINGROUPS
			printf("nbins=%d, lowbin=%d, highbin=%d, tablen=%d, extrabins=%d, "
				"cntlspan=%d, binspan=%d\n\n",
				nbins, lowshelfbin, highshelfbin, cntltablen, extrabins,
				cntlspan, binspan);
#endif

			// first, linear mapping
			const int end = (cntltablen - cntlspan) - 1;
			int bingroup = 1;
			while (bingroup < end)
				bin_groups[bidx++] = bingroup++;

			// then map using sum-of-integers series
			int incr = 1;
			int count = 0;
			while (bidx < highshelfbin) {
				bin_groups[bidx++] = bingroup;
				if (++count == incr) {
					count = 0;
					if (bingroup < cntltablen - 2)
						bingroup++;
					incr++;
				}
			}
		}

		// assign high shelf group
		const int last = cntltablen - 1;
		while (bidx < nbins)
			bin_groups[bidx++] = last;
	}

	// print a user-readable listing of bin groups
	if (_print_stats) {
		printf("\n%s:  %s table bin groups\n", instname(), type);
		printf("------------------------------------------\n");
		int cntltabslot = 0;
		int startbin = 0;
		for (int i = 0; i < nbins; i++) {
			const int thisslot = bin_groups[i];
			if (thisslot > cntltabslot) {
				// print stats for previous control table slot <cntltabslot>
				const int startfreq = int(_fund_anal_freq * startbin + 0.5f);
				if (i - startbin > 1) {
					const int endfreq = int(_fund_anal_freq * (i - 1) + 0.5f);
					printf("  [%d]\t%d-%d Hz (%d bins)\n",
					          cntltabslot, startfreq, endfreq, i - startbin);
				}
				else
					printf("  [%d]\t%d Hz\n", cntltabslot, startfreq);
				cntltabslot = thisslot;
				startbin = i;
			}
		}
		// print stats for last control table slot
		const int startfreq = int(_fund_anal_freq * startbin + 0.5f);
		if (nbins - startbin > 1)
			printf("  [%d]\t%d-%d Hz (%d bins)\n\n",
						 cntltabslot, startfreq, int(_nyquist), nbins - startbin);
		else
			printf("  [%d]\t%d Hz\n\n", cntltabslot, startfreq);
		fflush(stdout);
	}

#ifdef DEBUG_BINGROUPS
	printf("bin_groups[] -----------------------------\n");
	for (int i = 0; i < nbins; i++)
		printf("[%d] %d (%f)\n", i, bin_groups[i], i * _fund_anal_freq);
#endif
#ifdef CHECK_BINGROUPS
	for (int i = 1; i < nbins; i++) {
		int diff = bin_groups[i] - bin_groups[i - 1];
		if (diff < 0 || diff > 1)
			printf("bin group (%p) index %d not 0 or 1 greater than prev entry\n",
			       bin_groups, i);
	}
#endif
}
Пример #2
0
void SpectacleBase::update_bin_groups(
	int bin_groups[],
	int binmaptable[],
	const float minfreq,
	const float maxfreq,
	const int control_table_size)
{
	if (control_table_size == 0)				// no control table
		return;

	const int nbins = _half_fftlen;
	const int *bmtable = binmaptable ? binmaptable : _binmaptable;
	
	// The optional <bmtable> has <control_table_size> elements, each giving
	// the number of adjacent FFT bins controlled by that element in any of the
	// control tables (e.g., EQ).  Copy this information into the <bin_groups>
	// array, which is sized to <nbins>.  We ignore minfreq and maxfreq.

	if (bmtable != NULL) {
#ifdef DEBUG_BINGROUPS
		post("using binmap table -----------------------------");
		for (int i = 0; i < control_table_size; i++)
			post("[%d] %d", i, bmtable[i]);
#endif
		int bidx = 0;
		for (int i = 0; i < control_table_size; i++) {
			int bincount = bmtable[i];
			while (bincount-- > 0) {
				if (bidx == nbins)
					goto highcount;
				bin_groups[bidx++] = i;
			}
		}
highcount:
		if (bidx < nbins) {
			const int last = control_table_size - 1;
			while (bidx < nbins)
				bin_groups[bidx++] = last;
		}
	}

	// If there is no binmap table...
	// If freq. range is full bandwidth, and control table size is >= to the
	// number of bins, then use linear mapping of control table slots to bins,
	// as in SPECTACLE v1.  If table is larger than the number of bins, warn 
	// about ignoring the extra table slots.

	else if (control_table_size >= nbins
				&& minfreq == 0 && maxfreq == _nyquist) {
		for (int i = 0; i < nbins; i++)
			bin_groups[i] = i;

		if (control_table_size > nbins) {
			const int ignorevals = control_table_size - nbins;
			if (ignorevals != _prev_bg_ignorevals) {
				post("%s: Control table of size %d too large for "
			                    "frequency range...ignoring last %d values",
			                    instname(), control_table_size, ignorevals);
				_prev_bg_ignorevals = ignorevals;
			}
		}
	}

	// Otherwise, there is either a freq. range that is not full bandwidth, or
	// the control table size is less than the number of bins.  If the former,
	// we insure that the first array slot affects all bins whose frequencies
	// are below (and possibly a little above) the min. freq., and that the last
	// array slot affects all bins whose frequencies are above (and possibly a
	// little below) the max. freq.  If the control table is smaller than the
	// number of bins within the freq. range, then we construct a one-to-one or
	// one-to-many mapping of control table slots to bins, arranged so that we
	// can control lower frequencies with greater resolution.
	//
	// Depending on the difference between the control table size and the number
	// of FFT bins, we create a mapping that begins linearly and grows
	// arithmetically after a certain point.  The purpose is to get higher
	// resolution in the lower frequencies of the range, where it matters most.
	// So near the low end of the range, there is a one-to-one mapping of control
	// array slots to FFT bins.  Near the high end of the range, one control
	// array slot affects many FFT bins.  We attempt to transition smoothly
	// between these two extremes.  As an example, the number of FFT bins
	// controlled by each slot of a control table array might look like this:
	//
	//            number of bins spanned by each cntl slot
	// (lowshelf) 1 1 1 1 1 1 1 1 1 1 1 2 3 4 5 6 7 8 9 10 14 (highshelf)
	//
	// The scheme isn't perfect -- e.g., the penultimate slot might control more
	// than you would expect -- but it does guarantee that each control table
	// slot affects at least one FFT bin.

	else {
		const int lowshelfbin = closest_bin(minfreq);
		int highshelfbin = closest_bin(maxfreq);
		bool maxfreq_is_nyquist = false;
		if (highshelfbin == nbins) {
			maxfreq_is_nyquist = true;
			highshelfbin--;		// we don't control the nyquist bin
		}
		int cntltablen = control_table_size;
		const float endflatrange = minfreq + (cntltablen * _fund_anal_freq);
		bool linear_map = true;
		if (endflatrange > maxfreq - _fund_anal_freq) {
			const int ignorevals = int((endflatrange - maxfreq)
			                                                 / _fund_anal_freq);
			if (ignorevals > 0) {
				cntltablen = control_table_size - ignorevals;
				if (ignorevals != _prev_bg_ignorevals) {
					post("%s: Control table of size %d too large for "
			                       "frequency range...ignoring last %d values",
			                       instname(), control_table_size, ignorevals);
					_prev_bg_ignorevals = ignorevals;
				}
			}
		}
		else
			linear_map = false;
#ifdef DEBUG_BINGROUPS
		post("lowbin=%d, highbin=%d, endflatrange=%f, map=%s",
					lowshelfbin, highshelfbin, endflatrange,
					linear_map ? "linear" : "nonlinear");
#endif

		// assign low shelf group
		int bidx = 0;
		while (bidx <= lowshelfbin)
			bin_groups[bidx++] = 0;

		// assign interior groups
		if (linear_map) {
			const int lastbingroup = maxfreq_is_nyquist ? cntltablen - 1
			                                            : cntltablen - 2;
			int bingroup = 1;
			while (bidx < highshelfbin) {
				bin_groups[bidx++] = bingroup;
				if (bingroup < lastbingroup)
					bingroup++;
			}
		}
		else {	// higher array slots control more and more bins
			const int extrabins = (highshelfbin - lowshelfbin) - cntltablen;
			if (extrabins <= 0)
				error("%s: program error - contact [email protected]", instname());
			const int nsums = int(sqrt(2 * extrabins) + 2);

			// Compute the sum of integers for n in [nsums-2, nsums);
			// formula is the closed-form equation: x = n * (n + 1) / 2.
			const int an = nsums - 2;
			const int bn = nsums - 1;
			const int a = (an * (an + 1)) / 2;
			const int b = (bn * (bn + 1)) / 2;
			int cntlspan = 0, binspan = 0;
			if (a > extrabins) {
				cntlspan = an;
				binspan = a;
			}
			else if (b > extrabins) {
				cntlspan = bn;
				binspan = b;
			}
			else		// this should never happen
				error("%s: program error - contact [email protected]", instname());

#ifdef DEBUG_BINGROUPS
			post("nbins=%d, lowbin=%d, highbin=%d, tablen=%d, extrabins=%d, "
				"cntlspan=%d, binspan=%d, maxfreqisnyq=%d\n",
				nbins, lowshelfbin, highshelfbin, cntltablen, extrabins,
				cntlspan, binspan, maxfreq_is_nyquist);
#endif

			// first, linear mapping
			const int end = (cntltablen - cntlspan) - 1;
			int bingroup = 1;
			while (bingroup < end)
				bin_groups[bidx++] = bingroup++;

			// then map using sum-of-integers series
			const int lastbingroup = maxfreq_is_nyquist ? cntltablen - 1
			                                            : cntltablen - 2;
			int incr = 1;
			int count = 0;
			while (bidx < highshelfbin) {
				bin_groups[bidx++] = bingroup;
				if (++count == incr) {
					count = 0;
					if (bingroup < lastbingroup)
						bingroup++;
					incr++;
				}
			}
		}

		// assign high shelf group
		const int last = cntltablen - 1;
		while (bidx < nbins)
			bin_groups[bidx++] = last;
	}

#ifdef DEBUG_BINGROUPS
	post("bin_groups[] -----------------------------");
	for (int i = 0; i < nbins; i++)
		post("[%d] %d (%f)", i, bin_groups[i], i * _fund_anal_freq);
#endif
#ifdef CHECK_BINGROUPS
	for (int i = 1; i < nbins; i++) {
		int diff = bin_groups[i] - bin_groups[i - 1];
		if (diff < 0 || diff > 1)
			error("%s: bin group (%p) index %d not 0 or 1 greater than prev entry",
			       instname(), bin_groups, i);
	}
#endif
}