/* Sound_to_PointProcess.c */
/* Paul Boersma, May 25, 1999 */

#include "Sound_to_PointProcess.h"
#include "Sound_to_Pitch.h"
#include "Pitch_to_PointProcess.h"

PointProcess Sound_to_PointProcess_extrema (Sound me, int interpolation, int includeMaxima, int includeMinima) {
	PointProcess thee = NULL;
	float *y = my z [1];
	long numberOfMaxima, numberOfMinima, i;

	/*
	 * Pass 1: count the extrema. There may be a maximum and minimum in the same interval!
	 */
	numberOfMaxima = numberOfMinima = 0;
	for (i = 2; i <= my nx - 1; i ++) {
		if (includeMaxima && y [i] > y [i - 1] && y [i] >= y [i + 1]) numberOfMaxima ++;
		if (includeMinima && y [i] <= y [i - 1] && y [i] < y [i + 1]) numberOfMinima ++;
	}

	/*
	 * Create the empty result.
	 */	
	thee = PointProcess_create (my xmin, my xmax, numberOfMaxima + numberOfMinima);
	if (! thee) return NULL;

	/*
	 * Pass 2: compute and register the extrema.
	 */
	for (i = 2; i <= my nx - 1; i ++) {
		double time, value, i_real;
		if (includeMaxima && y [i] > y [i - 1] && y [i] >= y [i + 1]) {
			value = NUMimproveMaximum_f (y, my nx, i, interpolation, & i_real);
			time = my x1 + (i_real - 1.0) * my dx;
			PointProcess_addPoint (thee, time);
		}
		if (includeMinima && y [i] <= y [i - 1] && y [i] < y [i + 1]) {
			value = NUMimproveMinimum_f (y, my nx, i, interpolation, & i_real);
			time = my x1 + (i_real - 1.0) * my dx;
			PointProcess_addPoint (thee, time);
		}
	}
	return thee;
}

PointProcess Sound_to_PointProcess_maxima (Sound me, int interpolation)
	{ return Sound_to_PointProcess_extrema (me, interpolation, TRUE, FALSE); }
PointProcess Sound_to_PointProcess_minima (Sound me, int interpolation)
	{ return Sound_to_PointProcess_extrema (me, interpolation, FALSE, TRUE); }
PointProcess Sound_to_PointProcess_allExtrema (Sound me, int interpolation)
	{ return Sound_to_PointProcess_extrema (me, interpolation, TRUE, TRUE); }

PointProcess Sound_to_PointProcess_zeroes (Sound me, int includeRaisers, int includeFallers) {
	PointProcess thee = NULL;
	float *y = my z [1];
	long numberOfRaisers, numberOfFallers, i;

	/*
	 * Pass 1: count the zeroes.
	 */
	numberOfRaisers = numberOfFallers = 0;
	for (i = 2; i <= my nx; i ++) {
		if (includeRaisers && y [i - 1] < 0.0 && y [i] >= 0.0) numberOfRaisers ++;
		if (includeFallers && y [i - 1] >= 0.0 && y [i] < 0.0) numberOfFallers ++;
	}

	/*
	 * Create the empty result.
	 */	
	thee = PointProcess_create (my xmin, my xmax, numberOfRaisers + numberOfFallers);
	if (! thee) return NULL;

	/*
	 * Pass 2: compute and register the zeroes.
	 */
	for (i = 2; i <= my nx; i ++) {
		if (includeRaisers && y [i - 1] < 0.0 && y [i] >= 0.0 ||
		    includeFallers && y [i - 1] >= 0.0 && y [i] < 0.0) {
			double time = Sampled_indexToX (me, i - 1) + my dx * y [i - 1] / (y [i - 1] - y [i]);   /* Linear. */
			PointProcess_addPoint (thee, time);
		}
	}
	return thee;
}

PointProcess Sound_to_PointProcess_periodic (Sound me, double fmin, double fmax) {
	PointProcess thee = NULL;
	Pitch pitch = Sound_to_Pitch (me, 0.8 / fmin, fmin, fmax);
	if (! pitch) goto error;
	if (! (thee = Sound_Pitch_to_PointProcess (me, pitch))) goto error;
	forget (pitch);
	return thee;
error:
	forget (pitch);
	forget (thee);
	return Melder_errorp ("(Sound_to_PointProcess:) Not performed.");
}

/* End of file Sound_to_PointProcess.c */
