Mercurial > hg > aim92
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/model/review.c Fri May 20 15:19:45 2011 +0100 @@ -0,0 +1,666 @@ +/* + 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); + } + }