📄 wav2mfcc-pipe.c
字号:
/** * @file wav2mfcc-pipe.c * @author Akinobu LEE * @date Thu Feb 17 18:12:30 2005 * * <JA> * @brief 不兰侨妨から MFCC 泼魔翁へ恃垂する (フレ〖ム帽疤) * * ここでは wav2mfcc.c の簇眶をフレ〖ム票袋に借妄するために恃垂した * 簇眶が羌められていますˉ千急借妄を不兰掐蜗と士乖して乖う眷圭·こちらの * 簇眶が脱いられますˉ * </JA> * * <EN> * @brief Convert speech inputs into MFCC parameter vectors (per input frame) * * There are functions are derived from wav2mfcc.c, to compute * MFCC vectors in per-frame basis. When performing on-line recognition, * these functions will be used instead of ones in wav2mfcc.c * </EN> * * $Revision: 1.9 $ * *//* * Copyright (c) 1991-2006 Kawahara Lab., Kyoto University * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology * Copyright (c) 2005-2006 Julius project team, Nagoya Institute of Technology * All rights reserved *//* wav2mfcc-pipe.c --- split Wav2MFCC to perform per-frame-basis, and also realtime CMN for 1st-pass pipe-lining *//************************************************************************//* wav2mfcc.c Convert Speech file to MFCC_E_D_(Z) file *//*----------------------------------------------------------------------*//* Author : Yuichiro Nakano *//* *//* Copyright(C) Yuichiro Nakano 1996-1998 *//*----------------------------------------------------------------------*//************************************************************************/#include <sent/stddefs.h>#include <sent/mfcc.h>/** * initialize and setup buffers for a MFCC computataion. * * @param para [in] configuration parameters * @param bf [out] pointer to the entry point of workspace for FFT * @param ssbuf [in] noise spectrum, or NULL if not using spectral subtraction * @param ssbuflen [in] length of above, ignoredwhen @a ssbuf is NULL */voidWMP_init(Value para, float **bf, float *ssbuf, int ssbuflen){ int bflen; /* initialize module */ WMP_calc_init(para, bf, &bflen); if (ssbuf != NULL) { /* check ssbuf length */ if (ssbuflen != bflen) { j_error("Error: Wav2MFCC: noise spectrum length not match\n"); } }}/***********************************************************************//** * Allocate a new delta cycle buffer. * * @param veclen [in] length of a vector * @param windowlen [in] window width for computing delta * * @return pointer to newly allocated delta cycle buffer structure. */DeltaBuf *WMP_deltabuf_new(int veclen, int windowlen){ int i; DeltaBuf *db; db = (DeltaBuf *)mymalloc(sizeof(DeltaBuf)); db->veclen = veclen; db->win = windowlen; db->len = windowlen * 2 + 1; db->mfcc = (float **)mymalloc(sizeof(float *) * db->len); db->is_on = (boolean *) mymalloc(sizeof(boolean) * db->len); for (i=0;i<db->len;i++) { db->mfcc[i] = (float *)mymalloc(sizeof(float) * veclen * 2); } db->B = 0; for(i = 1; i <= windowlen; i++) db->B += i * i; db->B *= 2; return (db);}/** * Destroy the delta cycle buffer. * * @param db [i/o] delta cycle buffer */voidWMP_deltabuf_free(DeltaBuf *db){ int i; for (i=0;i<db->len;i++) { free(db->mfcc[i]); } free(db->is_on); free(db->mfcc); free(db);}/** * Reset and clear the delta cycle buffer. * * @param db [i/o] delta cycle buffer */voidWMP_deltabuf_prepare(DeltaBuf *db){ int i; db->store = 0; for (i=0;i<db->len;i++) { db->is_on[i] = FALSE; }}/** * Calculate delta coefficients of the specified point in the cycle buffer. * * @param db [i/o] delta cycle buffer * @param cur [in] target point to calculate the delta coefficients */static voidWMP_deltabuf_calc(DeltaBuf *db, int cur){ int n, theta, p; float A1, A2, sum; int last_valid_left, last_valid_right; for (n = 0; n < db->veclen; n++) { sum = 0.0; last_valid_left = last_valid_right = cur; for (theta = 1; theta <= db->win; theta++) { p = cur - theta; if (p < 0) p += db->len; if (db->is_on[p]) { A1 = db->mfcc[p][n]; last_valid_left = p; } else { A1 = db->mfcc[last_valid_left][n]; } p = cur + theta; if (p >= db->len) p -= db->len; if (db->is_on[p]) { A2 = db->mfcc[p][n]; last_valid_right = p; } else { A2 = db->mfcc[last_valid_right][n]; } sum += theta * (A2 - A1); } db->mfcc[cur][db->veclen + n] = sum / db->B; }}/** * Store the given MFCC vector into the delta cycle buffer, and compute the * latest delta coefficients. * * @param db [i/o] delta cycle buffer * @param new_mfcc [in] MFCC vector * * @return TRUE if next delta coeff. computed, in that case it is saved * in db->delta[], or FALSE if delta is not yet computed by short of data. */booleanWMP_deltabuf_proceed(DeltaBuf *db, float *new_mfcc) { int cur; boolean ret; /* copy data to store point */ memcpy(db->mfcc[db->store], new_mfcc, sizeof(float) * db->veclen); db->is_on[db->store] = TRUE; /* get current calculation point */ cur = db->store - db->win; if (cur < 0) cur += db->len; /* if the current point is fulfilled, compute delta */ if (db->is_on[cur]) { WMP_deltabuf_calc(db, cur); db->vec = db->mfcc[cur]; ret = TRUE; } else { ret = FALSE; } /* move store pointer to next */ db->store++; if (db->store >= db->len) db->store -= db->len; /* return TRUE if delta computed for current, or -1 if not calculated yet */ return (ret);}/** * Flush the delta cycle buffer the delta coefficients * left in the cycle buffer. * * @param db [i/o] delta cycle buffer * * @return TRUE if next delta coeff. computed, in that case it is saved * in db->delta[], or FALSE if all delta computation has been flushed and * no data is available. * */booleanWMP_deltabuf_flush(DeltaBuf *db) { int cur; boolean ret; /* clear store point */ db->is_on[db->store] = FALSE; /* get current calculation point */ cur = db->store - db->win; if (cur < 0) cur += db->len; /* if the current point if fulfilled, compute delta */ if (db->is_on[cur]) { WMP_deltabuf_calc(db, cur); db->vec = db->mfcc[cur]; ret = TRUE; } else { ret = FALSE; } /* move store pointer to next */ db->store++; if (db->store >= db->len) db->store -= db->len; /* return TRUE if delta computed for current, or -1 if not calculated yet */ return (ret);}/***********************************************************************//* MAP-CMN *//***********************************************************************/#define CPMAX 500 ///< Maximum number of frames to store ceptral mean for CMN update/** * Hold sentence sum of MFCC * */typedef struct { float *mfcc_sum; ///< values of sum of MFCC parameters int framenum; ///< summed number of frames} CMEAN;#define CPSTEP 5 ///< clist allocate stepstatic CMEAN *clist; ///< List of MFCC sum for previous inputsstatic int clist_max; ///< Allocated number of CMEAN in cliststatic int clist_num; ///< Currentlly filled CMEAN in cliststatic int dim; ///< Local workarea to store the number of MFCC dimension.static float cweight; ///< Weight of initial cepstral meanstatic float *cmean_init; ///< Initial cepstral mean for each inputstatic boolean cmean_init_set; ///< TRUE if cmean_init was setstatic CMEAN now; ///< Work area to hold current cepstral mean/** * Initialize MAP-CMN at startup. * * @param dimension [in] vector dimension * @param weight [in] initial cepstral mean weight * */voidCMN_realtime_init(int dimension, float weight){ int i; dim = dimension; cweight = weight; clist_max = CPSTEP; clist_num = 0; clist = (CMEAN *)mymalloc(sizeof(CMEAN) * clist_max); for(i=0;i<clist_max;i++) { clist[i].mfcc_sum = (float *)mymalloc(sizeof(float)*dim); clist[i].framenum = 0; } now.mfcc_sum = (float *)mymalloc(sizeof(float) * dim); cmean_init = (float *)mymalloc(sizeof(float) * dim); cmean_init_set = FALSE;}/** * Prepare for MAP-CMN at start of each input * */voidCMN_realtime_prepare(){ int d; for(d=0;d<dim;d++) now.mfcc_sum[d] = 0.0; now.framenum = 0;}/** * Perform MAP-CMN for incoming MFCC vectors * * @param mfcc [in] MFCC vector * @param dim [in] dimension * */voidCMN_realtime(float *mfcc, int dim){ int d; double x, y; now.framenum++; if (cmean_init_set) { for(d=0;d<dim;d++) { /* accumulate value of given MFCC to sum */ now.mfcc_sum[d] += mfcc[d]; /* calculate map-cmn and perform subtraction to the given vector */ x = now.mfcc_sum[d] + cweight * cmean_init[d]; y = (double)now.framenum + cweight; mfcc[d] -= x / y; } } else { for(d=0;d<dim;d++) { now.mfcc_sum[d] += mfcc[d]; mfcc[d] -= now.mfcc_sum[d] / now.framenum; } }}/** * Update initial cepstral mean from previous utterances for next input. * */voidCMN_realtime_update(){ float *tmp; int i, d; int frames; /* if CMN_realtime was never called before this, return immediately */ /* this may occur by pausing just after startup */ if (now.framenum == 0) return; /* compute cepstral mean from now and previous sums up to CPMAX frames */ for(d=0;d<dim;d++) cmean_init[d] = now.mfcc_sum[d]; frames = now.framenum; for(i=0;i<clist_num;i++) { for(d=0;d<dim;d++) cmean_init[d] += clist[i].mfcc_sum[d]; frames += clist[i].framenum; if (frames >= CPMAX) break; } for(d=0;d<dim;d++) cmean_init[d] /= (float) frames; cmean_init_set = TRUE; /* expand clist if neccessary */ if (clist_num == clist_max && frames < CPMAX) { clist_max += CPSTEP; clist = (CMEAN *)myrealloc(clist, sizeof(CMEAN) * clist_max); for(i=clist_num;i<clist_max;i++) { clist[i].mfcc_sum = (float *)mymalloc(sizeof(float)*dim); clist[i].framenum = 0; } } /* shift clist */ tmp = clist[clist_max-1].mfcc_sum; memcpy(&(clist[1]), &(clist[0]), sizeof(CMEAN) * (clist_max - 1)); clist[0].mfcc_sum = tmp; /* copy now to clist[0] */ memcpy(clist[0].mfcc_sum, now.mfcc_sum, sizeof(float) * dim); clist[0].framenum = now.framenum; if (clist_num < clist_max) clist_num++;}/** * Read binary with byte swap (assume file is Big Endian) * * @param buf [out] data buffer * @param unitbyte [in] size of unit in bytes * @param unitnum [in] number of units to be read * @param fp [in] file pointer * * @return TRUE if required number of units are fully read, FALSE if failed. */static booleanmyread(void *buf, size_t unitbyte, int unitnum, FILE *fp){ if (myfread(buf, unitbyte, unitnum, fp) < (size_t)unitnum) { return(FALSE); }#ifndef WORDS_BIGENDIAN swap_bytes(buf, unitbyte, unitnum);#endif return(TRUE);}/** * Write binary with byte swap (assume data is Big Endian) * * @param buf [in] data buffer * @param unitbyte [in] size of unit in bytes * @param unitnum [in] number of units to write * @param fd [in] file descriptor * * @return TRUE if required number of units are fully written, FALSE if failed. */static booleanmywrite(void *buf, size_t unitbyte, int unitnum, int fd){#ifndef WORDS_BIGENDIAN swap_bytes(buf, unitbyte, unitnum);#endif if (write(fd, buf, unitbyte * unitnum) < unitbyte * unitnum) { return(FALSE); }#ifndef WORDS_BIGENDIAN swap_bytes(buf, unitbyte, unitnum);#endif return(TRUE);}/** * Load CMN parameter from file. If the number of MFCC dimension in the * file does not match the specified one, an error will occur. * * @param filename [in] file name * @param dim [in] required number of MFCC dimensions * * @return TRUE on success, FALSE on failure. */booleanCMN_load_from_file(char *filename, int dim){ FILE *fp; int veclen; if ((fp = fopen_readfile(filename)) == NULL) { j_printerr("Error: CMN_load_from_file: failed to open\n"); return(FALSE); } /* read header */ if (myread(&veclen, sizeof(int), 1, fp) == FALSE) { j_printerr("Error: CMN_load_from_file: failed to read header\n"); fclose_readfile(fp); return(FALSE); } /* check length */ if (veclen != dim) { j_printerr("Error: CMN_load_from_file: vector dimension mismatch\n"); fclose_readfile(fp); return(FALSE); } /* read body */ if (myread(cmean_init, sizeof(float), dim, fp) == FALSE) { j_printerr("Error: CMN_load_from_file: failed to read\n"); fclose_readfile(fp); return(FALSE); } if (fclose_readfile(fp) == -1) { j_printerr("Error: CMN_load_from_file: failed to close\n"); return(FALSE); } cmean_init_set = TRUE; return(TRUE);}/** * Save the current CMN vector to a file. * * @param filename [in] filename to save the data. * * @return TRUE on success, FALSE on failure. */booleanCMN_save_to_file(char *filename){ int fd; if ((fd = creat(filename, 0644)) == -1) { j_printerr("Error: CMN_save_to_file: failed to open\n"); return(FALSE); } /* write header */ if (mywrite(&dim, sizeof(int), 1, fd) == FALSE) { j_printerr("Error: CMN_save_to_file: failed to write header\n"); close(fd); return(FALSE); } /* write body */ if (mywrite(cmean_init, sizeof(float), dim, fd) == FALSE) { j_printerr("Error: CMN_save_to_file: failed to write header\n"); close(fd); return(FALSE); } close(fd); return(TRUE);}/***********************************************************************//* energy normalization and scaling on live input *//***********************************************************************/static LOGPROB energy_max_last; ///< Maximum energy value of last inputstatic LOGPROB energy_min_last; ///< Minimum floored energy value of last inputstatic LOGPROB energy_max; ///< Maximum energy value of current input/** * Initialize work area for energy normalization on live input. * This should be called once on startup. * */voidenergy_max_init(){ energy_max = 5.0;}/** * Prepare values for energy normalization on live input. * This should be called before each input segment. * * @param para [in] MFCC computation configuration parameter */voidenergy_max_prepare(Value *para){ energy_max_last = energy_max; energy_min_last = energy_max - (para->silFloor * LOG_TEN) / 10.0; energy_max = 0.0;}/** * Peform energy normalization using maximum of last input. * * @param f [in] raw energy * @param para [in] MFCC computation configuration parameter * * @return value of the normalized log energy. */LOGPROBenergy_max_normalize(LOGPROB f, Value *para){ if (energy_max < f) energy_max = f; if (f < energy_min_last) f = energy_min_last; return(1.0 - (energy_max_last - f) * para->escale);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -