Metropoli BBS
VIEWER: ok.c MODE: TEXT (ASCII)
/***************************************************************************
 *		  Copyright (C) 1994  Charles P. Peterson                  *
 *	     4007 Enchanted Sun, San Antonio, Texas 78244-1254             *
 *              Email: Charles_P_Peterson@fcircus.sat.tx.us                *
 *                                                                         *
 *		  This is free software with NO WARRANTY.                  *
 *	      See gfft.c, or run program itself, for details.              *
 *		      Support is available for a fee.                      *
 ***************************************************************************
 *
 * Program:     gfft--General FFT analysis
 * File:        ok.c
 * Purpose:     OK! Do it!  (Whatever it is to be done)
 * Author:      Charles Peterson (CPP)
 * History:     23-August-1993 CPP; Created.
 *              5-Aug-94 CPP (1.05); Fix nameless append mode
 *              1-Oct-94 CPP (1.14); Fix 'not enough frames' off-by-1 error
 *              10-Feb-95 CPP (1.38); Cleanup if output stopped
 *              13-Feb-95 CPP (1.40); Header on spectrum files
 * Comment:
 */

#include <string.h>
#include "gfft.h"
#include "settings.h" /* Power, Amplitude, ReadPtr */
#include "format.h"   /* ID_8SVX */


static void check_output_parameters (BOOLEAN do_it_for_real);
static void check_plot_parameters (void);
static void spectrum_file_cleanup (void );


static BOOLEAN temporary_name_used = FALSE;

/*
 * First, the interface(s)
 */

char *ok (char *arguments)
{
    if (InputFormat.zero != 0)
    {
	int sample_width = (InputFormat.bits > 8) ? 16 : 8;
	InputFormat.zero = ((unsigned long) 0xffffffff >> 
			    (33 - sample_width)) + (unsigned long) 1;
    }
    CATCH_ERROR
    {
	do_ok (TRUE);
    }
    ON_ERROR
    {
	spectrum_file_cleanup ();
    }
    END_CATCH_ERROR;

    return arguments;
}

char *re_plot (char *arguments)
{
    check_plot_parameters ();
    if (WriteName && strlen(WriteName))
    {
	OkWriteName = WriteName;  /* Probably used Append to load pre-ex */
    }
    if (!OkWriteName || !strlen(OkWriteName))
    {
	error_message (NO_WRITE_FILE);
	RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
    }
    do_re_plot ();
    return arguments;
}

char *re_output (char *arguments)
{
    CATCH_ERROR
    {
	check_output_parameters (TRUE);
	do_re_output ();
	if (WritePtr != stdout) 
	{
	    FILE *write_ptr = WritePtr;
	    WritePtr = NULL;
	    fclose (write_ptr);
	}
	if (Plot)
	{
	    ok_plot ();
	}
	if (temporary_name_used) WriteName = NULL;
    }
    ON_ERROR
    {
	spectrum_file_cleanup ();
    }
    END_CATCH_ERROR;
    return arguments;
}

static void spectrum_file_cleanup (void)
{
    if (WritePtr != stdout && WritePtr != NULL) 
    {
	FILE *write_ptr = WritePtr;
	WritePtr = NULL;
	fclose (write_ptr);
    }
    if (temporary_name_used) WriteName = NULL;
}    

/*
 * Now, the 'main routine' used by OK
 */

