view model/review.c @ 0:5242703e91d3 tip

Initial checkin for AIM92 aimR8.2 (last updated May 1997).
author tomwalters
date Fri, 20 May 2011 15:19:45 +0100
parents
children
line wrap: on
line source
/*
    Copyright (c) Applied Psychology Unit, Medical Research Council. 1988, 1989
    ===========================================================================

    Permission to use, copy, modify, and distribute this software without fee
    is hereby granted for research purposes, provided that this copyright
    notice appears in all copies and in all supporting documentation, and that
    the software is not redistributed for any fee (except for a nominal shipping
    charge). Anyone wanting to incorporate all or part of this software in a
    commercial product must obtain a license from the Medical Research Council.

    The MRC makes no representations about the suitability of this
    software for any purpose.  It is provided "as is" without express or implied
    warranty.

    THE MRC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE
    A.P.U. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/*
    review.c
    ========

    formerly known as revsai.c - reviews .ctn screen dump files from disk.


    Copyright (c), 1989  The Medical Research Council, Applied Psychology Unit.


    Authors : Paul Manson and John Holdsworth.
    Written : 11th March, 1989

    Edited  :

    03 April 1989 (Paul Manson) -- A new star on the horizon! The all-singing, all-dancing
				   new revue emerges from the ashes of last week's version.

    19 April 1989 (Paul Manson) -- Added the <input> option. Changed the name to revsai.

    27 April 1989 (Paul Manson) -- The port to the DecStation (and by implication, the VAX)
				   has revealed several problems and bugs. All such known
				   bugs have been fixed. The <memory> option has been
				   introduced (for non-PCs only) to permit rapid reviewing
				   on X-windows servers. NOTE THAT THE SCREEN SIZE FOR NON
				   PC MACHINES HAS BEEN HARD_CODED! THIS SHOULD CHANGE!

    05 May   1989 (Paul Manson) -- The above problem has been temporarily rectified by
				   using the default width and height options to indicate
				   the actual screen size. Also, the options format change
				   has been accounted for.

    11 May   1989 (Paul Manson) -- Altered options to conform to the new(est) r'egime.

    15 May   1989 (Paul Manson) -- Incorporated the PC-style wildcarding into the Unix version.
				   Made display use "NULL" instead of (char *) 0.

    05 June  1989 (Paul Manson) -- Altered a couple of the option comments to reflect their
				   behaviour more accurately. I also encountered the rather
				   suspicious "bug" whereby revsai gets a segmentation fault
				   whenever it is run on an old "sai" file ... those generated
				   by sai now appear to be OK... If this really is a problem,
				   it should be tracked down!

    06 July  1989 (Paul Manson) -- As well as altering revsai to accomodate all of the new
				   options names, I note that the abovementioned bug appears
				   to have disappeared without trace; hopefully it was just
				   due to previous (buggy) files, etc.

    3 August 1993 (M. Akeroyd) --  Added declarations of "colourstr"  and "planemaskstr".
                                   They aren't used, but are in X.c (and thus libglib.a),
				   and are therfore required to fool the linker.

    25 March 1994 (M. Akeroyd) --  Added colour. mono etc, so that 'review' would actually work.
                                   (the previuos cahnge just made it compile.)
*/

#include <string.h>
#include <stdio.h>
#include <math.h>

#if defined(THINK_C) || defined(NeXT) 
#include <stdlib.h>
#else
#include <malloc.h>
#endif

#include "windows.h"
#include "options.h"


char *monostr, *colourstr, *planemaskstr;   /* MAA 3-8-1993 */
char *fgcolourstr, *bgcolourstr;  /* MAA 19-8-1993 */
#ifndef  lint
static char *sccs_id = "@(#)review.c	1.13 Paul Manson, John Holdsworth (MRC-APU) 5/31/91";
#endif

#define max(A,B) (((A) > (B)) ? (A) : (B))
#define LENGTH_STR "remainder"
#define MAX_LENGTH (9999)

#define CENTER_STR "center"
#define IMAGE_SUFFIX ".ctn"

