/* Sound_to_Intensity.c
 *
 * Copyright (C) 1992-2003 Paul Boersma
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * pb 2001/07/03
 * pb 2002/07/16 GPL
 * pb 2003/05/20 default time step is four times oversampling
 * pb 2003/07/10 NUMbessel_i0_f
 * pb 2003/11/19 Sound_to_Intensity veryAccurate
 * pb 2003/12/15 removed but introduced by previous change
 */

#include "Sound_to_Intensity.h"

static double Sound_smoothAt (Sound me, double midTime, double windowDuration) {
	double halfWindowDuration = 0.5 * windowDuration;
	double leftTime = midTime - halfWindowDuration, rightTime = midTime + halfWindowDuration;
	long i, leftSample = Sampled_xToHighIndex (me, leftTime), rightSample = Sampled_xToLowIndex (me, rightTime);
	float *amplitude = my z [1], sumxw = 0.0, sumw = 0.0;

	if (leftSample < 1) leftSample = 1;
	if (rightSample > my nx) rightSample = my nx;
	for (i = leftSample; i <= rightSample; i ++) {
		double t = Sampled_indexToX (me, i), x = (midTime - t) / halfWindowDuration, root = 1 - x * x;
		double kaiser = root <= 0.0 ? 0.0 : NUMbessel_i0_f ((2 * NUMpi * NUMpi + 0.5) * sqrt (root));
		sumxw += amplitude [i] * kaiser;
		sumw += kaiser;
	}
	return sumxw / sumw;
}

Intensity Sound_to_Intensity (Sound me, double minimumPitch, double timeStep) {
	int veryAccurate = FALSE;
	Sound up = NULL;
	Intensity smooth = NULL;
	float *amplitude;
	long i, iframe, numberOfFrames;
	double windowDuration, thyFirstTime;

	/* Step 1: upsample by a factor of two. */
	up = veryAccurate ?
		Sound_upsample (me) :   /* Because frequency content will be doubled in the next step. */
		Data_copy (me);   /* Because the Sound will be modified in the next step. */
		cherror

	/* Step 2: square all samples (this doubles frequency content). */
	amplitude = up -> z [1];
	for (i = 1; i <= up -> nx; i ++)
		amplitude [i] *= amplitude [i];

	/* Step 3: smooth and resample. */
	Melder_assert (minimumPitch > 0.0);
	windowDuration = 6.4 / minimumPitch;
	if (timeStep <= 0.0) timeStep = 0.8 / minimumPitch;   /* Default: four times oversampling Hanning-wise. */
	if (! Sampled_shortTermAnalysis (up, windowDuration, timeStep, & numberOfFrames, & thyFirstTime)) {
		Melder_error ("Sound should be at least 6.4 / minimumPitch long.");
		goto end;
	}
	smooth = Intensity_create (my xmin, my xmax, numberOfFrames, timeStep, thyFirstTime); cherror
	for (iframe = 1; iframe <= numberOfFrames; iframe ++) {
		double midTime = Sampled_indexToX (smooth, iframe);
		double intensity = Sound_smoothAt (up, midTime, windowDuration);
		if (intensity != 0.0) intensity /= 4e-10;
		smooth -> z [1] [iframe] = intensity < 1e-30 ? -300 : 10 * log10 (intensity);
	}

	/* Clean up and return. */
end:
	forget (up);
	iferror return Melder_errorp ("Intensity analysis not performed.");
	return smooth;
}

IntensityTier Sound_to_IntensityTier (Sound me, double minimumPitch, double timeStep) {
	Intensity intensity = Sound_to_Intensity (me, minimumPitch, timeStep);
	IntensityTier thee;
	if (! intensity) return NULL;
	thee = Intensity_downto_IntensityTier (intensity);
	forget (intensity);
	return thee;
}

/* End of file Sound_to_Intensity.c */
