diff -Naur --exclude Makefile --exclude info wfdb-10.4.15/app/wfdbtime.c wfdb-10.4.16/app/wfdbtime.c --- wfdb-10.4.15/app/wfdbtime.c 2009-02-16 23:36:19.000000000 -0500 +++ wfdb-10.4.16/app/wfdbtime.c 2009-03-01 16:33:04.000000000 -0500 @@ -27,32 +27,33 @@ #include #include -main(argc, argv) -int argc; -char **argv; +main(int argc, char **argv) { - char sbuf[32]; + char *record = NULL, sbuf[32]; int i; WFDB_Time t; - if (strcmp(argv[1], "-H") == 0) { - setgvmode(WFDB_HIGHRES); - argc--; argv++; + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-r") == 0) { + if (record) wfdbquit(); + setgvmode(WFDB_HIGHRES); + if (++i == argc) break; + record = argv[i]; + if (isigopen(record, NULL, 0) < 0) exit(2); + } + else if (record) { + if ((t = strtim(argv[i])) < 0L) t = -t; + sprintf(sbuf, "s%ld", t); + printf("%15s\t%15s", sbuf, (t == 0L) ? "0:00.000" : mstimstr(t)); + printf("\t%15s\n", mstimstr(-t)); + } } - if (strcmp(argv[1], "-r") <= 0 && isigopen(argv[2], NULL, 0) < 0) { - fprintf(stderr, "usage: %s [-H] -r RECORD TIME [ TIME ... ]\n", - argv[0]); + if (record == NULL) { + fprintf(stderr, "usage: %s [ -r RECORD [ TIME ] ]\n", argv[0]); fprintf(stderr, " where RECORD is the name of the input record\n"); - fprintf(stderr, " (use -H for high resolution mode multifrequency" - " record)\n"); fprintf(stderr, " Each TIME is a time to be converted\n"); exit(1); } - for (i = 3; i < argc; i++) { - if ((t = strtim(argv[i])) < 0L) t = -t; - sprintf(sbuf, "s%ld", t); - printf("%15s\t%15s", sbuf, (t == 0L) ? "0:00.000" : mstimstr(t)); - printf("\t%15s\n", mstimstr(-t)); - } + wfdbquit(); exit(0); } diff -Naur --exclude Makefile --exclude info wfdb-10.4.15/app/wrann.c wfdb-10.4.16/app/wrann.c --- wfdb-10.4.15/app/wrann.c 2008-03-14 13:52:09.000000000 -0400 +++ wfdb-10.4.16/app/wrann.c 2009-02-27 09:45:08.000000000 -0500 @@ -1,9 +1,9 @@ /* file wrann.c G. Moody 6 July 1983 - Last revised: 14 March 2008 + Last revised: 27 February 2009 ------------------------------------------------------------------------------- wrann: Translate an ASCII file in 'rdann' output format to an annotation file -Copyright (C) 1983-2008 George B. Moody +Copyright (C) 1983-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 @@ -103,22 +103,22 @@ if (annopen(record, &ai, 1) < 0) /* open annotation file */ exit(2); while (fgets(line, sizeof(line), stdin) != NULL) { + static char a[256]; p = line+9; if (line[0] == '[') while (*p != ']') p++; while (*p != ' ') p++; - (void)sscanf(p+1, "%ld%s%d%d%d", &tm, annstr, &sub, &ch, &nm); + *(a+1) = '\0'; + (void)sscanf(p+1, "%ld%s%d%d%d\t%s", &tm, annstr, &sub, &ch, &nm, a+1); annot.anntyp = strann(annstr); annot.time = tm; annot.subtyp = sub; annot.chan = ch; annot.num = nm; - for (p = line+40; *p; p++) - if (*p == '\t') { - *p = strlen(p+1) - 1; - annot.aux = p; - break; - } - if (*p == '\0') + if (*(a+1)) { + *a = strlen(a+1); + annot.aux = a; + } + else annot.aux = NULL; (void)putann(0, &annot); } diff -Naur --exclude Makefile --exclude info wfdb-10.4.15/convert/wfdb2mat.c wfdb-10.4.16/convert/wfdb2mat.c --- wfdb-10.4.15/convert/wfdb2mat.c 2009-02-26 18:27:21.000000000 -0500 +++ wfdb-10.4.16/convert/wfdb2mat.c 2009-03-01 10:47:38.000000000 -0500 @@ -1,5 +1,5 @@ -/* file: wfdb2mat.c G. Moody 26 February 2009 - +/* file: wfdb2mat.c G. Moody 26 February 2009 + Last revised: 1 March 2009 ------------------------------------------------------------------------------- wfdb2mat: Convert (all or part of) a WFDB signal file to Matlab .mat format Copyright (C) 2009 George B. Moody @@ -40,7 +40,9 @@ files are written in column-major order (i.e., all of column n precedes all of column n+1), each vector of samples is written as a column rather than as a row, so that the column number in the .mat file equals the sample number in the -input record. If this seems odd, transpose your matrix after reading it! +input record (minus however many samples were skipped at the beginning of the +record, as specified using the -f option). If this seems odd, transpose your +matrix after reading it! This program writes version 4 MAT-file format output files, as documented in http://www.mathworks.com/access/helpdesk/help/pdf_doc/matlab/matfile_format.pdf @@ -71,14 +73,26 @@ #include #include +/* Dynamic memory allocation macros. */ +#define MEMERR(P, N, S) \ + { wfdb_error("%s: can't allocate (%ld*%ld) bytes for %s\n", \ + pname, (size_t)N, (size_t)S, #P); \ + exit(1); } +#define SFREE(P) { if (P) { free (P); P = 0; } } +#define SUALLOC(P, N, S) { if (!(P = calloc((N), (S)))) MEMERR(P, (N), (S)); } +#define SALLOC(P, N, S) { SFREE(P); SUALLOC(P, (N), (S)) } +#define SREALLOC(P, N, S) { if (!(P = realloc(P, (N)*(S)))) MEMERR(P,(N),(S)); } +#define SSTRCPY(P, Q) { if (Q) { \ + SALLOC(P, (size_t)strlen(Q)+1,1); strcpy(P, Q); } } + char *pname; main(argc, argv) int argc; char *argv[]; { - char *matname, *orec, *p, *record = NULL, *search = NULL, *prog_name(); - static int prolog[6]; /* assumes sizeof(int) == 4; if not true, fix! */ + char *matname, *orec, *p, *q, *record = NULL, *search = NULL, *prog_name(); + static char prolog[24]; int highres = 0, i, isiglist, nisig, nosig = 0, pflag = 0, s, *sig = NULL, type = 50, vflag = 0; WFDB_Frequency freq; @@ -165,11 +179,8 @@ exit(1); } if ((nisig = isigopen(record, NULL, 0)) <= 0) exit(2); - if ((vi = malloc(nisig * sizeof(WFDB_Sample))) == NULL || - (si = malloc(nisig * sizeof(WFDB_Siginfo))) == NULL) { - (void)fprintf(stderr, "%s: insufficient memory\n", pname); - exit(2); - } + SUALLOC(si, nisig, sizeof(WFDB_Siginfo)); + SUALLOC(vi, nisig, sizeof(WFDB_Sample)); if ((nisig = isigopen(record, si, nisig)) <= 0) exit(2); for (i = 0; i < nisig; i++) @@ -185,12 +196,9 @@ to = -to; if (nosig) { /* convert samples only from specified signals */ - if ((sig = (int *)malloc((unsigned)nosig*sizeof(int))) == NULL || - (vo = malloc(nosig * sizeof(WFDB_Sample))) == NULL || - (so = malloc((unsigned)nosig * sizeof(WFDB_Siginfo))) == NULL) { - (void)fprintf(stderr, "%s: insufficient memory\n", pname); - exit(2); - } + SUALLOC(so, nosig, sizeof(WFDB_Siginfo)); + SUALLOC(vo, nosig, sizeof(WFDB_Sample)); + SUALLOC(sig, nosig, sizeof(int)); for (i = 0; i < nosig; i++) { if ((s = findsig(argv[isiglist+i])) < 0) { (void)fprintf(stderr, "%s: can't read signal '%s'\n", pname, @@ -202,11 +210,9 @@ } else { /* convert samples from all signals */ nosig = nisig; - if ((sig = (int *)malloc((unsigned)nosig*sizeof(int))) == NULL || - (so = malloc((unsigned)nosig * sizeof(WFDB_Siginfo))) == NULL) { - (void)fprintf(stderr, "%s: insufficient memory\n", pname); - exit(2); - } + SUALLOC(so, nosig, sizeof(WFDB_Siginfo)); + SUALLOC(vo, nosig, sizeof(WFDB_Sample)); + SUALLOC(sig, nosig, sizeof(int)); for (i = 0; i < nosig; i++) sig[i] = i; } @@ -237,14 +243,11 @@ exit(1); } - /* Generate the names for the output .mat file, and the output record. */ - if ((matname = (char *)malloc(strlen(record)+5)) == NULL || - (orec = (char *)malloc(strlen(record)+1)) == NULL) { - (void)fprintf(stderr, "%s: insufficient memory\n", pname); - exit(2); - } + /* Generate the names for the output .mat file and the output record. */ + SUALLOC(matname, strlen(record)+6, sizeof(char)); + sprintf(matname, "%sm.mat", record); + SUALLOC(orec, strlen(record)+2, sizeof(char)); sprintf(orec, "%sm", record); - sprintf(matname, "%s.mat", orec); /* Determine if we can write 8-bit unsigned samples, or if 16 bits are needed per sample. */ @@ -254,6 +257,7 @@ so[i] = si[sig[i]]; so[i].fname = matname; so[i].fmt = (type == 30) ? 16 : 80; + if (so[i].units == NULL) SSTRCPY(so[i].units, "mV"); } /* Create an empty .mat file. */ @@ -262,36 +266,62 @@ exit(1); } - /* Fill in the .mat file's prolog and write it. */ - prolog[0] = type; /* format */ - prolog[1] = nosig; /* number of rows */ - prolog[2] = to - from; /* number of columns */ - prolog[3] = 0; /* matrix is real */ - prolog[4] = 4; /* strlen("val") + 1 */ - prolog[5] = ((int)'v') | ((int)'a' << 8) | ((int)'l' << 16); /* "val" */ - wfdbputprolog((char *)prolog, sizeof(prolog), 0); + /* Fill in the .mat file's prolog and write it. (Elements of prolog[] + not set explicitly below are always zero.) */ + prolog[ 0] = type & 0xff; /* format */ + prolog[ 1] = (type >> 8) & 0xff; + prolog[ 4] = nosig & 0xff; /* number of rows */ + prolog[ 5] = (nosig >> 8) & 0xff; + prolog[ 6] = (nosig >> 16) & 0xff; + prolog[ 7] = (nosig >> 24) & 0xff; + prolog[ 8] = (to - from) & 0xff; /* number of columns */ + prolog[ 9] = ((to - from) >> 8) & 0xff; + prolog[10] = ((to - from) >> 16) & 0xff; + prolog[11] = ((to - from) >> 24) & 0xff; + prolog[16] = 4; /* strlen("val") + 1 */ + sprintf(prolog+20, "val"); + wfdbputprolog((char *)prolog, 24, 0); /* Copy the selected data into the .mat file. */ - for (t = from; from < to && getvec(vi) >= 0; t++) { + for (t = from; t < to && getvec(vi) >= 0; t++) { for (i = 0; i < nosig; i++) vo[i] = vi[sig[i]]; if (putvec(vo) != nosig) break; } + if (t != to) + fprintf(stderr, "%s (warning): matrix is missing final %ld columns\n", + pname, to - t); + /* Create the new header file. */ newheader(orec); - if (p = malloc(strlen(record)+40)) { - sprintf(p, "created using wfdb2mat from record %s", record); - putinfo(p); - free(p); + /* Copy info from the old record, if any */ + if (p = getinfo(NULL)) + do { + (void)putinfo(p); + } while (p = getinfo((char *)NULL)); + /* Append additional info summarizing what wfdb2mat has done. */ + SUALLOC(p, strlen(record)+80, 1); + (void)sprintf(p, "Creator: %s", pname); + (void)putinfo(p); + (void)sprintf(p, "Source: record %s", record); + q = mstimstr(-from); + while (*q == ' ') q++; + if (from != 0 || *q == '[') { + strcat(p, " Start: "); + strcat(p, q); } + (void)putinfo(p); /* Summarize the contents of the .mat file. */ - printf("Generated %s, containing matrix 'val'\n", matname); - printf(" with %d rows and %d columns\n", nosig, to-from); + printf("%s\n", p); + printf("val has %d row%s (signal%s) and %d column%s (sample%s/signal)\n", + nosig, nosig == 1 ? "" : "s", nosig == 1 ? "" : "s", + to-from, to == from+1 ? "" : "s", to == from+1 ? "" : "s"); printf("Duration: %s\n", timstr(to-from)); - printf("Sampling frequency: %g columns/second\n", sampfreq(NULL)); + printf("Sampling frequency: %g Hz Sampling interval: %g sec\n", + freq, 1/freq); printf("Row\tSignal\tGain\tBase\tUnits\n"); for (i = 0; i < nosig; i++) printf("%d\t%s\t%g\t%d\t%s\n", i+1, so[i].desc, so[i].gain, @@ -299,6 +329,7 @@ printf("\nTo convert from raw units to the physical units shown\n" "above, subtract 'base' and divide by 'gain'.\n"); + SFREE(p); wfdbquit(); exit(0); /*NOTREACHED*/ diff -Naur --exclude Makefile --exclude info wfdb-10.4.15/doc/wag-src/wfdbtime.1 wfdb-10.4.16/doc/wag-src/wfdbtime.1 --- wfdb-10.4.15/doc/wag-src/wfdbtime.1 2009-02-18 18:25:33.000000000 -0500 +++ wfdb-10.4.16/doc/wag-src/wfdbtime.1 2009-03-01 17:35:49.000000000 -0500 @@ -1,8 +1,8 @@ -.TH WFDBTIME 1 "18 February 2009" "WFDB 10.4.14" "WFDB Applications Guide" +.TH WFDBTIME 1 "1 March 2009" "WFDB 10.4.16" "WFDB Applications Guide" .SH NAME wfdbtime \- convert time to sample number, elapsed, and absolute time .SH SYNOPSIS -\fBwfdbtime\fR [ \fB-H\fR ] \fB-r\fR \fIrecord\fR \fItime\fR [ \fItime\fR ... ] +\fBwfdbtime\fR \fB-r\fR \fIrecord\fR \fItime\fR [ \fItime\fR ... ] .SH DESCRIPTION .PP Using the specified \fIrecord\fR as a reference for determining the @@ -17,6 +17,10 @@ DD/MM/YYYY\fR]). If the base time for the record is undefined, the absolute time cannot be calculated, and in this case the elapsed time appears (a second time) instead. +.PP +Additional \fB-r\fI record\fR arguments may be given in the same command, +to reset the sample interval length and base time for any subsequent \fItime\fR +arguments. .SH EXAMPLES .PP The command @@ -25,6 +29,7 @@ .LP produces the output .IP +.br s0 0:00.000 [12:40:38.000 20/07/1995] .br s75000 10:00.000 [12:50:38.000 20/07/1995] diff -Naur --exclude Makefile --exclude info wfdb-10.4.15/lib/signal.c wfdb-10.4.16/lib/signal.c --- wfdb-10.4.15/lib/signal.c 2009-02-26 18:09:34.000000000 -0500 +++ wfdb-10.4.16/lib/signal.c 2009-03-01 15:45:39.000000000 -0500 @@ -3098,7 +3098,7 @@ if (strchr(p, '/')) days = strdat(p) - bdate; else days = atol(p+1); } - t = strtim(string+1) - (WFDB_Time)(btime*f/1000.0); + t = strtim(string+1) - (WFDB_Time)(btime*f/1000.0 + 0.5); if (days > 0L) t += (WFDB_Time)(days*24*60*60*f); return (-t); default: diff -Naur --exclude Makefile --exclude info wfdb-10.4.15/lib/wfdb.h wfdb-10.4.16/lib/wfdb.h --- wfdb-10.4.15/lib/wfdb.h 2009-02-26 22:52:13.000000000 -0500 +++ wfdb-10.4.16/lib/wfdb.h 2009-03-03 07:27:43.000000000 -0500 @@ -33,7 +33,7 @@ /* WFDB library version. */ #define WFDB_MAJOR 10 #define WFDB_MINOR 4 -#define WFDB_RELEASE 15 +#define WFDB_RELEASE 16 #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.4.15/NEWS wfdb-10.4.16/NEWS --- wfdb-10.4.15/NEWS 2009-02-26 23:06:17.000000000 -0500 +++ wfdb-10.4.16/NEWS 2009-03-03 12:01:38.000000000 -0500 @@ -1,3 +1,13 @@ +10.4.16: + WFDB library function strtim() now rounds rather than truncating when + the sampling frequency is not an integer. + + WFDB application wrann is now (slightly) less fussy about its input + and no longer requires the tab character preceding an aux string to + occur in a specific column as did earlier versions. + + Bug fixes in convert/wfdbtomat. + 10.4.15: WFDB library function mstimstr() now outputs time to the nearest millisecond, rather than truncating its calculation to the next