#ifdef PC
#define READ_BINARY "rb"
#else
#define READ_BINARY "r"
#endif

/* configurables */

static char *helpstr                               ;
static char *speed1str, *speed2str                 ;
static char *xstr, *ystr, *widthstr,  *heightstr   ;
static char *start1str,   *stop1str,  *step1str    ;
static char *start2str,   *stop2str,  *step2str    ;
static char *minstr ,     *maxstr  ,  *framestr    ;
static char *in1str,      *in2str,    *downstr     ;

#if !defined( PC )
extern void exit();
static char *memorystr;
#endif

static Option res[] = {
 { "help",       "none",       &helpstr,   "<wave1> [<wave2>]\n\n\
	Redisplays stored images from memory or directly from disk.\n\
	Review responds to various simple commands, viz.\n\n\
	1\t Activate only wave1 (default when only one wave named).\n\
	2\t Activate only wave2.\n\
	b or B\t Activate Both waves (default when two waves named).\n\n\
	a or A\t Animate cartoon wave(s). Hitting space bar is equivalent.\n\
	s or S\t Single-step activated wave(s). Hit space bar to step.\n\
	+\t Animate activated wave(s) faster.\n\
	-\t Animate activated wave(s) slower.\n\n\
	q or Q\t Quit Revue.\n", SilentOption },
 { "input1",   NULL_OPTION,  &in1str,     "Default input file name 1",               InputOption},
 { "start1" ,     "0" ,      &start1str , "Start point in wave 1 (in ms)",           InputOption},
 { "length1", LENGTH_STR,    &stop1str  , "Length of wave 1 to display (in ms)",     InputOption},
 { "step1"  ,     "1" ,      &step1str  , "Display every step-th image of wave 1",   InputOption},
 { "speed1",     "1" ,       &speed1str,  "Image 1 display speed (1 is  fastest)", InputOption},

 { "input2",   NULL_OPTION,  &in2str,     "Default input file name 2\n",             InputOption},
 { "start2" ,     "0" ,      &start2str , "Start point in wave 2 (in ms)",           InputOption},
 { "length2", LENGTH_STR,    &stop2str  , "Length of wave 2 to display (in ms)",     InputOption},
 { "step2"  ,     "1" ,      &step2str  , "Display every step-th image of wave 2",   InputOption},
 { "speed2",     "1" ,       &speed2str,  "Image 2 display speed (1 is  fastest)",   InputOption},

 { "x0_win",  CENTER_STR,    &xstr,       "Left edge of window (in pixels)" ,        SilentOption},
 { "y0_win",  CENTER_STR,    &ystr,       "Upper edge of window (in pixels)",        SilentOption},
 { "width_screen", "960",    &widthstr,   "Physical screen width  in pixels",        SilentOption},
 { "height_screen","750",    &heightstr,  "Physical screen height in pixels",        SilentOption},

/* MAA: 25 March 1994
 * These next added because they are used from within X.c (although defined in gen.c), and thus the graphics
 * calls. They are of NO meaning, however; they define how the Model makes the bitmaps.
 * Once made, you cannot edit bitmaps ... 
 */
 { "fg_col",         "black", &fgcolourstr, "Foreground Colour.\n",                   SilentOption},
 { "bg_col",         "white", &bgcolourstr, "Background Colour.\n",                   SilentOption},
 {    "mono_ctn",   ON_OPTION, &monostr, "Force monochrome (single plane) cartoons.", SilentOption},
 {  "colour_ctn",  OFF_OPTION, &colourstr, "Force colour (multi-plane) cartoons.", SilentOption},
 {"planemask_ctn", "1", &planemaskstr, "Planemask for creating cartoons.\n", SilentOption},
/* MAA: End of that bit */

#if !defined( PC )
 { "memory",     ON_OPTION,  &memorystr,  "Read images into memory for reviewing\n", InputOption},
#endif
 ( char * ) 0 } ;

