Initial import to Tizen
[profile/ivi/sphinxbase.git] / src / libsphinxbase / feat / agc.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  * agc.c -- Various forms of automatic gain control (AGC)
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.5  2005/06/21  19:25:41  arthchan2003
50  * 1, Fixed doxygen documentation. 2, Added $ keyword.
51  * 
52  * Revision 1.3  2005/03/30 01:22:46  archan
53  * Fixed mistakes in last updates. Add
54  *
55  * 
56  * 04-Nov-95    M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
57  *              Created.
58  */
59
60 #include <string.h>
61 #ifdef HAVE_CONFIG_H
62 #include <config.h>
63 #endif
64
65 #include "sphinxbase/err.h"
66 #include "sphinxbase/ckd_alloc.h"
67 #include "sphinxbase/agc.h"
68
69 /* NOTE!  These must match the enum in agc.h */
70 const char *agc_type_str[] = {
71     "none",
72     "max",
73     "emax",
74     "noise"
75 };
76 static const int n_agc_type_str = sizeof(agc_type_str)/sizeof(agc_type_str[0]);
77
78 agc_type_t
79 agc_type_from_str(const char *str)
80 {
81     int i;
82
83     for (i = 0; i < n_agc_type_str; ++i) {
84         if (0 == strcmp(str, agc_type_str[i]))
85             return (agc_type_t)i;
86     }
87     E_FATAL("Unknown AGC type '%s'\n", str);
88     return AGC_NONE;
89 }
90
91 agc_t *agc_init(void)
92 {
93     agc_t *agc;
94     agc = ckd_calloc(1, sizeof(*agc));
95     agc->noise_thresh = FLOAT2MFCC(2.0);
96     
97     return agc;
98 }
99
100 void agc_free(agc_t *agc)
101 {
102     ckd_free(agc);
103 }
104
105 /**
106  * Normalize c0 for all frames such that max(c0) = 0.
107  */
108 void
109 agc_max(agc_t *agc, mfcc_t **mfc, int32 n_frame)
110 {
111     int32 i;
112
113     if (n_frame <= 0)
114         return;
115     agc->obs_max = mfc[0][0];
116     for (i = 1; i < n_frame; i++) {
117         if (mfc[i][0] > agc->obs_max) {
118             agc->obs_max = mfc[i][0];
119             agc->obs_frame = 1;
120         }
121     }
122
123     E_INFO("AGCMax: obs=max= %.2f\n", agc->obs_max);
124     for (i = 0; i < n_frame; i++)
125         mfc[i][0] -= agc->obs_max;
126 }
127
128 void
129 agc_emax_set(agc_t *agc, float32 m)
130 {
131     agc->max = FLOAT2MFCC(m);
132     E_INFO("AGCEMax: max= %.2f\n", m);
133 }
134
135 float32
136 agc_emax_get(agc_t *agc)
137 {
138     return MFCC2FLOAT(agc->max);
139 }
140
141 void
142 agc_emax(agc_t *agc, mfcc_t **mfc, int32 n_frame)
143 {
144     int i;
145
146     if (n_frame <= 0)
147         return;
148     for (i = 1; i < n_frame; ++i) {
149         if (mfc[i][0] > agc->obs_max) {
150             agc->obs_max = mfc[i][0];
151             agc->obs_frame = 1;
152         }
153         mfc[i][0] -= agc->max;
154     }
155 }
156
157 /* Update estimated max for next utterance */
158 void
159 agc_emax_update(agc_t *agc)
160 {
161     if (agc->obs_frame) {            /* Update only if some data observed */
162         agc->obs_max_sum += agc->obs_max;
163         agc->obs_utt++;
164
165         /* Re-estimate max over past history; decay the history */
166         agc->max = agc->obs_max_sum / agc->obs_utt;
167         if (agc->obs_utt == 8) {
168             agc->obs_max_sum /= 2;
169             agc->obs_utt = 4;
170         }
171     }
172     E_INFO("AGCEMax: obs= %.2f, new= %.2f\n", agc->obs_max, agc->max);
173
174     /* Reset the accumulators for the next utterance. */
175     agc->obs_frame = 0;
176     agc->obs_max = FLOAT2MFCC(-1000.0); /* Less than any real C0 value (hopefully!!) */
177 }
178
179 void
180 agc_noise(agc_t *agc,
181           mfcc_t **cep,
182           int32 nfr)
183 {
184     mfcc_t min_energy; /* Minimum log-energy */
185     mfcc_t noise_level;        /* Average noise_level */
186     int32 i;           /* frame index */
187     int32 noise_frames;        /* Number of noise frames */
188
189     /* Determine minimum log-energy in utterance */
190     min_energy = cep[0][0];
191     for (i = 0; i < nfr; ++i) {
192         if (cep[i][0] < min_energy)
193             min_energy = cep[i][0];
194     }
195
196     /* Average all frames between min_energy and min_energy + agc->noise_thresh */
197     noise_frames = 0;
198     noise_level = 0;
199     min_energy += agc->noise_thresh;
200     for (i = 0; i < nfr; ++i) {
201         if (cep[i][0] < min_energy) {
202             noise_level += cep[i][0];
203             noise_frames++;
204         }
205     }
206     noise_level /= noise_frames;
207
208     E_INFO("AGC NOISE: max= %6.3f\n", MFCC2FLOAT(noise_level));
209
210     /* Subtract noise_level from all log_energy values */
211     for (i = 0; i < nfr; ++i)
212         cep[i][0] -= noise_level;
213 }
214
215 void
216 agc_set_threshold(agc_t *agc, float32 threshold)
217 {
218     agc->noise_thresh = FLOAT2MFCC(threshold);
219 }
220
221 float32
222 agc_get_threshold(agc_t *agc)
223 {
224     return FLOAT2MFCC(agc->noise_thresh);
225 }