Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
pcb_smoother.cc
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1997 */
6 /* All Rights Reserved. */
7 /* */
8 /* Permission is hereby granted, free of charge, to use and distribute */
9 /* this software and its documentation without restriction, including */
10 /* without limitation the rights to use, copy, modify, merge, publish, */
11 /* distribute, sublicense, and/or sell copies of this work, and to */
12 /* permit persons to whom this work is furnished to do so, subject to */
13 /* the following conditions: */
14 /* 1. The code must retain the above copyright notice, this list of */
15 /* conditions and the following disclaimer. */
16 /* 2. Any modifications must be clearly marked as such. */
17 /* 3. Original authors' names are not deleted. */
18 /* 4. The authors' names are not used to endorse or promote products */
19 /* derived from this software without specific prior written */
20 /* permission. */
21 /* */
22 /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23 /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24 /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25 /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26 /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27 /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28 /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29 /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30 /* THIS SOFTWARE. */
31 /* */
32 /*************************************************************************/
33 /* Author : Paul Bagshaw */
34 /* Date : 1993 */
35 /*-----------------------------------------------------------------------*/
36 /* */
37 /* The above copyright was given by Paul Bagshaw, he retains */
38 /* his original rights */
39 /* */
40 /*************************************************************************/
41 #include <cmath>
42 #include <cstdio>
43 #include "array_smoother.h"
44 #include "EST_cutils.h"
45 
46 #define MAX_LEN 127
47 
48 #define MODULE "array_smoother"
49 
50 float median (int *counter, float valin, float valbuf[], int lmed, int mmed);
51 float hanning (int *counter, float valin, float valhan[], float win_coeff[],
52  struct Ms_Op *ms);
53 void mk_window_coeffs (int length, float win_coeff[]);
54 
55 struct Ms_Op *default_ms_op(struct Ms_Op *ms);
56 
57 void array_smoother (float *p_array, int arraylen, struct Ms_Op *ms)
58 {
59  int i, j, mid1, mid2 = 0, filler, nloops;
60  int C1, C2 = 0, C3 = 0, C4 = 0, c1, c2, c3, c4;
61  int delay, delx = 0, dely = 0;
62  int in = 0, out = 0;
63  float input, output;
64  float *inarray;
65  float xdel[2 * MAX_LEN - 2], ydel[2 * MAX_LEN - 2];
66  float medbuf1[MAX_LEN], medbuf2[MAX_LEN];
67  float hanbuf1[MAX_LEN], hanbuf2[MAX_LEN], win_coeffs[MAX_LEN];
68  float medval1, medval2, hanval1, hanval2, zatn;
69 
70  inarray = new float[arraylen];
71  for (i = 0; i < arraylen; ++i)
72  inarray[i] = p_array[i];
73 
74  if (ms == NULL)
75  {
76  ms = new Ms_Op;
77  default_ms_op(ms);
78  }
79 
80  mk_window_coeffs (ms->window_length, win_coeffs);
81  /* determine the size and delay of each stage concerned */
82  mid1 = ms->first_median / 2;
83  C1 = delay = ms->first_median - 1;
84  if (ms->apply_hanning)
85  {
86  C2 = ms->window_length - 1;
87  delay = ms->first_median + ms->window_length - 2;
88  }
89  if (ms->smooth_double) {
90  mid2 = ms->second_median / 2;
91  C3 = ms->second_median - 1;
92  if (!ms->apply_hanning) {
93  delx = ms->first_median;
94  dely = ms->second_median;
95  }
96  else {
97  C4 = ms->window_length - 1;
98  delx = ms->first_median + ms->window_length - 1;
99  dely = ms->second_median + ms->window_length - 1;
100  }
101  delay = delx + dely - 2;
102  }
103  /* prepare for smoothing */
104  c1 = C1;
105  c2 = C2;
106  c3 = C3;
107  c4 = C4;
108  if (!ms->extrapolate) {
109  /* pad with breakers at the beginning */
110  for (i = 0; i < delay / 2; i++)
111  p_array[out++] = ms->breaker;
112  filler = 0;
113  nloops = arraylen;
114  }
115  else {
116  /* extrapolate by initialising filter with dummy breakers */
117  filler = delay / 2;
118  nloops = arraylen + delay;
119  }
120  /* smooth track element by track element */
121  for (j = 0; j < nloops; j++)
122  {
123  if (j < filler || j >= nloops - filler)
124  input = ms->breaker;
125  else
126  input = inarray[in++];
127 
128  /* store input value if double smoothing */
129  if (ms->smooth_double) {
130  for (i = delx - 1; i > 0; i--)
131  xdel[i] = xdel[i - 1];
132  xdel[0] = input;
133  }
134  /* first median smoothing */
135 
136  medval1 = median (&c1, input, medbuf1, ms->first_median, mid1);
137 
138  if (c1 == -1)
139  {
140  output = medval1;
141  /* first hanning window (optional) */
142  if (ms->apply_hanning)
143  {
144  hanval1 = hanning (&c2, medval1, hanbuf1, win_coeffs, ms);
145  if (c2 == -1)
146  output = hanval1;
147  else
148  continue;
149  }
150  /* procedures for double smoothing (optional) */
151  if (ms->smooth_double)
152  {
153  /* compute rough component z(n) */
154  if (output != ms->breaker && xdel[delx - 1]
155  != ms->breaker)
156  zatn = xdel[delx - 1] - output;
157  else
158  zatn = ms->breaker;
159  /* store results of first smoothing */
160  for (i = dely - 1; i > 0; i--)
161  ydel[i] = ydel[i - 1];
162  ydel[0] = output;
163  /* second median smoothing */
164  medval2 = median (&c3, zatn, medbuf2,
165  ms->second_median, mid2);
166  if (c3 == -1)
167  {
168  output = medval2;
169  /* second hanning smoothing (optional) */
170  if (ms->apply_hanning) {
171  hanval2 = hanning (&c4, medval2, hanbuf2,
172  win_coeffs, ms);
173  if (c4 == -1)
174  output = hanval2;
175  else
176  continue;
177  }
178  if (output != ms->breaker && ydel[dely - 1]
179  != ms->breaker)
180  output += ydel[dely - 1];
181  else
182  output = ms->breaker;
183  }
184  else
185  continue;
186  }
187  /* write filtered result */
188  p_array[out++] = output;
189  }
190  }
191  if (!ms->extrapolate) /* pad with breakers at the end */
192  for (i = 0; i < delay / 2; i++)
193  p_array[out++] = ms->breaker;
194 
195  delete inarray;
196 }
197 
198 float median (int *counter, float valin, float valbuf[], int lmed, int mmed)
199 {
200  int i, j;
201  float tmp, filmed[MAX_LEN];
202 
203  for (i = lmed - 1; i > 0; i--)
204  valbuf[i] = valbuf[i - 1];
205  valbuf[0] = valin;
206 
207  if (*counter > 0)
208  {
209  (*counter)--;
210  return (0.0);
211  }
212  else
213  {
214  *counter = -1;
215 
216  for (i = 0; i < lmed; i++)
217  filmed[i] = valbuf[i];
218 
219  for (j = lmed - 1; j > 0; j--)
220  for (i = 0; i < j; i++)
221  if (filmed[i] > filmed[i + 1])
222  {
223  tmp = filmed[i + 1];
224  filmed[i + 1] = filmed[i];
225  filmed[i] = tmp;
226  }
227  return (filmed[mmed]);
228  }
229 
230 }
231 
232 #define TWO_PI 6.28318530717958647698
233 
234 void mk_window_coeffs (int length, float win_coeff[])
235 {
236  int i;
237  double x;
238 
239  for (i = 0; i < length; i++) {
240  x = TWO_PI * (i + 1.0) / (length + 1.0);
241  win_coeff[i] = (1.0 - (float) cos (x)) / (length + 1.0);
242  }
243 
244 }
245 
246 float hanning (int *counter, float valin, float valhan[], float win_coeff[],
247  struct Ms_Op *par)
248 {
249  int i, j, k = 0;
250  float valout = 0.0, weight[MAX_LEN];
251 
252  for (i = par->window_length - 1; i > 0; i--)
253  valhan[i] = valhan[i - 1];
254  valhan[0] = valin;
255  if (*counter > 0) {
256  (*counter)--;
257  return (0.0);
258  }
259  else {
260  *counter = -1;
261  for (i = 0; i < par->window_length; i++)
262  if (valhan[i] == par->breaker)
263  k++;
264  if (!k)
265  for (i = 0; i < par->window_length; i++)
266  valout += valhan[i] * win_coeff[i];
267  else if (k <= par->window_length / 2 && par->extrapolate) {
268  mk_window_coeffs (par->window_length - k, weight);
269  for (i = 0, j = 0; i < par->window_length; i++)
270  if (valhan[i] != par->breaker)
271  valout += valhan[i] * weight[j++];
272  }
273  else
274  valout = par->breaker;
275  return (valout);
276  }
277 
278 }
279 
280 void initialise_parameters (struct Ms_Op *p_par)
281 {
282  p_par->smooth_double = 0;
283  p_par->apply_hanning = 0;
284  p_par->extrapolate = 0;
285  p_par->window_length = DEFAULT_WLEN;
286  p_par->first_median = DEFAULT_MED_1;
287  p_par->second_median = DEFAULT_MED_2;
288  return;
289 }
290 
291 struct Ms_Op *default_ms_op(struct Ms_Op *ms)
292 {
293  ms->smooth_double = FALSE;
294  ms->apply_hanning = TRUE;
295  ms->extrapolate = TRUE;
296  ms->first_median = 11;
297  ms->second_median = 1;
298  ms->window_length = 7;
299  ms->breaker = -1.0;
300  return (ms);
301 }