real AudioExtractor::GetMaxAmplitude(real startTime, real duration) const
{
	if (fSamples == NULL || duration < 0.0f)
		return 0.0f;

	uint32	i, start, end;
	real	sample, max = -PG_HUGE;

	start = TimeToSample(startTime, true);
	end = TimeToSample(startTime + duration, true);
	if (end == start)
		return 0.0f;
	for (i = start; i < end; i++)
	{
		sample = PG_FABS(fSamples[i]);
		if (sample > 1.001f)
			continue;
		max = PG_MAX(max, sample);
	}
	return max;
}
real AudioExtractor::GetRMSAmplitude(real startTime, real duration) const
{
	if (fSamples == NULL || duration < 0.0f)
		return 0.0f;

	uint32	i, start, end;
	real	sample, total = 0.0f;

	start = TimeToSample(startTime, true);
	end = TimeToSample(startTime + duration, true);
	if (end == start)
		return 0.0f;
	for (i = start; i < end; i++)
	{
		sample = PG_FABS(fSamples[i]);
		if (sample > 1.001f)
			continue;
		total += sample * sample;
	}
	total = total / (real)(end - start);
	return (real)sqrt(total);
}
int DexApparatus::CheckAccelerationPeaks( float min_amplitude, float max_amplitude, int max_bad_peaks, const char *msg, const char *picture ) {
	
	const char *fmt;
	bool  error = false;

	int		bad_peaks = 0, lows = 0, highs = 0; 
	int		movements = 0;
	int		first, last;
	int		start_sample, end_sample, smpl;
	int		i, j, n;

	double average, delta, peak;

	// First we should look for the start and end of the actual movement based on 
	// events such as when the subject reaches the first target. 
	FindAnalysisFrameRange( first, last );

	// Step through each marked movement trigger.
	FindAnalysisEventRange( first, last );
	for ( i = first; i < last - 1; i++ ) {
		if ( eventList[i].event == TRIGGER_MOVE_UP || eventList[i].event == TRIGGER_MOVE_DOWN ) {
			movements++;
			// Find when the next movement started.
			for ( j = i + 1; j < last - 1; j++ ) {
				if ( eventList[i].event == TRIGGER_MOVE_UP || eventList[i].event == TRIGGER_MOVE_DOWN ) break;
			}

			// Compute the average force through the movement.
			start_sample = TimeToSample( eventList[i].time );
			end_sample = TimeToSample( eventList[j].time );
			average = 0.0;
			n = 0;
			for ( smpl = start_sample; smpl < end_sample; smpl++ ) { 
				average += acquiredHighAcceleration[smpl];
				n++;
			}
			average /= n;

			// Find the peak force relative to the average during the period.
			peak = 0.0;
			for ( smpl = start_sample; smpl < end_sample; smpl++ ) { 
				delta = fabs( acquiredHighAcceleration[smpl] - average );
				if ( delta > peak ) peak = delta;
			}
			if ( peak < min_amplitude || peak > max_amplitude ) bad_peaks++;
			if ( peak < min_amplitude ) lows++;
			if ( peak > max_amplitude ) highs++;

		}
	}

	// Check if the computed number of incorrect starting positions is in the desired range.
	error = ( bad_peaks > max_bad_peaks );

	// This format string is used to add debugging information to the event notification.
	// It is used whether there is an error or not.
	fmt = "%s\n\n Min Acc Peak: %.2f\n Max Acc Peak: %.2f\n\nTotal Movements: %d\n  Errors Detected: %d\n   Highs: %d\n   Lows: %d\n  Maximum Allowed: %d";

	// If not, signal the error to the subject.
	// Here I take the approach of calling a method to signal the error.
	// We agree instead that the routine should either return a null pointer
	// if there is no error, or return the error message as a static string.
	if ( error ) {
		
		// If the user provided a message to signal a visibilty error, use it.
		// If not, generate a generic message.
		if ( !msg ) msg = "To many collisions outside acceleration range.";
		int response = 
			fSignalError( MB_ABORTRETRYIGNORE, picture, fmt, msg, min_amplitude, max_amplitude, 
							movements, bad_peaks, highs, lows, max_bad_peaks );
		
		if ( response == IDABORT ) return( ABORT_EXIT );
		if ( response == IDRETRY ) return( RETRY_EXIT );
		if ( response == IDIGNORE ) return( IGNORE_EXIT );
		
	}
	
	// This is my means of signalling the event to ground.
	monitor->SendEvent( fmt, "Peak Accelerations OK.", movements, bad_peaks, highs, lows, max_bad_peaks );
	return( NORMAL_EXIT );
	
}