static Option hiddenRes[] = {
 { "downsample",     "20",   &downstr,    "Image file frame size (in ms)",           InputOption},
 { "frstep_aid",     "20",   &framestr,   "Image file frame size (in ms)",           InputOption},
 { "mincf_afb",     "220",   &minstr  ,   "Minimum Center Frequency in Hertz",       InputOption},
 { "maxcf_afb",    "4400",   &maxstr  ,   "Maximum Center Frequency in Hertz",       InputOption},
 { "width_win",     "900",   &widthstr,   "Window width  (pixels)",                  InputOption},
 { "height_win",    "600",   &heightstr,  "Window height (pixels)",                  InputOption},
 ( char * ) 0 } ;

#define ONE (1)
#define TWO (2)
#define BOTH (0)

#define FALSE (0)
#define TRUE (1)
#define OVERTHETOP (10000)
#define AXES_WIDTH (15)

static int msToImages(frame, ms)
  double frame;
  double ms   ;
{
  return (((int) (ms / frame)) + 1); /* Round Up */
}

/* File Name Suffix Conversion Parameters */

#define BACKSLASH_CHAR  '\\'
#define SLASH_CHARACTER '/'
#define NULL_CHARACTER  '\000'
#define DOT_CHARACTER '.'

/******************************************************************************************/
/*                                                                                        */
/*    AlterSuffix(). Returns its argument fileName with a newSuffix appended in place of  */
/*                   any previous suffix it may have had. It should be noted that this    */
/*                   suffix must include any DOT it wishes to have appended to the name.  */
/*                                                                                        */
/******************************************************************************************/

char *AlterSuffix(fileName, newSuffix)
     char *fileName, *newSuffix;
{
  char *temp, *temp2, *lastPart;
  int i;

  temp = malloc((unsigned) (strlen(fileName) + strlen(newSuffix) + 1));

  temp = strcpy(temp, fileName);

#if defined( PC )
  /* Change all backslashes to forward slashes */
  for (i = 0; temp[i] != NULL_CHARACTER; i++)
    if (temp[i] == BACKSLASH_CHAR)
      temp[i] = SLASH_CHARACTER;
#endif

  if ((lastPart = strrchr(temp, SLASH_CHARACTER)) == NULL)
    lastPart = temp;
  else
    lastPart++; /* Skip over the actual "/" */

  /* lastPart points to the tail name of the path */

  if ((temp2 = strchr(lastPart, DOT_CHARACTER)) == NULL)
    temp = strcat(temp, newSuffix);
  else
    temp2 = strcpy(temp2, newSuffix);

  return (temp);
}

/* -----------------------------------------------------------------------------------

   A Routine to extend revsai for in-memory animation. This copies every image from
   <start> to <stop> by <step> into the images buffer for the window <w>. It then
   expects contiguous animation of these images. The integer returned is the number
   of images that were saved; subsequent image Recall() calls should refer to images
   in the range [1 .. this returned value].

   ----------------------------------------------------------------------------------- */

static int readIntoMemory(w, filePtr, start, stop, step)
     WindowObject w;
     FILE *filePtr ;
     int      start;
     int       stop;
     int       step;
{
  int fileImage, memImage;

  memImage = 0;

  fileImage = start;

  while (fileImage <= stop && Read(w, filePtr, fileImage)) {
    Store(w);
    fileImage += step;
    memImage++;
  }

  return (memImage);
}

