| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
|
|
| #include <stdio.h> |
| #include <string.h> |
| #include <assert.h> |
|
|
| #include <pocketsphinx.h> |
|
|
| #include "util/ckd_alloc.h" |
| #include "util/strfuncs.h" |
| #include "util/pio.h" |
|
|
| #include "pocketsphinx_internal.h" |
| #include "allphone_search.h" |
|
|
| static ps_lattice_t * |
| allphone_search_lattice(ps_search_t * search) |
| { |
| (void) search; |
| return NULL; |
| } |
|
|
| static int |
| allphone_search_prob(ps_search_t * search) |
| { |
| (void) search; |
| return 0; |
| } |
|
|
| static void |
| allphone_backtrace(allphone_search_t * allphs, int32 f, int32 *out_score); |
| static void |
| allphone_clear_segments(allphone_search_t * allphs); |
|
|
| static void |
| allphone_search_seg_free(ps_seg_t * seg) |
| { |
| ckd_free(seg); |
| } |
|
|
| static void |
| allphone_search_fill_iter(ps_seg_t *seg, phseg_t *phseg) |
| { |
| seg->sf = phseg->sf; |
| seg->ef = phseg->ef; |
| seg->ascr = phseg->score; |
| seg->lscr = phseg->tscore; |
| seg->text = bin_mdef_ciphone_str(ps_search_acmod(seg->search)->mdef, phseg->ci); |
| seg->wid = BAD_S3WID; |
| } |
|
|
| static ps_seg_t * |
| allphone_search_seg_next(ps_seg_t * seg) |
| { |
| phseg_iter_t *itor = (phseg_iter_t *) seg; |
| phseg_t *phseg; |
|
|
| itor->seg = itor->seg->next; |
| |
| if (itor->seg == NULL) { |
| allphone_search_seg_free(seg); |
| return NULL; |
| } |
| phseg = gnode_ptr(itor->seg); |
| allphone_search_fill_iter(seg, phseg); |
|
|
| return seg; |
| } |
|
|
| static ps_segfuncs_t fsg_segfuncs = { |
| allphone_search_seg_next, |
| allphone_search_seg_free |
| }; |
|
|
|
|
| static ps_seg_t * |
| allphone_search_seg_iter(ps_search_t * search) |
| { |
| allphone_search_t *allphs = (allphone_search_t *) search; |
| phseg_iter_t *iter; |
|
|
| allphone_backtrace(allphs, allphs->frame - 1, NULL); |
| if (allphs->segments == NULL) |
| return NULL; |
| |
| iter = ckd_calloc(1, sizeof(phseg_iter_t)); |
|
|
| iter->base.vt = &fsg_segfuncs; |
| iter->base.search = search; |
| iter->seg = allphs->segments; |
| allphone_search_fill_iter((ps_seg_t *)iter, gnode_ptr(iter->seg)); |
|
|
| return (ps_seg_t *) iter; |
| } |
|
|
| static ps_searchfuncs_t allphone_funcs = { |
| allphone_search_start, |
| allphone_search_step, |
| allphone_search_finish, |
| allphone_search_reinit, |
| allphone_search_free, |
| allphone_search_lattice, |
| allphone_search_hyp, |
| allphone_search_prob, |
| allphone_search_seg_iter, |
| }; |
|
|
| |
| |
| |
| |
| static phmm_t * |
| phmm_lookup(allphone_search_t * allphs, s3pid_t pid) |
| { |
| phmm_t *p; |
| bin_mdef_t *mdef; |
| phmm_t **ci_phmm; |
|
|
| mdef = ((ps_search_t *) allphs)->acmod->mdef; |
| ci_phmm = allphs->ci_phmm; |
|
|
| for (p = ci_phmm[bin_mdef_pid2ci(mdef, pid)]; p; p = p->next) { |
| if (mdef_pid2tmatid(mdef, p->pid) == mdef_pid2tmatid(mdef, pid)) |
| if (mdef_pid2ssid(mdef, p->pid) == mdef_pid2ssid(mdef, pid)) |
| return p; |
| } |
|
|
| return NULL; |
| } |
|
|
| static int32 |
| phmm_link(allphone_search_t * allphs) |
| { |
| s3cipid_t ci, rc; |
| phmm_t *p, *p2; |
| int32 *rclist; |
| int32 i, n_link; |
| plink_t *l; |
| bin_mdef_t *mdef; |
| phmm_t **ci_phmm; |
|
|
| mdef = ((ps_search_t *) allphs)->acmod->mdef; |
| ci_phmm = allphs->ci_phmm; |
|
|
| rclist = (int32 *) ckd_calloc(mdef->n_ciphone + 1, sizeof(int32)); |
|
|
| |
| n_link = 0; |
| for (ci = 0; ci < mdef->n_ciphone; ci++) { |
| for (p = ci_phmm[ci]; p; p = p->next) { |
| |
| i = 0; |
| for (rc = 0; rc < mdef->n_ciphone; rc++) { |
| if (bitvec_is_set(p->rc, rc)) |
| rclist[i++] = rc; |
| } |
| rclist[i] = BAD_S3CIPID; |
|
|
| |
| for (i = 0; IS_S3CIPID(rclist[i]); i++) { |
| for (p2 = ci_phmm[rclist[i]]; p2; p2 = p2->next) { |
| if (bitvec_is_set(p2->lc, ci)) { |
| |
| l = (plink_t *) ckd_calloc(1, sizeof(*l)); |
| l->phmm = p2; |
| l->next = p->succlist; |
| p->succlist = l; |
|
|
| n_link++; |
| } |
| } |
| } |
| } |
| } |
|
|
| ckd_free(rclist); |
|
|
| return n_link; |
| } |
|
|
| |
| |
| |
| static int |
| phmm_build(allphone_search_t * allphs) |
| { |
| phmm_t *p, **pid2phmm; |
| bin_mdef_t *mdef; |
| int32 lrc_size; |
| uint32 *lc, *rc; |
| s3pid_t pid; |
| s3cipid_t ci; |
| s3cipid_t *filler; |
| int n_phmm, n_link; |
| int i, nphone; |
|
|
| mdef = ((ps_search_t *) allphs)->acmod->mdef; |
| allphs->ci_phmm = |
| (phmm_t **) ckd_calloc(bin_mdef_n_ciphone(mdef), sizeof(phmm_t *)); |
| pid2phmm = |
| (phmm_t **) ckd_calloc(bin_mdef_n_phone(mdef), sizeof(phmm_t *)); |
|
|
| |
| n_phmm = 0; |
| nphone = allphs->ci_only ? bin_mdef_n_ciphone(mdef) : bin_mdef_n_phone(mdef); |
| E_INFO("Building PHMM net of %d phones\n", nphone); |
| for (pid = 0; pid < nphone; pid++) { |
| if ((p = phmm_lookup(allphs, pid)) == NULL) { |
| |
| p = (phmm_t *) ckd_calloc(1, sizeof(*p)); |
| hmm_init(allphs->hmmctx, &(p->hmm), FALSE, |
| mdef_pid2ssid(mdef, pid), mdef->phone[pid].tmat); |
| p->pid = pid; |
| p->ci = bin_mdef_pid2ci(mdef, pid); |
| p->succlist = NULL; |
| p->next = allphs->ci_phmm[p->ci]; |
| allphs->ci_phmm[p->ci] = p; |
| n_phmm++; |
| } |
| pid2phmm[pid] = p; |
| } |
|
|
| |
| lrc_size = bitvec_size(bin_mdef_n_ciphone(mdef)); |
| lc = ckd_calloc(n_phmm * 2 * lrc_size, sizeof(bitvec_t)); |
| rc = lc + (n_phmm * lrc_size); |
| for (ci = 0; ci < mdef->n_ciphone; ci++) { |
| for (p = allphs->ci_phmm[ci]; p; p = p->next) { |
| p->lc = lc; |
| lc += lrc_size; |
| p->rc = rc; |
| rc += lrc_size; |
| } |
| } |
|
|
| |
| filler = |
| (s3cipid_t *) ckd_calloc(bin_mdef_n_ciphone(mdef) + 1, |
| sizeof(s3cipid_t)); |
|
|
| |
| i = 0; |
| for (ci = 0; ci < bin_mdef_n_ciphone(mdef); ci++) { |
| p = pid2phmm[ci]; |
| bitvec_set_all(p->lc, bin_mdef_n_ciphone(mdef)); |
| bitvec_set_all(p->rc, bin_mdef_n_ciphone(mdef)); |
| if (mdef->phone[ci].info.ci.filler) { |
| filler[i++] = ci; |
| } |
| } |
| filler[i] = BAD_S3CIPID; |
|
|
|
|
| |
| for (pid = bin_mdef_n_ciphone(mdef); pid < nphone; |
| pid++) { |
| p = pid2phmm[pid]; |
|
|
| if (mdef->phone[mdef->phone[pid].info.cd.ctx[1]].info.ci.filler) { |
| for (i = 0; IS_S3CIPID(filler[i]); i++) |
| bitvec_set(p->lc, filler[i]); |
| } |
| else |
| bitvec_set(p->lc, mdef->phone[pid].info.cd.ctx[1]); |
|
|
| if (mdef->phone[mdef->phone[pid].info.cd.ctx[2]].info.ci.filler) { |
| for (i = 0; IS_S3CIPID(filler[i]); i++) |
| bitvec_set(p->rc, filler[i]); |
| } |
| else |
| bitvec_set(p->rc, mdef->phone[pid].info.cd.ctx[2]); |
| } |
| ckd_free(pid2phmm); |
| ckd_free(filler); |
|
|
| |
| n_link = phmm_link(allphs); |
|
|
| E_INFO("%d nodes, %d links\n", n_phmm, n_link); |
| return 0; |
| } |
|
|
| static void |
| phmm_free(allphone_search_t * allphs) |
| { |
| s3cipid_t ci; |
| bin_mdef_t *mdef; |
|
|
| if (!allphs->ci_phmm) |
| return; |
| ckd_free(allphs->ci_phmm[0]->lc); |
| mdef = ((ps_search_t *) allphs)->acmod->mdef; |
| for (ci = 0; ci < mdef_n_ciphone(mdef); ++ci) { |
| phmm_t *p, *next; |
|
|
| for (p = allphs->ci_phmm[ci]; p; p = next) { |
| plink_t *l, *lnext; |
|
|
| next = p->next; |
| for (l = p->succlist; l; l = lnext) { |
| lnext = l->next; |
| ckd_free(l); |
| } |
| hmm_deinit(&(p->hmm)); |
| ckd_free(p); |
| } |
| } |
| ckd_free(allphs->ci_phmm); |
| } |
|
|
| |
| static int32 |
| phmm_eval_all(allphone_search_t * allphs, const int16 * senscr) |
| { |
| s3cipid_t ci; |
| phmm_t *p; |
| int32 best; |
| bin_mdef_t *mdef; |
| phmm_t **ci_phmm; |
|
|
| mdef = ((ps_search_t *) allphs)->acmod->mdef; |
| ci_phmm = allphs->ci_phmm; |
|
|
| best = WORST_SCORE; |
|
|
| hmm_context_set_senscore(allphs->hmmctx, senscr); |
| for (ci = 0; ci < mdef->n_ciphone; ci++) { |
| for (p = ci_phmm[(unsigned) ci]; p; p = p->next) { |
| if (hmm_frame(&(p->hmm)) == allphs->frame) { |
| int32 score; |
| allphs->n_hmm_eval++; |
| score = hmm_vit_eval((hmm_t *) p); |
| if (score > best) |
| best = score; |
| } |
| } |
| } |
|
|
| return best; |
| } |
|
|
| static void |
| phmm_exit(allphone_search_t * allphs, int32 best) |
| { |
| s3cipid_t ci; |
| phmm_t *p; |
| int32 th, nf; |
| history_t *h; |
| blkarray_list_t *history; |
| bin_mdef_t *mdef; |
| int32 curfrm; |
| phmm_t **ci_phmm; |
| int32 *ci2lmwid; |
|
|
| th = best + allphs->pbeam; |
|
|
| history = allphs->history; |
| mdef = ps_search_acmod(allphs)->mdef; |
| curfrm = allphs->frame; |
| ci_phmm = allphs->ci_phmm; |
| ci2lmwid = allphs->ci2lmwid; |
|
|
| nf = curfrm + 1; |
|
|
| for (ci = 0; ci < mdef->n_ciphone; ci++) { |
| for (p = ci_phmm[(unsigned) ci]; p; p = p->next) { |
| if (hmm_frame(&(p->hmm)) == curfrm) { |
|
|
| if (hmm_bestscore(&(p->hmm)) >= th) { |
|
|
| h = (history_t *) ckd_calloc(1, sizeof(*h)); |
| h->ef = curfrm; |
| h->phmm = p; |
| h->hist = hmm_out_history(&(p->hmm)); |
| h->score = hmm_out_score(&(p->hmm)); |
|
|
| if (!allphs->lm) { |
| h->tscore = allphs->inspen; |
| } |
| else { |
| if (h->hist > 0) { |
| int32 n_used; |
| history_t *pred = |
| blkarray_list_get(history, h->hist); |
|
|
| if (pred->hist > 0) { |
| history_t *pred_pred = |
| blkarray_list_get(history, |
| h->hist); |
| h->tscore = |
| ngram_tg_score(allphs->lm, |
| ci2lmwid |
| [pred_pred->phmm->ci], |
| ci2lmwid[pred-> |
| phmm->ci], |
| ci2lmwid[p->ci], |
| &n_used) >> |
| SENSCR_SHIFT; |
| } |
| else { |
| h->tscore = |
| ngram_bg_score(allphs->lm, |
| ci2lmwid |
| [pred->phmm->ci], |
| ci2lmwid[p->ci], |
| &n_used) >> |
| SENSCR_SHIFT; |
| } |
| } |
| else { |
| |
| |
| |
| |
| h->tscore = 0; |
| } |
| } |
|
|
| blkarray_list_append(history, h); |
|
|
| |
| hmm_frame(&(p->hmm)) = nf; |
| } |
| else { |
| |
| hmm_clear(&(p->hmm)); |
| } |
| } |
| } |
| } |
| } |
|
|
| static void |
| phmm_trans(allphone_search_t * allphs, int32 best, |
| int32 frame_history_start) |
| { |
| history_t *h; |
| phmm_t *from, *to; |
| plink_t *l; |
| int32 newscore, nf, curfrm; |
| int32 *ci2lmwid; |
| int32 hist_idx; |
|
|
| curfrm = allphs->frame; |
| nf = curfrm + 1; |
| ci2lmwid = allphs->ci2lmwid; |
|
|
| |
| for (hist_idx = frame_history_start; |
| hist_idx < blkarray_list_n_valid(allphs->history); hist_idx++) { |
| h = blkarray_list_get(allphs->history, hist_idx); |
| from = h->phmm; |
| for (l = from->succlist; l; l = l->next) { |
| int32 tscore; |
| to = l->phmm; |
|
|
| |
| if (!allphs->lm) |
| tscore = allphs->inspen; |
| else { |
| int32 n_used; |
| if (h->hist > 0) { |
| history_t *pred = |
| blkarray_list_get(allphs->history, h->hist); |
| tscore = |
| ngram_tg_score(allphs->lm, |
| ci2lmwid[pred->phmm->ci], |
| ci2lmwid[from->ci], |
| ci2lmwid[to->ci], |
| &n_used) >> SENSCR_SHIFT; |
| } |
| else { |
| tscore = ngram_bg_score(allphs->lm, |
| ci2lmwid[from->ci], |
| ci2lmwid[to->ci], |
| &n_used) >> SENSCR_SHIFT; |
| } |
| } |
|
|
| newscore = h->score + tscore; |
| if ((newscore > best + allphs->beam) |
| && (newscore > hmm_in_score(&(to->hmm)))) { |
| hmm_enter(&(to->hmm), newscore, hist_idx, nf); |
| } |
| } |
| } |
| } |
|
|
| ps_search_t * |
| allphone_search_init(const char *name, |
| ngram_model_t * lm, |
| ps_config_t * config, |
| acmod_t * acmod, dict_t * dict, dict2pid_t * d2p) |
| { |
| int i; |
| bin_mdef_t *mdef; |
| allphone_search_t *allphs; |
|
|
| allphs = (allphone_search_t *) ckd_calloc(1, sizeof(*allphs)); |
| ps_search_init(ps_search_base(allphs), &allphone_funcs, PS_SEARCH_TYPE_ALLPHONE, name, config, acmod, |
| dict, d2p); |
| mdef = acmod->mdef; |
|
|
| allphs->hmmctx = hmm_context_init(bin_mdef_n_emit_state(mdef), |
| acmod->tmat->tp, NULL, mdef->sseq); |
| if (allphs->hmmctx == NULL) { |
| ps_search_free(ps_search_base(allphs)); |
| return NULL; |
| } |
|
|
| allphs->ci_only = ps_config_bool(config, "allphone_ci"); |
| allphs->lw = ps_config_float(config, "lw"); |
|
|
| phmm_build(allphs); |
|
|
| if (lm) { |
| int32 silwid; |
| |
| allphs->lm = ngram_model_retain(lm); |
| |
| silwid = ngram_wid(allphs->lm, bin_mdef_ciphone_str(mdef, |
| mdef_silphone |
| (mdef))); |
| if (silwid == ngram_unknown_wid(allphs->lm)) { |
| E_ERROR("Phonetic LM does not have SIL phone in vocabulary\n"); |
| allphone_search_free((ps_search_t *) allphs); |
| return NULL; |
| } |
| |
| allphs->ci2lmwid = |
| (int32 *) ckd_calloc(mdef->n_ciphone, |
| sizeof(*allphs->ci2lmwid)); |
| for (i = 0; i < mdef->n_ciphone; i++) { |
| allphs->ci2lmwid[i] = |
| ngram_wid(allphs->lm, |
| (char *) bin_mdef_ciphone_str(mdef, i)); |
| |
| if (allphs->ci2lmwid[i] == ngram_unknown_wid(allphs->lm)) |
| allphs->ci2lmwid[i] = silwid; |
| } |
| } |
| else { |
| E_WARN |
| ("Failed to load language model specified in -allphone, doing unconstrained phone-loop decoding\n"); |
| allphs->inspen = |
| (int32) (logmath_log |
| (acmod->lmath, ps_config_float(config, "pip")) |
| * allphs->lw) >> SENSCR_SHIFT; |
| } |
|
|
| allphs->n_tot_frame = 0; |
| allphs->frame = -1; |
| allphs->segments = NULL; |
|
|
| |
| allphs->beam |
| = |
| (int32) logmath_log(acmod->lmath, |
| ps_config_float(config, "beam")) |
| >> SENSCR_SHIFT; |
| allphs->pbeam |
| = |
| (int32) logmath_log(acmod->lmath, |
| ps_config_float(config, "pbeam")) |
| >> SENSCR_SHIFT; |
|
|
| |
| allphs->history = blkarray_list_init(); |
|
|
| |
| allphs->ascale = 1.0 / ps_config_float(config, "ascale"); |
|
|
| E_INFO("Allphone(beam: %d, pbeam: %d)\n", allphs->beam, allphs->pbeam); |
|
|
| ptmr_init(&allphs->perf); |
|
|
| return (ps_search_t *) allphs; |
| } |
|
|
| int |
| allphone_search_reinit(ps_search_t * search, dict_t * dict, |
| dict2pid_t * d2p) |
| { |
| allphone_search_t *allphs = (allphone_search_t *) search; |
|
|
| |
| ps_search_base_reinit(search, dict, d2p); |
|
|
| if (!allphs->lm) { |
| E_WARN |
| ("-lm argument missing; doing unconstrained phone-loop decoding\n"); |
| allphs->inspen = |
| (int32) (logmath_log |
| (search->acmod->lmath, |
| ps_config_float(search->config, "pip")) |
| * allphs->lw) >> SENSCR_SHIFT; |
| } |
|
|
| return 0; |
| } |
|
|
| void |
| allphone_search_free(ps_search_t * search) |
| { |
| allphone_search_t *allphs = (allphone_search_t *) search; |
|
|
| |
| double n_speech = (double)allphs->n_tot_frame |
| / ps_config_int(ps_search_config(allphs), "frate"); |
|
|
| E_INFO("TOTAL allphone %.2f CPU %.3f xRT\n", |
| allphs->perf.t_tot_cpu, |
| allphs->perf.t_tot_cpu / n_speech); |
| E_INFO("TOTAL allphone %.2f wall %.3f xRT\n", |
| allphs->perf.t_tot_elapsed, |
| allphs->perf.t_tot_elapsed / n_speech); |
|
|
| ps_search_base_free(search); |
|
|
| allphone_clear_segments(allphs); |
| hmm_context_free(allphs->hmmctx); |
| phmm_free(allphs); |
| if (allphs->lm) |
| ngram_model_free(allphs->lm); |
| if (allphs->ci2lmwid) |
| ckd_free(allphs->ci2lmwid); |
| if (allphs->history) |
| blkarray_list_free(allphs->history); |
|
|
| ckd_free(allphs); |
| } |
|
|
| int |
| allphone_search_start(ps_search_t * search) |
| { |
| allphone_search_t *allphs; |
| bin_mdef_t *mdef; |
| s3cipid_t ci; |
| phmm_t *p; |
|
|
| allphs = (allphone_search_t *) search; |
| mdef = search->acmod->mdef; |
|
|
| |
| for (ci = 0; ci < bin_mdef_n_ciphone(mdef); ci++) { |
| for (p = allphs->ci_phmm[(unsigned) ci]; p; p = p->next) { |
| hmm_clear(&(p->hmm)); |
| } |
| } |
|
|
| allphs->n_hmm_eval = 0; |
| allphs->n_sen_eval = 0; |
|
|
| |
| blkarray_list_reset(allphs->history); |
|
|
| |
| allphs->frame = 0; |
| ci = bin_mdef_silphone(mdef); |
| if (NOT_S3CIPID(ci)) |
| E_FATAL("Cannot find CI-phone %s\n", S3_SILENCE_CIPHONE); |
| for (p = allphs->ci_phmm[ci]; p && (p->pid != ci); p = p->next); |
| if (!p) |
| E_FATAL("Cannot find HMM for %s\n", S3_SILENCE_CIPHONE); |
| hmm_enter(&(p->hmm), 0, 0, allphs->frame); |
|
|
| ptmr_reset(&allphs->perf); |
| ptmr_start(&allphs->perf); |
|
|
| return 0; |
| } |
|
|
| static void |
| allphone_search_sen_active(allphone_search_t * allphs) |
| { |
| acmod_t *acmod; |
| bin_mdef_t *mdef; |
| phmm_t *p; |
| int32 ci; |
|
|
| acmod = ps_search_acmod(allphs); |
| mdef = acmod->mdef; |
|
|
| acmod_clear_active(acmod); |
| for (ci = 0; ci < bin_mdef_n_ciphone(mdef); ci++) |
| for (p = allphs->ci_phmm[ci]; p; p = p->next) |
| if (hmm_frame(&(p->hmm)) == allphs->frame) |
| acmod_activate_hmm(acmod, &(p->hmm)); |
| } |
|
|
| int |
| allphone_search_step(ps_search_t * search, int frame_idx) |
| { |
| int32 bestscr, frame_history_start; |
| const int16 *senscr; |
| allphone_search_t *allphs = (allphone_search_t *) search; |
| acmod_t *acmod = search->acmod; |
|
|
| if (!acmod->compallsen) |
| allphone_search_sen_active(allphs); |
| senscr = acmod_score(acmod, &frame_idx); |
| allphs->n_sen_eval += acmod->n_senone_active; |
| bestscr = phmm_eval_all(allphs, senscr); |
|
|
| frame_history_start = blkarray_list_n_valid(allphs->history); |
| phmm_exit(allphs, bestscr); |
| phmm_trans(allphs, bestscr, frame_history_start); |
|
|
| allphs->frame++; |
|
|
| return 0; |
| } |
|
|
| static int32 |
| ascore(allphone_search_t * allphs, history_t * h) |
| { |
| int32 score = h->score; |
|
|
| if (h->hist > 0) { |
| history_t *pred = blkarray_list_get(allphs->history, h->hist); |
| score -= pred->score; |
| } |
|
|
| return score - h->tscore; |
| } |
|
|
| static void |
| allphone_clear_segments(allphone_search_t * allphs) |
| { |
| gnode_t *gn; |
| for (gn = allphs->segments; gn; gn = gn->next) { |
| ckd_free(gnode_ptr(gn)); |
| } |
| glist_free(allphs->segments); |
| allphs->segments = NULL; |
| } |
|
|
| static void |
| allphone_backtrace(allphone_search_t * allphs, int32 f, int32 *out_score) |
| { |
| int32 best, hist_idx, best_idx; |
| int32 frm, last_frm; |
| history_t *h; |
| phseg_t *s; |
|
|
| |
| allphone_clear_segments(allphs); |
|
|
| frm = last_frm = f; |
| |
| hist_idx = blkarray_list_n_valid(allphs->history) - 1; |
| while (hist_idx > 0) { |
| h = blkarray_list_get(allphs->history, hist_idx); |
| if (h->ef <= f) { |
| frm = last_frm = h->ef; |
| break; |
| } |
| hist_idx--; |
| } |
|
|
| if (hist_idx < 0) |
| return; |
|
|
| |
| best = MAX_NEG_INT32; |
| best_idx = -1; |
| while (frm == last_frm && hist_idx > 0) { |
| h = blkarray_list_get(allphs->history, hist_idx); |
| frm = h->ef; |
| if (h->score > best && frm == last_frm) { |
| best = h->score; |
| best_idx = hist_idx; |
| } |
| hist_idx--; |
| } |
|
|
| if (best_idx < 0) |
| return; |
|
|
| if (out_score) |
| *out_score = best; |
|
|
| |
| while (best_idx > 0) { |
| h = blkarray_list_get(allphs->history, best_idx); |
| s = (phseg_t *) ckd_calloc(1, sizeof(phseg_t)); |
| s->ci = h->phmm->ci; |
| s->sf = |
| (h->hist > |
| 0) ? ((history_t *) blkarray_list_get(allphs->history, |
| h->hist))->ef + 1 : 0; |
| s->ef = h->ef; |
| s->score = ascore(allphs, h); |
| s->tscore = h->tscore; |
| allphs->segments = glist_add_ptr(allphs->segments, s); |
|
|
| best_idx = h->hist; |
| } |
|
|
| return; |
| } |
|
|
| int |
| allphone_search_finish(ps_search_t * search) |
| { |
| allphone_search_t *allphs; |
| int32 cf, n_hist; |
|
|
| allphs = (allphone_search_t *) search; |
|
|
| allphs->n_tot_frame += allphs->frame; |
| n_hist = blkarray_list_n_valid(allphs->history); |
| E_INFO |
| ("%d frames, %d HMMs (%d/fr), %d senones (%d/fr), %d history entries (%d/fr)\n", |
| allphs->frame, allphs->n_hmm_eval, |
| (allphs->frame > 0) ? allphs->n_hmm_eval / allphs->frame : 0, |
| allphs->n_sen_eval, |
| (allphs->frame > 0) ? allphs->n_sen_eval / allphs->frame : 0, |
| n_hist, (allphs->frame > 0) ? n_hist / allphs->frame : 0); |
|
|
| |
| allphone_backtrace(allphs, allphs->frame - 1, NULL); |
|
|
| |
| ptmr_stop(&allphs->perf); |
| |
| cf = ps_search_acmod(allphs)->output_frame; |
| if (cf > 0) { |
| double n_speech = (double) (cf + 1) |
| / ps_config_int(ps_search_config(allphs), "frate"); |
| E_INFO("allphone %.2f CPU %.3f xRT\n", |
| allphs->perf.t_cpu, allphs->perf.t_cpu / n_speech); |
| E_INFO("allphone %.2f wall %.3f xRT\n", |
| allphs->perf.t_elapsed, allphs->perf.t_elapsed / n_speech); |
| } |
|
|
|
|
| return 0; |
| } |
|
|
| char const * |
| allphone_search_hyp(ps_search_t * search, int32 * out_score) |
| { |
| allphone_search_t *allphs; |
| phseg_t *p; |
| gnode_t *gn; |
| const char *phone_str; |
| bin_mdef_t *mdef; |
| int len, hyp_idx, phone_idx; |
|
|
| allphs = (allphone_search_t *) search; |
| mdef = search->acmod->mdef; |
|
|
| |
| if (search->hyp_str) |
| ckd_free(search->hyp_str); |
| search->hyp_str = NULL; |
|
|
| allphone_backtrace(allphs, allphs->frame - 1, out_score); |
| if (allphs->segments == NULL) { |
| return NULL; |
| } |
|
|
| len = glist_count(allphs->segments) * 10; |
|
|
| search->hyp_str = (char *) ckd_calloc(len, sizeof(*search->hyp_str)); |
| hyp_idx = 0; |
| for (gn = allphs->segments; gn; gn = gn->next) { |
| p = gnode_ptr(gn); |
| phone_str = bin_mdef_ciphone_str(mdef, p->ci); |
| phone_idx = 0; |
| while (phone_str[phone_idx] != '\0') |
| search->hyp_str[hyp_idx++] = phone_str[phone_idx++]; |
| search->hyp_str[hyp_idx++] = ' '; |
| } |
| search->hyp_str[--hyp_idx] = '\0'; |
| E_INFO("Hyp: %s\n", search->hyp_str); |
| return search->hyp_str; |
| } |
|
|