diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/app/Makefile.tpl wfdb-10.5.10/app/Makefile.tpl --- wfdb-10.5.9/app/Makefile.tpl 2009-05-04 00:57:32.000000000 -0400 +++ wfdb-10.5.10/app/Makefile.tpl 2011-11-16 14:47:07.000000000 -0500 @@ -1,5 +1,5 @@ # file: Makefile.tpl G. Moody 23 May 2000 -# Last revised: 26 February 2009 +# Last revised: 16 November 2011 # This section of the Makefile should not need to be changed. CFILES = ann2rr.c bxb.c calsig.c ecgeval.c epicmp.c fir.c ihr.c mfilt.c \ @@ -7,13 +7,14 @@ rdsamp.c rr2ann.c rxr.c sampfreq.c sigamp.c sigavg.c signame.c signum.c \ skewedit.c snip.c sortann.c sqrs.c sqrs125.c sumann.c sumstats.c tach.c \ time2sec.c wabp.c wfdb-config.c wfdbcat.c wfdbcollate.c wfdbdesc.c \ - wfdbtime.c wfdbwhich.c wqrs.c wrann.c wrsamp.c xform.c + wfdbmap.c wfdbsignals.c wfdbtime.c wfdbwhich.c wqrs.c wrann.c wrsamp.c xform.c +HFILES = signal-colors.h XFILES = ann2rr bxb calsig ecgeval epicmp fir ihr mfilt \ mrgann mxm nguess nst plotstm pscgen pschart psfd rdann \ rdsamp rr2ann rxr sampfreq sigamp sigavg signame signum \ skewedit snip sortann sqrs sqrs125 sumann sumstats tach \ time2sec wabp wfdb-config wfdbcat wfdbcollate wfdbdesc \ - wfdbtime wfdbwhich wqrs wrann wrsamp xform + wfdbmap wfdbsignals wfdbtime wfdbwhich wqrs wrann wrsamp xform SCRIPTS = cshsetwfdb setwfdb PSFILES = pschart.pro psfd.pro 12lead.pro MFILES = Makefile @@ -66,7 +67,7 @@ # `make listing': print a listing of WFDB applications sources listing: - $(PRINT) README $(MFILES) $(CFILES) $(PSFILES) + $(PRINT) README $(MFILES) $(CFILES) $(HFILES) $(PSFILES) # Rules for compiling applications that require non-standard options @@ -87,5 +88,7 @@ $(CC) $(CFLAGS) -DPROLOG=\"$(PSPDIR)/psfd.pro\" psfd.c -o $@ $(LDFLAGS) sigamp: sigamp.c $(CC) $(CFLAGS) sigamp.c -o $@ $(LDFLAGS) -lm +wfdbmap: wfdbmap.c signal-colors.h + $(CC) $(CFLAGS) wfdbmap.c -o $@ $(LDFLAGS) wqrs: wqrs.c $(CC) $(CFLAGS) wqrs.c -o $@ $(LDFLAGS) -lm diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/app/map-record wfdb-10.5.10/app/map-record --- wfdb-10.5.9/app/map-record 1969-12-31 19:00:00.000000000 -0500 +++ wfdb-10.5.10/app/map-record 2010-07-30 15:37:34.000000000 -0400 @@ -0,0 +1,12 @@ +#! /bin/bash + +# make a map of a WFDB record + +RL=$1 +RS=`basename $RL` +shift + +wfdbmap -r $RL $* >$RS.script +bash $RS.script >$RS.plt 2>/dev/null +lwcat -strip -eps $RS.plt >$RS.ps +convert -density 150 $RS.ps $RS.png diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/app/signal-colors.h wfdb-10.5.10/app/signal-colors.h --- wfdb-10.5.9/app/signal-colors.h 1969-12-31 19:00:00.000000000 -0500 +++ wfdb-10.5.10/app/signal-colors.h 2009-04-09 16:44:18.000000000 -0400 @@ -0,0 +1,311 @@ +struct sigcolor { + char *color; + char *class; + char *name; +} ctab[] = { +"red", "ECG", "Abdomen_1", +"red", "ECG", "Abdomen_2", +"red", "ECG", "Abdomen_3", +"red", "ECG", "Abdomen_4", +"green", "Resp", "Abdomen [ABMV]", +"green", "Resp", "ABDO RES", +"blue", "BP", "ABP", +"blue", "BP", "ABP_1/2", +"blue", "BP", "ABP_2/2", +"blue", "BP", "ABPDias", +"blue", "BP", "ABPMean", +"blue", "BP", "ABPSys", +"blue", "BP", "AOBP", +"blue", "BP", "AOBP_1/2", +"blue", "BP", "AOBP_2/2", +"blue", "BP", "AOBP Dias", +"blue", "BP", "AOBP Mean", +"blue", "BP", "AOBP Sys", +"blue", "BP", "NBP_1/2", +"blue", "BP", "NBP_2/2", +"blue", "BP", "NBP", +"blue", "BP", "NBPDias", +"blue", "BP", "NBPMean", +"blue", "BP", "NBPSys", +"blue", "BP", "ABP Dias", +"blue", "BP", "ABP Mean", +"blue", "BP", "ABP Sys", +"blue", "BP", "NBP Dias", +"blue", "BP", "NBP Mean", +"blue", "BP", "NBP Sys", +"blue", "BP", "ABP ", +"red", "ECG", "A-I", +"green", "Resp", "AIRFLOW", +"blue", "BP", "ART", +"blue", "BP", "ART_1/2", +"blue", "BP", "ART Dias", +"blue", "BP", "ART Mean", +"blue", "BP", "ART Sys", +"blue", "BP", "ART ", +"blue", "BP", "ART 1", +"blue", "BP", "ART1 ", +"blue", "BP", "ART^M ", +"red", "ECG", "A-S", +"red", "ECG", "avf", +"red", "ECG", "aVF", +"red", "ECG", "AVF", +"red", "ECG", "AVF+", +"red", "ECG", "avl", +"red", "ECG", "aVL", +"red", "ECG", "AVL", +"red", "ECG", "avr", +"red", "ECG", "aVR", +"red", "ECG", "AVR", +"darkgreen", "Temp", "BLOODT", +"darkgreen", "Temp", "BLOODT_1/3", +"darkgreen", "Temp", "BLOODT_2/3", +"darkgreen", "Temp", "BLOODT_3/3", +"blue", "BP", "BP", +"blue", "BP", " BP", +"pink", "noise", "BW noise, signal 0", +"pink", "noise", "BW noise, signal 1", +"darkred", "CO", "CO", +"darkred", "CO", "CO_1/2", +"darkred", "CO", "CO_1/3", +"darkred", "CO", "CO_2/2", +"darkred", "CO", "CO_2/3", +"darkred", "CO", "CO_3/3", +"purple", "CO2", "C02", +"blue", "BP", "CVP", +"blue", "BP", "CVP_1/2", +"blue", "BP", "CVP_1/3", +"blue", "BP", "CVP_2/2", +"blue", "BP", "CVP_2/3", +"blue", "BP", "CVP_3/3", +"red", "ECG", "CC5", +"red", "ECG", "chan 1", +"red", "ECG", "chan 2", +"red", "ECG", "chan 3", +"red", "ECG", "CM2", +"red", "ECG", "CM4", +"red", "ECG", "CM5", +"purple", "CO2", "Co2", +"purple", "CO2", "CO2", +"purple", "CO2", "CO2^M ", +"red", "ECG", "CS12", +"red", "ECG", "CS34", +"red", "ECG", "CS56", +"red", "ECG", "CS78", +"red", "ECG", "CS90", +"blue", "BP", "CVP", +"blue", "BP", "CVP 3", +"red", "ECG", "D3", +"red", "ECG", "D4", +"red", "ECG", "ECG", +"red", "ECG", " ECG", +"red", "ECG", "ECG0", +"red", "ECG", "ECG1", +"red", "ECG", "ECG 1", +"red", "ECG", "ECG 2", +"red", "ECG", "ECG 3", +"red", "ECG", "ECG AVF", +"red", "ECG", "ECG [ECG1]", +"red", "ECG", "ECG F", +"red", "ECG", "ECG I", +"red", "ECG", "ECG II", +"red", "ECG", "ECG III", +"red", "ECG", "ECG lead 1", +"red", "ECG", "ECG lead 2", +"red", "ECG", "ECG lead 3", +"red", "ECG", "ECG Lead AVF", +"red", "ECG", "ECG lead AVL", +"red", "ECG", "ECG lead I", +"red", "ECG", "ECG Lead I", +"red", "ECG", "ECG lead II", +"red", "ECG", "ECG lead II ", +"red", "ECG", "ECG LeadII", +"red", "ECG", "ECG Lead II", +"red", "ECG", "ECG lead III", +"red", "ECG", "ECG Lead III", +"red", "ECG", "ECG lead V", +"red", "ECG", "ECG Lead V", +"red", "ECG", "ECG Lead V ", +"red", "ECG", "ECG Lead V3", +"red", "ECG", "ECG Lead V4", +"red", "ECG", "ECG lead V5", +"red", "ECG", "ECG Lead V5", +"red", "ECG", "ECG lead V6", +"red", "ECG", "ECG MCL", +"red", "ECG", "ECG signal 0", +"red", "ECG", "ECG signal 1", +"red", "ECG", "ECG V", +"red", "ECG", "ECG V3", +"red", "ECG", "ECG V Lead", +"grey", "Annot", "EDF Annotations", +"yellow", "EEG", "EEG", +"yellow", "EEG", "EEG C3-A2 [C3A2]", +"yellow", "EEG", "EEG (C3-O1)", +"yellow", "EEG", "EEG (C4-A1)", +"yellow", "EEG", "EEG C4-A1 [C4A1]", +"yellow", "EEG", "EEG Fpz-Cz", +"yellow", "EEG", "EEG (O2-A1)", +"yellow", "EEG", "EEG Pz-Oz", +"yellow", "EEG", "EEG(sec)", +"orange", "EMG", "EMG", +"orange", "EMG", "EMG-Chin [EMYG]", +"orange", "EMG", "EMG submental", +"orange", "EMG", "EMG Submental", +"pink", "noise", "EM noise, signal 0", +"pink", "noise", "EM noise, signal 1", +"lightblue", "EOG", "EOG", +"lightblue", "EOG", "EOG E1-A1 [EOGL]", +"lightblue", "EOG", "EOG E2-A1 [EOGR]", +"lightblue", "EOG", "EOG horizontal", +"lightblue", "EOG", "EOG(L)", +"lightblue", "EOG", "EOG(R)", +"lightblue", "EOG", "EOG (right)", +"red", "ECG", "E-S", +"grey", "Annot", "Event marker", +"green", "Resp", "Flow [AFLO]", +"grey", "Annot", "Hypnogram", +"red", "ECG", "i", +"red", "ECG", "I", +"red", "ECG", "I ", +"red", "ECG", "I+", +"blue", "BP", "ICP", +"grey", "Annot", "ID+Sync+Error", +"red", "ECG", "ii", +"red", "ECG", "II", +"red", "ECG", "II ", +"red", "ECG", "II+", +"red", "ECG", "iii", +"red", "ECG", "III", +"red", "ECG", "III ", +"red", "ECG", "III+", +"blue", "BP", "LAP", +"red", "ECG", "lead I", +"red", "ECG", "lead II", +"red", "ECG", "lead V", +"pink", "noise", "MA noise, signal 0", +"pink", "noise", "MA noise, signal 1", +"red", "ECG", "MCL1", +"red", "ECG", "MCL1 ", +"red", "ECG", "MCL1+", +"red", "ECG", "ML2", +"red", "ECG", "ML5", +"red", "ECG", "MLI", +"red", "ECG", "MLII", +"red", "ECG", "MLIII", +"red", "ECG", "mod.V1", +"red", "ECG", "MV2", +"red", "ECG", "MV2 ", +"blue", "BP", "P1", +"blue", "BP", "P1 Dias", +"blue", "BP", "P1 Mean", +"blue", "BP", "P1 Sys", +"blue", "BP", "PA", +"blue", "BP", "PAP", +"blue", "BP", "PAP_1/2", +"blue", "BP", "PAP_2/2", +"blue", "BP", "PAP ", +"blue", "BP", "PAP Dias", +"blue", "BP", "PAP Mean", +"blue", "BP", "PAP Sys", +"blue", "BP", "PAP 2", +"blue", "BP", "PAWP", +"blue", "BP", "PAWP_1/2", +"blue", "BP", "PAWP_1/3", +"blue", "BP", "PAWP_2/2", +"blue", "BP", "PAWP_2/3", +"blue", "BP", "PAWP_3/3", +"darkblue", "PLETH", "PLETH", +"darkblue", "PLETH", "PLETH ", +"grey", "Pos", "Position", +"orangered", "HR", "HR", +"orangered", "HR", "HR_1/2", +"orangered", "HR", "HR_1/3", +"orangered", "HR", "HR_2/2", +"orangered", "HR", "HR_2/3", +"orangered", "HR", "HR_3/3", +"orangered", "HR", "PR", +"blue", "BP", "Pressure", +"blue", "BP", "Pressure ", +"blue", "BP", "Pressure1", +"blue", "BP", "Pressure 1", +"blue", "BP", "Pressure 2", +"blue", "BP", "Pressure 3", +"blue", "BP", "Pressure 4", +"orangered", "HR", "Pulse", +"orangered", "HR", "PULSE", +"orangered", "HR", "PULSE_1/2", +"orangered", "HR", "PULSE_1/3", +"orangered", "HR", "PULSE_2/2", +"orangered", "HR", "PULSE_2/3", +"orangered", "HR", "PULSE_3/3", +"orangered", "HR", "PVC Rate per Minute", +"orangered", "HR", "PVC Rate per Minute_1/2", +"orangered", "HR", "PVC Rate per Minute_1/3", +"orangered", "HR", "PVC Rate per Minute_2/3", +"orangered", "HR", "PVC Rate per Minute_3/3", +"blue", "BP", "RAP", +"green", "Resp", "RESP", +"green", "Resp", "RESP_1/2", +"green", "Resp", "RESP_1/3", +"green", "Resp", "RESP_2/2", +"green", "Resp", "RESP_2/3", +"green", "Resp", "RESP_3/3", +"green", "Resp", " RESP", +"green", "Resp", "RESP ", +"green", "Resp", "Resp A", +"green", "Resp", "Resp (abdomen)", +"green", "Resp", "Resp (abdominal)", +"green", "Resp", "Resp C", +"green", "Resp", "Resp (chest)", +"green", "Resp", "Resp Imp", +"green", "Resp", "Resp. Imp.", +"green", "Resp", "Resp.Imp.", +"green", "Resp", "RESP IMP", +"green", "Resp", "Resp Inp.", +"green", "Resp", "Resp N", +"green", "Resp", "Resp (nasal)", +"green", "Resp", "Resp oro-nasal", +"green", "Resp", "Resp (sum)", +"darkred", "O2", "SaO2", +"darkred", "O2", "SaO2 [OSAT]", +"darkred", "O2", "SO2", +"grey", "Sound", "Sound", +"darkred", "O2", "SpO2", +"darkred", "O2", "SpO2_1/2", +"darkred", "O2", "SpO2_1/3", +"darkred", "O2", "SpO2_2/2", +"darkred", "O2", "SpO2_2/3", +"darkred", "O2", "SpO2_3/3", +"green", "Resp", "Sum", +"magenta", "SV", "SV", +"darkgreen", "Temp", "Temp body", +"green", "Resp", "Thorax_1", +"green", "Resp", "Thorax_2", +"green", "Resp", "Thorax [CHMV]", +"green", "Resp", "THOR RES", +"blue", "BP", "UAP", +"blue", "BP", "UAP Dias", +"blue", "BP", "UAP Mean", +"blue", "BP", "UAP Sys", +"red", "ECG", "V", +"red", "ECG", "V ", +"red", "ECG", "V+", +"red", "ECG", "v1", +"red", "ECG", "V1", +"red", "ECG", "V1-V2", +"red", "ECG", "v2", +"red", "ECG", "V2", +"red", "ECG", "V2-V3", +"red", "ECG", "v3", +"red", "ECG", "V3", +"red", "ECG", "v4", +"red", "ECG", "V4", +"red", "ECG", "V4-V5", +"red", "ECG", "v5", +"red", "ECG", "V5", +"red", "ECG", "v6", +"red", "ECG", "V6", +"red", "ECG", "vx", +"red", "ECG", "vy", +"red", "ECG", "vz", +NULL, NULL, NULL +}; diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/app/wfdbmap.c wfdb-10.5.10/app/wfdbmap.c --- wfdb-10.5.9/app/wfdbmap.c 1969-12-31 19:00:00.000000000 -0500 +++ wfdb-10.5.10/app/wfdbmap.c 2011-11-15 15:19:40.000000000 -0500 @@ -0,0 +1,472 @@ +/* file: wfdbmap.c G. Moody 22 March 2009 + Last revised: 15 November 2011 + +------------------------------------------------------------------------------- +wfdbmap: generates a 'plt' script to make a PostScript map of a WFDB record +Copyright (C) 2009-2011 George B. Moody + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA. + +You may contact the author by e-mail (george@mit.edu) or postal mail +(MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software, +please visit PhysioNet (http://www.physionet.org/). +_______________________________________________________________________________ + +The file signal-colors.h in this directory defines the colors used by wfdbmap. +*/ + +#include +#include +#include +#include +#include + +char *pname; +WFDB_Anninfo *ai = NULL; +WFDB_Siginfo *si = NULL; +int mflag = 0; +int spm; + +main(argc, argv) +int argc; +char *argv[]; +{ + char *record = NULL, *prog_name(); + int i, j, length, **map = NULL, nann = 0, nsig; + void help(); + void map_sig(char *record, WFDB_Siginfo *si, int nsig,int **map,int length); + void map_ann(char *record, WFDB_Anninfo *ai, int nann,int **map,int length); + void write_map(int **map, int nsig, int nann, int length); + void write_script(int **map, int nsig, int nann, int length); + + pname = prog_name(argv[0]); + + /* Interpret command-line options. */ + for (i = 1; i < argc; i++) { + if (*argv[i] == '-') switch (*(argv[i]+1)) { + case 'a': /* annotators follow */ + if (++i >= argc) { + (void)fprintf(stderr, "%s: annotators must follow -a\n", + pname); + exit(1); + } + /* how may annotators are there? */ + for (j = i; j < argc && *argv[j] != '-'; j++) + ; + nann = j - i; + /* allocate *ai and initialize it */ + if (nann > 0) { + if ((ai = malloc(nann * sizeof(WFDB_Anninfo))) == NULL) { + fprintf(stderr, "%s: insufficient memory\n", pname); + exit(2); + } + for (j = 0; j < nann; j++) { + ai[j].name = argv[i++]; + ai[j].stat = WFDB_READ; + } + } + i--; + break; + case 'h': /* print usage summary and quit */ + help(); + exit(0); + break; + case 'm': /* print map only */ + mflag = 1; + break; + case 'r': /* input record name follows */ + if (++i >= argc) { + (void)fprintf(stderr, + "%s: input record name must follow -r\n", + pname); + exit(1); + } + record = argv[i]; + break; + default: + (void)fprintf(stderr, "%s: unrecognized option %s\n", + pname, argv[i]); + exit(1); + } + else { + (void)fprintf(stderr, "%s: unrecognized argument %s\n", + pname, argv[i]); + exit(1); + } + } + if (record == NULL) { + help(); + exit(1); + } + + nsig = isigopen(record, NULL, 0); + if (nsig > 0) { + if ((si = malloc(nsig * sizeof(WFDB_Siginfo))) == NULL) { + fprintf(stderr, "%s: insufficient memory\n", pname); + if (ai) { wfdbquit(); free(ai); } + exit(2); + } + if ((nsig = isigopen(record, si, nsig)) < 0) + nsig = 0; + } + spm = strtim("60"); + length = (strtim("e") + (spm-1))/spm; /* number of minutes in record */ + + if (length < 1 && nsig > 0) { + /* calculate the length of the record from the signal file size */ + char *p; + double fs = 0; + FILE *ifile; + long bpm; + + for (i = 0; i < nsig && si[i].group == 0; i++) + switch (si[i].fmt) { + case 8: + case 80: fs += si[i].spf; break; + case 310: + case 311: fs += 1.33333333*si[i].spf; break; + case 212: fs += 1.5*si[i].spf; break; + default: fs += 2*si[i].spf; break; + } + bpm = fs * spm + 0.5; /* bytes per minute */ + p = wfdbfile(si[i].fname, NULL); + ifile = fopen(p, "r"); + fseek(ifile, 0L, SEEK_END); + length = ftell(ifile)/bpm; + fclose(ifile); + } + + if (length < 1) { /* try to get length from annotation file(s) */ + int alen; + WFDB_Annotation annot; + WFDB_Time t; + + for (i = 0; i < nann; i++) { + if (annopen(record, &ai[i], 1) < 0) continue; + while (getann(0, &annot) >= 0) + t = annot.time; + alen = (t + (spm-1))/spm; + if (alen > length) length = alen; + } + } + + if (length > 60000) /* 1000 hours > 41 days */ + length = 60000; /* truncate extremely long records */ + + if (length < 1) { + fprintf(stderr, "%s: can't map record %s (length unspecified)\n", + pname, record); + exit(1); + } + + if ((map = malloc((nsig + 4*nann) * sizeof(int *))) == NULL) { + fprintf(stderr, "%s: insufficient memory\n", pname); + wfdbquit(); + if (ai) free(ai); + if (si) free(si); + exit(2); + } + for (i = 0; i < nsig + 4*nann; i++) + if ((map[i] = calloc(length, sizeof(int))) == NULL) { + fprintf(stderr, "%s: insufficient memory\n", pname); + while (--i > 0) + if (map[i]) free(map[i]); + free(map); + wfdbquit(); + if (ai) free(ai); + if (si) free(si); + exit(2); + } + + if (nsig > 0) map_sig(record, si, nsig, map, length); + if (nann > 0) map_ann(record, ai, nann, &map[nsig], length); + + if (mflag) { + printf("T"); + for (i = 0; i < nsig; i++) + printf("\t%s", si[i].desc); + for (i = 0; i < nann; i++) + printf("\t%s\tQRS\tEctopic\tVE", ai[i].name); + printf("\n"); + write_map(map, nsig, nann, length); + } + else + write_script(map, nsig, nann, length); + + for (i = 0; i < nsig + 4*nann; i++) + free(map[i]); + free(map); + wfdbquit(); + if (ai) free(ai); + if (si) free(si); + + exit(0); +} + +void map_sig(char *record, WFDB_Siginfo *si, int nsig, int **map, int length) +{ + if (si[0].nsamp == strtim("e") || si[0].nsamp != 0) { + /* fixed-layout record */ + int i, t; + for (i = 0; i < nsig; i++) + for (t = 0; t < length; t++) + map[i][t] = 1; + } + else { /* variable-layout record */ + char buf[256], *d, *p, *q, *r, *hfname, *shfname; + long m, m0, mf, spm = strtim("60"), t = 0, tf; + WFDB_FILE *ifile, *sfile; + + p = wfdbfile("hea", record); + hfname = calloc(strlen(p) + 1, 1); + strcpy(hfname, p); + if ((ifile = wfdb_fopen(hfname, "r")) == NULL) { + fprintf(stderr, "%s: can't open %s\n", pname, hfname); + free(hfname); + return; + } + for (d = p + strlen(p); d > p; d--) + if (*(d-1) == '/') { + *d = '\0'; + break; + } + shfname = calloc(strlen(hfname) + 16, 1); + strcpy(shfname, p); + d = shfname + strlen(shfname); /* d points to first char after '/' */ + wfdb_fgets(buf, sizeof(buf), ifile); /* read and ignore two lines */ + wfdb_fgets(buf, sizeof(buf), ifile); + + m0 = 0; + while (wfdb_fgets(buf, sizeof(buf), ifile)) {/* read a segment desc */ + char *tp; + + if (buf[0] == '~') { /* segment is null (all signals off) */ + t += atol(buf+2); + m0 = t/spm; + continue; + } + for (tp = buf+1; *tp != ' '; tp++) + ; + *tp = '\0'; + tf = t + atol(tp+1); + if ((mf = tf/spm) > length) mf = length; + sprintf(d, "%s.hea", buf); + if (sfile = wfdb_fopen(shfname, "r")) {/* open the segment header */ + char sbuf[256]; + int i; + + wfdb_fgets(sbuf, sizeof(sbuf), sfile);/* read & ignore a line */ + + while ((p = wfdb_fgets(sbuf, sizeof(sbuf), sfile)) && + *sbuf != '#') { + /* signal description line */ + for (q = sbuf, i = 0; *q; q++) + if (*q == ' ' && ++i == 8) break; + q++; + *(q + strlen(q) - 2) = '\0'; + for (i = 0; i < nsig; i++) + if (strcmp(si[i].desc, q) == 0) + for (m = m0; m < mf; m++) + map[i][m] = 1; + } + wfdb_fclose(sfile); + t = tf; + m0 = t/spm; + } + } + wfdb_fclose(ifile); + free(shfname); + free(hfname); + } +} + +int *namax; + +void map_ann(char *record, WFDB_Anninfo *ai, int nann, int **map, int length) +{ + int i; + + namax = malloc(nann * sizeof(int)); + wfdbquiet(); /* suppress warnings if an annotator can't be opened */ + for (i = 0; i < nann; i++) { + char tstring[10]; + int minutes, *na, *nq, *ne, *nv; + WFDB_Annotation annot; + WFDB_Time end_of_epoch; + + na = &map[4*i][0]; + namax[i] = 1; + + /* Open the annotators one at a time, and do not quit if any fail + to open. */ + if (annopen(record, &ai[i], 1) < 0) continue; + minutes = end_of_epoch = 0; + iannsettime(1L); + while (getann(0, &annot) >= 0) { + if (annot.time > end_of_epoch) { + if (*na > namax[i]) namax[i] = *na; + minutes = annot.time/spm; + na = &map[4*i][minutes]; + nq = &map[4*i + 1][minutes]; + ne = &map[4*i + 2][minutes]; + nv = &map[4*i + 3][minutes]; + if (++minutes > length) + break; /* stop at the end of the record */ + sprintf(tstring, "%d", 60*minutes); + end_of_epoch = strtim(tstring); + } + switch (annot.anntyp) { + case PVC: + case FUSION: + case VESC: + case RONT: + case FLWAV: (*nv)++; /* fall through, no break! */ + case APC: + case ABERR: + case NPC: + case SVPB: + case NESC: + case AESC: + case SVESC: (*ne)++; /* fall through, no break! */ + case NORMAL: + case LBBB: + case RBBB: + case PACE: + case UNKNOWN: + case BBB: + case LEARN: + case PFUS: (*nq)++; /* fall through, no break! */ + default: (*na)++; break; + } + } + if (*na > namax[i]) namax[i] = *na; + } + return; +} + +void write_map(int **map, int nsig, int nann, int length) +{ + int i, imax = nsig + 4*nann - 1, t; + + for (t = 0; t < length; t++) { + if (mflag == 0) printf("%d\t0\t", t); /* x0, y0 for histogram plots */ + printf("%d\t", t+1); + for (i = 0; i < imax; i++) + printf("%d\t", map[i][t]); + printf("%d\n", map[i][t]); + } +} + +#include "signal-colors.h" + +char *color(char *type) +{ + int i; + + for (i = 0; ctab[i].name != NULL; i++) + if (strcmp(type, ctab[i].name) == 0) return (ctab[i].color); + return ("grey"); +} + +void write_script(int **map, int nsig, int nann, int length) +{ + char *p, tstring[2][30]; + double ylow, ymax; + int i, j; + WFDB_Time tf = strtim("e"); + + strcpy(tstring[0], timstr(0)); + for (p = tstring[0]; *p == ' '; p++) + ; + if (tf) strcpy(tstring[1], timstr(-tf)); + else sprintf(tstring[1], "%d:%02d:00", length/60, length%60); + + ymax = 2*(nsig + 2*nann + 1); + ylow = 0.01 * ymax; + + printf("#! /bin/sh\n" + "cat >map.txt <= s && *p != '\\' && *p != ':') { + if (*p == '.') + *p = '\0'; /* strip off extension */ + if ('A' <= *p && *p <= 'Z') + *p += 'a' - 'A'; /* convert to lower case */ + p--; + } +#else + while (p >= s && *p != '/') + p--; +#endif + return (p+1); +} + +static char *help_strings[] = { + "usage: %s -r RECORD -a ANNOTATOR [OPTIONS ...]\n", + "where RECORD and ANNOTATOR specify the input, and OPTIONS may include:", + " -h print this usage summary", +NULL +}; + +void help() +{ + int i; + + (void)fprintf(stderr, help_strings[0], pname); + for (i = 1; help_strings[i] != NULL; i++) + (void)fprintf(stderr, "%s\n", help_strings[i]); +} diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/app/wfdbsignals.c wfdb-10.5.10/app/wfdbsignals.c --- wfdb-10.5.9/app/wfdbsignals.c 1969-12-31 19:00:00.000000000 -0500 +++ wfdb-10.5.10/app/wfdbsignals.c 2011-11-15 14:07:40.000000000 -0500 @@ -0,0 +1,89 @@ +/* file: wfdbsignals.c G. Moody June 1989 + Last revised: 15 November 2011 + +------------------------------------------------------------------------------- +wfdbdesc: List signals in a WFDB record +Copyright (C) 1989-2011 George B. Moody + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA. + +You may contact the author by e-mail (george@mit.edu) or postal mail +(MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software, +please visit PhysioNet (http://www.physionet.org/). +_______________________________________________________________________________ + +This program is a drastically pruned version of wfdbdesc. + +*/ + +#include +#include + +main(argc, argv) +int argc; +char *argv[]; +{ + char *info, *p, *pname, *prog_name(); + int i, msrec = 0, nsig; + FILE *ifile; + WFDB_Siginfo *s; + WFDB_Time t; + + pname = prog_name(argv[0]); + if (argc < 2) { + (void)fprintf(stderr, "usage: %s RECORD [-readable]\n", pname); + exit(1); + } + /* Discover the number of signals defined in the header. */ + if ((nsig = isigopen(argv[1], NULL, 0)) < 0) exit(2); + + /* Allocate storage for nsig signal information structures. */ + if (nsig > 0 && (s = malloc(nsig * sizeof(WFDB_Siginfo))) == NULL) { + fprintf(stderr, "%s: insufficient memory\n", pname); + exit(2); + } + + /* If the `-readable' option is given, report only on signals which can + be opened. Otherwise, report on all signals named in the header file, + without attempting to open them. */ + if (nsig > 0 && argc > 2 && + strncmp(argv[2], "-readable", strlen(argv[2])) == 0) + nsig = isigopen(argv[1], s, nsig); + else if (nsig > 0) + nsig = isigopen(argv[1], s, -nsig); + + for (i = 0; i < nsig; i++) + (void)printf("%s\n", s[i].desc); + exit(0); /*NOTREACHED*/ +} + +char *prog_name(s) +char *s; +{ + char *p = s + strlen(s); + +#ifdef MSDOS + while (p >= s && *p != '\\' && *p != ':') { + if (*p == '.') + *p = '\0'; /* strip off extension */ + if ('A' <= *p && *p <= 'Z') + *p += 'a' - 'A'; /* convert to lower case */ + p--; + } +#else + while (p >= s && *p != '/') + p--; +#endif + return (p+1); +} diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/doc/wag-src/maketoc-tex.sh wfdb-10.5.10/doc/wag-src/maketoc-tex.sh --- wfdb-10.5.9/doc/wag-src/maketoc-tex.sh 2002-10-29 15:29:41.000000000 -0500 +++ wfdb-10.5.10/doc/wag-src/maketoc-tex.sh 2011-11-16 14:08:19.000000000 -0500 @@ -1,6 +1,6 @@ #! /bin/sh # file: maketoc-tex.sh G. Moody 29 October 2002 -# +# Last revised: 16 November 2011 # Generate the table of contents and appendices for the WFDB Applications Guide prep() @@ -17,7 +17,7 @@ { P=`grep '%%Pages: ' >wag2.ps; P=`expr $P + 2`;; + *[13579]) cat wag2.ps blankpage >wag2b.ps; P=`expr $P + 2`;; *) P=`expr $P + 1`;; esac sed s/FIRSTPAGE/$P/ install.tex @@ -25,7 +25,7 @@ N=`grep '%%Pages: ' >wag3.ps; Q=`expr $Q + 1`;; + *[02468]) cat wag3.ps blankpage >wag3b.ps; Q=`expr $Q + 1`;; esac sed s/FIRSTPAGE/$Q/ eval.tex make wag4.ps @@ -45,6 +45,15 @@ head -$N1 >toc-log.$$ 2>&1 +if [ -e wag2b.ps ] +then + mv -f wag2b.ps wag2.ps +fi +if [ -e wag3b.ps ] +then + mv -f wag3b.ps wag3.ps +fi + cat <info.fmt == 0) ig->fp = NULL; /* Don't open a file for a null signal. */ else { - ig->fp = wfdb_open(hs->info.fname, (char *)NULL, WFDB_READ); + strcpy(filename, hs->info.fname); + ig->fp = wfdb_open(fullname, (char *)NULL, WFDB_READ); /* Skip this group if the signal file can't be opened. */ if (ig->fp == NULL) { SFREE(ig->buf); @@ -2010,6 +2023,7 @@ } g++; } + free(fullname); /* Produce a warning message if none of the requested signals could be opened. */ @@ -2032,7 +2046,6 @@ gvc = ispfmax; /* Initialize getvec's sample-within-frame counter. */ nisig += s; /* Update the count of open input signals. */ nigroups += g; /* Update the count of open input signal groups. */ - if (sigmap_init() < 0) return (-1); diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/lib/wfdb.h wfdb-10.5.10/lib/wfdb.h --- wfdb-10.5.9/lib/wfdb.h 2011-08-05 17:06:03.000000000 -0400 +++ wfdb-10.5.10/lib/wfdb.h 2011-11-16 14:51:34.000000000 -0500 @@ -32,7 +32,7 @@ /* WFDB library version. */ #define WFDB_MAJOR 10 #define WFDB_MINOR 5 -#define WFDB_RELEASE 9 +#define WFDB_RELEASE 10 #define WFDB_NETFILES 1 /* if 1, library includes code for HTTP, FTP clients */ #define WFDB_NETFILES_LIBCURL 1 diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/lib/wfdbio.c wfdb-10.5.10/lib/wfdbio.c --- wfdb-10.5.9/lib/wfdbio.c 2010-12-16 19:04:25.000000000 -0500 +++ wfdb-10.5.10/lib/wfdbio.c 2011-11-07 10:09:32.000000000 -0500 @@ -1,10 +1,10 @@ /* file: wfdbio.c G. Moody 18 November 1988 - Last revised: 16 December 2010 wfdblib 10.5.7 + Last revised: 7 November 2011 wfdblib 10.5.10 Low-level I/O functions for the WFDB library _______________________________________________________________________________ wfdb: a library for reading and writing annotated waveforms (time series data) -Copyright (C) 1988-2010 George B. Moody +Copyright (C) 1988-2011 George B. Moody This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free @@ -1214,6 +1214,10 @@ static void www_init(void) { if (!www_done_init) { + char *p, version[20]; + + if ((p = getenv("WFDB_PAGESIZE")) && *p) page_size = atol(p); + #if WFDB_NETFILES_LIBCURL /* Initialize the curl "easy" handle. */ curl_global_init(CURL_GLOBAL_ALL); @@ -1233,8 +1237,6 @@ information from libcurl) */ /* curl_easy_setopt(curl_ua, CURLOPT_VERBOSE, 1L); */ #else - char *p; - char version[20]; #ifdef USEHTCACHE char *cachedir = CACHEDIR; /* root of the netfile data cache */ @@ -1245,7 +1247,6 @@ if ((p = getenv("WFDB_CACHESIZE")) && *p) cachesize = atoi(p); if ((p = getenv("WFDB_CACHEENTRYSIZE")) && *p) entrysize = atoi(p); #endif - if ((p = getenv("WFDB_PAGESIZE")) && *p) page_size = atol(p); sprintf(version, "%d.%d.%d", WFDB_MAJOR, WFDB_MINOR, WFDB_RELEASE); HTProfile_newPreemptiveClient("WFDB", version); HTAlert_setInteractive(NO); diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/MANIFEST wfdb-10.5.10/MANIFEST --- wfdb-10.5.9/MANIFEST 2010-11-04 10:38:16.000000000 -0400 +++ wfdb-10.5.10/MANIFEST 2011-11-15 15:53:08.000000000 -0500 @@ -11,6 +11,7 @@ app/Makefile app/Makefile.top app/Makefile.tpl +app/map-record app/mfilt.c app/mrgann.c app/mxm.c @@ -31,6 +32,7 @@ app/setwfdb app/sigamp.c app/sigavg.c +app/signal-colors.h app/signame.c app/signum.c app/skewedit.c @@ -47,6 +49,8 @@ app/wfdbcollate.c app/wfdb-config.c app/wfdbdesc.c +app/wfdbmap.c +app/wfdbsignals.c app/wfdbtime.c app/wfdbwhich.c app/wqrs.c @@ -345,6 +349,7 @@ doc/wag-src/wfdb-config.1 doc/wag-src/wfdbdesc.1 doc/wag-src/wfdbf.3 +doc/wag-src/wfdbmap.1 doc/wag-src/wfdbtime.1 doc/wag-src/wfdbwhich.1 doc/wag-src/wqrs.1 @@ -575,12 +580,6 @@ wave/xview-patches wave/xvwave.c wave/xvwave.h -wfdbmap -wfdbmap/Makefile -wfdbmap/map-record -wfdbmap/README -wfdbmap/signal-colors.h -wfdbmap/wfdbmap.c wfdb.spec xml xml/annxml.c diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/NEWS wfdb-10.5.10/NEWS --- wfdb-10.5.9/NEWS 2011-09-10 15:06:37.000000000 -0400 +++ wfdb-10.5.10/NEWS 2011-11-16 14:55:48.573806584 -0500 @@ -1,3 +1,29 @@ +10.5.10 (15 November 2011): + The WFDB library function isigopen(), in lib/signal.c, searches each + component of the WFDB path for the signal file(s) named in the + associated header file, until a match is found. Since signal files are + usually located in the same directories as header files, they can be + located most quickly by looking first in those directories. Thanks to + David Brooks for suggesting this optimization and for a sample + implementation. + + Attempts to set the default size for HTTP range requests (using the + environment variable WFDB_PAGESIZE) were ignored in previous versions + of the WFDB library when compiled with libcurl. Thanks again to David + for noting this limitation, which has been eliminated in this release + by a change in www_init() (in lib/wfdbio.c). + + 'wfdbmap', which has been available in its own directory since release + 10.5.6, is a now a standard application (app/wfdbmap.c). 'wfdbmap' is + used by the PhysioBank ATM to produce compact synoptic maps of WFDB- + compatible records. Previous versions of 'wfdbmap' were unable to map + multi-segment records unless all segment headers were local; this + limitation has been removed in this release. + + This release also includes 'wfdbsignals' (app/wfdbsignals.c), used by + the PhysioBank ATM to list the signals in a WFDB record. 'wfdbsignals' + is a stripped-down version of 'wfdbdesc'. + 10.5.9 (10 September 2011): When an application passes an array containing WFDB_INVALID_SAMPLE values to putvec(), the function translates these into the diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/wfdbmap/map-record wfdb-10.5.10/wfdbmap/map-record --- wfdb-10.5.9/wfdbmap/map-record 2010-07-30 15:37:34.000000000 -0400 +++ wfdb-10.5.10/wfdbmap/map-record 1969-12-31 19:00:00.000000000 -0500 @@ -1,12 +0,0 @@ -#! /bin/bash - -# make a map of a WFDB record - -RL=$1 -RS=`basename $RL` -shift - -wfdbmap -r $RL $* >$RS.script -bash $RS.script >$RS.plt 2>/dev/null -lwcat -strip -eps $RS.plt >$RS.ps -convert -density 150 $RS.ps $RS.png diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/wfdbmap/README wfdb-10.5.10/wfdbmap/README --- wfdb-10.5.9/wfdbmap/README 2010-11-04 10:28:34.000000000 -0400 +++ wfdb-10.5.10/wfdbmap/README 1969-12-31 19:00:00.000000000 -0500 @@ -1,38 +0,0 @@ -file: README G. Moody 30 July 2010 - -Software for creating 'maps' of PhysioBank records - -To build and install the software in this directory, first install the -WFDB and plt software packages from PhysioNet, ImageMagick (from -www.imagemagick.org), then return to this directory and type 'make'. - -This directory contains 'wfdbmap', a program that reads a WFDB record, -optionally including one or more associated annotation files, and generates a -script containing embedded data. When the script is run, it creates (using -'plt' and 'lwcat', from the plt package) a PostScript-format 'map' of the WFDB -record and its annotations. The maps displayed by the PhysioBank ATM are -created in this way. - -Also in this directory is 'map-record', a shell script that illustrates how -'wfdbmap' and (indirectly) 'plt are used to create a map, and how to convert -the PostScript map into a PNG-format map (using 'convert' from ImageMagick). -For example, to make a map of mitdb/200 and its associated 'atr' annotations, -run the command: - map-record mitdb/200 -a atr -The outputs of this command are 200.ps and 200.png. If other annotation files -are available, their annotator names can be given as additional command-line -arguments: - map-record RECORD -a ANN1 ANN2 ANN3 ... - -*** A MAJOR LIMITATION of this version of wfdbmap is that it cannot properly -map segments of a variable-layout multisegment record unless all of the -.hea files for that record are local (i.e., they can't be retrieved from a -web server as needed). For the ATM, this is not a limitation at all, since -the ATM is mapping local records on physionet.org. For general use, it's -a serious limitation, since variable-layout multisegment records are often -the records for which a map would be most useful. - -The symptoms of this problem are a warning message of the form: - wfdbmap: can't open http://physionet.org/physiobank/database/... -and an output map that shows all signals as missing. (The annotations are -mapped properly, however.) diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/wfdbmap/signal-colors.h wfdb-10.5.10/wfdbmap/signal-colors.h --- wfdb-10.5.9/wfdbmap/signal-colors.h 2009-04-09 16:44:18.000000000 -0400 +++ wfdb-10.5.10/wfdbmap/signal-colors.h 1969-12-31 19:00:00.000000000 -0500 @@ -1,311 +0,0 @@ -struct sigcolor { - char *color; - char *class; - char *name; -} ctab[] = { -"red", "ECG", "Abdomen_1", -"red", "ECG", "Abdomen_2", -"red", "ECG", "Abdomen_3", -"red", "ECG", "Abdomen_4", -"green", "Resp", "Abdomen [ABMV]", -"green", "Resp", "ABDO RES", -"blue", "BP", "ABP", -"blue", "BP", "ABP_1/2", -"blue", "BP", "ABP_2/2", -"blue", "BP", "ABPDias", -"blue", "BP", "ABPMean", -"blue", "BP", "ABPSys", -"blue", "BP", "AOBP", -"blue", "BP", "AOBP_1/2", -"blue", "BP", "AOBP_2/2", -"blue", "BP", "AOBP Dias", -"blue", "BP", "AOBP Mean", -"blue", "BP", "AOBP Sys", -"blue", "BP", "NBP_1/2", -"blue", "BP", "NBP_2/2", -"blue", "BP", "NBP", -"blue", "BP", "NBPDias", -"blue", "BP", "NBPMean", -"blue", "BP", "NBPSys", -"blue", "BP", "ABP Dias", -"blue", "BP", "ABP Mean", -"blue", "BP", "ABP Sys", -"blue", "BP", "NBP Dias", -"blue", "BP", "NBP Mean", -"blue", "BP", "NBP Sys", -"blue", "BP", "ABP ", -"red", "ECG", "A-I", -"green", "Resp", "AIRFLOW", -"blue", "BP", "ART", -"blue", "BP", "ART_1/2", -"blue", "BP", "ART Dias", -"blue", "BP", "ART Mean", -"blue", "BP", "ART Sys", -"blue", "BP", "ART ", -"blue", "BP", "ART 1", -"blue", "BP", "ART1 ", -"blue", "BP", "ART^M ", -"red", "ECG", "A-S", -"red", "ECG", "avf", -"red", "ECG", "aVF", -"red", "ECG", "AVF", -"red", "ECG", "AVF+", -"red", "ECG", "avl", -"red", "ECG", "aVL", -"red", "ECG", "AVL", -"red", "ECG", "avr", -"red", "ECG", "aVR", -"red", "ECG", "AVR", -"darkgreen", "Temp", "BLOODT", -"darkgreen", "Temp", "BLOODT_1/3", -"darkgreen", "Temp", "BLOODT_2/3", -"darkgreen", "Temp", "BLOODT_3/3", -"blue", "BP", "BP", -"blue", "BP", " BP", -"pink", "noise", "BW noise, signal 0", -"pink", "noise", "BW noise, signal 1", -"darkred", "CO", "CO", -"darkred", "CO", "CO_1/2", -"darkred", "CO", "CO_1/3", -"darkred", "CO", "CO_2/2", -"darkred", "CO", "CO_2/3", -"darkred", "CO", "CO_3/3", -"purple", "CO2", "C02", -"blue", "BP", "CVP", -"blue", "BP", "CVP_1/2", -"blue", "BP", "CVP_1/3", -"blue", "BP", "CVP_2/2", -"blue", "BP", "CVP_2/3", -"blue", "BP", "CVP_3/3", -"red", "ECG", "CC5", -"red", "ECG", "chan 1", -"red", "ECG", "chan 2", -"red", "ECG", "chan 3", -"red", "ECG", "CM2", -"red", "ECG", "CM4", -"red", "ECG", "CM5", -"purple", "CO2", "Co2", -"purple", "CO2", "CO2", -"purple", "CO2", "CO2^M ", -"red", "ECG", "CS12", -"red", "ECG", "CS34", -"red", "ECG", "CS56", -"red", "ECG", "CS78", -"red", "ECG", "CS90", -"blue", "BP", "CVP", -"blue", "BP", "CVP 3", -"red", "ECG", "D3", -"red", "ECG", "D4", -"red", "ECG", "ECG", -"red", "ECG", " ECG", -"red", "ECG", "ECG0", -"red", "ECG", "ECG1", -"red", "ECG", "ECG 1", -"red", "ECG", "ECG 2", -"red", "ECG", "ECG 3", -"red", "ECG", "ECG AVF", -"red", "ECG", "ECG [ECG1]", -"red", "ECG", "ECG F", -"red", "ECG", "ECG I", -"red", "ECG", "ECG II", -"red", "ECG", "ECG III", -"red", "ECG", "ECG lead 1", -"red", "ECG", "ECG lead 2", -"red", "ECG", "ECG lead 3", -"red", "ECG", "ECG Lead AVF", -"red", "ECG", "ECG lead AVL", -"red", "ECG", "ECG lead I", -"red", "ECG", "ECG Lead I", -"red", "ECG", "ECG lead II", -"red", "ECG", "ECG lead II ", -"red", "ECG", "ECG LeadII", -"red", "ECG", "ECG Lead II", -"red", "ECG", "ECG lead III", -"red", "ECG", "ECG Lead III", -"red", "ECG", "ECG lead V", -"red", "ECG", "ECG Lead V", -"red", "ECG", "ECG Lead V ", -"red", "ECG", "ECG Lead V3", -"red", "ECG", "ECG Lead V4", -"red", "ECG", "ECG lead V5", -"red", "ECG", "ECG Lead V5", -"red", "ECG", "ECG lead V6", -"red", "ECG", "ECG MCL", -"red", "ECG", "ECG signal 0", -"red", "ECG", "ECG signal 1", -"red", "ECG", "ECG V", -"red", "ECG", "ECG V3", -"red", "ECG", "ECG V Lead", -"grey", "Annot", "EDF Annotations", -"yellow", "EEG", "EEG", -"yellow", "EEG", "EEG C3-A2 [C3A2]", -"yellow", "EEG", "EEG (C3-O1)", -"yellow", "EEG", "EEG (C4-A1)", -"yellow", "EEG", "EEG C4-A1 [C4A1]", -"yellow", "EEG", "EEG Fpz-Cz", -"yellow", "EEG", "EEG (O2-A1)", -"yellow", "EEG", "EEG Pz-Oz", -"yellow", "EEG", "EEG(sec)", -"orange", "EMG", "EMG", -"orange", "EMG", "EMG-Chin [EMYG]", -"orange", "EMG", "EMG submental", -"orange", "EMG", "EMG Submental", -"pink", "noise", "EM noise, signal 0", -"pink", "noise", "EM noise, signal 1", -"lightblue", "EOG", "EOG", -"lightblue", "EOG", "EOG E1-A1 [EOGL]", -"lightblue", "EOG", "EOG E2-A1 [EOGR]", -"lightblue", "EOG", "EOG horizontal", -"lightblue", "EOG", "EOG(L)", -"lightblue", "EOG", "EOG(R)", -"lightblue", "EOG", "EOG (right)", -"red", "ECG", "E-S", -"grey", "Annot", "Event marker", -"green", "Resp", "Flow [AFLO]", -"grey", "Annot", "Hypnogram", -"red", "ECG", "i", -"red", "ECG", "I", -"red", "ECG", "I ", -"red", "ECG", "I+", -"blue", "BP", "ICP", -"grey", "Annot", "ID+Sync+Error", -"red", "ECG", "ii", -"red", "ECG", "II", -"red", "ECG", "II ", -"red", "ECG", "II+", -"red", "ECG", "iii", -"red", "ECG", "III", -"red", "ECG", "III ", -"red", "ECG", "III+", -"blue", "BP", "LAP", -"red", "ECG", "lead I", -"red", "ECG", "lead II", -"red", "ECG", "lead V", -"pink", "noise", "MA noise, signal 0", -"pink", "noise", "MA noise, signal 1", -"red", "ECG", "MCL1", -"red", "ECG", "MCL1 ", -"red", "ECG", "MCL1+", -"red", "ECG", "ML2", -"red", "ECG", "ML5", -"red", "ECG", "MLI", -"red", "ECG", "MLII", -"red", "ECG", "MLIII", -"red", "ECG", "mod.V1", -"red", "ECG", "MV2", -"red", "ECG", "MV2 ", -"blue", "BP", "P1", -"blue", "BP", "P1 Dias", -"blue", "BP", "P1 Mean", -"blue", "BP", "P1 Sys", -"blue", "BP", "PA", -"blue", "BP", "PAP", -"blue", "BP", "PAP_1/2", -"blue", "BP", "PAP_2/2", -"blue", "BP", "PAP ", -"blue", "BP", "PAP Dias", -"blue", "BP", "PAP Mean", -"blue", "BP", "PAP Sys", -"blue", "BP", "PAP 2", -"blue", "BP", "PAWP", -"blue", "BP", "PAWP_1/2", -"blue", "BP", "PAWP_1/3", -"blue", "BP", "PAWP_2/2", -"blue", "BP", "PAWP_2/3", -"blue", "BP", "PAWP_3/3", -"darkblue", "PLETH", "PLETH", -"darkblue", "PLETH", "PLETH ", -"grey", "Pos", "Position", -"orangered", "HR", "HR", -"orangered", "HR", "HR_1/2", -"orangered", "HR", "HR_1/3", -"orangered", "HR", "HR_2/2", -"orangered", "HR", "HR_2/3", -"orangered", "HR", "HR_3/3", -"orangered", "HR", "PR", -"blue", "BP", "Pressure", -"blue", "BP", "Pressure ", -"blue", "BP", "Pressure1", -"blue", "BP", "Pressure 1", -"blue", "BP", "Pressure 2", -"blue", "BP", "Pressure 3", -"blue", "BP", "Pressure 4", -"orangered", "HR", "Pulse", -"orangered", "HR", "PULSE", -"orangered", "HR", "PULSE_1/2", -"orangered", "HR", "PULSE_1/3", -"orangered", "HR", "PULSE_2/2", -"orangered", "HR", "PULSE_2/3", -"orangered", "HR", "PULSE_3/3", -"orangered", "HR", "PVC Rate per Minute", -"orangered", "HR", "PVC Rate per Minute_1/2", -"orangered", "HR", "PVC Rate per Minute_1/3", -"orangered", "HR", "PVC Rate per Minute_2/3", -"orangered", "HR", "PVC Rate per Minute_3/3", -"blue", "BP", "RAP", -"green", "Resp", "RESP", -"green", "Resp", "RESP_1/2", -"green", "Resp", "RESP_1/3", -"green", "Resp", "RESP_2/2", -"green", "Resp", "RESP_2/3", -"green", "Resp", "RESP_3/3", -"green", "Resp", " RESP", -"green", "Resp", "RESP ", -"green", "Resp", "Resp A", -"green", "Resp", "Resp (abdomen)", -"green", "Resp", "Resp (abdominal)", -"green", "Resp", "Resp C", -"green", "Resp", "Resp (chest)", -"green", "Resp", "Resp Imp", -"green", "Resp", "Resp. Imp.", -"green", "Resp", "Resp.Imp.", -"green", "Resp", "RESP IMP", -"green", "Resp", "Resp Inp.", -"green", "Resp", "Resp N", -"green", "Resp", "Resp (nasal)", -"green", "Resp", "Resp oro-nasal", -"green", "Resp", "Resp (sum)", -"darkred", "O2", "SaO2", -"darkred", "O2", "SaO2 [OSAT]", -"darkred", "O2", "SO2", -"grey", "Sound", "Sound", -"darkred", "O2", "SpO2", -"darkred", "O2", "SpO2_1/2", -"darkred", "O2", "SpO2_1/3", -"darkred", "O2", "SpO2_2/2", -"darkred", "O2", "SpO2_2/3", -"darkred", "O2", "SpO2_3/3", -"green", "Resp", "Sum", -"magenta", "SV", "SV", -"darkgreen", "Temp", "Temp body", -"green", "Resp", "Thorax_1", -"green", "Resp", "Thorax_2", -"green", "Resp", "Thorax [CHMV]", -"green", "Resp", "THOR RES", -"blue", "BP", "UAP", -"blue", "BP", "UAP Dias", -"blue", "BP", "UAP Mean", -"blue", "BP", "UAP Sys", -"red", "ECG", "V", -"red", "ECG", "V ", -"red", "ECG", "V+", -"red", "ECG", "v1", -"red", "ECG", "V1", -"red", "ECG", "V1-V2", -"red", "ECG", "v2", -"red", "ECG", "V2", -"red", "ECG", "V2-V3", -"red", "ECG", "v3", -"red", "ECG", "V3", -"red", "ECG", "v4", -"red", "ECG", "V4", -"red", "ECG", "V4-V5", -"red", "ECG", "v5", -"red", "ECG", "V5", -"red", "ECG", "v6", -"red", "ECG", "V6", -"red", "ECG", "vx", -"red", "ECG", "vy", -"red", "ECG", "vz", -NULL, NULL, NULL -}; diff -Naur --exclude Makefile --exclude info wfdb-10.5.9/wfdbmap/wfdbmap.c wfdb-10.5.10/wfdbmap/wfdbmap.c --- wfdb-10.5.9/wfdbmap/wfdbmap.c 2009-03-30 02:22:56.000000000 -0400 +++ wfdb-10.5.10/wfdbmap/wfdbmap.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,469 +0,0 @@ -/* file: wfdbmap.c G. Moody 22 March 2009 - Last revised: 30 March 2009 - -------------------------------------------------------------------------------- -wfdbmap: generates a 'plt' script to make a PostScript map of a WFDB record -Copyright (C) 2009 George B. Moody - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; either version 2 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place - Suite 330, Boston, MA 02111-1307, USA. - -You may contact the author by e-mail (george@mit.edu) or postal mail -(MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software, -please visit PhysioNet (http://www.physionet.org/). -_______________________________________________________________________________ - -*/ - -#include -#include -#include -#include - -char *pname; -WFDB_Anninfo *ai = NULL; -WFDB_Siginfo *si = NULL; -int mflag = 0; -int spm; - -main(argc, argv) -int argc; -char *argv[]; -{ - char *record = NULL, *prog_name(); - int i, j, length, **map = NULL, nann = 0, nsig; - void help(); - void map_sig(char *record, WFDB_Siginfo *si, int nsig,int **map,int length); - void map_ann(char *record, WFDB_Anninfo *ai, int nann,int **map,int length); - void write_map(int **map, int nsig, int nann, int length); - void write_script(int **map, int nsig, int nann, int length); - - pname = prog_name(argv[0]); - - /* Interpret command-line options. */ - for (i = 1; i < argc; i++) { - if (*argv[i] == '-') switch (*(argv[i]+1)) { - case 'a': /* annotators follow */ - if (++i >= argc) { - (void)fprintf(stderr, "%s: annotators must follow -a\n", - pname); - exit(1); - } - /* how may annotators are there? */ - for (j = i; j < argc && *argv[j] != '-'; j++) - ; - nann = j - i; - /* allocate *ai and initialize it */ - if (nann > 0) { - if ((ai = malloc(nann * sizeof(WFDB_Anninfo))) == NULL) { - fprintf(stderr, "%s: insufficient memory\n", pname); - exit(2); - } - for (j = 0; j < nann; j++) { - ai[j].name = argv[i++]; - ai[j].stat = WFDB_READ; - } - } - i--; - break; - case 'h': /* print usage summary and quit */ - help(); - exit(0); - break; - case 'm': /* print map only */ - mflag = 1; - break; - case 'r': /* input record name follows */ - if (++i >= argc) { - (void)fprintf(stderr, - "%s: input record name must follow -r\n", - pname); - exit(1); - } - record = argv[i]; - break; - default: - (void)fprintf(stderr, "%s: unrecognized option %s\n", - pname, argv[i]); - exit(1); - } - else { - (void)fprintf(stderr, "%s: unrecognized argument %s\n", - pname, argv[i]); - exit(1); - } - } - if (record == NULL) { - help(); - exit(1); - } - - nsig = isigopen(record, NULL, 0); - if (nsig > 0) { - if ((si = malloc(nsig * sizeof(WFDB_Siginfo))) == NULL) { - fprintf(stderr, "%s: insufficient memory\n", pname); - if (ai) { wfdbquit(); free(ai); } - exit(2); - } - if ((nsig = isigopen(record, si, nsig)) < 0) - nsig = 0; - } - spm = strtim("60"); - length = (strtim("e") + (spm-1))/spm; /* number of minutes in record */ - - if (length < 1 && nsig > 0) { - /* calculate the length of the record from the signal file size */ - char *p; - double fs = 0; - FILE *ifile; - long bpm; - - for (i = 0; i < nsig && si[i].group == 0; i++) - switch (si[i].fmt) { - case 8: - case 80: fs += si[i].spf; break; - case 310: - case 311: fs += 1.33333333*si[i].spf; break; - case 212: fs += 1.5*si[i].spf; break; - default: fs += 2*si[i].spf; break; - } - bpm = fs * spm + 0.5; /* bytes per minute */ - p = wfdbfile(si[i].fname, NULL); - ifile = fopen(p, "r"); - fseek(ifile, 0L, SEEK_END); - length = ftell(ifile)/bpm; - fclose(ifile); - } - - if (length < 1) { /* try to get length from annotation file(s) */ - int alen; - WFDB_Annotation annot; - WFDB_Time t; - - for (i = 0; i < nann; i++) { - if (annopen(record, &ai[i], 1) < 0) continue; - while (getann(0, &annot) >= 0) - t = annot.time; - alen = (t + (spm-1))/spm; - if (alen > length) length = alen; - } - } - - if (length > 60000) /* 1000 hours > 41 days */ - length = 60000; /* truncate extremely long records */ - - if (length < 1) { - fprintf(stderr, "%s: can't map record %s (length unspecified)\n", - pname, record); - exit(1); - } - - if ((map = malloc((nsig + 4*nann) * sizeof(int *))) == NULL) { - fprintf(stderr, "%s: insufficient memory\n", pname); - wfdbquit(); - if (ai) free(ai); - if (si) free(si); - exit(2); - } - for (i = 0; i < nsig + 4*nann; i++) - if ((map[i] = calloc(length, sizeof(int))) == NULL) { - fprintf(stderr, "%s: insufficient memory\n", pname); - while (--i > 0) - if (map[i]) free(map[i]); - free(map); - wfdbquit(); - if (ai) free(ai); - if (si) free(si); - exit(2); - } - - if (nsig > 0) map_sig(record, si, nsig, map, length); - if (nann > 0) map_ann(record, ai, nann, &map[nsig], length); - - if (mflag) { - printf("T"); - for (i = 0; i < nsig; i++) - printf("\t%s", si[i].desc); - for (i = 0; i < nann; i++) - printf("\t%s\tQRS\tEctopic\tVE", ai[i].name); - printf("\n"); - write_map(map, nsig, nann, length); - } - else - write_script(map, nsig, nann, length); - - for (i = 0; i < nsig + 4*nann; i++) - free(map[i]); - free(map); - wfdbquit(); - if (ai) free(ai); - if (si) free(si); - - exit(0); -} - -void map_sig(char *record, WFDB_Siginfo *si, int nsig, int **map, int length) -{ - if (si[0].nsamp == strtim("e") || si[0].nsamp != 0) { - /* fixed-layout record */ - int i, t; - for (i = 0; i < nsig; i++) - for (t = 0; t < length; t++) - map[i][t] = 1; - } - else { /* variable-layout record */ - char buf[256], *d, *p, *q, *r, *hfname, *shfname; - long m, m0, mf, spm = strtim("60"), t = 0, tf; - FILE *ifile, *sfile; - - p = wfdbfile("hea", record); - hfname = calloc(strlen(p) + 1, 1); - strcpy(hfname, p); - if ((ifile = fopen(hfname, "r")) == NULL) { - fprintf(stderr, "%s: can't open %s\n", pname, hfname); - free(hfname); - return; - } - for (d = p + strlen(p); d > p; d--) - if (*(d-1) == '/') { - *d = '\0'; - break; - } - shfname = calloc(strlen(hfname) + 16, 1); - strcpy(shfname, p); - d = shfname + strlen(shfname); /* d points to first char after '/' */ - fgets(buf, sizeof(buf), ifile); /* read and ignore first two lines */ - fgets(buf, sizeof(buf), ifile); - - m0 = 0; - while (fgets(buf, sizeof(buf), ifile)) {/* read a segment descriptor */ - char *tp; - - if (buf[0] == '~') { /* segment is null (all signals off) */ - t += atol(buf+2); - m0 = t/spm; - continue; - } - for (tp = buf+1; *tp != ' '; tp++) - ; - *tp = '\0'; - tf = t + atol(tp+1); - if ((mf = tf/spm) > length) mf = length; - sprintf(d, "%s.hea", buf); - if (sfile = fopen(shfname, "r")) {/* open the segment header file */ - char sbuf[256]; - int i; - - fgets(sbuf, sizeof(sbuf), sfile);/* read & ignore first line */ - - while ((p = fgets(sbuf, sizeof(sbuf), sfile)) && *sbuf != '#') { - /* signal description line */ - for (q = sbuf, i = 0; *q; q++) - if (*q == ' ' && ++i == 8) break; - q++; - *(q + strlen(q) - 2) = '\0'; - for (i = 0; i < nsig; i++) - if (strcmp(si[i].desc, q) == 0) - for (m = m0; m < mf; m++) - map[i][m] = 1; - } - fclose(sfile); - t = tf; - m0 = t/spm; - } - } - fclose(ifile); - free(shfname); - free(hfname); - } -} - -int *namax; - -void map_ann(char *record, WFDB_Anninfo *ai, int nann, int **map, int length) -{ - int i; - - namax = malloc(nann * sizeof(int)); - wfdbquiet(); /* suppress warnings if an annotator can't be opened */ - for (i = 0; i < nann; i++) { - char tstring[10]; - int minutes, *na, *nq, *ne, *nv; - WFDB_Annotation annot; - WFDB_Time end_of_epoch; - - na = &map[4*i][0]; - namax[i] = 1; - - /* Open the annotators one at a time, and do not quit if any fail - to open. */ - if (annopen(record, &ai[i], 1) < 0) continue; - minutes = end_of_epoch = 0; - iannsettime(1L); - while (getann(0, &annot) >= 0) { - if (annot.time > end_of_epoch) { - if (*na > namax[i]) namax[i] = *na; - minutes = annot.time/spm; - na = &map[4*i][minutes]; - nq = &map[4*i + 1][minutes]; - ne = &map[4*i + 2][minutes]; - nv = &map[4*i + 3][minutes]; - if (++minutes > length) - break; /* stop at the end of the record */ - sprintf(tstring, "%d", 60*minutes); - end_of_epoch = strtim(tstring); - } - switch (annot.anntyp) { - case PVC: - case FUSION: - case VESC: - case RONT: - case FLWAV: (*nv)++; /* fall through, no break! */ - case APC: - case ABERR: - case NPC: - case SVPB: - case NESC: - case AESC: - case SVESC: (*ne)++; /* fall through, no break! */ - case NORMAL: - case LBBB: - case RBBB: - case PACE: - case UNKNOWN: - case BBB: - case LEARN: - case PFUS: (*nq)++; /* fall through, no break! */ - default: (*na)++; break; - } - } - if (*na > namax[i]) namax[i] = *na; - } - return; -} - -void write_map(int **map, int nsig, int nann, int length) -{ - int i, imax = nsig + 4*nann - 1, t; - - for (t = 0; t < length; t++) { - if (mflag == 0) printf("%d\t0\t", t); /* x0, y0 for histogram plots */ - printf("%d\t", t+1); - for (i = 0; i < imax; i++) - printf("%d\t", map[i][t]); - printf("%d\n", map[i][t]); - } -} - -#include "signal-colors.h" - -char *color(char *type) -{ - int i; - - for (i = 0; ctab[i].name != NULL; i++) - if (strcmp(type, ctab[i].name) == 0) return (ctab[i].color); - return ("grey"); -} - -void write_script(int **map, int nsig, int nann, int length) -{ - char *p, tstring[2][30]; - double ylow, ymax; - int i, j; - WFDB_Time tf = strtim("e"); - - strcpy(tstring[0], timstr(0)); - for (p = tstring[0]; *p == ' '; p++) - ; - if (tf) strcpy(tstring[1], timstr(-tf)); - else sprintf(tstring[1], "%d:%02d:00", length/60, length%60); - - ymax = 2*(nsig + 2*nann + 1); - ylow = 0.01 * ymax; - - printf("#! /bin/sh\n" - "cat >map.txt <= s && *p != '\\' && *p != ':') { - if (*p == '.') - *p = '\0'; /* strip off extension */ - if ('A' <= *p && *p <= 'Z') - *p += 'a' - 'A'; /* convert to lower case */ - p--; - } -#else - while (p >= s && *p != '/') - p--; -#endif - return (p+1); -} - -static char *help_strings[] = { - "usage: %s -r RECORD -a ANNOTATOR [OPTIONS ...]\n", - "where RECORD and ANNOTATOR specify the input, and OPTIONS may include:", - " -h print this usage summary", -NULL -}; - -void help() -{ - int i; - - (void)fprintf(stderr, help_strings[0], pname); - for (i = 1; help_strings[i] != NULL; i++) - (void)fprintf(stderr, "%s\n", help_strings[i]); -}