1 /*
2     MPEG Maaate: An Australian MPEG audio analysis toolkit
3     Copyright (C) 2000 Commonwealth Scientific and Industrial Research Organisation
4     (CSIRO), Australia.
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 
21 #include "module.H"
22 
23 #include "tools.H"
24 
25 #include <math.h>
26 
27 #define ROUND(number) floor((number)+0.5)
28 
29 // initialisation
30 static void
init_bandnrjratio(Module * m)31 init_bandnrjratio(Module * m) {
32 
33   // set up member values
34   m->set_name (string("BandNrjRatio"));
35   m->set_desc (string("Band Energy Ratio for one granule"));
36   m->set_author (string("CSIRO-MIS AAS Thomas VINCENT"));
37   m->set_copyright (string("(c) 2002 CSIRO"));
38   m->set_url (string("http://www.cmis.csiro.au/Maaate/docs/modules.html"));
39 
40   // set up input parameter list
41   m->inputSpecs()->clear();
42 
43   // first parameter: sound file
44   m->inputSpecs()->push_back
45     (ModuleParamSpec(string("soundfile"),
46 		     string("the SOUND file for which the signal "
47 			    "energy gets calculated"),
48 		     MAAATE_TYPE_SOUNDFILE,
49 		     new ModuleParam((SOUNDfile*)NULL)) // default
50      );
51 
52   // second parameter: start time
53   MaaateConstraint * constraint = new MaaateConstraint();
54   constraint->addConstraintGreaterThan(0.0);
55   m->inputSpecs()->push_back
56     (ModuleParamSpec(string("starttime"),
57 		     string("time instant from which to start the "
58 			    "band energy ratio calculation"),
59 		     MAAATE_TYPE_REAL,
60 		     new ModuleParam((double)0.0), // default
61 		     constraint));
62 
63   // third parameter: end time
64   constraint = new MaaateConstraint();
65   constraint->clear();
66   constraint->addConstraintGreaterThan(0.0);
67   m->inputSpecs()->push_back
68     (ModuleParamSpec(string("endtime"),
69 		     string("time instant until which to calculate "
70 			    "the band energy ratio"),
71 		     MAAATE_TYPE_REAL,
72 		     new ModuleParam((double)DBL_MAX), // default
73 		     constraint));
74 
75   // forth parameter: I subband boundary
76   constraint = new MaaateConstraint();
77   constraint->clear();
78   constraint->addConstraintGreaterThan(1);
79   m->inputSpecs()->push_back
80     (ModuleParamSpec(string("subbandboundary"),
81 		     string("subband boundary between low and"
82 			    "high frequencies"),
83 		     MAAATE_TYPE_INT,
84 		     new ModuleParam(3), // default
85 		     constraint));
86 
87   // fifth parameter: window function
88   constraint = new MaaateConstraint();
89   constraint->clear();
90   constraint->addConstraintRange(0, 3);
91   m->inputSpecs()->push_back
92     (ModuleParamSpec(string("window-numero"),
93 		     string("choice the window function to apply"
94 			    "during the calculation"),
95 		     MAAATE_TYPE_INT,
96 		     new ModuleParam(0), // default
97 		     constraint));
98 
99 
100   // set up output parameter list
101   m->outputSpecs()->clear();
102 
103   // first parameter: subband energies curves
104   m->outputSpecs()->push_back
105     (ModuleParamSpec(string("Band energy ratio curve"),
106 		     string("indicator of voice/unvoice signal"),
107 		     MAAATE_TYPE_SEGMENTDATA,
108 		     new ModuleParam((SegmentData*)NULL)) // default
109      );
110 
111 };
112 
113 
114 // function to suggest parameter values given that some of the input
115 // parameters have already been set; also changes constraints accordingly
116 static void
suggest_bandnrjratio(Module * m,list<ModuleParam> * paramsIn)117 suggest_bandnrjratio (Module * m, list<ModuleParam> * paramsIn) {
118   list<ModuleParam>::iterator iter;
119 
120   // get module's input parameter specifications
121   list<ModuleParamSpec> * inSpecs = m->inputSpecs();
122   list<ModuleParamSpec>::iterator iterSpecs;
123 
124   iter = paramsIn->begin(); // SOUND file
125   iterSpecs = inSpecs->begin();
126   if (iter == paramsIn->end()) return;
127   SOUNDfile * mf = (*iter).get_sf();
128   if (mf == NULL) return;
129 
130   ++iter; // start time
131   ++iterSpecs;
132   (*iterSpecs).constraint()->clear();
133   (*iterSpecs).constraint()->addConstraintRange(0.0, mf->file_duration());
134   double startTime = (*iter).get_r();
135 
136   ++iter; // end time
137   ++iterSpecs;
138   (*iterSpecs).constraint()->clear();
139   (*iterSpecs).constraint()->addConstraintRange(0.0, mf->file_duration());
140   double endTime = (*iter).get_r();
141 
142   //check time
143   if (endTime < startTime) {
144     endTime = startTime;
145     (*iter).set(startTime);
146   }
147 
148   //I subband boundary
149   ++iter;
150   ++iterSpecs;
151   (*iterSpecs).constraint()->clear();
152   (*iterSpecs).constraint()->addConstraintRange(1, (mf->nb_subbands(LOW) - 1) );
153 
154   //nothing more to check for window number
155 
156 }
157 
158 // function to work on input parameters and return output parameters
159 static list<ModuleParam> *
apply_bandnrjratio(Module * m,list<ModuleParam> * paramsIn)160 apply_bandnrjratio (Module * m, list<ModuleParam> * paramsIn) {
161 
162   // the output parameter list
163   list<ModuleParam> * mpl = new list<ModuleParam>();
164 
165   // iterator in input parmeter list
166   list<ModuleParam>::iterator iter;
167 
168   //Getting input parameters and last checking
169   //SOUND file
170   iter = paramsIn->begin();
171   if (iter == paramsIn->end()) return mpl;
172   SOUNDfile * mf = (*iter).get_sf();
173   if (mf == NULL) return mpl;
174 
175   //start time
176   ++iter;
177   double startTime = (*iter).get_r();
178 
179   //end time
180   ++iter;
181   double endTime = (*iter).get_r();
182 
183   //check time
184   if (endTime < startTime) {
185     endTime = startTime;
186   }
187 
188   //subband boundary
189   ++iter;
190   int I = (*iter).get_i();
191 
192   //getting window numero
193   ++iter;
194   int window = (*iter).get_i();
195 
196   //End getting and checking
197 
198 
199   //convert time into window number
200   long start = mf->time2window( (float)startTime);
201 
202   long end = mf->time2window( (float)endTime);
203 
204   // go to start window within soundfile
205   if (!mf->seek_window(start)) {
206     cerr << "MaaateM: Error when positioning" << endl;
207     cerr << "         startposition = 0.0" << endl;
208     mf->seek_window(0);
209     start = 0;
210   }
211 
212 
213   // go to the first window to analyse
214   if (!mf->next_window(LOW)) {
215     cerr << "MaaateM: Warning: could not analyse first window." << endl;
216     return mpl;
217   }
218 
219   //number of colunms
220   long columns = end - start;
221   columns = (columns > mf->file_window_number()) ? mf->file_window_number() : columns;
222 
223 
224   SegmentData *result = new SegmentData(startTime,
225 					endTime,
226 					columns,
227 					1);
228 
229   //set window function:
230   double (* h) (unsigned int, int) = 0;
231   switch (window) {
232   case 0: //Square
233     h = &square_window;
234     break;
235   case 1: //Hamming
236     h = &hamming_window;
237     break;
238   case 2: //Welch
239     h = &welch_window;
240     break;
241   case 3: //Bartlett
242     h = &bartlett_window;
243     break;
244   default:
245     h = &square_window;
246     break; //never used
247   }
248 
249   // value of the window at one given time
250   double hvalue;
251 
252 
253   //temporary value of the sum
254   double sumup = 0.0;
255   double sumdown = 0.0;
256   double temp;
257   int nb_SB, Mmax, sb;
258 
259   while (mf->at_window() <= end) {
260     // nb of samples in one window, it is also on how many samples
261     //the signal energy is calculated
262     Mmax = mf->timeticks(LOW);
263 
264     nb_SB = mf->nb_subbands(LOW);
265 
266     //sum in the time domain
267     for (int m = 0; m < Mmax; m++) {
268       //calculate the value of h(n-m) for this value of m, with n=Mmax-1
269       //hvalue = square_window ( Mmax-1, (Mmax-1)-m);
270       hvalue = (*h) (Mmax-1, (Mmax -1)-m);
271 
272       temp = 0.0;
273 
274       //sumup in the frequency domain
275       for (sb = 0; sb < I; sb++)
276 	  {
277 		  temp += pow(mf->freqvalue_st_mean(sb,m,LOW),2);
278       }
279       sumup += hvalue * temp;
280 
281       temp = 0.0;
282 
283       //sumdown in the frequency domain
284       for (sb = I; sb < nb_SB; sb++) {
285 	temp += pow(mf->freqvalue_st_mean(sb,m,LOW),2);
286       }
287       sumdown += hvalue * temp;
288     }
289 
290     //final result
291     if ( sumdown != 0.0 ) {
292       result->data[result->colFilled++][0] = sumup / sumdown;
293     } else {
294       result->data[result->colFilled++][0] = DBL_MAX;
295     }
296     //init sums
297     sumup=0.0;
298     sumdown=0.0;
299 
300 
301     // analyse next window
302     if (!mf->next_window(LOW)) {
303       break;
304     }
305 
306   }
307 
308 #ifdef DEBUG
309   cout << "Columns filled:" << result->colFilled << endl;
310   cout << "Sum:" << result->sum() << endl;
311   cout << "Average:" << result->avg() << endl;
312   cout << *result;
313 #endif
314 
315   mpl->push_back(ModuleParam(result));
316 
317   return mpl;
318 
319 };
320 
321 
322 Module
loadBandNrjRatioModule(void)323 loadBandNrjRatioModule (void)
324 {
325   return Module(init_bandnrjratio,
326 		NULL,
327 		suggest_bandnrjratio,
328 		apply_bandnrjratio ,
329 		NULL,
330 		NULL);
331 }
332