main( argc, argv )
int argc ;
char *argv[] ;
{
    WindowObject w1, w2;
    int   screenWidth,  screenHeight ;
    int   firstWidth ,  firstHeight  ;
    int   secondWidth,  secondHeight ;
    int   firstPixels,  secondPixels ;
    FILE *firstWave  , *secondWave   ;

    int OneWave, TwoWaves, spareWidth,
	spareHeight                  ;

    int waveMode , image1    , image2;
    int            count1    , count2;
    int stopFirst, stopSecond        ;
    int start1   , stop1     , step1 ;
    int start2   , stop2     , step2 ;
    int speed1   , speed2            ;

    char command, *firstWaveName,
      *secondWaveName,
      *programName;

    double mincf1, mincf2, maxcf1, maxcf2, frame1, frame2;
    int inMemory, x, y;

    programName = argv[0];

    (void) getopts( res, &argc, &argv );

    /* Extract any information from the opts which is NECESSARY for the
       operation of revue */

    screenWidth = atoi( widthstr );
    screenHeight= atoi( heightstr);

#if defined( PC )
    inMemory = FALSE;
#else
    inMemory = isON( memorystr );
#endif

    if (argc > 2 || (argc == 0 && isNULL(in1str))) {
      (void) helpopts(res, programName);
      exit(1);
    }
    else {
      OneWave = ((argc == 0 && !isNULL(in1str)) ||
		 (argc == 1 &&  isNULL(in2str)));
      TwoWaves = !OneWave;
    }

    if (argc == 0)
      firstWaveName = AlterSuffix(in1str, IMAGE_SUFFIX) ;
    else
      firstWaveName = AlterSuffix(argv[0], IMAGE_SUFFIX);

    if ((firstWave = fopen(firstWaveName, READ_BINARY )) == NULL) {
      (void) fprintf(stderr, "Could not open the image file %s.\n", firstWaveName);
      exit(1);
    }

    (void) readopts(res, firstWave);

    if (fseek(firstWave, 0l, 0)) {
	(void) fprintf(stderr, "revsai: Could not re-seek the %s file.\n",
		       firstWaveName);
	exit(1);
    }

    (void) readopts(hiddenRes, firstWave);

    if( framestr == (char *) 0 )
		if( downstr == (char *) 0 )
		 	frame1 = 1 ;
		else
			frame1 = atof(downstr);
    else if ((frame1 = atof(framestr)) < 0.0)
	frame1 = 0.0;

    firstWidth  = atoi( widthstr );
    firstHeight = atoi( heightstr);

    start1 = msToImages(frame1, atof( start1str ));

    if (strcmp(stop1str, LENGTH_STR) == 0)
      stop1 = MAX_LENGTH;
    else
      stop1  = msToImages(frame1, atof( stop1str  )) + start1;

    step1  = atoi( step1str  );
    if (step1 < 1)
      step1 = 1;

    firstPixels = 1; /* atoi( pixelstr ); */

    mincf1 = atof( minstr );
    maxcf1 = atof( maxstr );

    if (TwoWaves) {

      if (argc == 1)
	secondWaveName = AlterSuffix(in2str, IMAGE_SUFFIX);
      else
	secondWaveName = AlterSuffix(argv[1],IMAGE_SUFFIX);

      if ((secondWave = fopen(secondWaveName, READ_BINARY )) == NULL) {
	(void) fprintf(stderr, "Could not open the image file %s.\n",
		       secondWaveName);
	exit(1);
      }

      (void) readopts(res, secondWave);
      if (fseek(secondWave, 0l, 0)) {
	  (void) fprintf(stderr, "revsai: Could not re-seek the %s file.\n",
			 secondWaveName);
	  exit(1);
      }
      (void) readopts(hiddenRes, secondWave);

      if( framestr == (char *) 0 )
		if( downstr == (char *) 0 )
		 	frame2 = 1. ;
		else
		  frame2 = atof(downstr);
      else if ((frame2 = atof(framestr)) < 0.0)
	  frame2 = atof(downstr);

      secondWidth  = atoi( widthstr );
      secondHeight = atoi( heightstr);

      start2 = msToImages(frame2, atof( start2str ));

      if (strcmp(stop2str, LENGTH_STR) == 0)
	stop2 = MAX_LENGTH;
      else
	stop2  = msToImages(frame2, atof( stop2str  )) + start2;

      step2  = atoi( step2str  );
      if (step2 < 1)
	step2 = 1;

      secondPixels = 1; /* atoi( pixelstr ); */

      mincf2 = atof( minstr );
      maxcf2 = atof( maxstr );

    }


    /* Open display window(s) */

    if (TwoWaves) {
      /* Center them both for height, but try to fit them both on the screen
	 at once, width-wise. Firstly, get the REAL screen size */
#if defined( PC )
      w1 = newDisplayWindow(firstWaveName, -1, -1, OVERTHETOP, OVERTHETOP, 1);
      screenWidth  = Width(w1);
      screenHeight = Height(w1);
      Close(w1);
#endif

      if (screenHeight < firstHeight || screenHeight < secondHeight) {
	(void) fprintf(stderr, "revsai: One (or both) of the waves specified was too\n        high for this screen.\n");
	exit(1);
      }
      if (screenWidth < firstWidth + secondWidth) {
	(void) fprintf(stderr, "revsai: These two waves are too wide to be viewed side-by-side.\n        Please revue them one at a time, or perhaps generate them smaller.\n");
	exit(1);
      }

      spareWidth  = screenWidth  - (firstWidth  + secondWidth  + (2 * AXES_WIDTH));
      spareHeight = screenHeight - (firstHeight + (2 * AXES_WIDTH));

      w1 = newDisplayWindow(firstWaveName, spareWidth/6 + AXES_WIDTH, spareHeight/2,
			    firstWidth, firstHeight, firstPixels);
      Axes(w1, firstWaveName, 0.0, frame1, "Image Frame Size (in ms)",
	       mincf1, maxcf1, "Center Frequency (in Hz)");

      spareHeight = screenHeight - (secondHeight + (2 * AXES_WIDTH));

      w2 = newDisplayWindow(secondWaveName, (5 * spareWidth / 6) +
				     firstWidth + (2 * AXES_WIDTH),
				     spareHeight/2, secondWidth, secondHeight,
				     secondPixels);
      Axes(w2, secondWaveName, 0.0, frame2, "Image Frame Size (in ms)",
	       mincf2, maxcf2, "Center Frequency (in Hz)");
    }
    else {
      /* Easy .. MetaPC Centers it for us */
      if (OptionStringsEqual(xstr, CENTER_STR))
	x = -1;
      else
	x = atoi(xstr);

      if (OptionStringsEqual(ystr, CENTER_STR))
	y = -1;
      else
	y = atoi(ystr);

      w1 = newDisplayWindow(firstWaveName, x, y, firstWidth, firstHeight,
			    firstPixels );
      Axes(w1, firstWaveName, 0.0, frame1, "Image Frame Size (in ms)",
	       mincf1, maxcf1, "Center Frequency (in Hz)");

#if defined( SUN )
      /* Kludge to overcome the window-sizing inconsistency when
	 you open a SunView window with a frame */

      if (Height(w1) >  firstHeight || Width(w1) >  firstWidth) {
#else
      if (Height(w1) != firstHeight || Width(w1) != firstWidth) {
#endif
	(void) fprintf(stderr, "revsai: The wave you wish to view is too large (ie. either too wide\nor too tall) for the current screen.\n");
	exit(1);
      }
    }

    /* Do the actual reviewing */

    if (TwoWaves)
      waveMode = BOTH;
    else
      waveMode = ONE ;

    speed1 = atoi( speed1str );
    if (speed1 < 1)
      speed1 = 1;
    speed2 = atoi( speed2str );
    if (speed2 < 1)
      speed2 = 1;

    /* Initially, just open the files and display the first frame of each, */
    /* UNLESS the inMemory switch is set, in which case you should read in */
    /* all of the images and adjust start, stop to suit.                   */

    if (inMemory) {
	stop1 = readIntoMemory(w1, firstWave, start1, stop1, step1);
	start1 = 1; /* Now runs from 0 to the adjusted stop */
	step1  = 1; /* Now the images are contiguous        */
	if (TwoWaves) {
	  stop2 = readIntoMemory(w2, secondWave, start2, stop2, step2);
	  start2 = 1; /* Now runs from 0 to the adjusted stop */
	  step2  = 1; /* Now the images are contiguous        */
	}
    }
    else {
      if (!Read(w1, firstWave, start1)) {
	(void) fprintf(stderr, "revsai: Could not read the first image from the first wave.\n");
	exit(1);
      }

      if (TwoWaves && !Read(w2, secondWave, start2)) {
	(void) fprintf(stderr, "revsai: Couldn't read the first image from the second wave.\n");
	exit(1);
      }
    }

    /* Sit and take commands */

    while ((command = Pause(w1)) != 'q' && command != 'Q') {
      switch (command) {
      case '1':
	    /* Toggle to Wave number One */
	    waveMode = ONE;
	break;
      case '2':
	    /* Try to toggle to Wave number Two */
	    if (TwoWaves)
	      waveMode = TWO;
	    break;
      case 'b': case 'B':
	    /* Try to toggle to Both Waves */
	    if (TwoWaves)
	      waveMode = BOTH;
	    break;
      case '+':
	    /* Speed up current Wave(s) */
	if (waveMode == ONE || waveMode == BOTH)
	  speed1 = ((speed1 > 1) ? (speed1 /= 2) : (1));
	    if (waveMode == TWO || waveMode == BOTH)
	  speed2 = ((speed2 > 1) ? (speed2 /= 2) : (1));
	    break;
      case '-':
	    /* Slow down current Wave(s) */
	if (waveMode == ONE || waveMode == BOTH)
	  speed1 *= 2;
	    if (waveMode == TWO || waveMode == BOTH)
	  speed2 *= 2;
	    break;
      case 's': case 'S':
	stopFirst  = (waveMode == TWO);
	stopSecond = (waveMode == ONE);
	image1 = start1;
	image2 = start2;
	while (!(stopFirst && stopSecond) && (Pause(w1) == ' ')) {
	    if (!stopFirst) {
		if (inMemory)
			  Recall(w1, image1);
		else
			  stopFirst  = !Read(w1, firstWave , image1);
		if (!stopFirst) {
			  image1 += step1;
			  stopFirst = (image1 > stop1);
		}
	    }
	    if (!stopSecond) {
		if (inMemory)
			  Recall(w2, image2);
			else
			  stopSecond = !Read(w2, secondWave, image2);
		if (!stopSecond) {
			  image2 += step2;
			  stopSecond = (image2 > stop2);
		}
	    }
	}
	break;
      case 'a': case 'A': case ' ':
	stopFirst  = (waveMode == TWO);
	stopSecond = (waveMode == ONE);
	image1 = start1;
	image2 = start2;
	count1 = count2 = 0    ;
	while (!(stopFirst && stopSecond)) {
		if (stopFirst || image1 > stop1) {
		if (waveMode == BOTH && !stopSecond && image2 <= stop2 &&
		    image1 > start1  && count1 == 0) {
			/* Redisplay the previous image for constant speed */
			if (inMemory)
			  Recall(w1, image1-1);
			else
			  stopFirst = !Read(w1, firstWave, image1-1);
		    }
		    stopFirst = TRUE;
		}
		else {
		    if (inMemory)
		      Recall(w1, image1);
		    else
		      stopFirst = !Read(w1, firstWave, image1);
		    if (!stopFirst)
			    if (++count1 >= speed1) {
			      image1 += step1;
			      count1  = 0    ;
			}
	    }
		if (stopSecond || image2 > stop2) {
		if (waveMode == BOTH && !stopFirst && image1 <= stop1 &&
		    image2 > start2  && count2 == 0) {
			/* Redisplay the previous image for constant speed */
			if (inMemory)
			  Recall(w2, image2-1);
			else
			  stopSecond = !Read(w2, secondWave, image2-1);
			}
		    stopSecond = TRUE;
		}
		else {
		    if (inMemory)
		      Recall(w2, image2);
		    else
		      stopSecond = !Read(w2, secondWave, image2);
		    if (!stopSecond)
			    if (++count2 >= speed2) {
			      image2 += step2;
			      count2  = 0    ;
			}
	    }
	}
	break;
      default:
	    break;
      }
    }
    if (fclose(firstWave)) {
	(void) fprintf(stderr, "revsai: Could not close file % correctly.\n",
		       firstWaveName);
	exit(1);
    }
    if (TwoWaves && fclose(secondWave)) {
	(void) fprintf(stderr, "revsai: Could not close file % correctly.\n",
		       secondWaveName);
	exit(1);
    }
  }