summaryrefslogtreecommitdiffstats
path: root/media/pocketsphinx/src/allphone_search.c
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /media/pocketsphinx/src/allphone_search.c
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'media/pocketsphinx/src/allphone_search.c')
-rw-r--r--media/pocketsphinx/src/allphone_search.c913
1 files changed, 913 insertions, 0 deletions
diff --git a/media/pocketsphinx/src/allphone_search.c b/media/pocketsphinx/src/allphone_search.c
new file mode 100644
index 000000000..974cdba4f
--- /dev/null
+++ b/media/pocketsphinx/src/allphone_search.c
@@ -0,0 +1,913 @@
+/* ====================================================================
+ * Copyright (c) 2014 Carnegie Mellon University. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
+ * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
+ * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ====================================================================
+ *
+ */
+
+/*
+* allphone_search.c -- Search for phonetic decoding.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sphinxbase/err.h>
+#include <sphinxbase/ckd_alloc.h>
+#include <sphinxbase/strfuncs.h>
+#include <sphinxbase/pio.h>
+#include <sphinxbase/cmd_ln.h>
+
+#include "pocketsphinx_internal.h"
+#include "allphone_search.h"
+
+static ps_lattice_t *
+allphone_search_lattice(ps_search_t * search)
+{
+ //cap
+ return NULL;
+}
+
+static int
+allphone_search_prob(ps_search_t * search)
+{
+ return 0;
+}
+
+static void
+allphone_backtrace(allphone_search_t * allphs, int32 f);
+
+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->word = bin_mdef_ciphone_str(ps_search_acmod(seg->search)->mdef, phseg->ci);
+}
+
+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 = {
+ /* seg_next */ allphone_search_seg_next,
+ /* seg_free */ allphone_search_seg_free
+};
+
+
+static ps_seg_t *
+allphone_search_seg_iter(ps_search_t * search, int32 * out_score)
+{
+ allphone_search_t *allphs = (allphone_search_t *) search;
+ phseg_iter_t *iter;
+
+ allphone_backtrace(allphs, allphs->frame - 1);
+ 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 = {
+ /* name: */ "allphone",
+ /* start: */ allphone_search_start,
+ /* step: */ allphone_search_step,
+ /* finish: */ allphone_search_finish,
+ /* reinit: */ allphone_search_reinit,
+ /* free: */ allphone_search_free,
+ /* lattice: */ allphone_search_lattice,
+ /* hyp: */ allphone_search_hyp,
+ /* prob: */ allphone_search_prob,
+ /* seg_iter: */ allphone_search_seg_iter,
+};
+
+/**
+ * Find PHMM node with same senone sequence and tmat id as the given triphone.
+ * Return ptr to PHMM node if found, NULL otherwise.
+ */
+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;
+ }
+
+ //not found
+ 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));
+
+ /* Create successor links between PHMM nodes */
+ n_link = 0;
+ for (ci = 0; ci < mdef->n_ciphone; ci++) {
+ for (p = ci_phmm[ci]; p; p = p->next) {
+ /* Build rclist for p */
+ 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 each rc in rclist, transition to PHMMs for rc if left context = ci */
+ 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)) {
+ /* transition from p to p2 */
+ 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;
+}
+
+/**
+ * Build net from phone HMMs
+ */
+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 *));
+
+ /* For each unique ciphone/triphone entry in mdef, create a PHMM node */
+ 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) {
+ //not found, should be created
+ 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;
+ }
+
+ /* Fill out bitvecs of each PHMM node, alloc continuous memory chunk for context bitvectors */
+ 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;
+ }
+ }
+
+ /* Fill out lc and rc bitmaps (remember to map all fillers to each other!!) */
+ filler =
+ (s3cipid_t *) ckd_calloc(bin_mdef_n_ciphone(mdef) + 1,
+ sizeof(s3cipid_t));
+
+ /* Connect fillers */
+ 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;
+
+
+ /* Loop over cdphones only if ci_only is not set */
+ 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);
+
+ /* Create links between PHMM nodes */
+ 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)
+ //nothing to free
+ 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);
+}
+
+/** Evaluate active PHMMs */
+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 {
+ /*
+ * This is the beginning SIL and in srch_allphone_begin()
+ * it's inscore is set to 0.
+ */
+ h->tscore = 0;
+ }
+ }
+
+ blkarray_list_append(history, h);
+
+ /* Mark PHMM active in next frame */
+ hmm_frame(&(p->hmm)) = nf;
+ }
+ else {
+ /* Reset state scores */
+ 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;
+
+ /* Transition from exited nodes to initial states of HMMs */
+ 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;
+
+ /* No LM, just use uniform (insertion penalty). */
+ if (!allphs->lm)
+ tscore = allphs->inspen;
+ /* If they are not in the LM, kill this
+ * transition. */
+ else if (ci2lmwid[to->ci] == NGRAM_INVALID_WID)
+ continue;
+ 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(ngram_model_t * lm,
+ cmd_ln_t * config,
+ acmod_t * acmod, dict_t * dict, dict2pid_t * d2p)
+{
+ int i;
+ bin_mdef_t *mdef;
+ allphone_search_t *allphs;
+ static char *lmname = "default";
+
+ allphs = (allphone_search_t *) ckd_calloc(1, sizeof(*allphs));
+ ps_search_init(ps_search_base(allphs), &allphone_funcs, 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 = cmd_ln_boolean_r(config, "-allphone_ci");
+ allphs->lw = cmd_ln_float32_r(config, "-lw");
+
+ phmm_build(allphs);
+
+ if (lm) {
+ //language model is defined
+ allphs->lm = ngram_model_set_init(config, &lm, &lmname, NULL, 1);
+ if (!allphs->lm) {
+ E_ERROR
+ ("Failed to initialize ngram model set for phoneme decoding");
+ 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));
+ /* Map filler phones to silence if not found */
+ if (allphs->ci2lmwid[i] == NGRAM_INVALID_WID
+ && bin_mdef_ciphone_str(mdef, i))
+ allphs->ci2lmwid[i] =
+ ngram_wid(allphs->lm,
+ (char *) bin_mdef_ciphone_str(mdef,
+ mdef_silphone
+ (mdef)));
+ }
+ }
+ else {
+ E_WARN
+ ("Failed to load language model specified in -allphone, doing unconstrained phone-loop decoding\n");
+ allphs->inspen =
+ (int32) (logmath_log
+ (acmod->lmath, cmd_ln_float32_r(config, "-pip"))
+ * allphs->lw) >> SENSCR_SHIFT;
+ }
+
+ allphs->n_tot_frame = 0;
+ allphs->frame = -1;
+ allphs->segments = NULL;
+
+ /* Get search pruning parameters */
+ allphs->beam
+ =
+ (int32) logmath_log(acmod->lmath,
+ cmd_ln_float64_r(config, "-beam"))
+ >> SENSCR_SHIFT;
+ allphs->pbeam
+ =
+ (int32) logmath_log(acmod->lmath,
+ cmd_ln_float64_r(config, "-pbeam"))
+ >> SENSCR_SHIFT;
+
+ /* LM related weights/penalties */
+ allphs->history = blkarray_list_init();
+
+ /* Acoustic score scale for posterior probabilities. */
+ allphs->ascale = 1.0 / cmd_ln_float32_r(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;
+
+ /* Free old dict2pid, dict */
+ 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,
+ cmd_ln_float32_r(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
+ / cmd_ln_int32_r(ps_search_config(allphs), "-frate");
+
+ E_INFO("TOTAL fwdflat %.2f CPU %.3f xRT\n",
+ allphs->perf.t_tot_cpu,
+ allphs->perf.t_tot_cpu / n_speech);
+ E_INFO("TOTAL fwdflat %.2f wall %.3f xRT\n",
+ allphs->perf.t_tot_elapsed,
+ allphs->perf.t_tot_elapsed / n_speech);
+
+ ps_search_deinit(search);
+ hmm_context_free(allphs->hmmctx);
+ phmm_free(allphs);
+ if (allphs->lm)
+ ngram_model_free(allphs->lm);
+ if (allphs->ci2lmwid)
+ ckd_free(allphs->ci2lmwid);
+
+ 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;
+
+ /* Reset all HMMs. */
+ 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;
+
+ /* Free history nodes, if any */
+ blkarray_list_reset(allphs->history);
+
+ /* Initialize start state of the SILENCE PHMM */
+ 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 best, hist_idx, best_idx;
+ int32 frm, last_frm;
+ history_t *h;
+ phseg_t *s;
+
+ /* Clear old list */
+ allphone_clear_segments(allphs);
+
+ frm = last_frm = f;
+ /* Find the first history entry for the requested frame */
+ 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;
+
+ /* Find bestscore */
+ best = (int32) 0x80000000;
+ 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;
+
+ /* Backtrace */
+ 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);
+
+ /* Now backtrace. */
+ allphone_backtrace(allphs, allphs->frame - 1);
+
+ /* Print out some statistics. */
+ ptmr_stop(&allphs->perf);
+ /* This is the number of frames processed. */
+ cf = ps_search_acmod(allphs)->output_frame;
+ if (cf > 0) {
+ double n_speech = (double) (cf + 1)
+ / cmd_ln_int32_r(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,
+ int32 * out_is_final)
+{
+ 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;
+
+ /* Create hypothesis */
+ if (search->hyp_str)
+ ckd_free(search->hyp_str);
+ search->hyp_str = NULL;
+
+ allphone_backtrace(allphs, allphs->frame - 1);
+ if (allphs->segments == NULL) {
+ return NULL;
+ }
+
+ len = glist_count(allphs->segments) * 10; // maximum length of one phone with spacebar
+
+ 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;
+}