autoPitchTier Pitch_AnyTier_to_PitchTier (Pitch pitch, AnyTier tier, int checkMethod) {
	try {
		SortedSetOfDouble points = tier -> points;
		if (checkMethod == 2) {
			autoPitchTier temp = Pitch_to_PitchTier (pitch);
			autoPitchTier thee = PitchTier_AnyTier_to_PitchTier (temp.peek(), tier);
			return thee.transfer();
		}

		/*
		 * Result's domain is a union of both domains.
		 */
		autoPitchTier thee = PitchTier_create (
			pitch -> xmin < tier -> xmin ? pitch -> xmin : tier -> xmin,
			pitch -> xmax > tier -> xmax ? pitch -> xmax : tier -> xmax);

		/*
		 * Copy pitch's frequencies at tier's points to the resulting PitchTier.
		 */
		for (long ipoint = 1; ipoint <= points -> size; ipoint ++) {
			AnyPoint point = (AnyPoint) points -> item [ipoint];
			double time = point -> number;
			double frequency = Pitch_getValueAtTime (pitch, time, kPitch_unit_HERTZ, Pitch_LINEAR);
			if (frequency == NUMundefined && checkMethod)
				Melder_throw (U"No periodicity at time ", time, U" seconds.");
			RealTier_addPoint (thee.peek(), time, frequency);
		}

		return thee;
	} catch (MelderError) {
		Melder_throw (pitch, U" & ", tier, U": not converted to PitchTier.");
	}
}
autoPitchTier PitchTier_AnyTier_to_PitchTier (PitchTier pitch, AnyTier tier) {
	try {
		SortedSetOfDouble points = tier -> points;
		if (pitch -> points -> size == 0) Melder_throw (U"No pitch points.");

		/*
		 * Result's domain is a union of both domains.
		 */
		autoPitchTier thee = PitchTier_create (
			pitch -> xmin < tier -> xmin ? pitch -> xmin : tier -> xmin,
			pitch -> xmax > tier -> xmax ? pitch -> xmax : tier -> xmax);

		/*
		 * Copy pitch's frequencies at tier's points to the resulting PitchTier.
		 */
		for (long ipoint = 1; ipoint <= points -> size; ipoint ++) {
			AnyPoint point = (AnyPoint) points -> item [ipoint];
			double time = point -> number;
			double frequency = RealTier_getValueAtTime (pitch, time);
			RealTier_addPoint (thee.peek(), time, frequency);
		}

		return thee;
	} catch (MelderError) {
		Melder_throw (pitch, U" & ", tier, U": not converted to PitchTier.");
	}
}
Esempio n. 3
0
Sound FormantGrid_to_Sound (FormantGrid me, double samplingFrequency,
	double tStart, double f0Start, double tMid, double f0Mid, double tEnd, double f0End,
	double adaptFactor, double maximumPeriod, double openPhase, double collisionPhase, double power1, double power2)
{
	try {
		autoPitchTier pitch = PitchTier_create (my xmin, my xmax);
		RealTier_addPoint (pitch.peek(), my xmin + tStart * (my xmax - my xmin), f0Start);
		RealTier_addPoint (pitch.peek(), my xmin + tMid * (my xmax - my xmin), f0Mid);
		RealTier_addPoint (pitch.peek(), my xmax - (1.0 - tEnd) * (my xmax - my xmin), f0End);
		autoSound thee = PitchTier_to_Sound_phonation (pitch.peek(), samplingFrequency,
			adaptFactor, maximumPeriod, openPhase, collisionPhase, power1, power2, false);
		Sound_FormantGrid_filter_inline (thee.peek(), me);
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, ": not converted to Sound.");
	}
}
static void menu_cb_addPointAtCursor (FormantGridEditor me, EDITOR_ARGS_DIRECT) {
	Editor_save (me, U"Add point");
	FormantGrid grid = (FormantGrid) my data;
	Ordered tiers = my editingBandwidths ? grid -> bandwidths.get() : grid -> formants.get();
	RealTier tier = (RealTier) tiers -> item [my selectedFormant];
	RealTier_addPoint (tier, 0.5 * (my d_startSelection + my d_endSelection), my ycursor);
	FunctionEditor_redraw (me);
	Editor_broadcastDataChanged (me);
}
Esempio n. 5
0
int FormantGrid_addBandwidthPoint (FormantGrid me, long iformant, double t, double value) {
	if (iformant < 1 || iformant > my formants -> size) error1 (L"No such formant number.");
	{
		RealTier bandwidthTier = (structRealTier *)my bandwidths -> item [iformant];
		RealTier_addPoint (bandwidthTier, t, value);
	}
end:
	iferror return 0;
	return 1;
}
Esempio n. 6
0
void FormantGrid_addBandwidthPoint (FormantGrid me, long iformant, double t, double value) {
	try {
		if (iformant < 1 || iformant > my formants -> size)
			Melder_throw ("No such formant number.");
		RealTier bandwidthTier = (RealTier) my bandwidths -> item [iformant];
		RealTier_addPoint (bandwidthTier, t, value);
	} catch (MelderError) {
		Melder_throw (me, ": bandwidth point not added.");
	}
}
Esempio n. 7
0
Sound FormantGrid_to_Sound (FormantGrid me, double samplingFrequency,
	double tStart, double f0Start, double tMid, double f0Mid, double tEnd, double f0End,
	double adaptFactor, double maximumPeriod, double openPhase, double collisionPhase, double power1, double power2)
{
	PitchTier pitch = NULL;
	Sound thee = NULL;

	pitch = PitchTier_create (my xmin, my xmax); cherror
	RealTier_addPoint (pitch, my xmin + tStart * (my xmax - my xmin), f0Start); cherror
	RealTier_addPoint (pitch, my xmin + tMid * (my xmax - my xmin), f0Mid); cherror
	RealTier_addPoint (pitch, my xmax - (1.0 - tEnd) * (my xmax - my xmin), f0End); cherror
	thee = PitchTier_to_Sound_phonation (pitch, samplingFrequency,
		adaptFactor, maximumPeriod, openPhase, collisionPhase, power1, power2, false); cherror
	Sound_FormantGrid_filter_inline (thee, me);
end:
	forget (pitch);
	iferror forget (thee);
	return thee;
}
Esempio n. 8
0
autoRealTier PointProcess_upto_RealTier (PointProcess me, double value, ClassInfo klas) {
	try {
		autoRealTier thee = RealTier_createWithClass (my xmin, my xmax, klas);
		for (long i = 1; i <= my nt; i ++) {
			RealTier_addPoint (thee.get(), my t [i], value);
		}
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": not converted to RealTier.");
	}
}
Esempio n. 9
0
autoRealTier Vector_to_RealTier (Vector me, long channel, ClassInfo klas) {
	try {
		autoRealTier thee = RealTier_createWithClass (my xmin, my xmax, klas);
		for (long i = 1; i <= my nx; i ++) {
			RealTier_addPoint (thee.get(), Sampled_indexToX (me, i), my z [channel] [i]);
		}
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": not converted to ", klas -> className, U".");
	}
}
Esempio n. 10
0
DurationTier PointProcess_upto_DurationTier (PointProcess me) {
	try {
		autoDurationTier thee = DurationTier_create (my xmin, my xmax);
		for (long i = 1; i <= my nt; i ++) {
			RealTier_addPoint (thee.peek(), my t [i], 1.0);
		}
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, U": not converted to DurationTier.");
	}
}
Esempio n. 11
0
static void menu_cb_addPointAtCursor (RealTierEditor me, EDITOR_ARGS_DIRECT) {
	if (NUMdefined (my v_minimumLegalValue ()) && my ycursor < my v_minimumLegalValue ())
		Melder_throw (U"Cannot add a point below ", my v_minimumLegalValue (), my v_rightTickUnits (), U".");
	if (NUMdefined (my v_maximumLegalValue ()) && my ycursor > my v_maximumLegalValue ())
		Melder_throw (U"Cannot add a point above ", my v_maximumLegalValue (), my v_rightTickUnits (), U".");
	Editor_save (me, U"Add point");
	RealTier_addPoint ((RealTier) my data, 0.5 * (my d_startSelection + my d_endSelection), my ycursor);
	RealTierEditor_updateScaling (me);
	FunctionEditor_redraw (me);
	Editor_broadcastDataChanged (me);
}
Esempio n. 12
0
int RealTier_interpolateQuadratically (I, long numberOfPointsPerParabola, int logarithmically) {
	iam (RealTier);
	RealTier thee = (structRealTier *)Data_copy (me); cherror
	for (long ipoint = 1; ipoint < my points -> size; ipoint ++) {
		RealPoint point1 = (structRealPoint *)my points -> item [ipoint], point2 = (structRealPoint *)my points -> item [ipoint + 1];
		double time1 = point1 -> time, time2 = point2 -> time, tmid = 0.5 * (time1 + time2);
		double value1 = point1 -> value, value2 = point2 -> value, valuemid;
		double timeStep = (tmid - time1) / (numberOfPointsPerParabola + 1);
		if (logarithmically) value1 = log (value1), value2 = log (value2);
		valuemid = 0.5 * (value1 + value2);
		/*
		 * Left from the midpoint.
		 */
		for (long inewpoint = 1; inewpoint <= numberOfPointsPerParabola; inewpoint ++) {
			double newTime = time1 + inewpoint * timeStep;
			double phase = (newTime - time1) / (tmid - time1);
			double newValue = value1 + (valuemid - value1) * phase * phase;
			if (logarithmically) newValue = exp (newValue);
			RealTier_addPoint (thee, newTime, newValue); cherror
		}
		/*
		 * The midpoint.
		 */
		RealTier_addPoint (thee, tmid, logarithmically ? exp (valuemid) : valuemid); cherror
		/*
		 * Right from the midpoint.
		 */
		for (long inewpoint = 1; inewpoint <= numberOfPointsPerParabola; inewpoint ++) {
			double newTime = tmid + inewpoint * timeStep;
			double phase = (time2 - newTime) / (time2 - tmid);
			double newValue = value2 + (valuemid - value2) * phase * phase;
			if (logarithmically) newValue = exp (newValue);
			RealTier_addPoint (thee, newTime, newValue); cherror
		}
	}
end:
	iferror { forget (thee); return 0; }
	Thing_swap (me, thee);
	forget (thee);
	return 1;
}
Esempio n. 13
0
void RealTier_interpolateQuadratically (RealTier me, long numberOfPointsPerParabola, int logarithmically) {
	try {
		autoRealTier thee = Data_copy (me);
		for (long ipoint = 1; ipoint < my points.size; ipoint ++) {
			RealPoint point1 = my points.at [ipoint], point2 = my points.at [ipoint + 1];
			double time1 = point1 -> number, time2 = point2 -> number, tmid = 0.5 * (time1 + time2);
			double value1 = point1 -> value, value2 = point2 -> value, valuemid;
			double timeStep = (tmid - time1) / (numberOfPointsPerParabola + 1);
			if (logarithmically) value1 = log (value1), value2 = log (value2);
			valuemid = 0.5 * (value1 + value2);
			/*
			 * Left from the midpoint.
			 */
			for (long inewpoint = 1; inewpoint <= numberOfPointsPerParabola; inewpoint ++) {
				double newTime = time1 + inewpoint * timeStep;
				double phase = (newTime - time1) / (tmid - time1);
				double newValue = value1 + (valuemid - value1) * phase * phase;
				if (logarithmically) newValue = exp (newValue);
				RealTier_addPoint (thee.get(), newTime, newValue);
			}
			/*
			 * The midpoint.
			 */
			RealTier_addPoint (thee.get(), tmid, logarithmically ? exp (valuemid) : valuemid);
			/*
			 * Right from the midpoint.
			 */
			for (long inewpoint = 1; inewpoint <= numberOfPointsPerParabola; inewpoint ++) {
				double newTime = tmid + inewpoint * timeStep;
				double phase = (time2 - newTime) / (time2 - tmid);
				double newValue = value2 + (valuemid - value2) * phase * phase;
				if (logarithmically) newValue = exp (newValue);
				RealTier_addPoint (thee.get(), newTime, newValue);
			}
		}
		Thing_swap (me, thee.get());
	} catch (MelderError) {
		Melder_throw (me, U": not interpolated quadratically.");
	}
}
PitchTier PointProcess_to_PitchTier (PointProcess me, double maximumInterval) {
	try {
		autoPitchTier thee = PitchTier_create (my xmin, my xmax);
		for (long i = 1; i < my nt; i ++) {
			double interval = my t [i + 1] - my t [i];
			if (interval <= maximumInterval) {
				RealTier_addPoint (thee.peek(), my t [i] + 0.5 * interval, 1.0 / interval);
			}
		}
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, ": not converted to PitchTier.");
	}
}
PitchTier PitchTier_PointProcess_to_PitchTier (PitchTier me, PointProcess pp) {
	try {
		if (my points -> size == 0) Melder_throw ("No pitch points.");
		autoPitchTier thee = PitchTier_create (pp -> xmin, pp -> xmax);
		for (long i = 1; i <= pp -> nt; i ++) {
			double time = pp -> t [i];
			double value = RealTier_getValueAtTime (me, time);
			RealTier_addPoint (thee.peek(), time, value);
		}
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, " & ", pp, ": not converted to PitchTier.");
	}
}
Esempio n. 16
0
autoAmplitudeTier PointProcess_Sound_to_AmplitudeTier_point (PointProcess me, Sound thee) {
	try {
		long imin, imax, numberOfPeaks = PointProcess_getWindowPoints (me, my xmin, my xmax, & imin, & imax);
		if (numberOfPeaks < 3) return nullptr;
		autoAmplitudeTier him = AmplitudeTier_create (my xmin, my xmax);
		for (long i = imin; i <= imax; i ++) {
			double value = Vector_getValueAtX (thee, my t [i], Vector_CHANNEL_AVERAGE, Vector_VALUE_INTERPOLATION_SINC700);
			if (NUMdefined (value)) RealTier_addPoint (him.peek(), my t [i], value);
		}
		return him;
	} catch (MelderError) {
		Melder_throw (me, U" & ", thee, U": not converted to AmplitudeTier.");
	}
}
Esempio n. 17
0
autoIntensityTier IntensityTier_PointProcess_to_IntensityTier (IntensityTier me, PointProcess pp) {
	try {
		if (my points -> size == 0) Melder_throw (U"No intensity points.");
		autoIntensityTier thee = IntensityTier_create (pp -> xmin, pp -> xmax);
		for (long i = 1; i <= pp -> nt; i ++) {
			double time = pp -> t [i];
			double value = RealTier_getValueAtTime (me, time);
			RealTier_addPoint (thee.peek(), time, value);
		}
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U" & ", pp, U": not converted to IntensityTier.");
	}
}
Esempio n. 18
0
IntensityTier Formant_and_Spectrogram_to_IntensityTier (Formant me, Spectrogram thee, long iformant) {
	try {
		if (my xmin != thy xmin || my xmax != thy xmax) {
			Melder_throw ("The start and end times of the Formant and the Spectrogram must be equal.");
		}
		if (iformant < 1 || iformant > my maxnFormants) {
			Melder_throw ("Formant number not in range [1, ", my maxnFormants, "].");
		}
		autoIntensityTier him = IntensityTier_create (my xmin, my xmax);
		double previousValue = -80000; // can never occur
		double previousTime = my xmin;
		for (long iframe = 1; iframe <= my nx; iframe++) {
			Formant_Frame frame = & my d_frames [iframe];
			long numberOfFormants = frame -> nFormants;
			double time = Sampled_indexToX (me, iframe);
			double value = 0;
			if (iformant <= numberOfFormants) {
				double f = frame -> formant[iformant].frequency;
				value = Matrix_getValueAtXY (thee, time, f);
				value = value == NUMundefined ? 0.0 : value;
			}
			value = 10.0 * log10 ((value + 1e-30) / 4.0e-10); /* dB / Hz */
			if (value != previousValue) {
				if (iframe > 1 && previousTime < time - 1.5 * my dx) { // mark the end of the same interval
					RealTier_addPoint (him.peek(), time - my dx, previousValue);
				}
				RealTier_addPoint (him.peek(), time, value);
				previousTime = time;
			}
			previousValue = value;
		}
		return him.transfer();
	} catch (MelderError) {
		Melder_throw ("IntensityTier not created from ", me, " and ", thee, ".");
	}
}
Esempio n. 19
0
autoRealTier Vector_to_RealTier_valleys (Vector me, long channel, ClassInfo klas) {
	try {
		autoRealTier thee = RealTier_createWithClass (my xmin, my xmax, klas);
		for (long i = 2; i < my nx; i ++) {
			double left = my z [channel] [i - 1], centre = my z [channel] [i], right = my z [channel] [i + 1];
			if (left >= centre && right > centre) {
				double x, minimum;
				Vector_getMinimumAndX (me, my x1 + (i - 2.5) * my dx, my x1 + (i + 0.5) * my dx,
					channel, NUM_PEAK_INTERPOLATE_PARABOLIC, & minimum, & x);
				RealTier_addPoint (thee.get(), x, minimum);
			}
		}
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": not converted to ", klas -> className, U" (valleys).");
	}
}
Esempio n. 20
0
Sound Sound_lengthen_overlapAdd (Sound me, double fmin, double fmax, double factor) {
	try {
		if (my ny > 1)
			Melder_throw (U"Overlap-add works only on mono sounds.");
		autoSound sound = Data_copy (me);
		Vector_subtractMean (sound.peek());
		autoPitch pitch = Sound_to_Pitch (sound.peek(), 0.8 / fmin, fmin, fmax);
		autoPointProcess pulses = Sound_Pitch_to_PointProcess_cc (sound.peek(), pitch.peek());
		autoPitchTier pitchTier = Pitch_to_PitchTier (pitch.peek());
		autoDurationTier duration = DurationTier_create (my xmin, my xmax);
		RealTier_addPoint (duration.peek(), 0.5 * (my xmin + my xmax), factor);
		autoSound thee = Sound_Point_Pitch_Duration_to_Sound (sound.peek(), pulses.peek(), pitchTier.peek(), duration.peek(), 1.5 / fmin);
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, U": not lengthened.");
	}
}
static void menu_cb_addPointAt (FormantGridEditor me, EDITOR_ARGS_FORM) {
	EDITOR_FORM (U"Add point", nullptr)
		REAL (U"Time (s)", U"0.0")
		POSITIVE (U"Frequency (Hz)", U"200.0")
	EDITOR_OK
		SET_REAL (U"Time", 0.5 * (my d_startSelection + my d_endSelection))
		SET_REAL (U"Frequency", my ycursor)
	EDITOR_DO
		Editor_save (me, U"Add point");
		FormantGrid grid = (FormantGrid) my data;
		Ordered tiers = my editingBandwidths ? grid -> bandwidths.get() : grid -> formants.get();
		RealTier tier = (RealTier) tiers -> item [my selectedFormant];
		RealTier_addPoint (tier, GET_REAL (U"Time"), GET_REAL (U"Frequency"));
		FunctionEditor_redraw (me);
		Editor_broadcastDataChanged (me);
	EDITOR_END
}
Esempio n. 22
0
static void menu_cb_addPointAt (EDITOR_ARGS) {
	EDITOR_IAM (FormantGridEditor);
	EDITOR_FORM (L"Add point", 0)
		REAL (L"Time (s)", L"0.0")
		POSITIVE (L"Frequency (Hz)", L"200.0")
	EDITOR_OK
		SET_REAL (L"Time", 0.5 * (my startSelection + my endSelection))
		SET_REAL (L"Frequency", my ycursor)
	EDITOR_DO
		Editor_save (me, L"Add point");
		FormantGrid grid = (FormantGrid) my data;
		Ordered tiers = my editingBandwidths ? grid -> bandwidths : grid -> formants;
		RealTier tier = (RealTier) tiers -> item [my selectedFormant];
		RealTier_addPoint (tier, GET_REAL (L"Time"), GET_REAL (L"Frequency"));
		FunctionEditor_redraw (me);
		my broadcastDataChanged ();
	EDITOR_END
}
Esempio n. 23
0
autoPitchTier Pitch_to_PitchTier (Pitch me) {
	try {
		autoPitchTier thee = PitchTier_create (my xmin, my xmax);
		for (long i = 1; i <= my nx; i ++) {
			double frequency = my frame [i]. candidate [1]. frequency;

			/*
			 * Count only voiced frames.
			 */
			if (frequency > 0.0 && frequency < my ceiling) {
				double time = Sampled_indexToX (me, i);
				RealTier_addPoint (thee.get(), time, frequency);
			}
		}
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": not converted to PitchTier.");
	}
}
Esempio n. 24
0
autoVocalTract VocalTractTier_to_VocalTract (VocalTractTier me, double time) {
	try {
		VocalTractPoint vtp = (VocalTractPoint) my d_vocalTracts -> item[1];
		long numberOfSections = vtp -> d_vocalTract -> nx;
		autoVocalTract thee = VocalTract_create (numberOfSections, vtp -> d_vocalTract -> dx);
		for (long isection = 1; isection <= numberOfSections; isection++) {
			autoRealTier section = RealTier_create (my xmin, my xmax);
			for (long i = 1; i <= my d_vocalTracts -> size; i++) {
				VocalTractPoint vtpi = (VocalTractPoint) my d_vocalTracts -> item[i];
				double areai = vtpi -> d_vocalTract -> z[1][isection];
				RealTier_addPoint (section.peek(), vtpi -> number, areai);
			}
			thy z[1][isection] = RealTier_getValueAtTime (section.peek(), time);
		}
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": no VocalTract created.");
	}
}
Esempio n. 25
0
autoLPC VocalTractTier_to_LPC (VocalTractTier me, double timeStep) {
	try {
		if (my d_vocalTracts -> size == 0) {
			Melder_throw (U"Empty VocalTractTier");
		}
		long numberOfFrames = (long) floor ((my xmax - my xmin) / timeStep);
		VocalTractPoint vtp = (VocalTractPoint) my d_vocalTracts -> item[1];
		long numberOfSections = vtp -> d_vocalTract -> nx;
		double samplingPeriod = 1.0 / (1000.0 * numberOfSections);
		autoNUMmatrix<double> area (1, numberOfFrames, 1, numberOfSections + 1);
		autoNUMvector<double> areavec (1, numberOfSections + 1);
		autoLPC thee = LPC_create (my xmin, my xmax, numberOfFrames, timeStep, timeStep / 2, numberOfSections, samplingPeriod);
		// interpolate each section
		for (long isection = 1; isection <= numberOfSections; isection++) {
			autoRealTier sectioni = RealTier_create (my xmin, my xmax);
			for (long i = 1; i <= my d_vocalTracts -> size; i++) {
				VocalTractPoint vtpi = (VocalTractPoint) my d_vocalTracts -> item[i];
				double areai = vtpi -> d_vocalTract -> z[1][isection];
				RealTier_addPoint (sectioni.peek(), vtpi -> number, areai);
			}
			for (long iframe = 1; iframe <= numberOfFrames; iframe++) {
				double time = thy x1 + (iframe - 1) * thy dx;
				area[iframe][isection] = RealTier_getValueAtTime (sectioni.peek(), time);
				area[iframe][numberOfSections + 1] = 0.0001; // normalisation is area[n+1] = 0.0001
			}
		}
		for (long iframe = 1; iframe <= numberOfFrames; iframe++) {
			LPC_Frame frame = &thy d_frames[iframe];
			LPC_Frame_init (frame, numberOfSections);
			for (long i = 1; i <= numberOfSections + 1; i++) {
				areavec[i] = area[iframe][numberOfSections + 1 - i];
			}
			NUMlpc_area_to_lpc (areavec.peek(), numberOfSections + 1, frame -> a);
			frame -> gain = 1e-6; // something
		}
		return thee;
	} catch (MelderError) {
		Melder_throw (U": not converted to LPC.");
	}
}
Esempio n. 26
0
autoAmplitudeTier PointProcess_Sound_to_AmplitudeTier_period (PointProcess me, Sound thee, double tmin, double tmax,
	double pmin, double pmax, double maximumPeriodFactor)
{
	try {
		if (tmax <= tmin) tmin = my xmin, tmax = my xmax;
		long imin, imax;
		long numberOfPeaks = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax);
		if (numberOfPeaks < 3) Melder_throw (U"Too few pulses between ", tmin, U" and ", tmax, U" seconds.");
		autoAmplitudeTier him = AmplitudeTier_create (tmin, tmax);
		for (long i = imin + 1; i < imax; i ++) {
			double p1 = my t [i] - my t [i - 1], p2 = my t [i + 1] - my t [i];
			double intervalFactor = p1 > p2 ? p1 / p2 : p2 / p1;
			if (pmin == pmax || (p1 >= pmin && p1 <= pmax && p2 >= pmin && p2 <= pmax && intervalFactor <= maximumPeriodFactor)) {
				double peak = Sound_getHannWindowedRms (thee, my t [i], 0.2 * p1, 0.2 * p2);
				if (NUMdefined (peak) && peak > 0.0)
					RealTier_addPoint (him.peek(), my t [i], peak);
			}
		}
		return him;
	} catch (MelderError) {
		Melder_throw (me, U" & ", thee, U": not converted to AmplitudeTier.");
	}
}