/* file: macview.c July 1992 View DB records on a Macintosh This program was contributed by Patrick Hamilton. I have renamed it and reformatted it slightly so that PC types can more easily read it -- if you don't like the name or the indentation, blame me, not Pat! As written, this program assumes that the record to be displayed contains two signals, each sampled at 360 Hz (as in the original MIT-BIH Arrhythmia Database). --GBM */ /****************************************************************************** * The following code allows data from the MIT/BIH arrhythmia database to be * * displayed on a Macintosh screen. Data is displayed sweeping from left to * * right. Additionally, the most recent screen's worth of data can be copied * * to the clip board. * * I developed this code primarily as an exercise in learning to use the Mac * * interface and resources. I used "Macintosh C programming Primer Volume I: * * Inside the Toolbox" as a reference. The code was compiled and run with * * THINK C 5.0. Feel free to copy this code. If you have any questions * * contact me: * * * * Patrick Hamilton * * Lafayette College * * Easton, PA 18042 * * EMAIL: hp#0@LAFAYACS.BITNET * * PHONE: 215-250-5411 * * * ******************************************************************************/ #include #include #include "db.h" #define WNE_TRAP_NUM 0x60 #define UNIMPL_TRAP_NUM 0x9F #define OPEN_ITEM 1 #define COPY_ITEM 2 #define QUIT_ITEM 3 #define GO_ITEM 1 #define STOP_ITEM 2 #define BASE_RES_ID 128 #define NIL_POINTER 0L #define MOVE_TO_FRONT -1 #define REMOVE_ALL_EVENTS 0 #define FILE_MENU_ID BASE_RES_ID #define DISP_MENU_ID FILE_MENU_ID+1 #define DISP_LGTH 500 #define STATUS_LINE 390 #define CH1_OFFSET 140 #define CH2_OFFSET 290 WindowPtr ecgDisplayWindow, myDialog; MenuHandle FileMenu, DisplayMenu; Boolean WNEImplemented, Done, Running, FileOpen; EventRecord TheEvent; int DataBuffer[2][DISP_LGTH], DBPtr = 0, CopyChannel = 0; main() { int rval, i; int v1[2], v2[2]; ToolBoxInit(); WindowInit(); MenuBarInit(); dbquiet(); WNEImplemented = (NGetTrapAddress (WNE_TRAP_NUM, ToolTrap) != NGetTrapAddress(UNIMPL_TRAP_NUM, ToolTrap)); Done = Running = FileOpen = FALSE; while (!Done) { HandleEvent(); /* Display data while running. */ for (i = 0; i < 5; ++i) { if (Running == TRUE) { PlotData(0); ShowTime(0); ShowTime(0); rval = getvec(v1); rval = getvec(v2); DataBuffer[0][DBPtr] = (v1[0]+v2[0]) >> 1; DataBuffer[1][DBPtr] = (v2[1]+v2[1]) >> 1; PlotData(1); if (++DBPtr == DISP_LGTH) DBPtr = 0; if (rval < 0) Running = FileOpen = FALSE; } } } } ToolBoxInit() { InitGraf(&thePort); InitFonts(); FlushEvents(everyEvent, REMOVE_ALL_EVENTS); InitWindows(); InitMenus(); TEInit(); InitDialogs(NIL_POINTER); InitCursor(); } WindowInit() { ecgDisplayWindow = GetNewWindow (BASE_RES_ID, NIL_POINTER, (WindowPtr) MOVE_TO_FRONT); ShowWindow(ecgDisplayWindow); SetPort(ecgDisplayWindow); } #define FILE_NUM_FIELD 1 #define OK_BUTTON 3 HandleFileDialog(str) char *str; { WindowPtr myDialog; Boolean dialogDone = FALSE; int itemHit; int itemType; Rect itemRect; Handle itemHandle; char *sptr; myDialog = GetNewDialog(BASE_RES_ID, NIL_POINTER, (WindowPtr) MOVE_TO_FRONT); ShowWindow(myDialog); while (dialogDone == FALSE) { ModalDialog(NIL_POINTER, &itemHit); switch(itemHit) { case OK_BUTTON: dialogDone = TRUE; } } GetDItem(myDialog, FILE_NUM_FIELD, &itemType, &itemHandle, &itemRect); GetIText(itemHandle, str); DisposeWindow(myDialog); PtoCstr(str); } #define FIRST_RADIO 1 #define SECOND_RADIO 2 #define CD_OK 4 #define ON 1 #define OFF 0 HandleCopyDialog() { WindowPtr myDialog; Boolean dialogDone = FALSE; int itemHit; int itemType; Rect itemRect; Handle itemHandle; char *sptr; myDialog = GetNewDialog(BASE_RES_ID+1, NIL_POINTER, (WindowPtr) MOVE_TO_FRONT); if (CopyChannel == 0) { GetDItem(myDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect); SetCtlValue(itemHandle, ON); } else { GetDItem(myDialog, SECOND_RADIO, &itemType, &itemHandle, &itemRect); SetCtlValue(itemHandle, ON); } ShowWindow(myDialog); while (dialogDone == FALSE) { ModalDialog(NIL_POINTER, &itemHit); switch(itemHit) { case FIRST_RADIO: CopyChannel = 0; GetDItem(myDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect); SetCtlValue(itemHandle, ON); GetDItem(myDialog, SECOND_RADIO,&itemType, &itemHandle, &itemRect); SetCtlValue(itemHandle, OFF); break; case SECOND_RADIO: CopyChannel = 1; GetDItem(myDialog, SECOND_RADIO,&itemType, &itemHandle, &itemRect); SetCtlValue(itemHandle, ON); GetDItem(myDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect); SetCtlValue(itemHandle, OFF); break; case CD_OK: dialogDone = TRUE; } } DisposeWindow(myDialog); } MenuBarInit() { Handle myMenuBar; myMenuBar = GetNewMBar(BASE_RES_ID); SetMenuBar(myMenuBar); FileMenu = GetMenu(BASE_RES_ID); DisplayMenu = GetMenu(BASE_RES_ID+1); InsertMenu(FileMenu, 0); InsertMenu(DisplayMenu, 0); DrawMenuBar(); } HandleEvent() { if (WNEImplemented) WaitNextEvent(everyEvent, &TheEvent, 0L, 0L); else { SystemTask(); GetNextEvent(everyEvent, &TheEvent); } switch (TheEvent.what) { case mouseDown: HandleMouseDown(); break; } } HandleMouseDown() { WindowPtr whichWindow; short int thePart; long int menuChoice; thePart = FindWindow(TheEvent.where, &whichWindow); switch (thePart) { case inMenuBar: menuChoice = MenuSelect(TheEvent.where); HandleMenuChoice(menuChoice); break; case inSysWindow: SystemClick(&TheEvent, whichWindow); break; } } HandleMenuChoice(menuChoice) long int menuChoice; { int theMenu, theItem; if (menuChoice != 0) { theMenu = HiWord(menuChoice); theItem = LoWord(menuChoice); switch (theMenu) { case FILE_MENU_ID: HandleFileChoice(theItem); break; case DISP_MENU_ID: HandleDispChoice(theItem); break; } HiliteMenu(0); } } HandleFileChoice(theItem) int theItem; { char recordName[80], str[80]; struct siginfo s[2]; int i; int rval, v1[2], v2[2]; switch(theItem) { case OPEN_ITEM: HandleFileDialog(recordName); if (isigopen(recordName, s, 2) < 1) { NoteAlert(128, 0L); FileOpen = FALSE; } else { FileOpen = TRUE; MoveTo(190, STATUS_LINE); sprintf(str, "RECORD: %s", recordName); TextMode(srcCopy); DrawString(CtoPstr(str)); ShowTime(1); } break; case COPY_ITEM: HandleCopyDialog(); CopyECGToClip(); break; case QUIT_ITEM: Done = TRUE; break; } } HandleDispChoice(theItem) int theItem; { switch(theItem) { case GO_ITEM: if (FileOpen == TRUE) Running = TRUE; break; case STOP_ITEM: Running = FALSE; break; } } PlotData(color) int color; { if (color == 0) { /* erase old data */ PenMode(patBic); if (DBPtr != DISP_LGTH - 1) { MoveTo(DBPtr+10, CH1_OFFSET - ((DataBuffer[0][DBPtr ]-0x400)>>2)); LineTo(DBPtr+11, CH1_OFFSET - ((DataBuffer[0][DBPtr+1]-0x400)>>2)); MoveTo(DBPtr+10, CH2_OFFSET - ((DataBuffer[1][DBPtr ]-0x400)>>2)); LineTo(DBPtr+11, CH2_OFFSET - ((DataBuffer[1][DBPtr+1]-0x400)>>2)); } } else { PenMode(patOr); if (DBPtr != 0) { MoveTo(DBPtr+ 9, CH1_OFFSET - ((DataBuffer[0][DBPtr-1]-0x400)>>2)); LineTo(DBPtr+10, CH1_OFFSET - ((DataBuffer[0][DBPtr ]-0x400)>>2)); MoveTo(DBPtr+ 9, CH2_OFFSET - ((DataBuffer[1][DBPtr-1]-0x400)>>2)); LineTo(DBPtr+10, CH2_OFFSET - ((DataBuffer[1][DBPtr ]-0x400)>>2)); } } } ShowTime(init) int init; { static int samples, sec, min; char str[80]; if (init) { samples = sec = min = 0; sprintf(str, "TIME: %.2d:%.2d", min, sec); MoveTo(290, STATUS_LINE); TextMode(srcCopy); DrawString(CtoPstr(str)); } else { if (++samples == 360) { samples = 0; if (++sec == 60) { sec = 0; ++min; } sprintf(str, "TIME: %.2d:%.2d", min, sec); MoveTo(290, STATUS_LINE); TextMode(srcCopy); DrawString(CtoPstr(str)); } } } CopyECGToClip() { char str[40]; int data[DISP_LGTH]; PicHandle wavePic; long psize; Rect pFrame, myRect; int max, min, baseline, i, j; /* Copy data from data buffer to a temporary buffer. */ for (i = 0, j = DBPtr; i < DISP_LGTH; ++i) { data[i] = DataBuffer[CopyChannel][j]; if (++j == DISP_LGTH) j = 0; } for (max = min = data[0], i = 1; i < DISP_LGTH; ++i) { if (data[i] > max) max = data[i]; if (data[i] < min) min = data[i]; } baseline = (max+min)>>1; for (i = 0; i < DISP_LGTH; ++i) data[i] = 150 - ((data[i] - baseline)>>2); pFrame.top = 0; pFrame.bottom = 300; pFrame.left = 0; pFrame.right = DISP_LGTH; wavePic = OpenPicture(&pFrame); PenMode(patOr); MoveTo(0, data[0]); for (i = 1; i < DISP_LGTH; ++i) LineTo(i, data[i]); ClosePicture(); ZeroScrap(); psize = GetHandleSize(wavePic); PutScrap(psize, 'PICT', *wavePic); /* <-- shouldn't that be "PICT"? -GBM */ KillPicture(wavePic); }