SphinxBase  0.6
feat.c
1 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* ====================================================================
3  * Copyright (c) 1999-2004 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  * This work was supported in part by funding from the Defense Advanced
19  * Research Projects Agency and the National Science Foundation of the
20  * United States of America, and the CMU Sphinx Speech Consortium.
21  *
22  * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
23  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
26  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * ====================================================================
35  *
36  */
37 /*
38  * feat.c -- Feature vector description and cepstra->feature computation.
39  *
40  * **********************************************
41  * CMU ARPA Speech Project
42  *
43  * Copyright (c) 1996 Carnegie Mellon University.
44  * ALL RIGHTS RESERVED.
45  * **********************************************
46  *
47  * HISTORY
48  * $Log$
49  * Revision 1.22 2006/02/23 03:59:40 arthchan2003
50  * Merged from branch SPHINX3_5_2_RCI_IRII_BRANCH: a, Free buffers correctly. b, Fixed dox-doc.
51  *
52  * Revision 1.21.4.3 2005/10/17 04:45:57 arthchan2003
53  * Free stuffs in cmn and feat corectly.
54  *
55  * Revision 1.21.4.2 2005/09/26 02:19:57 arthchan2003
56  * Add message to show the directory which the feature is searched for.
57  *
58  * Revision 1.21.4.1 2005/07/03 22:55:50 arthchan2003
59  * More correct deallocation in feat.c. The cmn deallocation is still not correct at this point.
60  *
61  * Revision 1.21 2005/06/22 03:29:35 arthchan2003
62  * Makefile.am s for all subdirectory of libs3decoder/
63  *
64  * Revision 1.4 2005/04/21 23:50:26 archan
65  * Some more refactoring on the how reporting of structures inside kbcore_t is done, it is now 50% nice. Also added class-based LM test case into test-decode.sh.in. At this moment, everything in search mode 5 is already done. It is time to test the idea whether the search can really be used.
66  *
67  * Revision 1.3 2005/03/30 01:22:46 archan
68  * Fixed mistakes in last updates. Add
69  *
70  *
71  * 20.Apr.2001 RAH (rhoughton@mediasite.com, ricky.houghton@cs.cmu.edu)
72  * Adding feat_free() to free allocated memory
73  *
74  * 02-Jan-2001 Rita Singh (rsingh@cs.cmu.edu) at Carnegie Mellon University
75  * Modified feat_s2mfc2feat_block() to handle empty buffers at
76  * the end of an utterance
77  *
78  * 30-Dec-2000 Rita Singh (rsingh@cs.cmu.edu) at Carnegie Mellon University
79  * Added feat_s2mfc2feat_block() to allow feature computation
80  * from sequences of blocks of cepstral vectors
81  *
82  * 12-Jun-98 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
83  * Major changes to accommodate arbitrary feature input types. Added
84  * feat_read(), moved various cep2feat functions from other files into
85  * this one. Also, made this module object-oriented with the feat_t type.
86  * Changed definition of s2mfc_read to let the caller manage MFC buffers.
87  *
88  * 03-Oct-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
89  * Added unistd.h include.
90  *
91  * 02-Oct-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
92  * Added check for sf argument to s2mfc_read being within file size.
93  *
94  * 18-Sep-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
95  * Added sf, ef parameters to s2mfc_read().
96  *
97  * 10-Jan-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
98  * Added feat_cepsize().
99  * Added different feature-handling (s2_4x, s3_1x39 at this point).
100  * Moved feature-dependent functions to feature-dependent files.
101  *
102  * 09-Jan-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
103  * Moved constant declarations from feat.h into here.
104  *
105  * 04-Nov-95 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
106  * Created.
107  */
108 
109 
110 /*
111  * This module encapsulates different feature streams used by the Sphinx group. New
112  * stream types can be added by augmenting feat_init() and providing an accompanying
113  * compute_feat function. It also provides a "generic" feature vector definition for
114  * handling "arbitrary" speech input feature types (see the last section in feat_init()).
115  * In this case the speech input data should already be feature vectors; no computation,
116  * such as MFC->feature conversion, is available or needed.
117  */
118 
119 #include <assert.h>
120 #include <string.h>
121 #ifdef HAVE_CONFIG_H
122 #include <config.h>
123 #endif
124 
125 #ifdef _MSC_VER
126 #pragma warning (disable: 4244 4996)
127 #endif
128 
129 #include "sphinxbase/fe.h"
130 #include "sphinxbase/feat.h"
131 #include "sphinxbase/bio.h"
132 #include "sphinxbase/pio.h"
133 #include "sphinxbase/cmn.h"
134 #include "sphinxbase/agc.h"
135 #include "sphinxbase/err.h"
136 #include "sphinxbase/ckd_alloc.h"
137 #include "sphinxbase/prim_type.h"
138 #include "sphinxbase/glist.h"
139 
140 #define FEAT_VERSION "1.0"
141 #define FEAT_DCEP_WIN 2
142 
143 #ifdef DUMP_FEATURES
144 static void
145 cep_dump_dbg(feat_t *fcb, mfcc_t **mfc, int32 nfr, const char *text)
146 {
147  int32 i, j;
148 
149  E_INFO("%s\n", text);
150  for (i = 0; i < nfr; i++) {
151  for (j = 0; j < fcb->cepsize; j++) {
152  fprintf(stderr, "%f ", MFCC2FLOAT(mfc[i][j]));
153  }
154  fprintf(stderr, "\n");
155  }
156 }
157 static void
158 feat_print_dbg(feat_t *fcb, mfcc_t ***feat, int32 nfr, const char *text)
159 {
160  E_INFO("%s\n", text);
161  feat_print(fcb, feat, nfr, stderr);
162 }
163 #else /* !DUMP_FEATURES */
164 #define cep_dump_dbg(fcb,mfc,nfr,text)
165 #define feat_print_dbg(fcb,mfc,nfr,text)
166 #endif
167 
168 int32 **
169 parse_subvecs(char const *str)
170 {
171  char const *strp;
172  int32 n, n2, l;
173  glist_t dimlist; /* List of dimensions in one subvector */
174  glist_t veclist; /* List of dimlists (subvectors) */
175  int32 **subvec;
176  gnode_t *gn, *gn2;
177 
178  veclist = NULL;
179 
180  strp = str;
181  for (;;) {
182  dimlist = NULL;
183 
184  for (;;) {
185  if (sscanf(strp, "%d%n", &n, &l) != 1)
186  E_FATAL("'%s': Couldn't read int32 @pos %d\n", str,
187  strp - str);
188  strp += l;
189 
190  if (*strp == '-') {
191  strp++;
192 
193  if (sscanf(strp, "%d%n", &n2, &l) != 1)
194  E_FATAL("'%s': Couldn't read int32 @pos %d\n", str,
195  strp - str);
196  strp += l;
197  }
198  else
199  n2 = n;
200 
201  if ((n < 0) || (n > n2))
202  E_FATAL("'%s': Bad subrange spec ending @pos %d\n", str,
203  strp - str);
204 
205  for (; n <= n2; n++) {
206  gnode_t *gn;
207  for (gn = dimlist; gn; gn = gnode_next(gn))
208  if (gnode_int32(gn) == n)
209  break;
210  if (gn != NULL)
211  E_FATAL("'%s': Duplicate dimension ending @pos %d\n",
212  str, strp - str);
213 
214  dimlist = glist_add_int32(dimlist, n);
215  }
216 
217  if ((*strp == '\0') || (*strp == '/'))
218  break;
219 
220  if (*strp != ',')
221  E_FATAL("'%s': Bad delimiter @pos %d\n", str, strp - str);
222 
223  strp++;
224  }
225 
226  veclist = glist_add_ptr(veclist, (void *) dimlist);
227 
228  if (*strp == '\0')
229  break;
230 
231  assert(*strp == '/');
232  strp++;
233  }
234 
235  /* Convert the glists to arrays; remember the glists are in reverse order of the input! */
236  n = glist_count(veclist); /* #Subvectors */
237  subvec = (int32 **) ckd_calloc(n + 1, sizeof(int32 *)); /* +1 for sentinel */
238  subvec[n] = NULL; /* sentinel */
239 
240  for (--n, gn = veclist; (n >= 0) && gn; gn = gnode_next(gn), --n) {
241  gn2 = (glist_t) gnode_ptr(gn);
242 
243  n2 = glist_count(gn2); /* Length of this subvector */
244  if (n2 <= 0)
245  E_FATAL("'%s': 0-length subvector\n", str);
246 
247  subvec[n] = (int32 *) ckd_calloc(n2 + 1, sizeof(int32)); /* +1 for sentinel */
248  subvec[n][n2] = -1; /* sentinel */
249 
250  for (--n2; (n2 >= 0) && gn2; gn2 = gnode_next(gn2), --n2)
251  subvec[n][n2] = gnode_int32(gn2);
252  assert((n2 < 0) && (!gn2));
253  }
254  assert((n < 0) && (!gn));
255 
256  /* Free the glists */
257  for (gn = veclist; gn; gn = gnode_next(gn)) {
258  gn2 = (glist_t) gnode_ptr(gn);
259  glist_free(gn2);
260  }
261  glist_free(veclist);
262 
263  return subvec;
264 }
265 
266 void
267 subvecs_free(int32 **subvecs)
268 {
269  int32 **sv;
270 
271  for (sv = subvecs; sv && *sv; ++sv)
272  ckd_free(*sv);
273  ckd_free(subvecs);
274 }
275 
276 int
277 feat_set_subvecs(feat_t *fcb, int32 **subvecs)
278 {
279  int32 **sv;
280  int32 n_sv, n_dim, i;
281 
282  if (subvecs == NULL) {
283  subvecs_free(fcb->subvecs);
284  ckd_free(fcb->sv_buf);
285  ckd_free(fcb->sv_len);
286  fcb->n_sv = 0;
287  fcb->subvecs = NULL;
288  fcb->sv_len = NULL;
289  fcb->sv_buf = NULL;
290  fcb->sv_dim = 0;
291  return 0;
292  }
293 
294  if (fcb->n_stream != 1) {
295  E_ERROR("Subvector specifications require single-stream features!");
296  return -1;
297  }
298 
299  n_sv = 0;
300  n_dim = 0;
301  for (sv = subvecs; sv && *sv; ++sv) {
302  int32 *d;
303 
304  for (d = *sv; d && *d != -1; ++d) {
305  ++n_dim;
306  }
307  ++n_sv;
308  }
309  if (n_dim > feat_dimension(fcb)) {
310  E_ERROR("Total dimensionality of subvector specification %d "
311  "> feature dimensionality %d\n", n_dim, feat_dimension(fcb));
312  return -1;
313  }
314 
315  fcb->n_sv = n_sv;
316  fcb->subvecs = subvecs;
317  fcb->sv_len = ckd_calloc(n_sv, sizeof(*fcb->sv_len));
318  fcb->sv_buf = ckd_calloc(n_dim, sizeof(*fcb->sv_buf));
319  fcb->sv_dim = n_dim;
320  for (i = 0; i < n_sv; ++i) {
321  int32 *d;
322  for (d = subvecs[i]; d && *d != -1; ++d) {
323  ++fcb->sv_len[i];
324  }
325  }
326 
327  return 0;
328 }
329 
333 static void
334 feat_subvec_project(feat_t *fcb, mfcc_t ***inout_feat, uint32 nfr)
335 {
336  uint32 i;
337 
338  if (fcb->subvecs == NULL)
339  return;
340  for (i = 0; i < nfr; ++i) {
341  mfcc_t *out;
342  int32 j;
343 
344  out = fcb->sv_buf;
345  for (j = 0; j < fcb->n_sv; ++j) {
346  int32 *d;
347  for (d = fcb->subvecs[j]; d && *d != -1; ++d) {
348  *out++ = inout_feat[i][0][*d];
349  }
350  }
351  memcpy(inout_feat[i][0], fcb->sv_buf, fcb->sv_dim * sizeof(*fcb->sv_buf));
352  }
353 }
354 
355 mfcc_t ***
356 feat_array_alloc(feat_t * fcb, int32 nfr)
357 {
358  int32 i, j, k;
359  mfcc_t *data, *d, ***feat;
360 
361  assert(fcb);
362  assert(nfr > 0);
363  assert(feat_dimension(fcb) > 0);
364 
365  /* Make sure to use the dimensionality of the features *before*
366  LDA and subvector projection. */
367  k = 0;
368  for (i = 0; i < fcb->n_stream; ++i)
369  k += fcb->stream_len[i];
370  assert(k >= feat_dimension(fcb));
371  assert(k >= fcb->sv_dim);
372 
373  feat =
374  (mfcc_t ***) ckd_calloc_2d(nfr, feat_dimension1(fcb), sizeof(mfcc_t *));
375  data = (mfcc_t *) ckd_calloc(nfr * k, sizeof(mfcc_t));
376 
377  for (i = 0; i < nfr; i++) {
378  d = data + i * k;
379  for (j = 0; j < feat_dimension1(fcb); j++) {
380  feat[i][j] = d;
381  d += feat_dimension2(fcb, j);
382  }
383  }
384 
385  return feat;
386 }
387 
388 void
389 feat_array_free(mfcc_t ***feat)
390 {
391  ckd_free(feat[0][0]);
392  ckd_free_2d((void **)feat);
393 }
394 
395 static void
396 feat_s2_4x_cep2feat(feat_t * fcb, mfcc_t ** mfc, mfcc_t ** feat)
397 {
398  mfcc_t *f;
399  mfcc_t *w, *_w;
400  mfcc_t *w1, *w_1, *_w1, *_w_1;
401  mfcc_t d1, d2;
402  int32 i, j;
403 
404  assert(fcb);
405  assert(feat_cepsize(fcb) == 13);
406  assert(feat_n_stream(fcb) == 4);
407  assert(feat_stream_len(fcb, 0) == 12);
408  assert(feat_stream_len(fcb, 1) == 24);
409  assert(feat_stream_len(fcb, 2) == 3);
410  assert(feat_stream_len(fcb, 3) == 12);
411  assert(feat_window_size(fcb) == 4);
412 
413  /* CEP; skip C0 */
414  memcpy(feat[0], mfc[0] + 1, (feat_cepsize(fcb) - 1) * sizeof(mfcc_t));
415 
416  /*
417  * DCEP(SHORT): mfc[2] - mfc[-2]
418  * DCEP(LONG): mfc[4] - mfc[-4]
419  */
420  w = mfc[2] + 1; /* +1 to skip C0 */
421  _w = mfc[-2] + 1;
422 
423  f = feat[1];
424  for (i = 0; i < feat_cepsize(fcb) - 1; i++) /* Short-term */
425  f[i] = w[i] - _w[i];
426 
427  w = mfc[4] + 1; /* +1 to skip C0 */
428  _w = mfc[-4] + 1;
429 
430  for (j = 0; j < feat_cepsize(fcb) - 1; i++, j++) /* Long-term */
431  f[i] = w[j] - _w[j];
432 
433  /* D2CEP: (mfc[3] - mfc[-1]) - (mfc[1] - mfc[-3]) */
434  w1 = mfc[3] + 1; /* Final +1 to skip C0 */
435  _w1 = mfc[-1] + 1;
436  w_1 = mfc[1] + 1;
437  _w_1 = mfc[-3] + 1;
438 
439  f = feat[3];
440  for (i = 0; i < feat_cepsize(fcb) - 1; i++) {
441  d1 = w1[i] - _w1[i];
442  d2 = w_1[i] - _w_1[i];
443 
444  f[i] = d1 - d2;
445  }
446 
447  /* POW: C0, DC0, D2C0; differences computed as above for rest of cep */
448  f = feat[2];
449  f[0] = mfc[0][0];
450  f[1] = mfc[2][0] - mfc[-2][0];
451 
452  d1 = mfc[3][0] - mfc[-1][0];
453  d2 = mfc[1][0] - mfc[-3][0];
454  f[2] = d1 - d2;
455 }
456 
457 
458 static void
459 feat_s3_1x39_cep2feat(feat_t * fcb, mfcc_t ** mfc, mfcc_t ** feat)
460 {
461  mfcc_t *f;
462  mfcc_t *w, *_w;
463  mfcc_t *w1, *w_1, *_w1, *_w_1;
464  mfcc_t d1, d2;
465  int32 i;
466 
467  assert(fcb);
468  assert(feat_cepsize(fcb) == 13);
469  assert(feat_n_stream(fcb) == 1);
470  assert(feat_stream_len(fcb, 0) == 39);
471  assert(feat_window_size(fcb) == 3);
472 
473  /* CEP; skip C0 */
474  memcpy(feat[0], mfc[0] + 1, (feat_cepsize(fcb) - 1) * sizeof(mfcc_t));
475  /*
476  * DCEP: mfc[2] - mfc[-2];
477  */
478  f = feat[0] + feat_cepsize(fcb) - 1;
479  w = mfc[2] + 1; /* +1 to skip C0 */
480  _w = mfc[-2] + 1;
481 
482  for (i = 0; i < feat_cepsize(fcb) - 1; i++)
483  f[i] = w[i] - _w[i];
484 
485  /* POW: C0, DC0, D2C0 */
486  f += feat_cepsize(fcb) - 1;
487 
488  f[0] = mfc[0][0];
489  f[1] = mfc[2][0] - mfc[-2][0];
490 
491  d1 = mfc[3][0] - mfc[-1][0];
492  d2 = mfc[1][0] - mfc[-3][0];
493  f[2] = d1 - d2;
494 
495  /* D2CEP: (mfc[3] - mfc[-1]) - (mfc[1] - mfc[-3]) */
496  f += 3;
497 
498  w1 = mfc[3] + 1; /* Final +1 to skip C0 */
499  _w1 = mfc[-1] + 1;
500  w_1 = mfc[1] + 1;
501  _w_1 = mfc[-3] + 1;
502 
503  for (i = 0; i < feat_cepsize(fcb) - 1; i++) {
504  d1 = w1[i] - _w1[i];
505  d2 = w_1[i] - _w_1[i];
506 
507  f[i] = d1 - d2;
508  }
509 }
510 
511 
512 static void
513 feat_s3_cep(feat_t * fcb, mfcc_t ** mfc, mfcc_t ** feat)
514 {
515  assert(fcb);
516  assert(feat_n_stream(fcb) == 1);
517  assert(feat_window_size(fcb) == 0);
518 
519  /* CEP */
520  memcpy(feat[0], mfc[0], feat_cepsize(fcb) * sizeof(mfcc_t));
521 }
522 
523 static void
524 feat_s3_cepwin(feat_t * fcb, mfcc_t ** mfc, mfcc_t ** feat)
525 {
526  assert(fcb);
527  assert(feat_n_stream(fcb) == 1);
528 
529  /* CEP */
530  memcpy(feat[0], mfc[ -feat_window_size(fcb)],
531  (1 + 2 * feat_window_size (fcb)) * feat_cepsize(fcb) * sizeof(mfcc_t));
532 }
533 
534 
535 
536 static void
537 feat_s3_cep_dcep(feat_t * fcb, mfcc_t ** mfc, mfcc_t ** feat)
538 {
539  mfcc_t *f;
540  mfcc_t *w, *_w;
541  int32 i;
542 
543  assert(fcb);
544  assert(feat_n_stream(fcb) == 1);
545  assert(feat_stream_len(fcb, 0) == feat_cepsize(fcb) * 2);
546  assert(feat_window_size(fcb) == 2);
547 
548  /* CEP */
549  memcpy(feat[0], mfc[0], feat_cepsize(fcb) * sizeof(mfcc_t));
550 
551  /*
552  * DCEP: mfc[2] - mfc[-2];
553  */
554  f = feat[0] + feat_cepsize(fcb);
555  w = mfc[2];
556  _w = mfc[-2];
557 
558  for (i = 0; i < feat_cepsize(fcb); i++)
559  f[i] = w[i] - _w[i];
560 }
561 
562 static void
563 feat_1s_c_d_dd_cep2feat(feat_t * fcb, mfcc_t ** mfc, mfcc_t ** feat)
564 {
565  mfcc_t *f;
566  mfcc_t *w, *_w;
567  mfcc_t *w1, *w_1, *_w1, *_w_1;
568  mfcc_t d1, d2;
569  int32 i;
570 
571  assert(fcb);
572  assert(feat_n_stream(fcb) == 1);
573  assert(feat_stream_len(fcb, 0) == feat_cepsize(fcb) * 3);
574  assert(feat_window_size(fcb) == FEAT_DCEP_WIN + 1);
575 
576  /* CEP */
577  memcpy(feat[0], mfc[0], feat_cepsize(fcb) * sizeof(mfcc_t));
578 
579  /*
580  * DCEP: mfc[w] - mfc[-w], where w = FEAT_DCEP_WIN;
581  */
582  f = feat[0] + feat_cepsize(fcb);
583  w = mfc[FEAT_DCEP_WIN];
584  _w = mfc[-FEAT_DCEP_WIN];
585 
586  for (i = 0; i < feat_cepsize(fcb); i++)
587  f[i] = w[i] - _w[i];
588 
589  /*
590  * D2CEP: (mfc[w+1] - mfc[-w+1]) - (mfc[w-1] - mfc[-w-1]),
591  * where w = FEAT_DCEP_WIN
592  */
593  f += feat_cepsize(fcb);
594 
595  w1 = mfc[FEAT_DCEP_WIN + 1];
596  _w1 = mfc[-FEAT_DCEP_WIN + 1];
597  w_1 = mfc[FEAT_DCEP_WIN - 1];
598  _w_1 = mfc[-FEAT_DCEP_WIN - 1];
599 
600  for (i = 0; i < feat_cepsize(fcb); i++) {
601  d1 = w1[i] - _w1[i];
602  d2 = w_1[i] - _w_1[i];
603 
604  f[i] = d1 - d2;
605  }
606 }
607 
608 static void
609 feat_1s_c_d_ld_dd_cep2feat(feat_t * fcb, mfcc_t ** mfc, mfcc_t ** feat)
610 {
611  mfcc_t *f;
612  mfcc_t *w, *_w;
613  mfcc_t *w1, *w_1, *_w1, *_w_1;
614  mfcc_t d1, d2;
615  int32 i;
616 
617  assert(fcb);
618  assert(feat_n_stream(fcb) == 1);
619  assert(feat_stream_len(fcb, 0) == feat_cepsize(fcb) * 4);
620  assert(feat_window_size(fcb) == FEAT_DCEP_WIN * 2);
621 
622  /* CEP */
623  memcpy(feat[0], mfc[0], feat_cepsize(fcb) * sizeof(mfcc_t));
624 
625  /*
626  * DCEP: mfc[w] - mfc[-w], where w = FEAT_DCEP_WIN;
627  */
628  f = feat[0] + feat_cepsize(fcb);
629  w = mfc[FEAT_DCEP_WIN];
630  _w = mfc[-FEAT_DCEP_WIN];
631 
632  for (i = 0; i < feat_cepsize(fcb); i++)
633  f[i] = w[i] - _w[i];
634 
635  /*
636  * LDCEP: mfc[w] - mfc[-w], where w = FEAT_DCEP_WIN * 2;
637  */
638  f += feat_cepsize(fcb);
639  w = mfc[FEAT_DCEP_WIN * 2];
640  _w = mfc[-FEAT_DCEP_WIN * 2];
641 
642  for (i = 0; i < feat_cepsize(fcb); i++)
643  f[i] = w[i] - _w[i];
644 
645  /*
646  * D2CEP: (mfc[w+1] - mfc[-w+1]) - (mfc[w-1] - mfc[-w-1]),
647  * where w = FEAT_DCEP_WIN
648  */
649  f += feat_cepsize(fcb);
650 
651  w1 = mfc[FEAT_DCEP_WIN + 1];
652  _w1 = mfc[-FEAT_DCEP_WIN + 1];
653  w_1 = mfc[FEAT_DCEP_WIN - 1];
654  _w_1 = mfc[-FEAT_DCEP_WIN - 1];
655 
656  for (i = 0; i < feat_cepsize(fcb); i++) {
657  d1 = w1[i] - _w1[i];
658  d2 = w_1[i] - _w_1[i];
659 
660  f[i] = d1 - d2;
661  }
662 }
663 
664 static void
665 feat_copy(feat_t * fcb, mfcc_t ** mfc, mfcc_t ** feat)
666 {
667  int32 win, i, j;
668 
669  win = feat_window_size(fcb);
670 
671  /* Concatenate input features */
672  for (i = -win; i <= win; ++i) {
673  uint32 spos = 0;
674 
675  for (j = 0; j < feat_n_stream(fcb); ++j) {
676  uint32 stream_len;
677 
678  /* Unscale the stream length by the window. */
679  stream_len = feat_stream_len(fcb, j) / (2 * win + 1);
680  memcpy(feat[j] + ((i + win) * stream_len),
681  mfc[i] + spos,
682  stream_len * sizeof(mfcc_t));
683  spos += stream_len;
684  }
685  }
686 }
687 
688 feat_t *
689 feat_init(char const *type, cmn_type_t cmn, int32 varnorm,
690  agc_type_t agc, int32 breport, int32 cepsize)
691 {
692  feat_t *fcb;
693 
694  if (cepsize == 0)
695  cepsize = 13;
696  if (breport)
697  E_INFO
698  ("Initializing feature stream to type: '%s', ceplen=%d, CMN='%s', VARNORM='%s', AGC='%s'\n",
699  type, cepsize, cmn_type_str[cmn], varnorm ? "yes" : "no", agc_type_str[agc]);
700 
701  fcb = (feat_t *) ckd_calloc(1, sizeof(feat_t));
702  fcb->refcount = 1;
703  fcb->name = (char *) ckd_salloc(type);
704  if (strcmp(type, "s2_4x") == 0) {
705  /* Sphinx-II format 4-stream feature (Hack!! hardwired constants below) */
706  if (cepsize != 13) {
707  E_ERROR("s2_4x features require cepsize == 13\n");
708  ckd_free(fcb);
709  return NULL;
710  }
711  fcb->cepsize = 13;
712  fcb->n_stream = 4;
713  fcb->stream_len = (int32 *) ckd_calloc(4, sizeof(int32));
714  fcb->stream_len[0] = 12;
715  fcb->stream_len[1] = 24;
716  fcb->stream_len[2] = 3;
717  fcb->stream_len[3] = 12;
718  fcb->out_dim = 51;
719  fcb->window_size = 4;
720  fcb->compute_feat = feat_s2_4x_cep2feat;
721  }
722  else if ((strcmp(type, "s3_1x39") == 0) || (strcmp(type, "1s_12c_12d_3p_12dd") == 0)) {
723  /* 1-stream cep/dcep/pow/ddcep (Hack!! hardwired constants below) */
724  if (cepsize != 13) {
725  E_ERROR("s2_4x features require cepsize == 13\n");
726  ckd_free(fcb);
727  return NULL;
728  }
729  fcb->cepsize = 13;
730  fcb->n_stream = 1;
731  fcb->stream_len = (int32 *) ckd_calloc(1, sizeof(int32));
732  fcb->stream_len[0] = 39;
733  fcb->out_dim = 39;
734  fcb->window_size = 3;
735  fcb->compute_feat = feat_s3_1x39_cep2feat;
736  }
737  else if (strncmp(type, "1s_c_d_dd", 9) == 0) {
738  fcb->cepsize = cepsize;
739  fcb->n_stream = 1;
740  fcb->stream_len = (int32 *) ckd_calloc(1, sizeof(int32));
741  fcb->stream_len[0] = cepsize * 3;
742  fcb->out_dim = cepsize * 3;
743  fcb->window_size = FEAT_DCEP_WIN + 1; /* ddcep needs the extra 1 */
744  fcb->compute_feat = feat_1s_c_d_dd_cep2feat;
745  }
746  else if (strncmp(type, "1s_c_d_ld_dd", 12) == 0) {
747  fcb->cepsize = cepsize;
748  fcb->n_stream = 1;
749  fcb->stream_len = (int32 *) ckd_calloc(1, sizeof(int32));
750  fcb->stream_len[0] = cepsize * 4;
751  fcb->out_dim = cepsize * 4;
752  fcb->window_size = FEAT_DCEP_WIN * 2;
753  fcb->compute_feat = feat_1s_c_d_ld_dd_cep2feat;
754  }
755  else if (strncmp(type, "cep_dcep", 8) == 0 || strncmp(type, "1s_c_d", 6) == 0) {
756  /* 1-stream cep/dcep */
757  fcb->cepsize = cepsize;
758  fcb->n_stream = 1;
759  fcb->stream_len = (int32 *) ckd_calloc(1, sizeof(int32));
760  fcb->stream_len[0] = feat_cepsize(fcb) * 2;
761  fcb->out_dim = fcb->stream_len[0];
762  fcb->window_size = 2;
763  fcb->compute_feat = feat_s3_cep_dcep;
764  }
765  else if (strncmp(type, "cep", 3) == 0 || strncmp(type, "1s_c", 4) == 0) {
766  /* 1-stream cep */
767  fcb->cepsize = cepsize;
768  fcb->n_stream = 1;
769  fcb->stream_len = (int32 *) ckd_calloc(1, sizeof(int32));
770  fcb->stream_len[0] = feat_cepsize(fcb);
771  fcb->out_dim = fcb->stream_len[0];
772  fcb->window_size = 0;
773  fcb->compute_feat = feat_s3_cep;
774  }
775  else if (strncmp(type, "1s_3c", 5) == 0 || strncmp(type, "1s_4c", 5) == 0) {
776  /* 1-stream cep with frames concatenated, so called cepwin features */
777  if (strncmp(type, "1s_3c", 5) == 0)
778  fcb->window_size = 3;
779  else
780  fcb->window_size = 4;
781 
782  fcb->cepsize = cepsize;
783  fcb->n_stream = 1;
784  fcb->stream_len = (int32 *) ckd_calloc(1, sizeof(int32));
785  fcb->stream_len[0] = feat_cepsize(fcb) * (2 * fcb->window_size + 1);
786  fcb->out_dim = fcb->stream_len[0];
787  fcb->compute_feat = feat_s3_cepwin;
788  }
789  else {
790  int32 i, l, k;
791  char *strp;
792  char *mtype = ckd_salloc(type);
793  char *wd = ckd_salloc(type);
794  /*
795  * Generic definition: Format should be %d,%d,%d,...,%d (i.e.,
796  * comma separated list of feature stream widths; #items =
797  * #streams). An optional window size (frames will be
798  * concatenated) is also allowed, which can be specified with
799  * a colon after the list of feature streams.
800  */
801  l = strlen(mtype);
802  k = 0;
803  for (i = 1; i < l - 1; i++) {
804  if (mtype[i] == ',') {
805  mtype[i] = ' ';
806  k++;
807  }
808  else if (mtype[i] == ':') {
809  mtype[i] = '\0';
810  fcb->window_size = atoi(mtype + i + 1);
811  break;
812  }
813  }
814  k++; /* Presumably there are (#commas+1) streams */
815  fcb->n_stream = k;
816  fcb->stream_len = (int32 *) ckd_calloc(k, sizeof(int32));
817 
818  /* Scan individual feature stream lengths */
819  strp = mtype;
820  i = 0;
821  fcb->out_dim = 0;
822  fcb->cepsize = 0;
823  while (sscanf(strp, "%s%n", wd, &l) == 1) {
824  strp += l;
825  if ((i >= fcb->n_stream)
826  || (sscanf(wd, "%d", &(fcb->stream_len[i])) != 1)
827  || (fcb->stream_len[i] <= 0))
828  E_FATAL("Bad feature type argument\n");
829  /* Input size before windowing */
830  fcb->cepsize += fcb->stream_len[i];
831  if (fcb->window_size > 0)
832  fcb->stream_len[i] *= (fcb->window_size * 2 + 1);
833  /* Output size after windowing */
834  fcb->out_dim += fcb->stream_len[i];
835  i++;
836  }
837  if (i != fcb->n_stream)
838  E_FATAL("Bad feature type argument\n");
839  if (fcb->cepsize != cepsize)
840  E_FATAL("Bad feature type argument\n");
841 
842  /* Input is already the feature stream */
843  fcb->compute_feat = feat_copy;
844  ckd_free(mtype);
845  ckd_free(wd);
846  }
847 
848  if (cmn != CMN_NONE)
849  fcb->cmn_struct = cmn_init(feat_cepsize(fcb));
850  fcb->cmn = cmn;
851  fcb->varnorm = varnorm;
852  if (agc != AGC_NONE) {
853  fcb->agc_struct = agc_init();
854  /*
855  * No need to check if agc is set to EMAX; agc_emax_set() changes only emax related things
856  * Moreover, if agc is not NONE and block mode is used, feat_agc() SILENTLY
857  * switches to EMAX
858  */
859  /* HACK: hardwired initial estimates based on use of CMN (from Sphinx2) */
860  agc_emax_set(fcb->agc_struct, (cmn != CMN_NONE) ? 5.0 : 10.0);
861  }
862  fcb->agc = agc;
863  /*
864  * Make sure this buffer is large enough to be used in feat_s2mfc2feat_block_utt()
865  */
866  fcb->cepbuf = (mfcc_t **) ckd_calloc_2d((LIVEBUFBLOCKSIZE < feat_window_size(fcb) * 2) ? feat_window_size(fcb) * 2 : LIVEBUFBLOCKSIZE,
867  feat_cepsize(fcb),
868  sizeof(mfcc_t));
869  /* This one is actually just an array of pointers to "flatten out"
870  * wraparounds. */
871  fcb->tmpcepbuf = ckd_calloc(2 * feat_window_size(fcb) + 1,
872  sizeof(*fcb->tmpcepbuf));
873 
874  return fcb;
875 }
876 
877 
878 void
879 feat_print(feat_t * fcb, mfcc_t *** feat, int32 nfr, FILE * fp)
880 {
881  int32 i, j, k;
882 
883  for (i = 0; i < nfr; i++) {
884  fprintf(fp, "%8d:\n", i);
885 
886  for (j = 0; j < feat_dimension1(fcb); j++) {
887  fprintf(fp, "\t%2d:", j);
888 
889  for (k = 0; k < feat_dimension2(fcb, j); k++)
890  fprintf(fp, " %8.4f", MFCC2FLOAT(feat[i][j][k]));
891  fprintf(fp, "\n");
892  }
893  }
894 
895  fflush(fp);
896 }
897 
898 static void
899 feat_cmn(feat_t *fcb, mfcc_t **mfc, int32 nfr, int32 beginutt, int32 endutt)
900 {
901  cmn_type_t cmn_type = fcb->cmn;
902 
903  if (!(beginutt && endutt)
904  && cmn_type != CMN_NONE) /* Only cmn_prior in block computation mode. */
905  cmn_type = CMN_PRIOR;
906 
907  switch (cmn_type) {
908  case CMN_CURRENT:
909  cmn(fcb->cmn_struct, mfc, fcb->varnorm, nfr);
910  break;
911  case CMN_PRIOR:
912  cmn_prior(fcb->cmn_struct, mfc, fcb->varnorm, nfr);
913  if (endutt)
914  cmn_prior_update(fcb->cmn_struct);
915  break;
916  default:
917  ;
918  }
919  cep_dump_dbg(fcb, mfc, nfr, "After CMN");
920 }
921 
922 static void
923 feat_agc(feat_t *fcb, mfcc_t **mfc, int32 nfr, int32 beginutt, int32 endutt)
924 {
925  agc_type_t agc_type = fcb->agc;
926 
927  if (!(beginutt && endutt)
928  && agc_type != AGC_NONE) /* Only agc_emax in block computation mode. */
929  agc_type = AGC_EMAX;
930 
931  switch (agc_type) {
932  case AGC_MAX:
933  agc_max(fcb->agc_struct, mfc, nfr);
934  break;
935  case AGC_EMAX:
936  agc_emax(fcb->agc_struct, mfc, nfr);
937  if (endutt)
938  agc_emax_update(fcb->agc_struct);
939  break;
940  case AGC_NOISE:
941  agc_noise(fcb->agc_struct, mfc, nfr);
942  break;
943  default:
944  ;
945  }
946  cep_dump_dbg(fcb, mfc, nfr, "After AGC");
947 }
948 
949 static void
950 feat_compute_utt(feat_t *fcb, mfcc_t **mfc, int32 nfr, int32 win, mfcc_t ***feat)
951 {
952  int32 i;
953 
954  cep_dump_dbg(fcb, mfc, nfr, "Incoming features (after padding)");
955 
956  /* Create feature vectors */
957  for (i = win; i < nfr - win; i++) {
958  fcb->compute_feat(fcb, mfc + i, feat[i - win]);
959  }
960 
961  feat_print_dbg(fcb, feat, nfr - win * 2, "After dynamic feature computation");
962 
963  if (fcb->lda) {
964  feat_lda_transform(fcb, feat, nfr - win * 2);
965  feat_print_dbg(fcb, feat, nfr - win * 2, "After LDA");
966  }
967 
968  if (fcb->subvecs) {
969  feat_subvec_project(fcb, feat, nfr - win * 2);
970  feat_print_dbg(fcb, feat, nfr - win * 2, "After subvector projection");
971  }
972 }
973 
974 
987 static int32
988 feat_s2mfc_read_norm_pad(feat_t *fcb, char *file, int32 win,
989  int32 sf, int32 ef,
990  mfcc_t ***out_mfc,
991  int32 maxfr,
992  int32 cepsize)
993 {
994  FILE *fp;
995  int32 n_float32;
996  float32 *float_feat;
997  struct stat statbuf;
998  int32 i, n, byterev;
999  int32 start_pad, end_pad;
1000  mfcc_t **mfc;
1001 
1002  /* Initialize the output pointer to NULL, so that any attempts to
1003  free() it if we fail before allocating it will not segfault! */
1004  if (out_mfc)
1005  *out_mfc = NULL;
1006  E_INFO("Reading mfc file: '%s'[%d..%d]\n", file, sf, ef);
1007  if (ef >= 0 && ef <= sf) {
1008  E_ERROR("%s: End frame (%d) <= Start frame (%d)\n", file, ef, sf);
1009  return -1;
1010  }
1011 
1012  /* Find filesize; HACK!! To get around intermittent NFS failures, use stat_retry */
1013  if ((stat_retry(file, &statbuf) < 0)
1014  || ((fp = fopen(file, "rb")) == NULL)) {
1015  E_ERROR("Failed to open file '%s' for reading: %s\n", file, strerror(errno));
1016  return -1;
1017  }
1018 
1019  /* Read #floats in header */
1020  if (fread_retry(&n_float32, sizeof(int32), 1, fp) != 1) {
1021  E_ERROR("%s: fread(#floats) failed\n", file);
1022  fclose(fp);
1023  return -1;
1024  }
1025 
1026  /* Check if n_float32 matches file size */
1027  byterev = 0;
1028  if ((int32) (n_float32 * sizeof(float32) + 4) != (int32) statbuf.st_size) { /* RAH, typecast both sides to remove compile warning */
1029  n = n_float32;
1030  SWAP_INT32(&n);
1031 
1032  if ((int32) (n * sizeof(float32) + 4) != (int32) (statbuf.st_size)) { /* RAH, typecast both sides to remove compile warning */
1033  E_ERROR
1034  ("%s: Header size field: %d(%08x); filesize: %d(%08x)\n",
1035  file, n_float32, n_float32, statbuf.st_size,
1036  statbuf.st_size);
1037  fclose(fp);
1038  return -1;
1039  }
1040 
1041  n_float32 = n;
1042  byterev = 1;
1043  }
1044  if (n_float32 <= 0) {
1045  E_ERROR("%s: Header size field (#floats) = %d\n", file, n_float32);
1046  fclose(fp);
1047  return -1;
1048  }
1049 
1050  /* Convert n to #frames of input */
1051  n = n_float32 / cepsize;
1052  if (n * cepsize != n_float32) {
1053  E_ERROR("Header size field: %d; not multiple of %d\n", n_float32,
1054  cepsize);
1055  fclose(fp);
1056  return -1;
1057  }
1058 
1059  /* Check start and end frames */
1060  if (sf > 0) {
1061  if (sf >= n) {
1062  E_ERROR("%s: Start frame (%d) beyond file size (%d)\n", file,
1063  sf, n);
1064  fclose(fp);
1065  return -1;
1066  }
1067  }
1068  if (ef < 0)
1069  ef = n-1;
1070  else if (ef >= n) {
1071  E_WARN("%s: End frame (%d) beyond file size (%d), will truncate\n",
1072  file, ef, n);
1073  ef = n-1;
1074  }
1075 
1076  /* Add window to start and end frames */
1077  sf -= win;
1078  ef += win;
1079  if (sf < 0) {
1080  start_pad = -sf;
1081  sf = 0;
1082  }
1083  else
1084  start_pad = 0;
1085  if (ef >= n) {
1086  end_pad = ef - n + 1;
1087  ef = n - 1;
1088  }
1089  else
1090  end_pad = 0;
1091 
1092  /* Limit n if indicated by [sf..ef] */
1093  if ((ef - sf + 1) < n)
1094  n = (ef - sf + 1);
1095  if (maxfr > 0 && n + start_pad + end_pad > maxfr) {
1096  E_ERROR("%s: Maximum output size(%d frames) < actual #frames(%d)\n",
1097  file, maxfr, n + start_pad + end_pad);
1098  fclose(fp);
1099  return -1;
1100  }
1101 
1102  /* If no output buffer was supplied, then skip the actual data reading. */
1103  if (out_mfc != NULL) {
1104  /* Position at desired start frame and read actual MFC data */
1105  mfc = (mfcc_t **)ckd_calloc_2d(n + start_pad + end_pad, cepsize, sizeof(mfcc_t));
1106  if (sf > 0)
1107  fseek(fp, sf * cepsize * sizeof(float32), SEEK_CUR);
1108  n_float32 = n * cepsize;
1109 #ifdef FIXED_POINT
1110  float_feat = ckd_calloc(n_float32, sizeof(float32));
1111 #else
1112  float_feat = mfc[start_pad];
1113 #endif
1114  if (fread_retry(float_feat, sizeof(float32), n_float32, fp) != n_float32) {
1115  E_ERROR("%s: fread(%dx%d) (MFC data) failed\n", file, n, cepsize);
1116  ckd_free_2d(mfc);
1117  fclose(fp);
1118  return -1;
1119  }
1120  if (byterev) {
1121  for (i = 0; i < n_float32; i++) {
1122  SWAP_FLOAT32(&float_feat[i]);
1123  }
1124  }
1125 #ifdef FIXED_POINT
1126  for (i = 0; i < n_float32; ++i) {
1127  mfc[start_pad][i] = FLOAT2MFCC(float_feat[i]);
1128  }
1129  ckd_free(float_feat);
1130 #endif
1131 
1132  /* Normalize */
1133  feat_cmn(fcb, mfc + start_pad, n, 1, 1);
1134  feat_agc(fcb, mfc + start_pad, n, 1, 1);
1135 
1136  /* Replicate start and end frames if necessary. */
1137  for (i = 0; i < start_pad; ++i)
1138  memcpy(mfc[i], mfc[start_pad], cepsize * sizeof(mfcc_t));
1139  for (i = 0; i < end_pad; ++i)
1140  memcpy(mfc[start_pad + n + i], mfc[start_pad + n - 1],
1141  cepsize * sizeof(mfcc_t));
1142 
1143  *out_mfc = mfc;
1144  }
1145 
1146  fclose(fp);
1147  return n + start_pad + end_pad;
1148 }
1149 
1150 
1151 
1152 int32
1153 feat_s2mfc2feat(feat_t * fcb, const char *file, const char *dir, const char *cepext,
1154  int32 sf, int32 ef, mfcc_t *** feat, int32 maxfr)
1155 {
1156  char *path;
1157  char *ps = "/";
1158  int32 win, nfr;
1159  int32 file_length, cepext_length, path_length = 0;
1160  mfcc_t **mfc;
1161 
1162  if (fcb->cepsize <= 0) {
1163  E_ERROR("Bad cepsize: %d\n", fcb->cepsize);
1164  return -1;
1165  }
1166 
1167  if (cepext == NULL)
1168  cepext = "";
1169 
1170  /*
1171  * Create mfc filename, combining file, dir and extension if
1172  * necessary
1173  */
1174 
1175  /*
1176  * First we decide about the path. If dir is defined, then use
1177  * it. Otherwise assume the filename already contains the path.
1178  */
1179  if (dir == NULL) {
1180  dir = "";
1181  ps = "";
1182  /*
1183  * This is not true but some 3rd party apps
1184  * may parse the output explicitly checking for this line
1185  */
1186  E_INFO("At directory . (current directory)\n");
1187  }
1188  else {
1189  E_INFO("At directory %s\n", dir);
1190  /*
1191  * Do not forget the path separator!
1192  */
1193  path_length += strlen(dir) + 1;
1194  }
1195 
1196  /*
1197  * Include cepext, if it's not already part of the filename.
1198  */
1199  file_length = strlen(file);
1200  cepext_length = strlen(cepext);
1201  if ((file_length > cepext_length)
1202  && (strcmp(file + file_length - cepext_length, cepext) == 0)) {
1203  cepext = "";
1204  cepext_length = 0;
1205  }
1206 
1207  /*
1208  * Do not forget the '\0'
1209  */
1210  path_length += file_length + cepext_length + 1;
1211  path = (char*) ckd_calloc(path_length, sizeof(char));
1212 
1213 #ifdef HAVE_SNPRINTF
1214  /*
1215  * Paranoia is our best friend...
1216  */
1217  while ((file_length = snprintf(path, path_length, "%s%s%s%s", dir, ps, file, cepext)) > path_length) {
1218  path_length = file_length;
1219  path = (char*) ckd_realloc(path, path_length * sizeof(char));
1220  }
1221 #else
1222  sprintf(path, "%s%s%s%s", dir, ps, file, cepext);
1223 #endif
1224 
1225  win = feat_window_size(fcb);
1226  /* Pad maxfr with win, so we read enough raw feature data to
1227  * calculate the requisite number of dynamic features. */
1228  if (maxfr >= 0)
1229  maxfr += win * 2;
1230 
1231  if (feat != NULL) {
1232  /* Read mfc file including window or padding if necessary. */
1233  nfr = feat_s2mfc_read_norm_pad(fcb, path, win, sf, ef, &mfc, maxfr, fcb->cepsize);
1234  ckd_free(path);
1235  if (nfr < 0) {
1236  ckd_free_2d((void **) mfc);
1237  return -1;
1238  }
1239 
1240  /* Actually compute the features */
1241  feat_compute_utt(fcb, mfc, nfr, win, feat);
1242 
1243  ckd_free_2d((void **) mfc);
1244  }
1245  else {
1246  /* Just calculate the number of frames we would need. */
1247  nfr = feat_s2mfc_read_norm_pad(fcb, path, win, sf, ef, NULL, maxfr, fcb->cepsize);
1248  ckd_free(path);
1249  if (nfr < 0)
1250  return nfr;
1251  }
1252 
1253 
1254  return (nfr - win * 2);
1255 }
1256 
1257 static int32
1258 feat_s2mfc2feat_block_utt(feat_t * fcb, mfcc_t ** uttcep,
1259  int32 nfr, mfcc_t *** ofeat)
1260 {
1261  mfcc_t **cepbuf;
1262  int32 i, win, cepsize;
1263 
1264  win = feat_window_size(fcb);
1265  cepsize = feat_cepsize(fcb);
1266 
1267  /* Copy and pad out the utterance (this requires that the
1268  * feature computation functions always access the buffer via
1269  * the frame pointers, which they do) */
1270  cepbuf = ckd_calloc(nfr + win * 2, sizeof(mfcc_t *));
1271  memcpy(cepbuf + win, uttcep, nfr * sizeof(mfcc_t *));
1272 
1273  /* Do normalization before we interpolate on the boundary */
1274  feat_cmn(fcb, cepbuf + win, nfr, 1, 1);
1275  feat_agc(fcb, cepbuf + win, nfr, 1, 1);
1276 
1277  /* Now interpolate */
1278  for (i = 0; i < win; ++i) {
1279  cepbuf[i] = fcb->cepbuf[i];
1280  memcpy(cepbuf[i], uttcep[0], cepsize * sizeof(mfcc_t));
1281  cepbuf[nfr + win + i] = fcb->cepbuf[win + i];
1282  memcpy(cepbuf[nfr + win + i], uttcep[nfr - 1], cepsize * sizeof(mfcc_t));
1283  }
1284  /* Compute as usual. */
1285  feat_compute_utt(fcb, cepbuf, nfr + win * 2, win, ofeat);
1286  ckd_free(cepbuf);
1287  return nfr;
1288 }
1289 
1290 int32
1291 feat_s2mfc2feat_live(feat_t * fcb, mfcc_t ** uttcep, int32 *inout_ncep,
1292  int32 beginutt, int32 endutt, mfcc_t *** ofeat)
1293 {
1294  int32 win, cepsize, nbufcep;
1295  int32 i, j, nfeatvec;
1296  int32 zero = 0;
1297 
1298  /* Avoid having to check this everywhere. */
1299  if (inout_ncep == NULL) inout_ncep = &zero;
1300 
1301  /* Special case for entire utterances. */
1302  if (beginutt && endutt && *inout_ncep > 0)
1303  return feat_s2mfc2feat_block_utt(fcb, uttcep, *inout_ncep, ofeat);
1304 
1305  win = feat_window_size(fcb);
1306  cepsize = feat_cepsize(fcb);
1307 
1308  /* Empty the input buffer on start of utterance. */
1309  if (beginutt)
1310  fcb->bufpos = fcb->curpos;
1311 
1312  /* Calculate how much data is in the buffer already. */
1313  nbufcep = fcb->bufpos - fcb->curpos;
1314  if (nbufcep < 0)
1315  nbufcep = fcb->bufpos + LIVEBUFBLOCKSIZE - fcb->curpos;
1316  /* Add any data that we have to replicate. */
1317  if (beginutt && *inout_ncep > 0)
1318  nbufcep += win;
1319  if (endutt)
1320  nbufcep += win;
1321 
1322  /* Only consume as much input as will fit in the buffer. */
1323  if (nbufcep + *inout_ncep > LIVEBUFBLOCKSIZE) {
1324  /* We also can't overwrite the trailing window, hence the
1325  * reason why win is subtracted here. */
1326  *inout_ncep = LIVEBUFBLOCKSIZE - nbufcep - win;
1327  /* Cancel end of utterance processing. */
1328  endutt = FALSE;
1329  }
1330 
1331  /* FIXME: Don't modify the input! */
1332  feat_cmn(fcb, uttcep, *inout_ncep, beginutt, endutt);
1333  feat_agc(fcb, uttcep, *inout_ncep, beginutt, endutt);
1334 
1335  /* Replicate first frame into the first win frames if we're at the
1336  * beginning of the utterance and there was some actual input to
1337  * deal with. (FIXME: Not entirely sure why that condition) */
1338  if (beginutt && *inout_ncep > 0) {
1339  for (i = 0; i < win; i++) {
1340  memcpy(fcb->cepbuf[fcb->bufpos++], uttcep[0],
1341  cepsize * sizeof(mfcc_t));
1342  fcb->bufpos %= LIVEBUFBLOCKSIZE;
1343  }
1344  /* Move the current pointer past this data. */
1345  fcb->curpos = fcb->bufpos;
1346  nbufcep -= win;
1347  }
1348 
1349  /* Copy in frame data to the circular buffer. */
1350  for (i = 0; i < *inout_ncep; ++i) {
1351  memcpy(fcb->cepbuf[fcb->bufpos++], uttcep[i],
1352  cepsize * sizeof(mfcc_t));
1353  fcb->bufpos %= LIVEBUFBLOCKSIZE;
1354  ++nbufcep;
1355  }
1356 
1357  /* Replicate last frame into the last win frames if we're at the
1358  * end of the utterance (even if there was no input, so we can
1359  * flush the output). */
1360  if (endutt) {
1361  int32 tpos; /* Index of last input frame. */
1362  if (fcb->bufpos == 0)
1363  tpos = LIVEBUFBLOCKSIZE - 1;
1364  else
1365  tpos = fcb->bufpos - 1;
1366  for (i = 0; i < win; ++i) {
1367  memcpy(fcb->cepbuf[fcb->bufpos++], fcb->cepbuf[tpos],
1368  cepsize * sizeof(mfcc_t));
1369  fcb->bufpos %= LIVEBUFBLOCKSIZE;
1370  }
1371  }
1372 
1373  /* We have to leave the trailing window of frames. */
1374  nfeatvec = nbufcep - win;
1375  if (nfeatvec <= 0)
1376  return 0; /* Do nothing. */
1377 
1378  for (i = 0; i < nfeatvec; ++i) {
1379  /* Handle wraparound cases. */
1380  if (fcb->curpos - win < 0 || fcb->curpos + win >= LIVEBUFBLOCKSIZE) {
1381  /* Use tmpcepbuf for this case. Actually, we just need the pointers. */
1382  for (j = -win; j <= win; ++j) {
1383  int32 tmppos =
1384  (fcb->curpos + j + LIVEBUFBLOCKSIZE) % LIVEBUFBLOCKSIZE;
1385  fcb->tmpcepbuf[win + j] = fcb->cepbuf[tmppos];
1386  }
1387  fcb->compute_feat(fcb, fcb->tmpcepbuf + win, ofeat[i]);
1388  }
1389  else {
1390  fcb->compute_feat(fcb, fcb->cepbuf + fcb->curpos, ofeat[i]);
1391  }
1392  /* Move the read pointer forward. */
1393  ++fcb->curpos;
1394  fcb->curpos %= LIVEBUFBLOCKSIZE;
1395  }
1396 
1397  if (fcb->lda)
1398  feat_lda_transform(fcb, ofeat, nfeatvec);
1399 
1400  if (fcb->subvecs)
1401  feat_subvec_project(fcb, ofeat, nfeatvec);
1402 
1403  return nfeatvec;
1404 }
1405 
1406 feat_t *
1408 {
1409  ++f->refcount;
1410  return f;
1411 }
1412 
1413 int
1415 {
1416  if (f == NULL)
1417  return 0;
1418  if (--f->refcount > 0)
1419  return f->refcount;
1420 
1421  if (f->cepbuf)
1422  ckd_free_2d((void **) f->cepbuf);
1423  ckd_free(f->tmpcepbuf);
1424 
1425  if (f->name) {
1426  ckd_free((void *) f->name);
1427  }
1428  if (f->lda)
1429  ckd_free_3d((void ***) f->lda);
1430 
1431  ckd_free(f->stream_len);
1432  ckd_free(f->sv_len);
1433  ckd_free(f->sv_buf);
1434  subvecs_free(f->subvecs);
1435 
1436  cmn_free(f->cmn_struct);
1437  agc_free(f->agc_struct);
1438 
1439  ckd_free(f);
1440  return 0;
1441 }
1442 
1443 
1444 void
1446 {
1447  int i;
1448  E_INFO_NOFN("Initialization of feat_t, report:\n");
1449  E_INFO_NOFN("Feature type = %s\n", f->name);
1450  E_INFO_NOFN("Cepstral size = %d\n", f->cepsize);
1451  E_INFO_NOFN("Number of streams = %d\n", f->n_stream);
1452  for (i = 0; i < f->n_stream; i++) {
1453  E_INFO_NOFN("Vector size of stream[%d]: %d\n", i,
1454  f->stream_len[i]);
1455  }
1456  E_INFO_NOFN("Number of subvectors = %d\n", f->n_sv);
1457  for (i = 0; i < f->n_sv; i++) {
1458  int32 *sv;
1459 
1460  E_INFO_NOFN("Components of subvector[%d]:", i);
1461  for (sv = f->subvecs[i]; sv && *sv != -1; ++sv)
1462  E_INFOCONT(" %d", *sv);
1463  E_INFOCONT("\n");
1464  }
1465  E_INFO_NOFN("Whether CMN is used = %d\n", f->cmn);
1466  E_INFO_NOFN("Whether AGC is used = %d\n", f->agc);
1467  E_INFO_NOFN("Whether variance is normalized = %d\n", f->varnorm);
1468  E_INFO_NOFN("\n");
1469 }