Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
EST_Window.cc
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1994,1995,1996 */
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 : Simon King (taken from Tony Robinson) */
34 /* Date : July 1994 */
35 /*-----------------------------------------------------------------------*/
36 /* windowing functions */
37 /* */
38 /*=======================================================================*/
39 
40 #include <iostream>
41 #include <fstream>
42 #include "EST_system.h"
43 //#include "EST_sigpr.h"
44 #include "sigpr/EST_Window.h"
45 #include "EST_TNamedEnum.h"
46 #include "EST_math.h"
47 
48 //static inline int irint(float f) { return (int)(f+0.5); }
49 //static inline int irint(double f) { return (int)(f+0.5); }
50 static inline int min(int a, int b) { return (a<b)?a:b; }
51 static inline int max(int a, int b) { return (a>b)?a:b; }
52 
53  /*************************************************************************/
54  /* */
55  /* The actual window functions are defined here. */
56  /* */
57  /*************************************************************************/
58 
59 static void Rectangular(int size, EST_TBuffer<float> &r_window, int window_centre=-1)
60 {
61  // this may be a little silly
62  (void) window_centre; // not useful for rectangular window
63  r_window.ensure(size);
64 
65  for( int i=0; i<size; i++ )
66  r_window[i] = 1.0;
67 }
68 
69 static void Triangular(int size, EST_TBuffer<float> &r_window, int window_centre=-1)
70 {
71  int i, c, end=size-1;
72 
73  r_window.ensure(size);
74 
75  if( window_centre < 0 ) { // symmetric window (default)
76  c=size/2;
77  const float k = 2.0 / (float)size;
78 
79  if( (size & 1) != 0 ) // odd
80  r_window[c]=1.0;
81 
82  for( i=0; i<c; i++ ){
83  r_window[i] = i * k;
84  r_window[end-i] = r_window[i];
85  }
86  }
87  else{
88  c = window_centre;
89  const float k_left = 1.0 / (float) (window_centre+1);
90  const float k_right = 1.0 / (float) (size-(window_centre+1));
91 
92  r_window[c] = 1.0;
93 
94  // left half
95  for( i=0; i<c; ++i )
96  r_window[i] = i * k_left;
97 
98  // right half
99  const int righthand_size = size-1-window_centre;
100  for( i=0; i<righthand_size; ++i )
101  r_window[end-i] = i * k_right;
102  }
103 }
104 
105 static void Hanning(int size, EST_TBuffer<float> &r_window, int window_centre=-1)
106 {
107  int i,c;
108  float k;
109  r_window.ensure(size);
110  int end = size-1;
111 
112  if( window_centre < 0 ){ // symmetric window (default)
113  c = size/2;
114 
115  // only need to calculate one half + copy
116  if( (size & 1) != 0) // when odd
117  r_window[c]=1.0;
118 
119  k = 2.0 * M_PI / size;
120  for( i=0; i<c; ++i )
121  r_window[end-i] = r_window[i] = 0.5 - 0.5 * cos(k * (i + 0.5));
122  }
123  else{
124  c = window_centre;
125  r_window[c]=1.0; // we assume "centre" is 1.0
126 
127  // first half
128  int effective_size = (2*window_centre)+1;
129  k = 2.0 * M_PI / effective_size;
130  for( i=0; i<c; ++i )
131  r_window[i] = 0.5 - 0.5 * cos(k * (i + 0.5));
132 
133  // second half
134  const int righthand_size = size-1-window_centre;
135  effective_size = (2*righthand_size)+1;
136  k = 2.0 * M_PI / effective_size;
137  for( i=0; i<righthand_size; ++i )
138  r_window[end-i] = 0.5 - 0.5 * cos(k * (i + 0.5));
139  }
140 }
141 
142 static void Hamming(int size, EST_TBuffer<float> &r_window, int window_centre=-1)
143 {
144  float k;
145  int i, c, end=size-1;
146 
147  r_window.ensure(size);
148 
149  if( window_centre < 0 ){ // symmetric window (default)
150  c=size/2;
151  k = 2.0 * M_PI / size;
152 
153  if( (size & 1) != 0) // odd
154  r_window[c]=1.0;
155 
156  for( i=0; i<c; i++ ){
157  r_window[i] = 0.54 - 0.46 * cos(k * (i + 0.5));
158  r_window[end-i] = r_window[i];
159  }
160  }
161  else{
162  c = window_centre;
163  r_window[c] = 1.0;
164 
165  //first half
166  int effective_size = (2*window_centre)+1;
167  k = 2.0 * M_PI / effective_size;
168  for( i=0; i<c ; ++i )
169  r_window[i] = 0.54 - 0.46 * cos(k * (i + 0.5));
170 
171  //second half
172  const int righthand_size = size-1-window_centre;
173  effective_size = (2*righthand_size)+1;
174  k = 2.0 * M_PI / effective_size;
175  for( i=0; i<righthand_size; ++i )
176  r_window[end-i] = 0.54 - 0.46 * cos(k * (i + 0.5));
177  }
178 }
179 
180  /*************************************************************************/
181  /* */
182  /* Here is the interface. */
183  /* */
184  /*************************************************************************/
185 
186 typedef enum EST_WindowType {
187  wf_none=0,
188  wf_rectangle=1,
189  wf_triangle=2,
190  wf_hanning=3,
191  wf_hamming=4
192 } EST_WindowType;
193 
194 typedef struct Info {
195  EST_Window::Func *func;
196  const char *description;
197  } Info;
198 
200 {
201  { wf_none, { "none" },
202  {NULL, "unknown window type"}},
203  { wf_rectangle, {"rectangle", "rect", "rectangular"},
204  {Rectangular, "Rectangular window"}},
205  { wf_triangle, {"triangle", "tri", "triangular"},
206  {Triangular, "Triangular window"}},
207  { wf_hanning, {"hanning", "han"},
208  {Hanning, "Hanning window"}},
209  { wf_hamming, {"hamming", "ham"},
210  {Hamming, "Hamming window"}},
211  { wf_none, { NULL }},
212 };
213 
214 static EST_TNamedEnumI<EST_WindowType, Info> map(window_names);
215 
216 EST_Window::Func *EST_Window::creator(const char *name, bool report_error)
217 {
218  EST_WindowType key = map.token(name);
219 
220  if (key == wf_none)
221  {
222  if (report_error)
223  cerr << "no such window type %s" << name << endl;
224  return NULL;
225  }
226  else
227  return map.info(key).func;
228 }
229 
231 {
232  EST_WindowType key = map.token(name);
233 
234  return map.info(key).description;
235 }
236 
237 /** Return the dc offset for a section of speech.
238  * This can safely go off the limits of the waveform.
239  */
240 
241 static float find_dc(const EST_Wave &sig, int start, int size)
242 {
243  int i;
244  double sum = 0;
245 
246  start = max(0, start);
247  size = min(size, sig.num_samples()-start);
248 
249  for(i=0; i<size; i++)
250  sum += sig.a_no_check(start+i);
251 
252  return (sum / (float)size);
253 }
254 
255 void EST_Window::make_window( EST_TBuffer<float> &window_vals, int size,
256  const char *name, int window_centre )
257 {
258  EST_WindowFunc *make_window = EST_Window::creator(name);
259  window_vals.ensure(size, (bool)FALSE);
260  make_window(size, window_vals, window_centre);
261 }
262 
263 void EST_Window::make_window( EST_FVector &window_vals, int size,
264  const char *name, int window_centre )
265 {
266  EST_TBuffer<float> fwindow;
267  EST_WindowFunc *make_window = EST_Window::creator(name);
268  fwindow.ensure(size, (bool)FALSE);
269  make_window(size, fwindow, window_centre);
270  window_vals.resize(size);
271  for (int i = 0; i < size; ++i)
272  window_vals[i] = fwindow[i];
273 }
274 
276  EST_WindowFunc *make_window,
277  int start, int size,
278  EST_TBuffer<float> &window)
279 {
280  EST_TBuffer<float> window_vals(size);
281  int i;
282  float dc;
283 
284  // create the window shape
285  make_window(size, window_vals,-1);
286  window.ensure(size, (bool)FALSE);
287  dc = find_dc(sig, start, size);
288 
289  /* There are three separate loops, one each for the beginning and
290  ends, where virtual values off the end of the sig array are
291  requested, and one for the majority of the processing which falls
292  in the middle of the sig array.*/
293 
294  for(i=0; i<size && start+i<0; i++)
295  window[i] =0;
296 
297  for(; i<size && start+i < sig.num_samples(); i++)
298  window[i] = (window_vals(i) * (sig.a(start + i) - dc) + dc);
299 
300  for(; i<size; i++)
301  window[i] = 0;
302 
303 }
304 
306  const EST_String &window_name,
307  int start, int size,
308  EST_FVector &frame, int resize)
309 {
310  EST_WindowFunc *wf = creator(window_name, true);
311  window_signal(sig, wf, start, size, frame, resize);
312 }
313 
315  EST_WindowFunc *make_window,
316  int start, int size,
317  EST_FVector &frame, int resize)
318 {
319  EST_TBuffer<float> window_vals(size);
320  // create the window shape
321  make_window(size, window_vals,-1);
322 
323  window_signal(sig,
324  window_vals,
325  start, size,
326  frame, resize);
327 }
328 
330  EST_TBuffer<float> &window_vals,
331  int start, int size,
332  EST_FVector &frame, int resize)
333 {
334  int i;
335  float dc;
336 
337  if (resize)
338  frame.resize(size);
339  else if (frame.length() < size)
340  {
341  cerr << "Frame is wrong size: expected " << size << " got "
342  << frame.length() << endl;
343  return;
344  }
345 
346 /* cout << "window vals\n";
347  for (i = 0; i < size; ++i)
348  cout << window_vals[i] << " ";
349 
350  cout << endl << endl;
351 */
352 
353  dc = find_dc(sig, start, size);
354 // cout << "dc is " << dc << endl;
355  /* There are three separate loops, one each for the beginning and
356  ends, where virtual values off the end of the sig array are
357  requested, and one for the majority of the processing which falls
358  in the middle of the sig array.*/
359 
360  for(i = 0; i < size && start+i< 0; i++)
361  frame.a_no_check(i) = 0;
362 
363  for (; (i < size) && (start + i < sig.num_samples()); i++)
364  frame.a_no_check(i) = (window_vals(i) * (sig.a_no_check(start + i) - dc) + dc);
365 
366  for(; i < frame.length(); i++)
367  frame.a_no_check(i) = 0;
368 
369 /* cout << "sig vals\n";
370  for (i = 0; i < size; ++i)
371  cout << sig.a(i + start) << " ";
372 
373  cout << "frame vals\n";
374  for (i = 0; i < size; ++i)
375  cout << frame[i] << " ";
376 
377  cout << endl << endl;
378 */
379 }
380 
382 {
383  EST_String s;
384 
385  for(int n=0; n< map.n() ; n++)
386  {
387  const char *nm = map.name(map.token(n));
388  const char *d = map.info(map.token(n)).description;
389 
390  s += EST_String::cat(" ", nm, EST_String(" ")*(12-strlen(nm)), d, "\n");
391  }
392  return s;
393 }
394 
396 {
397  EST_String s("");
398 
399  for(int n=0; n< map.n() ; n++)
400  {
401  const char *nm = map.name(map.token(n));
402 
403  if (s != "")
404  s += ", ";
405 
406  s += nm;
407 
408  }
409  return s;
410 }
411 
412 #if defined(INSTANTIATE_TEMPLATES)
413 
414 #include "../base_class/EST_TNamedEnum.cc"
415 
418 
419 #endif