Uživatel:Kychot/exp2gdf.c
Vzhled
/* exp2gdf converts the EMG file from .EXP (Medelec export file) to .GDF */
// copyleft CC-BY-SA 3.0 by Petr Heřman aka Kychot
// v. 0.12 – NeuJahr 2011-01-01 im Wald - downsampling
int program_vermajor = 0;
int program_verminor = 12;
const char *program_name;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <getopt.h>
#include <errno.h>
//#include <biosig.h>
#include "biosig.h"
/* defs */
#define MAXCHAN 20
#define RBUFSIZE 1048576
#define WBUFSIZE 1048576
/* EXP header */
struct exphdrtype {
unsigned short nchan;
unsigned short sample_int_us;
unsigned short gain[MAXCHAN];
};
/* functions */
void exphdrread( void); // reads header of the EXP file
void hdrset( void); // sets the values into hdr
void datablock0( void); // copies the signal data
void datablock1( void); // copies the signal data
void datablock2( void); // copies and downsamples the signal data
/* global data */
int VERBOSE = 0;
char *infilename = NULL;
char *outfilename = NULL;
FILE *INFILE;
FILE *OUTFILE;
HDRTYPE *hdr;
struct exphdrtype exphdr;
struct stat stbuf;
int status;
int downsampl = 1;
int64_t nsamples;
int16_t rbuf[ RBUFSIZE]; // buffer for fread
int16_t wbuf[ WBUFSIZE]; // buffer for fwrite
long datapos; // beginning of the binary data
biosig_data_type databuf[ 100];
void print_help( FILE *stream)
{
fprintf( stream, "\tUsage:\n\t%s options file.EXP file.gdf\n", program_name);
fprintf( stream,
"\t\tfile.EXP = input file\n"
"\t\tfile.gdf = output file\n"
"\t\t-h --help Display this help screen.\n"
"\t\t-v --version Program version.\n"
"\t\t-V --verbose=v Verbosity level.\n"
"\t\t-d --downsample=d Downsampling d-times (1,2,...)\n"
"\t\t\n");
}
void print_version(FILE *stream)
{
fprintf(stream, "\t%s %d.%d\n", program_name, program_vermajor, program_verminor);
}
/* main – evaluates args and STDIN */
int main(int argc, char *argv[]){
//size_t count;
//uint16_t numopt = 0;
//enum FileFormat SOURCE_TYPE, TARGET_TYPE=GDF; // type of file format
//int COMPRESSION_LEVEL=0;
program_name = argv[0];
int next_option;
const char *short_options = "hvV:d:";
const struct option long_options[] = {
//long option, arg?, NULL, short
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'v' },
{ "verbose", 1, NULL, 'V' },
{ "downsampling", 1, NULL, 'd' },
{ NULL, 0, NULL, 0 }
};
/* Jmeno souboru pro vystup nebo NULL pro stdout */
//const char *output_file = NULL;
/* Jmeno souboru pro vstup nebo NULL pro stdin */
//const char *input_file = NULL;
do {
next_option = getopt_long(argc, argv, short_options, long_options, NULL);
switch(next_option)
{
case 'h': /* -h --help */
print_help(stdout);
exit(1);
case 'v': /* -v --version */
print_version(stdout);
exit(1);
case 'V': /* -V --verbose */
errno = 0;
VERBOSE = strtol(optarg, NULL, 10);
if(errno !=0) {perror("strtol"); print_help(stdout); exit(1);}
break;
case 'd': /* -d --downsampling */
errno = 0;
downsampl = strtol(optarg, NULL, 10);
if(errno !=0) {perror("strtol"); print_help(stdout); exit(1);}
break;
case '?': /* illegal option */
print_help(stderr);
exit(1);
case -1 : /* end loop */
break;
default:
abort();
}
} while(next_option != -1);
if(argc-optind > 2){
fprintf(stderr,"\tToo much arguments: ");
while (optind < argc) fprintf(stderr, "%s ", argv[optind++]); printf("\n");
print_help(stdout);
exit(1);
}
switch (argc-optind) {
case 0:
fprintf(stderr,"\tMissing input file name!\n");
case 1:
fprintf(stderr,"\tMissing output file name!\n");
print_help(stdout);
exit(1);
case 2:
infilename = argv[optind++];
outfilename = argv[optind++];
}
if (VERBOSE) printf("verbosity=%d, downsampling=%d\n", VERBOSE, downsampl);
if (VERBOSE>=1) printf( "%s -> %s\n", infilename, outfilename);
stat( infilename, &stbuf);
if (VERBOSE>8) printf( "filesize = %lu\n", stbuf.st_size);
INFILE = fopen( infilename, "rb");
exphdrread(); // read the EXP header into exphdr
nsamples = ((stbuf.st_size/2) - 2 - exphdr.nchan)/exphdr.nchan;
hdr = constructHDR( exphdr.nchan, 0); // NS channels, N_EVENT event elements
//hdr2ascii(hdr,stdout,1);
hdrset(); // set the appropriate values into hdr
//hdr2ascii(hdr,stdout,3);
//printf("tell position: INFILE = %ld, OUTFILE = %ld\n", ftell( INFILE), ftell( OUTFILE));
//hdr = sopen(outfilename, "w", hdr);
sopen(outfilename, "w", hdr);
if ((status=serror())) { destructHDR(hdr); exit(status);}
if (VERBOSE>7)
printf("\n[221] File %s opened. AS.bpb (bytes per block)=%i NS=%i NRec=%Li Des=%i\n",
hdr->FileName, hdr->AS.bpb, hdr->NS, hdr->NRec, hdr->FILE.Des);
if(VERBOSE>=2) hdr2ascii(hdr, stdout, VERBOSE-2);
//swrite(databuf, hdr->NRec, hdr);
//swrite(databuf, 100, hdr);
//if (VERBOSE>7) printf("[231] SWRITE finishes\n");
//if ((status=serror())) { destructHDR(hdr); exit(status);}
sclose(hdr);
if (VERBOSE>7) printf("[241] SCLOSE finished\n");
//exit(serror());
OUTFILE = fopen( outfilename, "ab");
datablock2();
fclose( OUTFILE);
fclose( INFILE);
destructHDR(hdr);
return( 0);
}
void exphdrread( void) {
size_t readed;
readed = fread( &exphdr, 2, 2, INFILE); // 2*2 bytes: nchan, sample_int_us
if(VERBOSE>7) printf("nchan = %d, sample_int_us = %d\ngain: ",exphdr.nchan, exphdr.sample_int_us);
readed = fread( exphdr.gain, 2, exphdr.nchan, INFILE); // 2*nchan bytes: gain
int ch;
for( ch=0; ch<exphdr.nchan; ch++) {
if (VERBOSE>7) printf( " %d", exphdr.gain[ch]);
}
printf( "\n");
}
void hdrset( void) { // set appropriate values into hdr:
hdr->TYPE = GDF;
hdr->VERSION = 2.10;
hdr->FileName = outfilename;
hdr->NS = exphdr.nchan; // number of channels
// hdr->HeadLen = 256*exphdr.nchan + 512; // the length of all headers [unit = bytes]
hdr->SPR = 1; // samples per record
// hdr->NRec = ((stbuf.st_size/2) - 2 - exphdr.nchan)/exphdr.nchan; // Number of records
hdr->NRec = nsamples/downsampl; // Number of records
hdr->SampleRate = 1000000/(exphdr.sample_int_us*downsampl); // Sampling frequency [Hz]
//hdr->T0 = // starttime of recording
//hdr->tzmin = // time zone (minutes of difference to UTC
strncpy (&(hdr->ID.Recording[0]), "00", MAX_LENGTH_RID+1);
strncpy (&(hdr->ID.Technician[0]), "K.", MAX_LENGTH_TECHNICIAN+1);
hdr->ID.Manufacturer.Name = "Medelec";
hdr->ID.Manufacturer.Model = "EMG";
strncpy (&(hdr->Patient.Name[0]), "XY", MAX_LENGTH_NAME+1);
strncpy (&(hdr->Patient.Id[0]), "00", MAX_LENGTH_PID+1);
/* channels */
int ch;
printf( "Ch |OnOff|Sam/Rec|\n");
for (ch = 0; ch < hdr->NS; ch++) {
//hdr->CHANNEL[ch].OnOff = 1;
hdr->CHANNEL[ch].GDFTYP = 3; // int16
//hdr->CHANNEL[ch].GDFTYP = 4; // uint16
hdr->CHANNEL[ch].SPR = 1;
hdr->CHANNEL[ch].PhysMin = -50;
hdr->CHANNEL[ch].PhysMax = 50;
hdr->CHANNEL[ch].DigMin = -2047;
hdr->CHANNEL[ch].DigMax = 2048;
hdr->CHANNEL[ch].Cal = 10;
hdr->CHANNEL[ch].Off = 0;
hdr->CHANNEL[ch].LowPass = 100;
hdr->CHANNEL[ch].HighPass = 1000;
hdr->CHANNEL[ch].Notch = 0; // does not allow empty value
//hdr->CHANNEL[ch].PhysDim = "uV"; // deprecated
hdr->CHANNEL[ch].PhysDimCode = 4275; // uV
hdr->CHANNEL[ch].LeadIdCode = 0;
}
strncpy (&(hdr->CHANNEL[0].Transducer)[0], "", MAX_LENGTH_TRANSDUCER+1);
strncpy (&(hdr->CHANNEL[1].Transducer)[0], "", MAX_LENGTH_TRANSDUCER+1);
strncpy (&(hdr->CHANNEL[2].Transducer)[0], "", MAX_LENGTH_TRANSDUCER+1);
strncpy (&(hdr->CHANNEL[3].Transducer)[0], "", MAX_LENGTH_TRANSDUCER+1);
strncpy (&(hdr->CHANNEL[0].Label)[0], "#1", MAX_LENGTH_LABEL+1);
strncpy (&(hdr->CHANNEL[1].Label)[0], "#2", MAX_LENGTH_LABEL+1);
strncpy (&(hdr->CHANNEL[2].Label)[0], "#3", MAX_LENGTH_LABEL+1);
strncpy (&(hdr->CHANNEL[3].Label)[0], "#4", MAX_LENGTH_LABEL+1);
}
void datablock0( void) { // copy only
unsigned readed;
while(( readed = fread( rbuf, 2, RBUFSIZE, INFILE) )) {
fwrite( rbuf, 2, readed, OUTFILE);
}
}
// <string.h>
// bcopy,
// memccpy, memcpy, memmove, mempcpy,
// strdup, strpcpy, strcpy, strncpy,
// wcscpy, wcsncpy, wmemcpy, wmempcpy
void datablock1( void) {
unsigned readed;
int nbuf = 0;
while(( readed = fread( rbuf, 2, RBUFSIZE, INFILE) )) {
if( VERBOSE>=2){ nbuf++; printf( "%d,", nbuf); fflush(stdout);}
memcpy( wbuf, rbuf, 2*readed);
fwrite( wbuf, 2, readed, OUTFILE);
}
if( VERBOSE>=2) printf(" done\n");
}
void datablock2( void) { // downsampling
int readed; // [integers] readed into readbuffer
int nbuf = 0; // how much times is the buffer used
int nchan = exphdr.nchan; // number of channels
int blocksize = nchan*downsampl; // [integers] one source block will be reduced to one dest. timepoint
int bcopy = 2*nchan; // how much bytes to copy at one timepoint
int maxblocks = RBUFSIZE / blocksize; // [integers] how much blocks fits into the readbuffer
int amount = maxblocks*blocksize; // [integers] max. amount of which will be read into the buffer
int nblocks, blkc; // number of blocks actualy readed, block counter
int16_t *src, *dest; // source pointer, destination pointer
while(( readed = fread( rbuf, 2, amount, INFILE) )) {
if( VERBOSE>=2) {nbuf++; printf("%d,", nbuf); fflush( stdout);}
blkc = nblocks = readed / blocksize;
src = rbuf;
dest = wbuf;
while( blkc--){
memcpy( dest, src, bcopy);
src += blocksize;
dest += nchan;
}
fwrite( wbuf, 2, nblocks*nchan, OUTFILE);
}
if( VERBOSE>=2) printf(" done\n");
}
/*
void datablock9( int ch) { // read all channels, no seek - more quick, about 0.7s
long initial_pos = datapos+2*ch;
//int skip = 2*(exphdr.nchan-1);
unsigned short buf[MAXCHAN];
printf( "ch = %d, initial_pos = %ld\n", ch, initial_pos);
fseek( INFILE, initial_pos, SEEK_SET);
while( fread( buf, 2, exphdr.nchan, INFILE)) {
fwrite( &buf[0], 2, 1, OUTFILE);
}
}
*/
/*----------- původní soubor -------------*/
#if 0
/* exp2gdf – adapted by Petr Heřman aka Robot from:
$Id: save2gdf.c 2360 2010-03-06 00:37:00Z schloegl $
GNU General Public License.
v.05 - zatím je to jen zjednoduššený save2gdf bez přepínačů,
konvertuje z GDF do GDF a vypisuje různé věci z hlaviček
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "biosig-dev.h"
#define MIN2HHMM(m) (sprintf( "%+02u00", (m)/60))
//VERBOSE_LEVEL = 9;
char *source, *dest, tmp[1024];
void hdrread( void);
void hdrprint( void);
tzset();
if (VERBOSE>8) printf("[002] hdr->TYPE = %d, hdr->VERSION = %f\n",hdr->TYPE,hdr->VERSION);
hdrread();
if (VERBOSE>1) hdrprint();
if (dest!=NULL) count = sread(NULL, 0, hdr->NRec, hdr);
// (biosig_data_type* DATA, size_t START, size_t LEN, HDRTYPE* hdr);
/* LEN data segments are read from file associated with hdr, starting from
segment START. The data is copied into DATA; if DATA == NULL, a
sufficient amount of memory is allocated, and the pointer to the data
is available in hdr->data.block.
In total, LEN * hdr->SPR * NS samples are read and stored in
data type of biosig_data_type (currently double).
NS is the number of channels with non-zero hdr->CHANNEL[].OnOff.
The number of successfully read data blocks is returned.
A pointer to the data block is also available from hdr->data.block,
the number of columns and rows is available from
hdr->data.size[0] and hdr->data.size[1] respectively.
The following flags will influence the result.
hdr->FLAG.UCAL = 0 scales the data to its physical values
hdr->FLAG.UCAL = 1 does not apply the scaling factors
hdr->FLAG.OVERFLOWDETECTION = 0 does not apply overflow detection
hdr->FLAG.OVERFLOWDETECTION = 1: replaces all values that exceed
the dynamic range (defined by Phys/Dig/Min/Max)
hdr->FLAG.ROW_BASED_CHANNELS = 0 each channel is in one column
hdr->FLAG.ROW_BASED_CHANNELS = 1 each channel is in one row */
biosig_data_type* data = hdr->data.block;
if ((VERBOSE>8) && (hdr->data.size[0]*hdr->data.size[1]>500))
printf("[122] UCAL=%i %e %e %e \n", hdr->FLAG.UCAL, data[100], data[110], data[500+hdr->SPR]);
if ((status=serror())) { destructHDR(hdr); exit(status);};
if (VERBOSE>8)
printf("\n[129] SREAD on %s successful [%i,%i].\n", hdr->FileName, hdr->data.size[0], hdr->data.size[1]);
if (VERBOSE>8)
printf("\n[130] File %s =%i/%i\n", hdr->FileName, hdr->FILE.OPEN, hdr->FILE.Des);
sclose(hdr);
SOURCE_TYPE = hdr->TYPE;
/*** write file ***/
strcpy(tmp,dest);
}
void hdrread( void) {
int status, k;
hdr->FileName = source;
hdr = sopen(source, "r", hdr); // (char* FileName, char* MODE, HDRTYPE* hdr)
//if (VERBOSE>8) printf("[112] SOPEN-R finished\n");
if ((status=serror())) { destructHDR(hdr); exit(status);}
if (VERBOSE>8) printf("[113] SOPEN-R finished\n");
// all channels are converted - channel selection currently not supported
for (k = 0; k < hdr->NS; k++) {
if (! hdr->CHANNEL[k].OnOff && hdr->CHANNEL[k].SPR) {
if ((hdr->SPR/hdr->CHANNEL[k].SPR)*hdr->CHANNEL[k].SPR != hdr->SPR)
printf("Warning: channel %i might be decimated!\n",k+1);
};
// hdr->CHANNEL[k].OnOff = 1; // convert all channels
}
}
void hdrprint( void) { // prints some items from the header
printf ("[[HDRPRINT:]]\n");
printf(
"[114] hdr->TYPE = %d, hdr->VERSION = %f\n",hdr->TYPE,hdr->VERSION);
printf("HeadLen = %zu, NS = %zu, SPR = %zu, NRec = %llu, SampleRate = %lf\n",
hdr->HeadLen, hdr->NS, hdr->SPR, hdr->NRec, hdr->SampleRate);
// 2 headers; Nuber of channelS; SamplesPerRecord (block);
// Number of Records/blocks (-1 indicates length is unknown)
printf ("HeadLen=%zu, NS=%u, SPR=%zu, NRec=%llu, SampleRate=%lf\n",
hdr->HeadLen, hdr->NS, hdr->SPR, hdr->NRec, hdr->SampleRate );
/* starttime of recording */
struct tm* T0tm;
char timestr[21+6];
T0tm = gdf_time2tm_time(hdr->T0);
// T0tm->__tm_gmtoff;
strftime( timestr, 20, "%F %T ", T0tm); // ISO 8601: %Y-%m-%dT%H:%M:%S
if (VERBOSE>8) printf( "[116] T0 = %s %+03d00\n", timestr, hdr->tzmin/60);
printf ("[[END(HDRPRINT)]]\n");
//hdr2ascii(hdr,stdout,VERBOSE);
hdr2ascii(hdr,stdout,3); // verbosity: 1=basic, 2=channels, 3=eventtable
}
#endif