esignal_fea.c
来自「speech signal process tools」· C语言 代码 · 共 1,315 行 · 第 1/3 页
C
1,315 行
/* * Skip forward "nrec" records in a file "strm" in the Esignal external * format specified by the field list and other header information in the * esignal_hd structure indicated by "esig_hd". For fixed-sized records, * just use the ESPS function "skiprec". For variable-sized records * (indicated by a return of -1 from esignal_rec_size) read and discard * records one at a time. */voidesignal_skip_recs(FILE *strm, long nrec, esignal_hd *hd){ long size; if (hd == NULL) { DebugMsg(1, "esignal_skip_recs: Esignal header pointer is NULL."); return; } if (nrec == 0) return; size = hd->rec_size; if (size != -1) skiprec(strm, nrec, (int) size); else { FieldSpec **lin_list = hd->lin_list; int arch = hd->arch; int i; if (nrec < 0) DebugMsg(1, "esignal_skip_recs: " "Can't back up in file with variable record size."); /* Avoid reading to possibly freed memory. */ for (i = 0; lin_list[i]; i++) lin_list[i]->data = NULL;/*!*//* Consider using ReadSamples when possible */ for ( ; nrec > 0 && ReadRecord(lin_list, arch, strm); nrec--) { } if (nrec > 0) DebugMsg(1, "esignal_skip_recs: ReadRecord failed."); }}/* * Read a record from an Esignal file and store the contents (or some * of the contents) in an ESPS FEA record structure. The file "file" * should be in Esignal format and positioned at the beginning of the * record to be read, and "rec" should point to the record structure. * The argument "hd" should point to an esignal_hd structure such as * "esignal_to_fea" creates when reading the Esignal file header. * The argument "fea_hd" should point to an ESPS FEA header structure * whose fields correspond in name, data type, rank, and dimensions * to some of the REQUIRED fields of the Esignal file. (Such a header * is returned by "esigal_to_fea".) The record record structure must * be compatible with the FEA header. The typical sequence of events * is: * * fea_hd = esignal_to_fea( ..., file); * hd = get_esignal_hdr(fea_hd); * rec = allo_fea_rec(fea_hd); * * followed by a loop that repeatedly executes: * * esignal_get_rec(rec, hd, fea_hd, file); * * The contents of Esignal fields that do not correspond to fields in * the FEA header are read and discarded. The function returns 1 upon * success and EOF upon error or end of file. *//*!*//* MEMORY LEAK: if the Esignal file contains fields of type ARRAY, * memory for the contents will be allocated and abandoned unfreed. * Should save a list of such fields and free them, or make provisions * not to create the array values in the first place. */intesignal_get_rec(struct fea_data *rec, esignal_hd *hd, struct header *fea_hd, FILE *file){ if (!rec || !hd || !file) { DebugMsg(1, "esignal_get_rec: NULL argument."); return EOF; } /* Setup code to make the "data" members of the field specs of the * fields to be read point to the right locations in the FEA * record to receive the data. Since get_fea_rec for a given * input file is typically called repeatedly with the same * fea_data structure, we want to avoid repeating the setup for * every call. We save a copy of *rec (i.e. the actual data pointers * in the fea_data structure, not the pointer "rec") and a pointer * to the "tag" member. If these pointers are unchanged from * the previous call we skip the setup. * Things will BREAK if the contents of the "data" member of an input * field spec are changed. Code that does so should first null out * "fea_tag_ptr" or part of "fea_rec" in the esignal_hd structure * so that the next call of this function will redo the setup. * Cf. "esignal_getsd_recs". */ /* Here we rely on the fact that the data pointers in a fea_data * structure comprise the part following the tag, which is a long * and is the first member. */ if (hd->fea_tag_ptr != &rec->tag || memcmp((char *) &hd->fea_rec + sizeof(long), (char *) rec + sizeof(long), sizeof(struct fea_data) - sizeof(long))) { FieldSpec *fld; int i, fld_count; char *name, **fld_names;/*!*//* Essentially the same code near the end of FieldList_to_fea * (this file and esig2fea.c). Consolidate? */ hd->fea_tag_ptr = &rec->tag; hd->fea_rec = *rec; if (fea_hd->common.tag) { fld = FindField(hd->lin_list, ESPS_TAG); fld->data = &rec->tag; } fld_count = fea_hd->hd.fea->field_count; fld_names = fea_hd->hd.fea->names; for (i = 0; i < fld_count; i++) { name = fld_names[i]; fld = FindField(hd->lin_list, name); fld->data = get_fea_ptr(rec, name, fea_hd); } } if (ReadRecord(hd->lin_list, hd->arch, file)) return 1; else return EOF;}/* * Read sampled data from an Esignal file and store the samples in a buffer * array. The file "file" should be in Esignal format and positioned at * the beginning of the sequence of records to be read, and "buffer" * should point to the beginning of the buffer array. The number of * records be read is given by "num_records". The argument "hd" * should point to an esignal_hd structure such as "esignal_to_fea" * creates when reading the Esignal file header. If the file has just * one REQUIRED field, and no OPTIONAL fields, the contents of that field * are read. If it has more than one field, one field must be named * "samples", and its contents are used; the contents of other fields are * discarded. The number of records actually read is returned; this * will be less than "num_records" in case of error or end of file. */longesignal_getsd_recs(char *buffer, long num_records, esignal_hd *hd, FILE *file){ FieldSpec **lin_list; int arch; if (buffer == NULL || hd == NULL || file == NULL) { DebugMsg(1, "esignal_getsd_recs: NULL arguments."); return 0; } if (num_records == 0) return 0; lin_list = hd->lin_list; if (lin_list == NULL) { DebugMsg(1, "esignal_getsd_recs: no fields to be read."); return 0; } arch = hd->arch; if (hd->one_fld) /* Can read with ReadSamples. */ { return ReadSamples(buffer, num_records, lin_list, arch, file); } else /* Read single records repeateldy. */ { FieldSpec *spec; long step; long num_read; /* * We are about to invalidate hd->fea_rec by changing the "data" * pointer in a field spec that may point into the fea_data * structure. (See comment in esignal_get_rec.) Null part of * hd->fea_rec to avoid fouling up the next call of esignal_get_rec. */ hd->fea_tag_ptr = NULL; hd->fea_rec.d_data = NULL; spec = FindField(hd->fields, "samples"); if (spec == NULL) { DebugMsg(1, "esignal_getsd_recs: " "couldn't find field \"samples\"."); } spec->data = buffer; step = InternTypeSize(spec->type); for (num_read = 0; num_read < num_records && ReadRecord(lin_list, arch, file); num_read++, spec->data = (char *) spec->data + step) { } return num_read; }}/* LOCAL FUNCTION DEFINITIONS *//* * Similar to ReadPreamble, but takes input from a character string in * memory instead of a file. Return Esignal preamble information via * pointer arguments. Return TRUE on success, FALSE on failure. */static intGetPreamble(char **version, /* version (output) */ char **arch, /* architecture (output) */ long *pre_size, /* preamble size (output) */ long *hdr_size, /* header size (output) */ long *rec_size, /* record size (output) */ char *str) /* start of input characters */{ char buf[PREAM_MAX + 1]; /* preamble line + null */ /* Check magic number, MAGIC. */ if (!GetLine(buf, 8, &str)) return FALSE; if (strcmp(buf, MAGIC) != 0) return FALSE; if (!GetLine(buf, 8, &str)) return FALSE; if (version != NULL) *version = StrDup(buf); /* Get architecture. */ if (!GetLine(buf, 8, &str)) return FALSE; if (arch != NULL) *arch = StrDup(buf); /* Get preamble size */ if (!GetLong(pre_size, 8, &str)) return FALSE; /* Could check *pre_size here. */ /* Get header size */ if (!GetLong(hdr_size, 8, &str)) return FALSE; /* Get record size */ if (!GetLong(rec_size, 8, &str)) return FALSE; return TRUE; /* success */}/* * Extract a line of length len (including '\n') into buf from * the string indicated by the variable whose addresss is "src". * Increment the variable to point to the next character after * the extracted substring. * Check length of line, presence of terminating newline, * and absence of trailing blanks. * Trim newline and leading blanks and supply terminating null. * Return TRUE on success, FALSE on failure. * This is like the function "GetLine" in esignal.c, but takes * characters from a string in memory rather than a file. */static intGetLine(char *buf, int len, char **src){ int i, j; if (src == NULL || *src == NULL) return FALSE; memcpy(buf, *src, (size_t) len); buf[len] = '\0'; *src += len; if (strlen(buf) != len || buf[len-1] != '\n') return FALSE; buf[len-1] = '\0'; /* count leading blanks */ for (j = 0; buf[j] == ' '; j++) { } if (j < len - 1 && buf[len-2] == ' ') return FALSE; /* not right justified */ if (j == 0) return TRUE; /* remove leading blanks */ for (i = 0; buf[j] != '\0'; i++,j++) buf[i] = buf[j]; buf[i] = '\0'; return TRUE; /* success */}/* * Extract a line of length len (including '\n') from the string * indicated by the variable whose addresss is "src". Increment the * variable to point to the next character after the extracted * substring. Check length of line and presence of terminating * newline. Convert to long integer, assign result through pointer * "val" if non-NULL. Check for garbage characters following the * constant. Return TRUE on success, FALSE on failure. */static intGetLong(long *val, int len, char **src){ char *buf; char *ptr; /* end-of-scan pointer from strtol */ long value; /* converted value */ buf = (char *) malloc(len+1); /* len + 1 for terminating null */ if (buf == NULL) return FALSE; /* Allocation failure. */ /* Get line; check length. */ if (src == NULL || *src == NULL) return FALSE; memcpy(buf, *src, (size_t) len); buf[len] = '\0'; *src += len; if (strlen(buf) != len || buf[len-1] != '\n') { free(buf); return FALSE; } /* Convert; check for bad format. */ value = strtol(buf, &ptr, 10); if (ptr != buf + (len-1)) { free(buf); return FALSE; } /* Clean up; return. */ free(buf); if (val != NULL) *val = value; return TRUE; /* success */}/*!*//* The functions "FieldList_to_fea", "FindStr", "StrArrayFromRect", * "FieldIsTag", "FieldIsFeaSubtype", and "ElibTypeToEsps" are verbatim * copies of functions in esig2fea.c (except for the conditions that * control printing of debug messages). Move to a separate file that * can be shared by the ESPS library and esig2fea. *//* * Convert an Esignal field list "list" to an ESPS FEA file header * that contains, generally speaking (1) a field definition for each * top-level REQUIRED field whose type corresponds to a possible FEA * field data type, and (2) a generic header item for each top-level * GLOBAL field whose type corresponds to a possible ESPS generic * header-item data type. However, if "fnames" is non-NULL, it is a * NULL-terminated string array that specifies names of a subset of * the REQUIRED and GLOBAL fields to be represented in the output; * other fields in "list" are ignored. If "copy_sources" is TRUE, * VIRTUAL fields in "list" with names of the form "source_<n>", are * translated into embedded source headers in the resulting FEA * header; otherwise the FEA header contains no embedded headers. The * return value is a pointer to the ESPS header, or NULL in case of * error. If "rec" is non-NULL, it gives the address of a variable in * which to return a pointer to an ESPS fea_data structure allocated * by calling "allo_fea_rec" on the returned header. In the Esignal * REQUIRED field specs that correspond to FEA fields in the ESPS * header, the "data" members are made to point to corresponding * locations in the fea_data structure (found with "get_fea_ptr"), so * that calling ReadRecord will read a record in Esignal format and * store valuse from its REQUIRED fields appropriately in the fea_data * structure.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?