ULONG do_ok (BOOLEAN do_it_for_real)
{
    ULONG bins_used = 0;

    if (!ReadPtr)
    {
	error_message (NO_READ_FILE);
	RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
    }
    if (NumberBins == INVALID_BINS)
    {
	error_message (INVALID_BINS_SPEC);
	RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
    }
    if (Interleave == INVALID_INTERLEAVE)
    {
	error_message (INVALID_INTERLEAVE_SPEC);
	RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
    }
    check_output_parameters (do_it_for_real);

    if (FileFormat)
    {
	if (!FileFormatOK)
	{
	    error_message (FORMAT_NOT_OK);
	    RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
	}
	if ((OneShotOnly || RepeatOnly) && FileFormat != ID_8SVX)
	{
	    error_message (ONESHOT_BUT_NOT_8SVX);
	    RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
	}
	OkRate = (Rate == AUTO_RATE) ? FileRate : Rate;/* user may ovride */
	OkOffset = FileDataOffset;
	OkChannels = FileChannels;

	OkOctaveOffset = ok_octave_offset (TRUE);

	if (OkOctaveOffset == 0)
	{
	    ULONG available_frames = FileFrames;

	    OkStartFrame = StartFrame;
	    OkStartFrame += (RepeatOnly) ? FileOneShotHiFrames : 0;
	    available_frames -= (RepeatOnly) ? FileOneShotHiFrames : 0;
	    available_frames -= (OneShotOnly) ? FileRepeatHiFrames : 0;
	    OkFrames = available_frames - StartFrame;
	    if (OkFrames < 1)
	    {
		error_message (NOT_ENOUGH_FRAMES);
		RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
	    }
	}
	else
	{
    /*
     * Deal with multi-octave stuff (and, OneShot/Repeat stuff here too)
     * since user asked for higher octave
     * We use indirection inherent in OkFrames and OkStartFrame.
     * (Otherwise, format reader defaults FileFrames to first octave.)
     *
     * NOTE!  Currently multi-octaves are only supported for 8SVX.
     * Also, I ought to move this stuff back into the format module for
     * better modularity.  Someday.
     */
	    ULONG octave_and_oneshot_offset = 0;
	    int power2 = 1;
	    int i;

	    for (i = 0; i < OkOctaveOffset; i++)
	    {
		octave_and_oneshot_offset += power2 * FileFrames;
		power2 *= 2;
	    }
	    OkFrames = power2 * FileFrames;
	    if (RepeatOnly)
	    {
		OkFrames -= power2 * FileOneShotHiFrames;
		octave_and_oneshot_offset += power2 * FileOneShotHiFrames;
	    }
	    if (OneShotOnly)
	    {
		OkFrames -= power2 * FileRepeatHiFrames;
	    }
	    OkStartFrame = StartFrame + octave_and_oneshot_offset;
	    OkFrames -= StartFrame;
	    if (OkFrames < 1)
	    {
		error_message (NOT_ENOUGH_FRAMES);
		RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
	    }
	}
    /*
     * Now, see if we have enough frames for user's specification
     */
	if (Frames <= OkFrames)
	{
	    OkFrames = Frames;
	}
	else
	{
	    if (Frames != ULONG_MAX)
	    {
		error_message (NOT_ENOUGH_FRAMES);
		RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
	    }
	}
    }
    else /* Unformatted file */
    {
	if (Rate == AUTO_RATE)
	{
	    error_message (NO_RATE_SPECIFIED);
	    RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
	}
	OkRate = Rate;
	OkOffset = StartByte;
	if (FileFrames == 0)  /* If file length unknown */
	{
	    OkFrames = ULONG_MAX;
	    OkStartFrame = StartFrame;
	}
	else
	{
	    if (FileFrames <= StartFrame) /* StartFrame is 0 based */
	    {
		error_message (NOT_ENOUGH_FRAMES);
		RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
	    }
	    OkFrames = FileFrames - StartFrame;
	    OkStartFrame = StartFrame;
	}
	OkChannels = 1;     /* unformatted files must have 1 channel now */
    }
    if (Channel > OkChannels || Channel < 1)
    {
	error_message (SPEC_CHANNEL_UNAVAIL);
	RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
    }
    /*
     * To permit multiple analyses without redundantly entering filename
     * it is reset to beginning here
     */
    ok_rewind ();

    if (Power || Amplitude)
    {
	if (Header && do_it_for_real)
	{
	    fprintf (WritePtr, "#FFT\n");
	    write_settings (WritePtr, "#", TRUE, FALSE);
	}
	if (Time3D)
	{
	    bins_used = ok_time3d_spectrum (do_it_for_real);
	}
	else
	{
	    bins_used = ok_spectrum (do_it_for_real);
	}
    }
    else
    {
	bins_used = ok_fft (do_it_for_real);
    }
    if (do_it_for_real)
    {
	if (WritePtr != stdout)
	{
	    FILE *write_ptr = WritePtr;
	    WritePtr = NULL;
	    fclose (write_ptr);
	}
	if (Plot)
	{
	    ok_plot ();
	}
	if (temporary_name_used) WriteName = NULL;
    }
    return bins_used;
}

	
/*
 * Now, the checking and utilty routines
 */

/*
 *  User selects 1 for lowest octave, 2 for second, etc.
 *   (Special case...0 for highest)
 * however, 8SVX octaves are stored in order highest first
 * so, we compute OkOctaveOffset to match storage order
 */

int ok_octave_offset (BOOLEAN report_error)
{
    int octave_offset = 0;
    if (Octave != 0)
    {
	octave_offset = FileOctaves - Octave;
	if (octave_offset < 0)
	{
	    if (report_error) error_message (OCTAVE_NOT_PRESENT);
	    RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
	}
    }
    return octave_offset;
}


static void check_output_parameters (BOOLEAN do_it_for_real)
{

    temporary_name_used = FALSE;

    if (Rate == INVALID_RATE)   /* Last rate command was invalid */
    {
	error_message (NO_RATE_SPECIFIED);
	RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
    }
    if (SmoothingSegments == INVALID_SMOOTHING)
    {
	error_message (INVALID_SMOOTHING_SPEC);
	RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
    }
    check_plot_parameters ();
    if (do_it_for_real)
    {
	if (WriteName && strlen (WriteName) && !WritePtr)
	{
	    char temp_filename[MAX_PATH+1];

	    strcpy (temp_filename, WriteName);
	    if (Appending)
	    {
		set_append (temp_filename);
	    }
	    else
	    {
		set_write (temp_filename);
	    }
	}
	if (Plot && !WritePtr)
	{
	    extern int Old_File_Count;
	    int file_number = (CombinePlots) ? Old_File_Count+1 : 1;
	    char *read_name = (ReadName) ? ReadName : NullString;
	    char temp_filename[MAX_PATH+1];
	    char temp_name[MAX_PATH+1];

	    temporary_name_used = TRUE;

	    stcgfn (temp_filename, read_name);  /* SAS/C SYSTEM DEPENDENT */
	    sprintf (temp_name, TEMP_DATAFILE_NAME, temp_filename,
		     file_number);
        /*
         * (1.05)
         */
	    if (Appending)
	    {
		set_append (temp_name);
	    }
	    else
	    {
		set_write (temp_name);
	    }
	}
	if (!WritePtr)
	{
	    error_message (NO_WRITE_FILE);
	    RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
	}
	OkWriteName = WriteName;

    } /* end if (do_it_for_real) */
}


static void check_plot_parameters (void)
{
    if (WritePtr == stdout && Plot)
    {
	error_message (CANT_PLOT_FROM_STDOUT);
	RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
    }
    if (RotX == INVALID_ROTATION)
    {
	error_message (INVALID_ROTATION_SPEC);
	RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
    }
    if (RotZ == INVALID_ROTATION)
    {
	error_message (INVALID_ROTATION_SPEC);
	RAISE_ERROR (NOTHING_SPECIAL);  /* longjmp outa here! */
    }
}
[ RETURN TO DIRECTORY ]