📄 fea.doc
字号:
ETM-S-86-25:rap page 6 hd->common.tag = YES; since FEA_ANA files are supposed to be tagged. The basic function for defining fields in feature files is add_fea_fld. The statement add_fea_fld("raw_power", maxraw, 1, (long *) NULL, FLOAT, (char **) NULL, hd); adds to the header information defining the size, type, and dimensions of the field raw_power. Similar invocations of add_fea_fld are required for the other FEA_ANA fields. The functions add_genhd_*(3-ESPS) add generic header items of various types to ESPS file headers. The one that adds long items is add_genhd_l. The function returns a pointer to the storage allocated in the header for the item, so a statement like *add_genhd_l("maxraw", (long *) NULL, 1, hd) = maxraw; both creates the item and assigns a value to it. One such statement is needed for each FEA_ANA generic header item. The functions new_header and add_fea_fld may return error codes that should be checked, though the checking code is not shown above. After the header is complete, but before any records are written, executing the statement write_header(hd, file); writes the header to the file. The steps above show what is required to create a feature-file header. Often there will be several programs that deal with a partic- ular feature-file subtype. In that case it is worth the effort to create a support module for the subtype and to include in it a routine like init_anafea_hd for filling in the header of a feature file and making it a file of the correct subtype. The routine creates generic header items as needed and creates the data record fields. In gen- eral, such a routine takes as arguments those values that affect the size of the data record. These values are stored in the file header (as generic header items). This routine is only used when creating a new FEA_ANA file for output. It is not used when reading a FEA_ANA file. This function returns zero on success and non-zero on failure. It uses a macro ADDFLD to simplify rewriting the series of 5 invocations of add_fea_fld and to check the return codes. #define ADDFLD(name, size, rank, dimen, type, enums) \ {if (add_fea_fld((name), (long)(size), (rank), (long*)(dimen), \ Version 3.3 ERL 1/22/93 ETM-S-86-25:rap page 7 type, (char**)(enums), hd) == -1) return 1;} int init_anafea_hd(hd, maxraw, maxlpc, maxpulses, order_vcd, order_unvcd) struct header *hd; int maxraw, maxlpc, maxpulses, order_vcd, order_unvcd; { /* file is tagged */ hd->common.tag = YES; /* save parameters in the header */ *add_genhd_l("maxraw", (long *) NULL, 1, hd) = maxraw; *add_genhd_l("maxlpc", (long *) NULL, 1, hd) = maxlpc; *add_genhd_l("maxpulses", (long *) NULL, 1, hd) = maxpulses; *add_genhd_l("order_vcd", (long *) NULL, 1, hd) = order_vcd; *add_genhd_l("order_unvcd", (long *) NULL, 1, hd) = order_unvcd; /* create the record fields */ ADDFLD("raw_power", maxraw, 1, NULL, FLOAT, NULL) ADDFLD("lpc_power", maxlpc, 1, NULL, FLOAT, NULL) ADDFLD("p_pulse_len", maxpulses, 1, NULL, FLOAT, NULL) ADDFLD("ref_coeff", MAX(order_vcd, order_unvcd), 1, NULL, FLOAT, NULL) ADDFLD("frame_len", 1, 0, NULL, LONG, NULL) hd->hd.fea->fea_type = FEA_ANA; /* this type code is assigned when the subtype becomes official */ return 0; } 4 . Allocating Data Records To deal with a data record, two structures are to be allocated: a fea_data structure to hold the data and an anafea structure to hold pointers to the locations in the fea_data structure where the various fields are stored. First we'll see how to allocate the structures and set up the pointers with just the basic feature-file facilities. Then comes code for a support-module function allo_anafea_rec that takes care of all these tasks. We begin with allocation of the anafea structure. Assuming a variable declaration struct anafea *ana; the statement ana = (struct anafea *) calloc(1, sizeof *ana); Version 3.3 ERL 1/22/93 ETM-S-86-25:rap page 8 will allocate the structure and assign a pointer to it to ana. Of course, depending on the needs of the program, the structure could have simply been declared at compile time. The data-record memory is allocated with the basic feature-file routine allo_fea_rec, which uses information in the file header to allocate the correct amount of memory of each data type. ana->fea_rec = fea_rec = allo_fea_rec(hd); The address of the feature-file record (the fea_data structure) is saved in the FEA_ANA subtype record (the anafea structure). This is so that subtype-specific routines can simply be passed a pointer to the subtype record and still have access to the underlying feature- file record. (We have also saved the address in a variable fea_rec for convenience of reference.) After the feature record is allocated, get_fea_ptr is called for a pointer to the memory associated with each particular named field. The return data type of this function is (char *), and it must be cast to the correct data type. (This is like malloc(3)). For example, ana->raw_power = (float *) get_fea_ptr(fea_rec, "raw_power", hd); makes ana->raw_power point to the storage for the first element of the float array field named "raw_power", and ana->frame_len = (long *) get_fea_ptr(fea_rec, "frame_len", hd); makes ana->frame_len point to the storage for the long scalar field named "frame_len". Then you can use statements like ana->lpc_power[i] = new_value; xx = *ana->frame_len; to set and get values of field elements. One invocation of get_fea_ptr is needed for each field defined for the subtype. If you fail to use the correct cast, you will get a compile-time error complaining about illegal pointer combinations. If you forget that frame_len is a pointer and say ana->frame_len instead of *ana->frame_len in an expression, you will get a funny number which is the address of the data. In some such cases you will get a message about illegal combination of pointer and integer or some such, but don't count on it. Since get_fea_ptr returns a pointer, you could use its return value directly to access the data instead of saving the pointer in a structure as we have shown. This probably is not the best way to use the function in general. In particular, you probably don't want to put the function call in a processing loop that gets executed 10,000 times. But this does work: Version 3.3 ERL 1/22/93 ETM-S-86-25:rap page 9 something = *(long *) get_fea_ptr(fea_rec, "frame_len", hd) + something_else; So does this: *(long *) get_fea_ptr(fea_rec, "frame_len", hd) = 779; The tag is handled specially, since it's the one field that is directly built in and preallocated in feature file records. ana->tag = &fea_rec->tag; ana->tag is a pointer containing the address of fea_rec->tag, so to say *ana->tag is to refer to the same memory as fea_rec->tag. You can access the tag as *ana->tag, but if you do not want to access it through a pointer, you can just use it directly from the feature file record. The function allo_anafea_rec allocates a feature-file record for the FEA file subtype FEA_ANA. It allocates a structure and assigns to the pointers in it the addresses of the data in the feature-file record. The function uses a macro GETPTR to simplify writing several invocations of get_fea_ptr The feature-file header must be set up before this function is called. #define GETPTR(member,type,field) \ {fana->member = (type *) get_fea_ptr(fea_rec, field, hd);} struct anafea * allo_anafea_rec(hd) struct header hd; { struct anafea *fana = (struct anafea *) calloc(1, sizeof *ana); struct fea_data *fea_rec = allo_fea_rec(hd); /* check to be sure this is the right kind of file */ if(hd->common.type != FT_FEA) error("Not a feature file"); if(hd->hd.fea->fea_type != FEA_ANA) error("Not a FEA_ANA file"); /* hook the pointers in the ana record up to the data area in the * feature file record */ fana->tag = &fea_rec->tag; GETPTR(raw_power, float, "raw_power") GETPTR(lpc_power, float, "lpc_power") GETPTR(p_pulse_len, float, "p_pulse_len") GETPTR(ref_coeff, float, "ref_coeff") GETPTR(frame_len, long, "frame_len") /* save the pointer to the feature file record in the ana record Version 3.3 ERL 1/22/93 ETM-S-86-25:rap page 10 */ fana->fea_rec = fea_rec; return fana; } 5 . Reading and Writing Records In addition to a header-initialization routine and a record- allocation function, a support module for a new file type typically includes get/put record functions that do the record input/output. In most cases the get/put functions simply read or write a feature file record. Since the subtype record consists of pointers to the data record memory there is no moving of data required. In some cases, however, it might be desirable to move the data into a dif- ferent type of data structure. For example, you might want to represent the data in the program as a matrix (this could also be done just by setting up an array of pointers, but in some cases it might be just as well to move the data). In such cases, the get/put routines would be where this movement of the data is done. We continue to use our example from above where we implement the FEA_ANA file type as a feature file and show the required support modules. 5 .1 . put_anafea_rec This routine writes a record of the FEA file subtype FEA_ANA. In this example, it does nothing more than write the feature-file record. In some other cases, it might have to do some transformation of the data (for example to support a matrix data structure). void put_anafea_rec(rec, hd, strm) struct anafea *rec; struct header *hd; FILE *strm; { if (hd->common.type != FT_FEA) error("Not a feature file"); if (hd->hd.fea->fea_type != FEA_ANA) error("Not a FEA_ANA file"); put_fea_rec(rec->fea_rec, hd, strm); } 5 .2 . get_anafea_rec This routine reads a record of the FEA file subtype FEA_ANA. Like the put function above, it does nothing more than get the feature file record. It returns 1 on success because all other ESPS get_record functions return EOF on end of file or a positive non-zero integer if the record is read correctly. Version 3.3 ERL 1/22/93
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -