PocketSphinx  5prealpha
kws_search.c
1 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* ====================================================================
3  * Copyright (c) 2013 Carnegie Mellon University. All rights
4  * reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  *
19  * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
20  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
23  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * ====================================================================
32  *
33  */
34 
35 /*
36 * kws_search.c -- Search object for key phrase spotting.
37 */
38 
39 #include <stdio.h>
40 #include <string.h>
41 #include <assert.h>
42 
43 #include <sphinxbase/err.h>
44 #include <sphinxbase/ckd_alloc.h>
45 #include <sphinxbase/strfuncs.h>
46 #include <sphinxbase/pio.h>
47 #include <sphinxbase/cmd_ln.h>
48 
49 #include "pocketsphinx_internal.h"
50 #include "kws_search.h"
51 
53 #define hmm_is_active(hmm) ((hmm)->frame > 0)
54 #define kws_nth_hmm(keyword,n) (&((keyword)->hmms[n]))
55 
56 static ps_lattice_t *
57 kws_search_lattice(ps_search_t * search)
58 {
59  return NULL;
60 }
61 
62 static int
63 kws_search_prob(ps_search_t * search)
64 {
65  return 0;
66 }
67 
68 static void
69 kws_seg_free(ps_seg_t *seg)
70 {
71  kws_seg_t *itor = (kws_seg_t *)seg;
72  ckd_free(itor);
73 }
74 
75 static void
76 kws_seg_fill(kws_seg_t *itor)
77 {
78  kws_detection_t* detection = (kws_detection_t*)gnode_ptr(itor->detection);
79 
80  itor->base.word = detection->keyphrase;
81  itor->base.sf = detection->sf;
82  itor->base.ef = detection->ef;
83  itor->base.prob = detection->prob;
84  itor->base.ascr = detection->ascr;
85  itor->base.lscr = 0;
86 }
87 
88 static ps_seg_t *
89 kws_seg_next(ps_seg_t *seg)
90 {
91  kws_seg_t *itor = (kws_seg_t *)seg;
92 
93  gnode_t *detect_head = gnode_next(itor->detection);
94  while (detect_head != NULL && ((kws_detection_t*)gnode_ptr(detect_head))->ef > itor->last_frame)
95  detect_head = gnode_next(detect_head);
96  itor->detection = detect_head;
97 
98  if (!itor->detection) {
99  kws_seg_free(seg);
100  return NULL;
101  }
102 
103  kws_seg_fill(itor);
104 
105  return seg;
106 }
107 
108 static ps_segfuncs_t kws_segfuncs = {
109  /* seg_next */ kws_seg_next,
110  /* seg_free */ kws_seg_free
111 };
112 
113 static ps_seg_t *
114 kws_search_seg_iter(ps_search_t * search, int32 * out_score)
115 {
116  kws_search_t *kwss = (kws_search_t *)search;
117  kws_seg_t *itor;
118  gnode_t *detect_head = kwss->detections->detect_list;
119 
120  while (detect_head != NULL && ((kws_detection_t*)gnode_ptr(detect_head))->ef > kwss->frame - kwss->delay)
121  detect_head = gnode_next(detect_head);
122 
123  if (!detect_head)
124  return NULL;
125 
126  if (out_score)
127  *out_score = 0;
128 
129  itor = (kws_seg_t *)ckd_calloc(1, sizeof(*itor));
130  itor->base.vt = &kws_segfuncs;
131  itor->base.search = search;
132  itor->base.lwf = 1.0;
133  itor->detection = detect_head;
134  itor->last_frame = kwss->frame - kwss->delay;
135  kws_seg_fill(itor);
136  return (ps_seg_t *)itor;
137 }
138 
139 static ps_searchfuncs_t kws_funcs = {
140  /* start: */ kws_search_start,
141  /* step: */ kws_search_step,
142  /* finish: */ kws_search_finish,
143  /* reinit: */ kws_search_reinit,
144  /* free: */ kws_search_free,
145  /* lattice: */ kws_search_lattice,
146  /* hyp: */ kws_search_hyp,
147  /* prob: */ kws_search_prob,
148  /* seg_iter: */ kws_search_seg_iter,
149 };
150 
151 /* Scans the dictionary and check if all words are present. */
152 static int
153 kws_search_check_dict(kws_search_t * kwss)
154 {
155  dict_t *dict;
156  char **wrdptr;
157  char *tmp_keyphrase;
158  int32 nwrds, wid;
159  int keyword_iter, i;
160  uint8 success;
161 
162  success = TRUE;
163  dict = ps_search_dict(kwss);
164 
165  for (keyword_iter = 0; keyword_iter < kwss->n_keyphrases; keyword_iter++) {
166  tmp_keyphrase = (char *) ckd_salloc(kwss->keyphrases[keyword_iter].word);
167  nwrds = str2words(tmp_keyphrase, NULL, 0);
168  wrdptr = (char **) ckd_calloc(nwrds, sizeof(*wrdptr));
169  str2words(tmp_keyphrase, wrdptr, nwrds);
170  for (i = 0; i < nwrds; i++) {
171  wid = dict_wordid(dict, wrdptr[i]);
172  if (wid == BAD_S3WID) {
173  E_ERROR("The word '%s' is missing in the dictionary\n",
174  wrdptr[i]);
175  success = FALSE;
176  break;
177  }
178  }
179  ckd_free(wrdptr);
180  ckd_free(tmp_keyphrase);
181  }
182  return success;
183 }
184 
185 /* Activate senones for scoring */
186 static void
187 kws_search_sen_active(kws_search_t * kwss)
188 {
189  int i, keyword_iter;
190 
191  acmod_clear_active(ps_search_acmod(kwss));
192 
193  /* active phone loop hmms */
194  for (i = 0; i < kwss->n_pl; i++)
195  acmod_activate_hmm(ps_search_acmod(kwss), &kwss->pl_hmms[i]);
196 
197  /* activate hmms in active nodes */
198  for (keyword_iter = 0; keyword_iter < kwss->n_keyphrases; keyword_iter++) {
199  kws_keyword_t *keyword = &kwss->keyphrases[keyword_iter];
200  for (i = 0; i < keyword->n_hmms; i++) {
201  if (hmm_is_active(kws_nth_hmm(keyword, i)))
202  acmod_activate_hmm(ps_search_acmod(kwss), kws_nth_hmm(keyword, i));
203  }
204  }
205 }
206 
207 /*
208 * Evaluate all the active HMMs.
209 * (Executed once per frame.)
210 */
211 static void
212 kws_search_hmm_eval(kws_search_t * kwss, int16 const *senscr)
213 {
214  int32 i, keyword_iter;
215  int32 bestscore = WORST_SCORE;
216 
217  hmm_context_set_senscore(kwss->hmmctx, senscr);
218 
219  /* evaluate hmms from phone loop */
220  for (i = 0; i < kwss->n_pl; ++i) {
221  hmm_t *hmm = &kwss->pl_hmms[i];
222  int32 score;
223 
224  score = hmm_vit_eval(hmm);
225  if (score BETTER_THAN bestscore)
226  bestscore = score;
227  }
228  /* evaluate hmms for active nodes */
229  for (keyword_iter = 0; keyword_iter < kwss->n_keyphrases; keyword_iter++) {
230  kws_keyword_t *keyword = &kwss->keyphrases[keyword_iter];
231  for (i = 0; i < keyword->n_hmms; i++) {
232  hmm_t *hmm = kws_nth_hmm(keyword, i);
233 
234  if (hmm_is_active(hmm)) {
235  int32 score;
236  score = hmm_vit_eval(hmm);
237  if (score BETTER_THAN bestscore)
238  bestscore = score;
239  }
240  }
241  }
242 
243  kwss->bestscore = bestscore;
244 }
245 
246 /*
247 * (Beam) prune the just evaluated HMMs, determine which ones remain
248 * active. Executed once per frame.
249 */
250 static void
251 kws_search_hmm_prune(kws_search_t * kwss)
252 {
253  int32 thresh, i, keyword_iter;
254 
255  thresh = kwss->bestscore + kwss->beam;
256 
257  for (keyword_iter = 0; keyword_iter < kwss->n_keyphrases; keyword_iter++) {
258  kws_keyword_t *keyword = &kwss->keyphrases[keyword_iter];
259  for (i = 0; i < keyword->n_hmms; i++) {
260  hmm_t *hmm = kws_nth_hmm(keyword, i);
261  if (hmm_is_active(hmm) && hmm_bestscore(hmm) < thresh)
262  hmm_clear(hmm);
263  }
264  }
265 }
266 
267 
271 static void
272 kws_search_trans(kws_search_t * kwss)
273 {
274  hmm_t *pl_best_hmm = NULL;
275  int32 best_out_score = WORST_SCORE;
276  int i, keyword_iter;
277 
278  /* select best hmm in phone-loop to be a predecessor */
279  for (i = 0; i < kwss->n_pl; i++)
280  if (hmm_out_score(&kwss->pl_hmms[i]) BETTER_THAN best_out_score) {
281  best_out_score = hmm_out_score(&kwss->pl_hmms[i]);
282  pl_best_hmm = &kwss->pl_hmms[i];
283  }
284 
285  /* out probs are not ready yet */
286  if (!pl_best_hmm)
287  return;
288 
289  /* Check whether keyword wasn't spotted yet */
290  for (keyword_iter = 0; keyword_iter < kwss->n_keyphrases; keyword_iter++) {
291  kws_keyword_t *keyword;
292  hmm_t *last_hmm;
293 
294  keyword = &kwss->keyphrases[keyword_iter];
295  last_hmm = kws_nth_hmm(keyword, keyword->n_hmms - 1);
296  if (hmm_is_active(last_hmm)
297  && hmm_out_score(pl_best_hmm) BETTER_THAN WORST_SCORE) {
298 
299  if (hmm_out_score(last_hmm) - hmm_out_score(pl_best_hmm)
300  >= keyword->threshold) {
301 
302  int32 prob = hmm_out_score(last_hmm) - hmm_out_score(pl_best_hmm);
303  kws_detections_add(kwss->detections, keyword->word,
304  hmm_out_history(last_hmm),
305  kwss->frame, prob,
306  hmm_out_score(last_hmm));
307  } /* keyword is spotted */
308  } /* last hmm of keyword is active */
309  } /* keywords loop */
310 
311  /* Make transition for all phone loop hmms */
312  for (i = 0; i < kwss->n_pl; i++) {
313  if (hmm_out_score(pl_best_hmm) + kwss->plp BETTER_THAN
314  hmm_in_score(&kwss->pl_hmms[i])) {
315  hmm_enter(&kwss->pl_hmms[i],
316  hmm_out_score(pl_best_hmm) + kwss->plp,
317  hmm_out_history(pl_best_hmm), kwss->frame + 1);
318  }
319  }
320 
321  /* Activate new keyword nodes, enter their hmms */
322  for (keyword_iter = 0; keyword_iter < kwss->n_keyphrases; keyword_iter++) {
323  kws_keyword_t *keyword = &kwss->keyphrases[keyword_iter];
324  for (i = keyword->n_hmms - 1; i > 0; i--) {
325  hmm_t *pred_hmm = kws_nth_hmm(keyword, i - 1);
326  hmm_t *hmm = kws_nth_hmm(keyword, i);
327 
328  if (hmm_is_active(pred_hmm)) {
329  if (!hmm_is_active(hmm)
330  || hmm_out_score(pred_hmm) BETTER_THAN
331  hmm_in_score(hmm))
332  hmm_enter(hmm, hmm_out_score(pred_hmm),
333  hmm_out_history(pred_hmm), kwss->frame + 1);
334  }
335  }
336 
337  /* Enter keyword start node from phone loop */
338  if (hmm_out_score(pl_best_hmm) BETTER_THAN
339  hmm_in_score(kws_nth_hmm(keyword, 0)))
340  hmm_enter(kws_nth_hmm(keyword, 0), hmm_out_score(pl_best_hmm),
341  kwss->frame, kwss->frame + 1);
342  } /* keywords loop */
343 }
344 
345 static int
346 kws_search_read_list(kws_search_t *kwss, const char* keyfile)
347 {
348  FILE *list_file;
349  lineiter_t *li;
350  char *line;
351  int i;
352 
353  if ((list_file = fopen(keyfile, "r")) == NULL) {
354  E_ERROR_SYSTEM("Failed to open keyword file '%s'", keyfile);
355  return -1;
356  }
357 
358  /* count keyphrases */
359  kwss->n_keyphrases = 0;
360  for (li = lineiter_start(list_file); li; li = lineiter_next(li))
361  if (li->len > 0)
362  kwss->n_keyphrases++;
363 
364  kwss->keyphrases = (kws_keyword_t *)ckd_calloc(kwss->n_keyphrases, sizeof(*kwss->keyphrases));
365  fseek(list_file, 0L, SEEK_SET);
366 
367  /* read keyphrases */
368  for (li = lineiter_start(list_file), i=0; li; li = lineiter_next(li), i++) {
369  size_t begin, end;
370  kwss->keyphrases[i].threshold = kwss->def_threshold;
371  line = string_trim(li->buf, STRING_BOTH);
372  end = strlen(line) - 1;
373  begin = end - 1;
374 
375  if (line[end] == '/') {
376  while (line[begin] != '/' && begin > 0)
377  begin--;
378  line[end] = 0;
379  line[begin] = 0;
380  kwss->keyphrases[i].threshold = (int32) logmath_log(kwss->base.acmod->lmath, atof_c(line + begin + 1))
381  >> SENSCR_SHIFT;
382  }
383  kwss->keyphrases[i].word = ckd_salloc(line);
384  }
385 
386  fclose(list_file);
387  return 0;
388 }
389 
390 ps_search_t *
391 kws_search_init(const char *name,
392  const char *keyphrase,
393  const char *keyfile,
394  cmd_ln_t * config,
395  acmod_t * acmod, dict_t * dict, dict2pid_t * d2p)
396 {
397  kws_search_t *kwss = (kws_search_t *) ckd_calloc(1, sizeof(*kwss));
398  ps_search_init(ps_search_base(kwss), &kws_funcs, PS_SEARCH_TYPE_KWS, name, config, acmod, dict,
399  d2p);
400 
401  kwss->detections = (kws_detections_t *)ckd_calloc(1, sizeof(*kwss->detections));
402 
403  kwss->beam =
404  (int32) logmath_log(acmod->lmath,
405  cmd_ln_float64_r(config,
406  "-beam")) >> SENSCR_SHIFT;
407 
408  kwss->plp =
409  (int32) logmath_log(acmod->lmath,
410  cmd_ln_float32_r(config,
411  "-kws_plp")) >> SENSCR_SHIFT;
412 
413 
414  kwss->def_threshold =
415  (int32) logmath_log(acmod->lmath,
416  cmd_ln_float64_r(config,
417  "-kws_threshold")) >>
418  SENSCR_SHIFT;
419 
420  kwss->delay = (int32) cmd_ln_int32_r(config, "-kws_delay");
421 
422  E_INFO("KWS(beam: %d, plp: %d, default threshold %d, delay %d)\n",
423  kwss->beam, kwss->plp, kwss->def_threshold, kwss->delay);
424 
425  if (keyfile) {
426  if (kws_search_read_list(kwss, keyfile) < 0) {
427  E_ERROR("Failed to create kws search\n");
428  kws_search_free(ps_search_base(kwss));
429  return NULL;
430  }
431  } else {
432  kwss->n_keyphrases = 1;
433  kwss->keyphrases = (kws_keyword_t *)ckd_calloc(kwss->n_keyphrases, sizeof(*kwss->keyphrases));
434  kwss->keyphrases[0].threshold = kwss->def_threshold;
435  kwss->keyphrases[0].word = ckd_salloc(keyphrase);
436  }
437 
438  /* Check if all words are in dictionary */
439  if (!kws_search_check_dict(kwss)) {
440  kws_search_free(ps_search_base(kwss));
441  return NULL;
442  }
443 
444  /* Reinit for provided keyword */
445  if (kws_search_reinit(ps_search_base(kwss),
446  ps_search_dict(kwss),
447  ps_search_dict2pid(kwss)) < 0) {
448  ps_search_free(ps_search_base(kwss));
449  return NULL;
450  }
451 
452  return ps_search_base(kwss);
453 }
454 
455 void
456 kws_search_free(ps_search_t * search)
457 {
458  int i;
459  kws_search_t *kwss;
460 
461  kwss = (kws_search_t *) search;
462  ps_search_base_free(search);
463  hmm_context_free(kwss->hmmctx);
464  kws_detections_reset(kwss->detections);
465  ckd_free(kwss->detections);
466 
467  ckd_free(kwss->pl_hmms);
468  for (i = 0; i < kwss->n_keyphrases; i++) {
469  ckd_free(kwss->keyphrases[i].hmms);
470  ckd_free(kwss->keyphrases[i].word);
471  }
472  ckd_free(kwss->keyphrases);
473  ckd_free(kwss);
474 }
475 
476 int
477 kws_search_reinit(ps_search_t * search, dict_t * dict, dict2pid_t * d2p)
478 {
479  char **wrdptr;
480  char *tmp_keyphrase;
481  int32 wid, pronlen;
482  int32 n_hmms, n_wrds;
483  int32 ssid, tmatid;
484  int i, j, p, keyword_iter;
485  kws_search_t *kwss = (kws_search_t *) search;
486  bin_mdef_t *mdef = search->acmod->mdef;
487  int32 silcipid = bin_mdef_silphone(mdef);
488 
489  /* Free old dict2pid, dict */
490  ps_search_base_reinit(search, dict, d2p);
491 
492  /* Initialize HMM context. */
493  if (kwss->hmmctx)
494  hmm_context_free(kwss->hmmctx);
495  kwss->hmmctx =
496  hmm_context_init(bin_mdef_n_emit_state(search->acmod->mdef),
497  search->acmod->tmat->tp, NULL,
498  search->acmod->mdef->sseq);
499  if (kwss->hmmctx == NULL)
500  return -1;
501 
502  /* Initialize phone loop HMMs. */
503  if (kwss->pl_hmms) {
504  for (i = 0; i < kwss->n_pl; ++i)
505  hmm_deinit((hmm_t *) & kwss->pl_hmms[i]);
506  ckd_free(kwss->pl_hmms);
507  }
508  kwss->n_pl = bin_mdef_n_ciphone(search->acmod->mdef);
509  kwss->pl_hmms =
510  (hmm_t *) ckd_calloc(kwss->n_pl, sizeof(*kwss->pl_hmms));
511  for (i = 0; i < kwss->n_pl; ++i) {
512  hmm_init(kwss->hmmctx, (hmm_t *) & kwss->pl_hmms[i],
513  FALSE,
514  bin_mdef_pid2ssid(search->acmod->mdef, i),
515  bin_mdef_pid2tmatid(search->acmod->mdef, i));
516  }
517 
518  for (keyword_iter = 0; keyword_iter < kwss->n_keyphrases; keyword_iter++) {
519  kws_keyword_t *keyword = &kwss->keyphrases[keyword_iter];
520 
521  /* Initialize keyphrase HMMs */
522  tmp_keyphrase = (char *) ckd_salloc(keyword->word);
523  n_wrds = str2words(tmp_keyphrase, NULL, 0);
524  wrdptr = (char **) ckd_calloc(n_wrds, sizeof(*wrdptr));
525  str2words(tmp_keyphrase, wrdptr, n_wrds);
526 
527  /* count amount of hmms */
528  n_hmms = 0;
529  for (i = 0; i < n_wrds; i++) {
530  wid = dict_wordid(dict, wrdptr[i]);
531  pronlen = dict_pronlen(dict, wid);
532  n_hmms += pronlen;
533  }
534 
535  /* allocate node array */
536  if (keyword->hmms)
537  ckd_free(keyword->hmms);
538  keyword->hmms = (hmm_t *) ckd_calloc(n_hmms, sizeof(hmm_t));
539  keyword->n_hmms = n_hmms;
540 
541  /* fill node array */
542  j = 0;
543  for (i = 0; i < n_wrds; i++) {
544  wid = dict_wordid(dict, wrdptr[i]);
545  pronlen = dict_pronlen(dict, wid);
546  for (p = 0; p < pronlen; p++) {
547  int32 ci = dict_pron(dict, wid, p);
548  if (p == 0) {
549  /* first phone of word */
550  int32 rc =
551  pronlen > 1 ? dict_pron(dict, wid, 1) : silcipid;
552  ssid = dict2pid_ldiph_lc(d2p, ci, rc, silcipid);
553  }
554  else if (p == pronlen - 1) {
555  /* last phone of the word */
556  int32 lc = dict_pron(dict, wid, p - 1);
557  xwdssid_t *rssid = dict2pid_rssid(d2p, ci, lc);
558  int j = rssid->cimap[silcipid];
559  ssid = rssid->ssid[j];
560  }
561  else {
562  /* word internal phone */
563  ssid = dict2pid_internal(d2p, wid, p);
564  }
565  tmatid = bin_mdef_pid2tmatid(mdef, ci);
566  hmm_init(kwss->hmmctx, &keyword->hmms[j], FALSE, ssid,
567  tmatid);
568  j++;
569  }
570  }
571 
572  ckd_free(wrdptr);
573  ckd_free(tmp_keyphrase);
574  }
575 
576  return 0;
577 }
578 
579 int
580 kws_search_start(ps_search_t * search)
581 {
582  int i;
583  kws_search_t *kwss = (kws_search_t *) search;
584 
585  kwss->frame = 0;
586  kwss->bestscore = 0;
587  kws_detections_reset(kwss->detections);
588 
589  /* Reset and enter all phone-loop HMMs. */
590  for (i = 0; i < kwss->n_pl; ++i) {
591  hmm_t *hmm = (hmm_t *) & kwss->pl_hmms[i];
592  hmm_clear(hmm);
593  hmm_enter(hmm, 0, -1, 0);
594  }
595  return 0;
596 }
597 
598 int
599 kws_search_step(ps_search_t * search, int frame_idx)
600 {
601  int16 const *senscr;
602  kws_search_t *kwss = (kws_search_t *) search;
603  acmod_t *acmod = search->acmod;
604 
605  /* Activate senones */
606  if (!acmod->compallsen)
607  kws_search_sen_active(kwss);
608 
609  /* Calculate senone scores for current frame. */
610  senscr = acmod_score(acmod, &frame_idx);
611 
612  /* Evaluate hmms in phone loop and in active keyword nodes */
613  kws_search_hmm_eval(kwss, senscr);
614 
615  /* Prune hmms with low prob */
616  kws_search_hmm_prune(kwss);
617 
618  /* Do hmms transitions */
619  kws_search_trans(kwss);
620 
621  ++kwss->frame;
622  return 0;
623 }
624 
625 int
626 kws_search_finish(ps_search_t * search)
627 {
628  /* Nothing here */
629  return 0;
630 }
631 
632 char const *
633 kws_search_hyp(ps_search_t * search, int32 * out_score,
634  int32 * out_is_final)
635 {
636  kws_search_t *kwss = (kws_search_t *) search;
637  if (out_score)
638  *out_score = 0;
639 
640  if (search->hyp_str)
641  ckd_free(search->hyp_str);
642  search->hyp_str = kws_detections_hyp_str(kwss->detections, kwss->frame, kwss->delay);
643 
644  return search->hyp_str;
645 }
646 
647 char *
648 kws_search_get_keywords(ps_search_t * search)
649 {
650  int i, c, len;
651  kws_search_t *kwss;
652  char* line;
653 
654  kwss = (kws_search_t *) search;
655 
656  len = 0;
657  for (i = 0; i < kwss->n_keyphrases; i++)
658  len += strlen(kwss->keyphrases[i].word);
659  len += kwss->n_keyphrases;
660 
661  c = 0;
662  line = (char *)ckd_calloc(len, sizeof(*line));
663  for (i = 0; i < kwss->n_keyphrases; i++) {
664  char *keyword_str = kwss->keyphrases[i].word;
665  memcpy(&line[c], keyword_str, strlen(keyword_str));
666  c += strlen(keyword_str);
667  line[c++] = '\n';
668  }
669  line[--c] = '\0';
670 
671  return line;
672 }
Internal implementation of PocketSphinx decoder.
frame_idx_t last_frame
Last frame to raise the detection.
Definition: kws_search.h:57
Base structure for search module.
void hmm_init(hmm_context_t *ctx, hmm_t *hmm, int mpx, int ssid, int tmatid)
Populate a previously-allocated HMM structure, allocating internal data.
Definition: hmm.c:89
POCKETSPHINX_EXPORT s3wid_t dict_wordid(dict_t *d, const char *word)
Return word id for given word string if present.
Definition: dict.c:399
void ps_search_base_reinit(ps_search_t *search, dict_t *dict, dict2pid_t *d2p)
Re-initialize base structure with new dictionary.
acmod_t * acmod
Acoustic model.
An individual HMM among the HMM search space.
gnode_t * detection
Keyword detection correspondent to segment.
Definition: kws_search.h:56
uint8 *** tp
The transition matrices; kept in the same scale as acoustic scores; tp[tmatid][from-state][to-state]...
Definition: tmat.h:107
int32 plp
Phone loop probability.
Definition: kws_search.h:82
ps_segfuncs_t * vt
V-table of seg methods.
int32 def_threshold
default threshold for p(hyp)/p(altern) ratio
Definition: kws_search.h:84
logmath_t * lmath
Log-math computation.
Definition: acmod.h:151
uint16 ** sseq
Unique senone sequences (2D array built at load time)
Definition: bin_mdef.h:134
void hmm_deinit(hmm_t *hmm)
Free an HMM structure, releasing internal data (but not the HMM structure itself).
Definition: hmm.c:111
int32 lscr
Language model score.
void acmod_activate_hmm(acmod_t *acmod, hmm_t *hmm)
Activate senones associated with an HMM.
Definition: acmod.c:1233
#define BAD_S3WID
Dictionary word id.
Definition: s3types.h:90
Segmentation "iterator" for KWS history.
Definition: kws_search.h:54
int32 bestscore
For beam pruning.
Definition: kws_search.h:83
int32 prob
Log posterior probability.
char const * word
Word string (pointer into dictionary hash)
ps_search_t * search
Search object from whence this came.
void ps_search_init(ps_search_t *search, ps_searchfuncs_t *vt, const char *type, const char *name, cmd_ln_t *config, acmod_t *acmod, dict_t *dict, dict2pid_t *d2p)
Initialize base structure.
hmm_t * pl_hmms
Phone loop hmms - hmms of CI phones.
Definition: kws_search.h:88
kws_keyword_t * keyphrases
Keyphrases to spot.
Definition: kws_search.h:76
int32 hmm_vit_eval(hmm_t *hmm)
Viterbi evaluation of given HMM.
Definition: hmm.c:789
#define dict2pid_rssid(d, ci, lc)
Access macros; not designed for arbitrary use.
Definition: dict2pid.h:115
hmm_context_t * hmmctx
HMM context.
Definition: kws_search.h:73
uint8 compallsen
Compute all senones?
Definition: acmod.h:188
int32 delay
Delay to wait for best detection score.
Definition: kws_search.h:85
hmm_context_t * hmm_context_init(int32 n_emit_state, uint8 **const *tp, int16 const *senscore, uint16 *const *sseq)
Create an HMM context.
Definition: hmm.c:56
void ps_search_base_free(ps_search_t *search)
Free search.
#define WORST_SCORE
Large "bad" score.
Definition: hmm.h:84
tmat_t * tmat
Transition matrices.
Definition: acmod.h:160
frame_idx_t ef
End frame.
int32 ascr
Acoustic score.
void hmm_enter(hmm_t *h, int32 score, int32 histid, int frame)
Enter an HMM with the given path score and history ID.
Definition: hmm.c:201
void acmod_clear_active(acmod_t *acmod)
Clear set of active senones.
Definition: acmod.c:1217
ps_seg_t base
Base structure.
Definition: kws_search.h:55
#define hmm_context_set_senscore(ctx, senscr)
Change the senone score array for a context.
Definition: hmm.h:227
#define SENSCR_SHIFT
Shift count for senone scores.
Definition: hmm.h:73
a structure for a dictionary.
Definition: dict.h:76
Word graph structure used in bestpath/nbest search.
s3ssid_t dict2pid_internal(dict2pid_t *d2p, int32 wid, int pos)
Return the senone sequence ID for the given word position.
Definition: dict2pid.c:367
void hmm_clear(hmm_t *h)
Reset the states of the HMM to the invalid condition.
Definition: hmm.c:183
cross word triphone model structure
Definition: dict2pid.h:73
char * hyp_str
Current hypothesis string.
frame_idx_t frame
Frame index.
Definition: kws_search.h:78
#define BETTER_THAN
Is one score better than another?
Definition: hmm.h:95
int32 n_pl
Number of CI phones.
Definition: kws_search.h:87
int n_keyphrases
Keyphrases amount.
Definition: kws_search.h:77
void hmm_context_free(hmm_context_t *ctx)
Free an HMM context.
Definition: hmm.c:80
bin_mdef_t * mdef
Model definition.
Definition: acmod.h:159
Implementation of KWS search structure.
Definition: kws_search.h:70
kws_detections_t * detections
Keyword spotting history.
Definition: kws_search.h:75
V-table for search algorithm.
Base structure for hypothesis segmentation iterator.
s3cipid_t * cimap
Index into ssid[] above for each ci phone.
Definition: dict2pid.h:75
#define dict_pron(d, w, p)
The CI phones of the word w at position p.
Definition: dict.h:165
Acoustic model structure.
Definition: acmod.h:148
float32 lwf
Language weight factor (for second-pass searches)
Building composite triphone (as well as word internal triphones) with the dictionary.
Definition: dict2pid.h:84
s3ssid_t * ssid
Senone Sequence ID list for all context ciphones.
Definition: dict2pid.h:74
frame_idx_t sf
Start frame.
int16 const * acmod_score(acmod_t *acmod, int *inout_frame_idx)
Score one frame of data.
Definition: acmod.c:1126