📄 files.doc
字号:
ETM-S-86-13:rap/jtb page 10 input file and call read_header on this file. This allocates memory for the input file header, checks the header on the input file, and reads to its end. The next read on this file will return data, rather than header, values. If read_header returns without error, then it has found a valid ESPS header. The program should now check common.type to be sure that the file is of the type expected by the program. If it is not, then an error message should be printed and the program should exit with a non-zero exit code (standard convention is to use exit(1)). Some programs may accept several (or any) of the valid ESPS file types. These programs should still consult common.type to determine which pointer in the union hd to use. The use of the wrong pointer will cause unpredictable results (most often a harmless bus error, but worse could happen). Since read_header returns a pointer to the main header structure, a pointer must be declared before read_header is called: struct header *h; . . . h = read header(file); - After the call to read_header, items in the header may be accessed. Here are some examples: char *ref file; float fre-uency, avg zero; . - . . if (h->common.type == FT SD) { /*verify file type*/ fprintf(stderr, "Inp-t file is not an SD file.\n"); exit(1) } ref file = h->variable.refer; /*get name of reference file for tags*/ fre-uency = h->hd.sd.sf; /*sampling frequency of data*/ avg zero = *(float *) get genhd("zero crossing", h); - - - In some ESPS programs (especially newer programs), the call to read_header and the file type checking is done within a library func- tion eopen, which also opens the file. An example of this is given later. If the output file of the program is the same type as the input file then copy_header is useful for creating the header of the new output file and filling in most values from the input file. Some of these values might have to be changed before write_header is called, but in many cases, the header of an output file is much like that of its input file. If the output file is of a different type than the input Version 3.5 ERL 1/22/93 ETM-S-86-13:rap/jtb page 11 file, or the programmer decides that none or very few values will be in common, then new_header should be used to create the header for the new output file. A type code must be specified when new_header is called. In either case, when creating an output ESPS file from source ESPS files, the source headers should be saved in the new output header. This is done by calling add_source_file. Here is an example of reading values from the header of an input file, and creating and writing an output file header. char *speaker name; float samp fr-q, zero crossing, *coh thresh; long num s-mples; - - . - . . ih = read header(in file); /* get input header */ speaker n-me = (cha- *) get genhd("speaker", ih); /*generic example*/ . - - . . oh = new header(FT FEA) /* create new output header */ (void) a-d source -ile(oh,in file,ih); /* save input header */ oh->variab-e.refe- = ih->var-able.refer; /*same refer file*/ /*add the command line as a comment*/ add comment(oh, get cmd line(argc, argv)); (vo-d) strcpy (oh->-omm-n.prog, progname); (void) strcpy (oh->common.vers, Version); /*add generic header items*/ (void)add genhd f("avg. zero crossing", &zero crossing, 1, ih) coh thres- = ad- genhd d("voicing threshold",-(double *)NULL, 1, ih); . - - - . . zero crossing = . . .; *coh-thresh = . . .; (voi-) write header(oh, ostrm); /*ostrm is output file stream*/ - The call to add_source_file results in the input header being stored on the new output file. This is done (within add_source_file ) by setting a pointer (variable.srchead) to point to the old header. There is a limit to the number of headers that can be embedded in this way. It is defined as MAX_SOURCES and its current value can be found in <esps/header.h>. The header item variable.nheads should be checked before calling add_source_file if the programmer wants to avoid the chance of a run-time error because of exceeding this limit. Of course, if the header is being stored in a new header and only once in the program, then it is safe to store a header without checking. This is the case in the above example. The example above includes both "styles" of adding generic header items - the add_genhd_X routines can either allocate space for the item and return a pointer to it, or accept a pointer to existing Version 3.5 ERL 1/22/93 ETM-S-86-13:rap/jtb page 12 space. Note that the actual values written out to the header are the values that exist when write_header is called, not the values that exist when the add_genhd_X routines are called. Thus, in the above example, the two lines prior to the write_header call determine the values written to the corresponding generic header items. There is, however, a "Hi-C" way to guarantee that the value written to the header is fixed at the time of the call to add_genhd_X routine, as follows: *add_genhd_f("avg. zero crossing", NULL, 1, ih) = zero_crossing; When writing programs that exploit the generic header items in the input ESPS files, it may be the case that the presence of those items is useful but not essential. In such cases, care should be taken allow the program to run on ESPS files that do not have the required gereric header items. This can be accomplished by using genhd_list, or by checking for a NULL return value from get_genhd. 6 . Data Structures The data structures for data records in the different types of ESPS files are specified in the Section 5 manual pages that describe the file formats. The general approach is to define a C structure that represents one data record in the file. Access functions are avail- able to support reading and writing such records, so that programmers can deal with the C structure and ignore the issue of how that struc- ture is stored in the file. 6 .1 . Data Access Routines In general a function named get_xx_rec and one named put_xx_rec are provided to get and put records from/onto an ESPS file type xx. There is also nallo_xx_rec function that allocates memory for one record. In most cases, the size of certain elements of the record, depend on values in the file header. For example, here is an example of reading a SPEC record: FILE *ifile; struct ana data *p; struct hea-er *ih; . . . ifile = fopen(in file,"r"); /* open the file */ ih = read header-ifile); /* read the header */ if (ih->c-mmon.type != FT SPEC) bomb();/* must be an ANA file */ p = allo ana rec(ih); - /* allocate the record */ if (!get-ana-rec(p,ih,ifile) eof(); /* read record */ nfreq = -->n-frqs; /* get number of frequencies*/ - Version 3.5 ERL 1/22/93 ETM-S-86-13:rap/jtb page 13 The pointer p could be used in subsequent calls to get_ana_rec pro- vided that the program deals with only one record at a time. If more than one record is needed at the same time within the program, addi- tional pointers must be declared and additional space must be allo- cated by calls to allo_ana_rec. In the case of the built in file types, the type of the data (e.g. float, integer, etc.) is fixed and defined by the file format itself. The header access routine write_header automatically sets the type fields in the common part of the header to their correct values (which depend on various other fields in the header). The type codes might be set by code like this (this is done within write_header - most ESPS programmers will never have to do anything like this): struct header *h; { . . . /* the tag doesn't count here */ h->common.ndouble = 0; h->common.nfloat = 3 * val1 + 2; h->common.nlong = 0; h->common.\fRshort = 1; h->common.nchar = 0; } The actual code in the library has additional logic to insure that it is being used properly. There is one case where the type code fields are not set properly by write_header - old style SD files. Since SD files can have data records of different types (unlike other current file types, in which the types in records are pre-defined), the user has specify what type of SD record is wanted. This is done by means of the function set_sd_type, which must be called before writing any data to the file and before calling write_header. SD files are exceptional in one other respect, namely that the "get" and "put" routines come in several flavors. Recognizing that programmers will sometimes want to read or write SD records to or from short, float, and double arrays, different routines are provided to support these cases. For example, the routine put_sd_recf will write SD records from a program array of type float. Note that the type of SD record (i.e., the type that will be stored in the SD file) does not matter here. Provided that there has been a previous call to set_sd_type, the right conversion will be performed on output. The new FEA_SD file type, which is intended to replace SD files, also allows separate specification of the data type stored in the file and the data type in memory (see init_feasd_hd and allo_feasd_recs). As mentioned above, FEA files provide a mechanism to define their own record structure. That is, users can determine the number, types, sizes, and names of the items stored in FEA records. FEA files include special support for labelling the records with pointers to Version 3.5 ERL 1/22/93
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -