PocketSphinx  0.6
src/libpocketsphinx/acmod.c
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
00002 /* ====================================================================
00003  * Copyright (c) 2008 Carnegie Mellon University.  All rights
00004  * reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer. 
00012  *
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in
00015  *    the documentation and/or other materials provided with the
00016  *    distribution.
00017  *
00018  * This work was supported in part by funding from the Defense Advanced 
00019  * Research Projects Agency and the National Science Foundation of the 
00020  * United States of America, and the CMU Sphinx Speech Consortium.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND 
00023  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
00024  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00025  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
00026  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00027  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
00028  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
00029  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
00030  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
00031  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
00032  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  * ====================================================================
00035  *
00036  */
00037 
00038 
00044 /* System headers. */
00045 #include <assert.h>
00046 #include <string.h>
00047 
00048 /* SphinxBase headers. */
00049 #include <sphinxbase/prim_type.h>
00050 #include <sphinxbase/err.h>
00051 #include <sphinxbase/cmd_ln.h>
00052 #include <sphinxbase/strfuncs.h>
00053 #include <sphinxbase/byteorder.h>
00054 #include <sphinxbase/feat.h>
00055 #include <sphinxbase/bio.h>
00056 
00057 /* Local headers. */
00058 #include "cmdln_macro.h"
00059 #include "acmod.h"
00060 #include "s2_semi_mgau.h"
00061 #include "ptm_mgau.h"
00062 #include "ms_mgau.h"
00063 
00064 /* Feature and front-end parameters that may be in feat.params */
00065 static const arg_t feat_defn[] = {
00066     waveform_to_cepstral_command_line_macro(),
00067     cepstral_to_feature_command_line_macro(),
00068     CMDLN_EMPTY_OPTION
00069 };
00070 
00071 #ifndef WORDS_BIGENDIAN
00072 #define WORDS_BIGENDIAN 1
00073 #endif
00074 
00075 static int32 acmod_process_mfcbuf(acmod_t *acmod);
00076 
00077 static int
00078 acmod_init_am(acmod_t *acmod)
00079 {
00080     char const *mdeffn, *tmatfn, *mllrfn;
00081 
00082     /* Read model definition. */
00083     if ((mdeffn = cmd_ln_str_r(acmod->config, "-mdef")) == NULL) {
00084         E_ERROR("Acoustic model definition is not specified neither with -mdef option nor with -hmm\n");
00085         return -1;
00086     }
00087 
00088     if ((acmod->mdef = bin_mdef_read(acmod->config, mdeffn)) == NULL) {
00089         E_ERROR("Failed to read acoustic model definition from %s\n", mdeffn);
00090         return -1;
00091     }
00092 
00093     /* Read transition matrices. */
00094     if ((tmatfn = cmd_ln_str_r(acmod->config, "-tmat")) == NULL) {
00095         E_ERROR("No tmat file specified\n");
00096         return -1;
00097     }
00098     acmod->tmat = tmat_init(tmatfn, acmod->lmath,
00099                             cmd_ln_float32_r(acmod->config, "-tmatfloor"),
00100                             TRUE);
00101 
00102     /* Read the acoustic models. */
00103     if ((cmd_ln_str_r(acmod->config, "-mean") == NULL)
00104         || (cmd_ln_str_r(acmod->config, "-var") == NULL)
00105         || (cmd_ln_str_r(acmod->config, "-tmat") == NULL)) {
00106         E_ERROR("No mean/var/tmat files specified\n");
00107         return -1;
00108     }
00109 
00110     if (cmd_ln_str_r(acmod->config, "-senmgau")) {
00111         E_INFO("Using general multi-stream GMM computation\n");
00112         acmod->mgau = ms_mgau_init(acmod->config, acmod->lmath, acmod->mdef);
00113         if (acmod->mgau == NULL)
00114             return -1;
00115     }
00116     else {
00117         E_INFO("Attempting to use SCHMM computation module\n");
00118         if ((acmod->mgau = s2_semi_mgau_init(acmod)) == NULL) {
00119             E_INFO("Attempting to use PTHMM computation module\n");
00120             if ((acmod->mgau = ptm_mgau_init(acmod, acmod->mdef)) == NULL) {
00121                 E_INFO("Falling back to general multi-stream GMM computation\n");
00122                 acmod->mgau = ms_mgau_init(acmod->config, acmod->lmath, acmod->mdef);
00123                 if (acmod->mgau == NULL)
00124                     return -1;
00125             }
00126         }
00127     }
00128 
00129     /* If there is an MLLR transform, apply it. */
00130     if ((mllrfn = cmd_ln_str_r(acmod->config, "-mllr"))) {
00131         ps_mllr_t *mllr = ps_mllr_read(mllrfn);
00132         if (mllr == NULL)
00133             return -1;
00134         acmod_update_mllr(acmod, mllr);
00135     }
00136 
00137     return 0;
00138 }
00139 
00140 static int
00141 acmod_init_feat(acmod_t *acmod)
00142 {
00143     acmod->fcb = 
00144         feat_init(cmd_ln_str_r(acmod->config, "-feat"),
00145                   cmn_type_from_str(cmd_ln_str_r(acmod->config,"-cmn")),
00146                   cmd_ln_boolean_r(acmod->config, "-varnorm"),
00147                   agc_type_from_str(cmd_ln_str_r(acmod->config, "-agc")),
00148                   1, cmd_ln_int32_r(acmod->config, "-ceplen"));
00149     if (acmod->fcb == NULL)
00150         return -1;
00151 
00152     if (cmd_ln_str_r(acmod->config, "-lda")) {
00153         E_INFO("Reading linear feature transformation from %s\n",
00154                cmd_ln_str_r(acmod->config, "-lda"));
00155         if (feat_read_lda(acmod->fcb,
00156                           cmd_ln_str_r(acmod->config, "-lda"),
00157                           cmd_ln_int32_r(acmod->config, "-ldadim")) < 0)
00158             return -1;
00159     }
00160 
00161     if (cmd_ln_str_r(acmod->config, "-svspec")) {
00162         int32 **subvecs;
00163         E_INFO("Using subvector specification %s\n", 
00164                cmd_ln_str_r(acmod->config, "-svspec"));
00165         if ((subvecs = parse_subvecs(cmd_ln_str_r(acmod->config, "-svspec"))) == NULL)
00166             return -1;
00167         if ((feat_set_subvecs(acmod->fcb, subvecs)) < 0)
00168             return -1;
00169     }
00170 
00171     if (cmd_ln_exists_r(acmod->config, "-agcthresh")
00172         && 0 != strcmp(cmd_ln_str_r(acmod->config, "-agc"), "none")) {
00173         agc_set_threshold(acmod->fcb->agc_struct,
00174                           cmd_ln_float32_r(acmod->config, "-agcthresh"));
00175     }
00176 
00177     if (acmod->fcb->cmn_struct
00178         && cmd_ln_exists_r(acmod->config, "-cmninit")) {
00179         char *c, *cc, *vallist;
00180         int32 nvals;
00181 
00182         vallist = ckd_salloc(cmd_ln_str_r(acmod->config, "-cmninit"));
00183         c = vallist;
00184         nvals = 0;
00185         while (nvals < acmod->fcb->cmn_struct->veclen
00186                && (cc = strchr(c, ',')) != NULL) {
00187             *cc = '\0';
00188             acmod->fcb->cmn_struct->cmn_mean[nvals] = FLOAT2MFCC(atof(c));
00189             c = cc + 1;
00190             ++nvals;
00191         }
00192         if (nvals < acmod->fcb->cmn_struct->veclen && *c != '\0') {
00193             acmod->fcb->cmn_struct->cmn_mean[nvals] = FLOAT2MFCC(atof(c));
00194         }
00195         ckd_free(vallist);
00196     }
00197     return 0;
00198 }
00199 
00200 int
00201 acmod_fe_mismatch(acmod_t *acmod, fe_t *fe)
00202 {
00203     /* Output vector dimension needs to be the same. */
00204     if (cmd_ln_int32_r(acmod->config, "-ceplen") != fe_get_output_size(fe)) {
00205         E_ERROR("Configured feature length %d doesn't match feature extraction output size %d\n", 
00206                 cmd_ln_int32_r(acmod->config, "-ceplen"), 
00207                 fe_get_output_size(fe));
00208         return TRUE;
00209     }
00210     /* Feature parameters need to be the same. */
00211     /* ... */
00212     return FALSE;
00213 }
00214 
00215 int
00216 acmod_feat_mismatch(acmod_t *acmod, feat_t *fcb)
00217 {
00218     /* Feature type needs to be the same. */
00219     if (0 != strcmp(cmd_ln_str_r(acmod->config, "-feat"), feat_name(fcb)))
00220         return TRUE;
00221     /* Input vector dimension needs to be the same. */
00222     if (cmd_ln_int32_r(acmod->config, "-ceplen") != feat_cepsize(fcb))
00223         return TRUE;
00224     /* FIXME: Need to check LDA and stuff too. */
00225     return FALSE;
00226 }
00227 
00228 acmod_t *
00229 acmod_init(cmd_ln_t *config, logmath_t *lmath, fe_t *fe, feat_t *fcb)
00230 {
00231     acmod_t *acmod;
00232     char const *featparams;
00233 
00234     acmod = ckd_calloc(1, sizeof(*acmod));
00235     acmod->config = config;
00236     acmod->lmath = lmath;
00237     acmod->state = ACMOD_IDLE;
00238 
00239     /* Look for feat.params in acoustic model dir. */
00240     if ((featparams = cmd_ln_str_r(acmod->config, "-featparams"))) {
00241         if (cmd_ln_parse_file_r(acmod->config, feat_defn, featparams, FALSE) != NULL) {
00242             E_INFO("Parsed model-specific feature parameters from %s\n", featparams);
00243         }
00244     }
00245 
00246     /* Initialize feature computation. */
00247     if (fe) {
00248         if (acmod_fe_mismatch(acmod, fe))
00249             goto error_out;
00250         fe_retain(fe);
00251         acmod->fe = fe;
00252     }
00253     else {
00254         /* Initialize a new front end. */
00255         cmd_ln_retain(config);
00256         acmod->fe = fe_init_auto_r(config);
00257         if (acmod->fe == NULL)
00258             goto error_out;
00259         if (acmod_fe_mismatch(acmod, acmod->fe))
00260             goto error_out;
00261     }
00262     if (fcb) {
00263         if (acmod_feat_mismatch(acmod, fcb))
00264             goto error_out;
00265         feat_retain(fcb);
00266         acmod->fcb = fcb;
00267     }
00268     else {
00269         /* Initialize a new fcb. */
00270         if (acmod_init_feat(acmod) < 0)
00271             goto error_out;
00272     }
00273 
00274     /* Load acoustic model parameters. */
00275     if (acmod_init_am(acmod) < 0)
00276         goto error_out;
00277 
00278 
00279     /* The MFCC buffer needs to be at least as large as the dynamic
00280      * feature window.  */
00281     acmod->n_mfc_alloc = acmod->fcb->window_size * 2 + 1;
00282     acmod->mfc_buf = (mfcc_t **)
00283         ckd_calloc_2d(acmod->n_mfc_alloc, acmod->fcb->cepsize,
00284                       sizeof(**acmod->mfc_buf));
00285 
00286     /* Feature buffer has to be at least as large as MFCC buffer. */
00287     acmod->n_feat_alloc = acmod->n_mfc_alloc + cmd_ln_int32_r(config, "-pl_window");
00288     acmod->feat_buf = feat_array_alloc(acmod->fcb, acmod->n_feat_alloc);
00289     acmod->framepos = ckd_calloc(acmod->n_feat_alloc, sizeof(*acmod->framepos));
00290 
00291     /* Senone computation stuff. */
00292     acmod->senone_scores = ckd_calloc(bin_mdef_n_sen(acmod->mdef),
00293                                                      sizeof(*acmod->senone_scores));
00294     acmod->senone_active_vec = bitvec_alloc(bin_mdef_n_sen(acmod->mdef));
00295     acmod->senone_active = ckd_calloc(bin_mdef_n_sen(acmod->mdef),
00296                                                      sizeof(*acmod->senone_active));
00297     acmod->log_zero = logmath_get_zero(acmod->lmath);
00298     acmod->compallsen = cmd_ln_boolean_r(config, "-compallsen");
00299     return acmod;
00300 
00301 error_out:
00302     acmod_free(acmod);
00303     return NULL;
00304 }
00305 
00306 void
00307 acmod_free(acmod_t *acmod)
00308 {
00309     if (acmod == NULL)
00310         return;
00311 
00312     feat_free(acmod->fcb);
00313     fe_free(acmod->fe);
00314 
00315     if (acmod->mfc_buf)
00316         ckd_free_2d((void **)acmod->mfc_buf);
00317     if (acmod->feat_buf)
00318         feat_array_free(acmod->feat_buf);
00319 
00320     if (acmod->mfcfh)
00321         fclose(acmod->mfcfh);
00322     if (acmod->rawfh)
00323         fclose(acmod->rawfh);
00324     if (acmod->senfh)
00325         fclose(acmod->senfh);
00326 
00327     ckd_free(acmod->framepos);
00328     ckd_free(acmod->senone_scores);
00329     ckd_free(acmod->senone_active_vec);
00330     ckd_free(acmod->senone_active);
00331 
00332     if (acmod->mdef)
00333         bin_mdef_free(acmod->mdef);
00334     if (acmod->tmat)
00335         tmat_free(acmod->tmat);
00336     if (acmod->mgau)
00337         ps_mgau_free(acmod->mgau);
00338     if (acmod->mllr)
00339         ps_mllr_free(acmod->mllr);
00340     
00341     ckd_free(acmod);
00342 }
00343 
00344 ps_mllr_t *
00345 acmod_update_mllr(acmod_t *acmod, ps_mllr_t *mllr)
00346 {
00347     if (acmod->mllr)
00348         ps_mllr_free(acmod->mllr);
00349     acmod->mllr = mllr;
00350     ps_mgau_transform(acmod->mgau, mllr);
00351 
00352     return mllr;
00353 }
00354 
00355 int
00356 acmod_write_senfh_header(acmod_t *acmod, FILE *logfh)
00357 {
00358     char nsenstr[64], logbasestr[64];
00359 
00360     sprintf(nsenstr, "%d", bin_mdef_n_sen(acmod->mdef));
00361     sprintf(logbasestr, "%f", logmath_get_base(acmod->lmath));
00362     return bio_writehdr(logfh,
00363                         "version", "0.1",
00364                         "mdef_file", cmd_ln_str_r(acmod->config, "-mdef"),
00365                         "n_sen", nsenstr,
00366                         "logbase", logbasestr, NULL);
00367 }
00368 
00369 int
00370 acmod_set_senfh(acmod_t *acmod, FILE *logfh)
00371 {
00372     if (acmod->senfh)
00373         fclose(acmod->senfh);
00374     acmod->senfh = logfh;
00375     if (logfh == NULL)
00376         return 0;
00377     return acmod_write_senfh_header(acmod, logfh);
00378 }
00379 
00380 int
00381 acmod_set_mfcfh(acmod_t *acmod, FILE *logfh)
00382 {
00383     int rv = 0;
00384 
00385     if (acmod->mfcfh)
00386         fclose(acmod->mfcfh);
00387     acmod->mfcfh = logfh;
00388     fwrite(&rv, 4, 1, acmod->mfcfh);
00389     return rv;
00390 }
00391 
00392 int
00393 acmod_set_rawfh(acmod_t *acmod, FILE *logfh)
00394 {
00395     if (acmod->rawfh)
00396         fclose(acmod->rawfh);
00397     acmod->rawfh = logfh;
00398     return 0;
00399 }
00400 
00401 void
00402 acmod_grow_feat_buf(acmod_t *acmod, int nfr)
00403 {
00404     mfcc_t ***new_feat_buf;
00405 
00406     new_feat_buf = feat_array_alloc(acmod->fcb, nfr);
00407     if (acmod->n_feat_frame || acmod->grow_feat) {
00408         memcpy(new_feat_buf[0][0], acmod->feat_buf[0][0],
00409                (acmod->n_feat_alloc
00410                 * feat_dimension(acmod->fcb)
00411                 * sizeof(***acmod->feat_buf)));
00412     }
00413     feat_array_free(acmod->feat_buf);
00414     acmod->framepos = ckd_realloc(acmod->framepos,
00415                                   nfr * sizeof(*acmod->framepos));
00416     acmod->feat_buf = new_feat_buf;
00417     acmod->n_feat_alloc = nfr;
00418 }
00419 
00420 int
00421 acmod_set_grow(acmod_t *acmod, int grow_feat)
00422 {
00423     int tmp = acmod->grow_feat;
00424     acmod->grow_feat = grow_feat;
00425 
00426     /* Expand feat_buf to a reasonable size to start with. */
00427     if (grow_feat && acmod->n_feat_alloc < 128)
00428         acmod_grow_feat_buf(acmod, 128);
00429 
00430     return tmp;
00431 }
00432 
00433 int
00434 acmod_start_utt(acmod_t *acmod)
00435 {
00436     fe_start_utt(acmod->fe);
00437     acmod->state = ACMOD_STARTED;
00438     acmod->n_mfc_frame = 0;
00439     acmod->n_feat_frame = 0;
00440     acmod->mfc_outidx = 0;
00441     acmod->feat_outidx = 0;
00442     acmod->output_frame = 0;
00443     acmod->senscr_frame = -1;
00444     acmod->n_senone_active = 0;
00445     acmod->mgau->frame_idx = 0;
00446     return 0;
00447 }
00448 
00449 int
00450 acmod_end_utt(acmod_t *acmod)
00451 {
00452     int32 nfr = 0;
00453 
00454     acmod->state = ACMOD_ENDED;
00455     if (acmod->n_mfc_frame < acmod->n_mfc_alloc) {
00456         int inptr;
00457         /* Where to start writing them (circular buffer) */
00458         inptr = (acmod->mfc_outidx + acmod->n_mfc_frame) % acmod->n_mfc_alloc;
00459         /* nfr is always either zero or one. */
00460         fe_end_utt(acmod->fe, acmod->mfc_buf[inptr], &nfr);
00461         acmod->n_mfc_frame += nfr;
00462         /* Process whatever's left, and any leadout. */
00463         if (nfr)
00464             nfr = acmod_process_mfcbuf(acmod);
00465     }
00466     if (acmod->mfcfh) {
00467         int32 outlen, rv;
00468         outlen = (ftell(acmod->mfcfh) - 4) / 4;
00469         if (!WORDS_BIGENDIAN)
00470             SWAP_INT32(&outlen);
00471         /* Try to seek and write */
00472         if ((rv = fseek(acmod->mfcfh, 0, SEEK_SET)) == 0) {
00473             fwrite(&outlen, 4, 1, acmod->mfcfh);
00474         }
00475         fclose(acmod->mfcfh);
00476         acmod->mfcfh = NULL;
00477     }
00478     if (acmod->rawfh) {
00479         fclose(acmod->rawfh);
00480         acmod->rawfh = NULL;
00481     }
00482 
00483     if (acmod->senfh) {
00484         fclose(acmod->senfh);
00485         acmod->senfh = NULL;
00486     }
00487 
00488     return nfr;
00489 }
00490 
00491 static int
00492 acmod_log_mfc(acmod_t *acmod,
00493               mfcc_t **cep, int n_frames)
00494 {
00495     int i, n;
00496     int32 *ptr = (int32 *)cep[0];
00497 
00498     n = n_frames * feat_cepsize(acmod->fcb);
00499     /* Swap bytes. */
00500     if (!WORDS_BIGENDIAN) {
00501         for (i = 0; i < (n * sizeof(mfcc_t)); ++i) {
00502             SWAP_INT32(ptr + i);
00503         }
00504     }
00505     /* Write features. */
00506     if (fwrite(cep[0], sizeof(mfcc_t), n, acmod->mfcfh) != n) {
00507         E_ERROR_SYSTEM("Failed to write %d values to log file", n);
00508     }
00509 
00510     /* Swap them back. */
00511     if (!WORDS_BIGENDIAN) {
00512         for (i = 0; i < (n * sizeof(mfcc_t)); ++i) {
00513             SWAP_INT32(ptr + i);
00514         }
00515     }
00516     return 0;
00517 }
00518 
00519 static int
00520 acmod_process_full_cep(acmod_t *acmod,
00521                        mfcc_t ***inout_cep,
00522                        int *inout_n_frames)
00523 {
00524     int32 nfr;
00525 
00526     /* Write to log file. */
00527     if (acmod->mfcfh)
00528         acmod_log_mfc(acmod, *inout_cep, *inout_n_frames);
00529 
00530     /* Resize feat_buf to fit. */
00531     if (acmod->n_feat_alloc < *inout_n_frames) {
00532         feat_array_free(acmod->feat_buf);
00533         acmod->feat_buf = feat_array_alloc(acmod->fcb, *inout_n_frames);
00534         acmod->n_feat_alloc = *inout_n_frames;
00535         acmod->n_feat_frame = 0;
00536         acmod->feat_outidx = 0;
00537     }
00538     /* Make dynamic features. */
00539     nfr = feat_s2mfc2feat_live(acmod->fcb, *inout_cep, inout_n_frames,
00540                                TRUE, TRUE, acmod->feat_buf);
00541     acmod->n_feat_frame = nfr;
00542     assert(acmod->n_feat_frame <= acmod->n_feat_alloc);
00543     *inout_cep += *inout_n_frames;
00544     *inout_n_frames = 0;
00545     return nfr;
00546 }
00547 
00548 static int
00549 acmod_process_full_raw(acmod_t *acmod,
00550                        int16 const **inout_raw,
00551                        size_t *inout_n_samps)
00552 {
00553     int32 nfr, ntail;
00554     mfcc_t **cepptr;
00555 
00556     /* Write to logging file if any. */
00557     if (acmod->rawfh)
00558         fwrite(*inout_raw, 2, *inout_n_samps, acmod->rawfh);
00559     /* Resize mfc_buf to fit. */
00560     if (fe_process_frames(acmod->fe, NULL, inout_n_samps, NULL, &nfr) < 0)
00561         return -1;
00562     if (acmod->n_mfc_alloc < nfr + 1) {
00563         ckd_free_2d(acmod->mfc_buf);
00564         acmod->mfc_buf = ckd_calloc_2d(nfr + 1, fe_get_output_size(acmod->fe),
00565                                        sizeof(**acmod->mfc_buf));
00566         acmod->n_mfc_alloc = nfr + 1;
00567     }
00568     acmod->n_mfc_frame = 0;
00569     acmod->mfc_outidx = 0;
00570     fe_start_utt(acmod->fe);
00571     if (fe_process_frames(acmod->fe, inout_raw, inout_n_samps,
00572                           acmod->mfc_buf, &nfr) < 0)
00573         return -1;
00574     fe_end_utt(acmod->fe, acmod->mfc_buf[nfr], &ntail);
00575     nfr += ntail;
00576 
00577     cepptr = acmod->mfc_buf;
00578     nfr = acmod_process_full_cep(acmod, &cepptr, &nfr);
00579     acmod->n_mfc_frame = 0;
00580     return nfr;
00581 }
00582 
00586 static int32
00587 acmod_process_mfcbuf(acmod_t *acmod)
00588 {
00589     mfcc_t **mfcptr;
00590     int32 ncep;
00591 
00592     ncep = acmod->n_mfc_frame;
00593     /* Also do this in two parts because of the circular mfc_buf. */
00594     if (acmod->mfc_outidx + ncep > acmod->n_mfc_alloc) {
00595         int32 ncep1 = acmod->n_mfc_alloc - acmod->mfc_outidx;
00596         int saved_state = acmod->state;
00597 
00598         /* Make sure we don't end the utterance here. */
00599         if (acmod->state == ACMOD_ENDED)
00600             acmod->state = ACMOD_PROCESSING;
00601         mfcptr = acmod->mfc_buf + acmod->mfc_outidx;
00602         ncep1 = acmod_process_cep(acmod, &mfcptr, &ncep1, FALSE);
00603         /* It's possible that not all available frames were filled. */
00604         ncep -= ncep1;
00605         acmod->n_mfc_frame -= ncep1;
00606         acmod->mfc_outidx += ncep1;
00607         acmod->mfc_outidx %= acmod->n_mfc_alloc;
00608         /* Restore original state (could this really be the end) */
00609         acmod->state = saved_state;
00610     }
00611     mfcptr = acmod->mfc_buf + acmod->mfc_outidx;
00612     ncep = acmod_process_cep(acmod, &mfcptr, &ncep, FALSE);
00613     acmod->n_mfc_frame -= ncep;
00614     acmod->mfc_outidx += ncep;
00615     acmod->mfc_outidx %= acmod->n_mfc_alloc;
00616     return ncep;
00617 }
00618 
00619 int
00620 acmod_process_raw(acmod_t *acmod,
00621                   int16 const **inout_raw,
00622                   size_t *inout_n_samps,
00623                   int full_utt)
00624 {
00625     int32 ncep;
00626 
00627     /* If this is a full utterance, process it all at once. */
00628     if (full_utt)
00629         return acmod_process_full_raw(acmod, inout_raw, inout_n_samps);
00630 
00631     /* Append MFCCs to the end of any that are previously in there
00632      * (in practice, there will probably be none) */
00633     if (inout_n_samps && *inout_n_samps) {
00634         int16 const *prev_audio_inptr = *inout_raw;
00635         int inptr;
00636 
00637         /* Total number of frames available. */
00638         ncep = acmod->n_mfc_alloc - acmod->n_mfc_frame;
00639         /* Where to start writing them (circular buffer) */
00640         inptr = (acmod->mfc_outidx + acmod->n_mfc_frame) % acmod->n_mfc_alloc;
00641 
00642         /* Write them in two (or more) parts if there is wraparound. */
00643         while (inptr + ncep > acmod->n_mfc_alloc) {
00644             int32 ncep1 = acmod->n_mfc_alloc - inptr;
00645             if (fe_process_frames(acmod->fe, inout_raw, inout_n_samps,
00646                                   acmod->mfc_buf + inptr, &ncep1) < 0)
00647                 return -1;
00648             /* Write to logging file if any. */
00649             if (acmod->rawfh) {
00650                 fwrite(prev_audio_inptr, 2,
00651                        *inout_raw - prev_audio_inptr,
00652                        acmod->rawfh);
00653                 prev_audio_inptr = *inout_raw;
00654             }
00655             /* ncep1 now contains the number of frames actually
00656              * processed.  This is a good thing, but it means we
00657              * actually still might have some room left at the end of
00658              * the buffer, hence the while loop.  Unfortunately it
00659              * also means that in the case where we are really
00660              * actually done, we need to get out totally, hence the
00661              * goto. */
00662             acmod->n_mfc_frame += ncep1;
00663             ncep -= ncep1;
00664             inptr += ncep1;
00665             inptr %= acmod->n_mfc_alloc;
00666             if (ncep1 == 0)
00667                 goto alldone;
00668         }
00669         assert(inptr + ncep <= acmod->n_mfc_alloc);
00670         if (fe_process_frames(acmod->fe, inout_raw, inout_n_samps,
00671                               acmod->mfc_buf + inptr, &ncep) < 0)
00672             return -1;
00673         /* Write to logging file if any. */
00674         if (acmod->rawfh) {
00675             fwrite(prev_audio_inptr, 2,
00676                    *inout_raw - prev_audio_inptr, acmod->rawfh);
00677             prev_audio_inptr = *inout_raw;
00678         }
00679         acmod->n_mfc_frame += ncep;
00680     alldone:
00681         ;
00682     }
00683 
00684     /* Hand things off to acmod_process_cep. */
00685     return acmod_process_mfcbuf(acmod);
00686 }
00687 
00688 int
00689 acmod_process_cep(acmod_t *acmod,
00690                   mfcc_t ***inout_cep,
00691                   int *inout_n_frames,
00692                   int full_utt)
00693 {
00694     int32 nfeat, ncep, inptr;
00695     int orig_n_frames;
00696 
00697     /* If this is a full utterance, process it all at once. */
00698     if (full_utt)
00699         return acmod_process_full_cep(acmod, inout_cep, inout_n_frames);
00700 
00701     /* Write to log file. */
00702     if (acmod->mfcfh)
00703         acmod_log_mfc(acmod, *inout_cep, *inout_n_frames);
00704 
00705     /* Maximum number of frames we're going to generate. */
00706     orig_n_frames = ncep = nfeat = *inout_n_frames;
00707 
00708     /* FIXME: This behaviour isn't guaranteed... */
00709     if (acmod->state == ACMOD_ENDED)
00710         nfeat += feat_window_size(acmod->fcb);
00711     else if (acmod->state == ACMOD_STARTED)
00712         nfeat -= feat_window_size(acmod->fcb);
00713 
00714     /* Clamp number of features to fit available space. */
00715     if (nfeat > acmod->n_feat_alloc - acmod->n_feat_frame) {
00716         /* Grow it as needed - we have to grow it at the end of an
00717          * utterance because we can't return a short read there. */
00718         if (acmod->grow_feat || acmod->state == ACMOD_ENDED)
00719             acmod_grow_feat_buf(acmod, acmod->n_feat_alloc + nfeat);
00720         else
00721             ncep -= (nfeat - (acmod->n_feat_alloc - acmod->n_feat_frame));
00722     }
00723 
00724     /* Where to start writing in the feature buffer. */
00725     if (acmod->grow_feat) {
00726         /* Grow to avoid wraparound if grow_feat == TRUE. */
00727         inptr = acmod->feat_outidx + acmod->n_feat_frame;
00728         while (inptr + nfeat >= acmod->n_feat_alloc)
00729             acmod_grow_feat_buf(acmod, acmod->n_feat_alloc * 2);
00730     }
00731     else {
00732         inptr = (acmod->feat_outidx + acmod->n_feat_frame) % acmod->n_feat_alloc;
00733     }
00734 
00735     /* Write them in two parts if there is wraparound. */
00736     if (inptr + nfeat > acmod->n_feat_alloc) {
00737         int32 ncep1 = acmod->n_feat_alloc - inptr;
00738         int saved_state = acmod->state;
00739 
00740         /* Make sure we don't end the utterance here. */
00741         if (acmod->state == ACMOD_ENDED)
00742             acmod->state = ACMOD_PROCESSING;
00743         nfeat = feat_s2mfc2feat_live(acmod->fcb, *inout_cep,
00744                                      &ncep1,
00745                                      (acmod->state == ACMOD_STARTED),
00746                                      (acmod->state == ACMOD_ENDED),
00747                                      acmod->feat_buf + inptr);
00748         if (nfeat < 0)
00749             return -1;
00750         /* Move the output feature pointer forward. */
00751         acmod->n_feat_frame += nfeat;
00752         assert(acmod->n_feat_frame <= acmod->n_feat_alloc);
00753         inptr += nfeat;
00754         inptr %= acmod->n_feat_alloc;
00755         /* Move the input feature pointers forward. */
00756         *inout_n_frames -= ncep1;
00757         *inout_cep += ncep1;
00758         ncep -= ncep1;
00759         /* Restore original state (could this really be the end) */
00760         acmod->state = saved_state;
00761     }
00762 
00763     nfeat = feat_s2mfc2feat_live(acmod->fcb, *inout_cep,
00764                                  &ncep,
00765                                  (acmod->state == ACMOD_STARTED),
00766                                  (acmod->state == ACMOD_ENDED),
00767                                  acmod->feat_buf + inptr);
00768     if (nfeat < 0)
00769         return -1;
00770     acmod->n_feat_frame += nfeat;
00771     assert(acmod->n_feat_frame <= acmod->n_feat_alloc);
00772     /* Move the input feature pointers forward. */
00773     *inout_n_frames -= ncep;
00774     *inout_cep += ncep;
00775     if (acmod->state == ACMOD_STARTED)
00776         acmod->state = ACMOD_PROCESSING;
00777     return orig_n_frames - *inout_n_frames;
00778 }
00779 
00780 int
00781 acmod_process_feat(acmod_t *acmod,
00782                    mfcc_t **feat)
00783 {
00784     int i, inptr;
00785 
00786     if (acmod->n_feat_frame == acmod->n_feat_alloc) {
00787         if (acmod->grow_feat)
00788             acmod_grow_feat_buf(acmod, acmod->n_feat_alloc * 2);
00789         else
00790             return 0;
00791     }
00792 
00793     if (acmod->grow_feat) {
00794         /* Grow to avoid wraparound if grow_feat == TRUE. */
00795         inptr = acmod->feat_outidx + acmod->n_feat_frame;
00796         while (inptr + 1 >= acmod->n_feat_alloc)
00797             acmod_grow_feat_buf(acmod, acmod->n_feat_alloc * 2);
00798     }
00799     else {
00800         inptr = (acmod->feat_outidx + acmod->n_feat_frame) % acmod->n_feat_alloc;
00801     }
00802     for (i = 0; i < feat_dimension1(acmod->fcb); ++i)
00803         memcpy(acmod->feat_buf[inptr][i],
00804                feat[i], feat_dimension2(acmod->fcb, i) * sizeof(**feat));
00805     ++acmod->n_feat_frame;
00806     assert(acmod->n_feat_frame <= acmod->n_feat_alloc);
00807 
00808     return 1;
00809 }
00810 
00811 static int
00812 acmod_read_senfh_header(acmod_t *acmod)
00813 {
00814     char **name, **val;
00815     int32 swap;
00816     int i;
00817 
00818     if (bio_readhdr(acmod->insenfh, &name, &val, &swap) < 0)
00819         goto error_out;
00820     for (i = 0; name[i] != NULL; ++i) {
00821         if (!strcmp(name[i], "n_sen")) {
00822             if (atoi(val[i]) != bin_mdef_n_sen(acmod->mdef)) {
00823                 E_ERROR("Number of senones in senone file (%d) does not match mdef (%d)\n",
00824                         atoi(val[i]), bin_mdef_n_sen(acmod->mdef));
00825                 goto error_out;
00826             }
00827         }
00828         if (!strcmp(name[i], "logbase")) {
00829             if (abs(atof(val[i]) - logmath_get_base(acmod->lmath)) > 0.001) {
00830                 E_ERROR("Logbase in senone file (%f) does not match acmod (%f)\n",
00831                         atof(val[i]), logmath_get_base(acmod->lmath));
00832                 goto error_out;
00833             }
00834         }
00835     }
00836     acmod->insen_swap = swap;
00837     bio_hdrarg_free(name, val);
00838     return 0;
00839 error_out:
00840     bio_hdrarg_free(name, val);
00841     return -1;
00842 }
00843 
00844 int
00845 acmod_set_insenfh(acmod_t *acmod, FILE *senfh)
00846 {
00847     acmod->insenfh = senfh;
00848     if (senfh == NULL) {
00849         acmod->n_feat_frame = 0;
00850         acmod->compallsen = cmd_ln_boolean_r(acmod->config, "-compallsen");
00851         return 0;
00852     }
00853     acmod->compallsen = TRUE;
00854     return acmod_read_senfh_header(acmod);
00855 }
00856 
00857 int
00858 acmod_rewind(acmod_t *acmod)
00859 {
00860     /* If the feature buffer is circular, this is not possible. */
00861     if (acmod->output_frame > acmod->n_feat_alloc) {
00862         E_ERROR("Circular feature buffer cannot be rewound (output frame %d, alloc %d)\n",
00863                acmod->output_frame, acmod->n_feat_alloc);
00864         return -1;
00865     }
00866 
00867     /* Frames consumed + frames available */
00868     acmod->n_feat_frame = acmod->output_frame + acmod->n_feat_frame;
00869 
00870     /* Reset output pointers. */
00871     acmod->feat_outidx = 0;
00872     acmod->output_frame = 0;
00873     acmod->senscr_frame = -1;
00874     acmod->mgau->frame_idx = 0;
00875 
00876     return 0;
00877 }
00878 
00879 int
00880 acmod_advance(acmod_t *acmod)
00881 {
00882     /* Advance the output pointers. */
00883     if (++acmod->feat_outidx == acmod->n_feat_alloc)
00884         acmod->feat_outidx = 0;
00885     --acmod->n_feat_frame;
00886     ++acmod->mgau->frame_idx;
00887 
00888     return ++acmod->output_frame;
00889 }
00890 
00891 int
00892 acmod_write_scores(acmod_t *acmod, int n_active, uint8 const *active,
00893                    int16 const *senscr, FILE *senfh)
00894 {
00895     int16 n_active2;
00896 
00897     /* Uncompressed frame format:
00898      *
00899      * (2 bytes) n_active: Number of active senones
00900      * If all senones active:
00901      * (n_active * 2 bytes) scores of active senones
00902      *
00903      * Otherwise:
00904      * (2 bytes) n_active: Number of active senones
00905      * (n_active bytes) deltas to active senones
00906      * (n_active * 2 bytes) scores of active senones
00907      */
00908     n_active2 = n_active;
00909     if (fwrite(&n_active2, 2, 1, senfh) != 1)
00910         goto error_out;
00911     if (n_active == bin_mdef_n_sen(acmod->mdef)) {
00912         if (fwrite(senscr, 2, n_active, senfh) != n_active)
00913             goto error_out;
00914     }
00915     else {
00916         int i, n;
00917         if (fwrite(active, 1, n_active, senfh) != n_active)
00918             goto error_out;
00919         for (i = n = 0; i < n_active; ++i) {
00920             n += active[i];
00921             if (fwrite(senscr + n, 2, 1, senfh) != 1)
00922                 goto error_out;
00923         }
00924     }
00925     return 0;
00926 error_out:
00927     E_ERROR_SYSTEM("Failed to write frame to senone file");
00928     return -1;
00929 }
00930 
00934 static int
00935 acmod_read_scores_internal(acmod_t *acmod)
00936 {
00937     FILE *senfh = acmod->insenfh;
00938     int16 n_active;
00939     int rv;
00940 
00941     if (acmod->n_feat_frame == acmod->n_feat_alloc) {
00942         if (acmod->grow_feat)
00943             acmod_grow_feat_buf(acmod, acmod->n_feat_alloc * 2);
00944         else
00945             return 0;
00946     }
00947 
00948     if (senfh == NULL)
00949         return -1;
00950     if ((rv = fread(&n_active, 2, 1, senfh)) < 0)
00951         goto error_out;
00952     else if (rv == 0)
00953         return 0;
00954 
00955     acmod->n_senone_active = n_active;
00956     if (acmod->n_senone_active == bin_mdef_n_sen(acmod->mdef)) {
00957         if ((rv = fread(acmod->senone_scores, 2,
00958                         acmod->n_senone_active, senfh)) < 0)
00959             goto error_out;
00960         else if (rv != acmod->n_senone_active)
00961             return 0;
00962     }
00963     else {
00964         int i, n;
00965         if ((rv = fread(acmod->senone_active, 1,
00966                         acmod->n_senone_active, senfh)) < 0)
00967             goto error_out;
00968         else if (rv != acmod->n_senone_active)
00969             return 0;
00970         for (i = 0, n = 0; i < acmod->n_senone_active; ++i) {
00971             int j, sen = n + acmod->senone_active[i];
00972             for (j = n + 1; j < sen; ++j)
00973                 acmod->senone_scores[j] = SENSCR_DUMMY;
00974             if ((rv = fread(acmod->senone_scores + sen, 2, 1, senfh)) < 0)
00975                 goto error_out;
00976             else if (rv == 0)
00977                 return 0;
00978             n = sen;
00979         }
00980         ++n;
00981         while (n < bin_mdef_n_sen(acmod->mdef))
00982             acmod->senone_scores[n++] = SENSCR_DUMMY;
00983     }
00984     return 1;
00985 error_out:
00986     E_ERROR_SYSTEM("Failed to read frame from senone file");
00987     return -1;
00988 }
00989 
00990 int
00991 acmod_read_scores(acmod_t *acmod)
00992 {
00993     int inptr, rv;
00994 
00995     if (acmod->grow_feat) {
00996         /* Grow to avoid wraparound if grow_feat == TRUE. */
00997         inptr = acmod->feat_outidx + acmod->n_feat_frame;
00998         /* Has to be +1, otherwise, next time acmod_advance() is
00999          * called, this will wrap around. */
01000         while (inptr + 1 >= acmod->n_feat_alloc)
01001             acmod_grow_feat_buf(acmod, acmod->n_feat_alloc * 2);
01002     }
01003     else {
01004         inptr = (acmod->feat_outidx + acmod->n_feat_frame) % acmod->n_feat_alloc;
01005     }
01006 
01007     if ((rv = acmod_read_scores_internal(acmod)) != 1)
01008         return rv;
01009 
01010     /* Set acmod->senscr_frame appropriately so that these scores
01011        get reused below in acmod_score(). */
01012     acmod->senscr_frame = acmod->output_frame + acmod->n_feat_frame;
01013 
01014     E_DEBUG(1,("Frame %d has %d active states\n",
01015                acmod->senscr_frame, acmod->n_senone_active));
01016 
01017     /* Increment the "feature frame counter" and record the file
01018      * position for the relevant frame in the (possibly circular)
01019      * buffer. */
01020     ++acmod->n_feat_frame;
01021     acmod->framepos[inptr] = ftell(acmod->insenfh);
01022 
01023     return 1;
01024 }
01025 
01026 static int
01027 calc_frame_idx(acmod_t *acmod, int *inout_frame_idx)
01028 {
01029     int frame_idx;
01030 
01031     /* Calculate the absolute frame index to be scored. */
01032     if (inout_frame_idx == NULL)
01033         frame_idx = acmod->output_frame;
01034     else if (*inout_frame_idx < 0)
01035         frame_idx = acmod->output_frame + 1 + *inout_frame_idx;
01036     else
01037         frame_idx = *inout_frame_idx;
01038 
01039     return frame_idx;
01040 }
01041 
01042 static int
01043 calc_feat_idx(acmod_t *acmod, int frame_idx)
01044 {
01045     int n_backfr, feat_idx;
01046 
01047     n_backfr = acmod->n_feat_alloc - acmod->n_feat_frame;
01048     if (frame_idx < 0 || acmod->output_frame - frame_idx > n_backfr) {
01049         E_ERROR("Frame %d outside queue of %d frames, %d alloc (%d > %d), cannot score\n",
01050                 frame_idx, acmod->n_feat_frame, acmod->n_feat_alloc,
01051                 acmod->output_frame - frame_idx, n_backfr);
01052         return -1;
01053     }
01054 
01055     /* Get the index in feat_buf/framepos of the frame to be scored. */
01056     feat_idx = ((acmod->feat_outidx + frame_idx - acmod->output_frame)
01057                 % acmod->n_feat_alloc);
01058     if (feat_idx < 0) feat_idx += acmod->n_feat_alloc;
01059 
01060     return feat_idx;
01061 }
01062 
01063 mfcc_t **
01064 acmod_get_frame(acmod_t *acmod, int *inout_frame_idx)
01065 {
01066     int frame_idx, feat_idx;
01067 
01068     /* Calculate the absolute frame index requested. */
01069     frame_idx = calc_frame_idx(acmod, inout_frame_idx);
01070 
01071     /* Calculate position of requested frame in circular buffer. */
01072     if ((feat_idx = calc_feat_idx(acmod, frame_idx)) < 0)
01073         return NULL;
01074 
01075     if (inout_frame_idx)
01076         *inout_frame_idx = frame_idx;
01077 
01078     return acmod->feat_buf[feat_idx];
01079 }
01080 
01081 int16 const *
01082 acmod_score(acmod_t *acmod, int *inout_frame_idx)
01083 {
01084     int frame_idx, feat_idx;
01085 
01086     /* Calculate the absolute frame index to be scored. */
01087     frame_idx = calc_frame_idx(acmod, inout_frame_idx);
01088 
01089     /* If all senones are being computed, or we are using a senone file,
01090        then we can reuse existing scores. */
01091     if ((acmod->compallsen || acmod->insenfh)
01092         && frame_idx == acmod->senscr_frame) {
01093         if (inout_frame_idx)
01094             *inout_frame_idx = frame_idx;
01095         return acmod->senone_scores;
01096     }
01097 
01098     /* Calculate position of requested frame in circular buffer. */
01099     if ((feat_idx = calc_feat_idx(acmod, frame_idx)) < 0)
01100         return NULL;
01101 
01102     /* If there is an input senone file locate the appropriate frame and read it. */
01103     if (acmod->insenfh) {
01104         fseek(acmod->insenfh, acmod->framepos[feat_idx], SEEK_SET);
01105         if (acmod_read_scores_internal(acmod) < 0)
01106             return NULL;
01107     }
01108     else {
01109         /* Build active senone list. */
01110         acmod_flags2list(acmod);
01111 
01112         /* Generate scores for the next available frame */
01113         ps_mgau_frame_eval(acmod->mgau,
01114                            acmod->senone_scores,
01115                            acmod->senone_active,
01116                            acmod->n_senone_active,
01117                            acmod->feat_buf[feat_idx],
01118                            frame_idx,
01119                            acmod->compallsen);
01120     }
01121 
01122     if (inout_frame_idx)
01123         *inout_frame_idx = frame_idx;
01124     acmod->senscr_frame = frame_idx;
01125 
01126     /* Dump scores to the senone dump file if one exists. */
01127     if (acmod->senfh) {
01128         if (acmod_write_scores(acmod, acmod->n_senone_active,
01129                                acmod->senone_active,
01130                                acmod->senone_scores,
01131                                acmod->senfh) < 0)
01132             return NULL;
01133         E_DEBUG(1,("Frame %d has %d active states\n", frame_idx, acmod->n_senone_active));
01134     }
01135 
01136     return acmod->senone_scores;
01137 }
01138 
01139 int
01140 acmod_best_score(acmod_t *acmod, int *out_best_senid)
01141 {
01142     int i, best;
01143 
01144     best = SENSCR_DUMMY;
01145     if (acmod->compallsen) {
01146         for (i = 0; i < bin_mdef_n_sen(acmod->mdef); ++i) {
01147             if (acmod->senone_scores[i] < best) {
01148                 best = acmod->senone_scores[i];
01149                 *out_best_senid = i;
01150             }
01151         }
01152     }
01153     else {
01154         int16 *senscr;
01155         senscr = acmod->senone_scores;
01156         for (i = 0; i < acmod->n_senone_active; ++i) {
01157             senscr += acmod->senone_active[i];
01158             if (*senscr < best) {
01159                 best = *senscr;
01160                 *out_best_senid = i;
01161             }
01162         }
01163     }
01164     return best;
01165 }
01166 
01167 
01168 void
01169 acmod_clear_active(acmod_t *acmod)
01170 {
01171     if (acmod->compallsen)
01172         return;
01173     bitvec_clear_all(acmod->senone_active_vec, bin_mdef_n_sen(acmod->mdef));
01174     acmod->n_senone_active = 0;
01175 }
01176 
01177 #define MPX_BITVEC_SET(a,h,i)                                   \
01178     if (hmm_mpx_ssid(h,i) != BAD_SSID)                          \
01179         bitvec_set((a)->senone_active_vec, hmm_mpx_senid(h,i))
01180 #define NONMPX_BITVEC_SET(a,h,i)                                        \
01181     bitvec_set((a)->senone_active_vec,                                  \
01182                hmm_nonmpx_senid(h,i))
01183 
01184 void
01185 acmod_activate_hmm(acmod_t *acmod, hmm_t *hmm)
01186 {
01187     int i;
01188 
01189     if (acmod->compallsen)
01190         return;
01191     if (hmm_is_mpx(hmm)) {
01192         switch (hmm_n_emit_state(hmm)) {
01193         case 5:
01194             MPX_BITVEC_SET(acmod, hmm, 4);
01195             MPX_BITVEC_SET(acmod, hmm, 3);
01196         case 3:
01197             MPX_BITVEC_SET(acmod, hmm, 2);
01198             MPX_BITVEC_SET(acmod, hmm, 1);
01199             MPX_BITVEC_SET(acmod, hmm, 0);
01200             break;
01201         default:
01202             for (i = 0; i < hmm_n_emit_state(hmm); ++i) {
01203                 MPX_BITVEC_SET(acmod, hmm, i);
01204             }
01205         }
01206     }
01207     else {
01208         switch (hmm_n_emit_state(hmm)) {
01209         case 5:
01210             NONMPX_BITVEC_SET(acmod, hmm, 4);
01211             NONMPX_BITVEC_SET(acmod, hmm, 3);
01212         case 3:
01213             NONMPX_BITVEC_SET(acmod, hmm, 2);
01214             NONMPX_BITVEC_SET(acmod, hmm, 1);
01215             NONMPX_BITVEC_SET(acmod, hmm, 0);
01216             break;
01217         default:
01218             for (i = 0; i < hmm_n_emit_state(hmm); ++i) {
01219                 NONMPX_BITVEC_SET(acmod, hmm, i);
01220             }
01221         }
01222     }
01223 }
01224 
01225 int32
01226 acmod_flags2list(acmod_t *acmod)
01227 {
01228     int32 w, l, n, b, total_dists, total_words, extra_bits;
01229     bitvec_t *flagptr;
01230 
01231     total_dists = bin_mdef_n_sen(acmod->mdef);
01232     if (acmod->compallsen) {
01233         acmod->n_senone_active = total_dists;
01234         return total_dists;
01235     }
01236     total_words = total_dists / BITVEC_BITS;
01237     extra_bits = total_dists % BITVEC_BITS;
01238     w = n = l = 0;
01239     for (flagptr = acmod->senone_active_vec; w < total_words; ++w, ++flagptr) {
01240         if (*flagptr == 0)
01241             continue;
01242         for (b = 0; b < BITVEC_BITS; ++b) {
01243             if (*flagptr & (1UL << b)) {
01244                 int32 sen = w * BITVEC_BITS + b;
01245                 int32 delta = sen - l;
01246                 /* Handle excessive deltas "lossily" by adding a few
01247                    extra senones to bridge the gap. */
01248                 while (delta > 255) {
01249                     acmod->senone_active[n++] = 255;
01250                     delta -= 255;
01251                 }
01252                 acmod->senone_active[n++] = delta;
01253                 l = sen;
01254             }
01255         }
01256     }
01257 
01258     for (b = 0; b < extra_bits; ++b) {
01259         if (*flagptr & (1UL << b)) {
01260             int32 sen = w * BITVEC_BITS + b;
01261             int32 delta = sen - l;
01262             /* Handle excessive deltas "lossily" by adding a few
01263                extra senones to bridge the gap. */
01264             while (delta > 255) {
01265                 acmod->senone_active[n++] = 255;
01266                 delta -= 255;
01267             }
01268             acmod->senone_active[n++] = delta;
01269             l = sen;
01270         }
01271     }
01272 
01273     acmod->n_senone_active = n;
01274     E_DEBUG(1, ("acmod_flags2list: %d active in frame %d\n",
01275                 acmod->n_senone_active, acmod->output_frame));
01276     return n;
01277 }