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 #define ROUND(number) floor((number)+0.5)
24 
25 // initialisation of the sum of scalefactor module
26 static void
init_sumscf(Module * m)27 init_sumscf(Module * m) {
28   // set up member values
29   m->set_name (string("sumscf"));
30   m->set_desc (string("sums the scalefactors over each subband to calculate"
31 		      "a loudness approximation"));
32   m->set_author (string("CSIRO-MIS DMIS"));
33   m->set_copyright (string("(c) 2002 CSIRO"));
34   m->set_url (string("http://www.cmis.csiro.au/Maaate/docs/modules.html"));
35 
36   // set up input parameter list
37   m->inputSpecs()->clear();
38 
39   // first parameter: sound file
40   m->inputSpecs()->push_back
41     (ModuleParamSpec(string("soundfile"),
42 		     string("the SOUND file for which the sum of "
43 			    "scalefactors gets calculated"),
44 		     MAAATE_TYPE_SOUNDFILE,
45 		     new ModuleParam((SOUNDfile*)NULL)) // default
46      );
47 
48   // second parameter: start time
49   MaaateConstraint * constraint = new MaaateConstraint();
50   constraint->addConstraintGreaterThan(0.0);
51   m->inputSpecs()->push_back
52     (ModuleParamSpec(string("starttime"),
53 		     string("time instant from which to start the "
54 			    "sum of scalefactor calculation"),
55 		     MAAATE_TYPE_REAL,
56 		     new ModuleParam((double)0.0), // default
57 		     constraint));
58 
59   // third parameter: end time
60   constraint = new MaaateConstraint();
61   constraint->clear();
62   constraint->addConstraintGreaterThan(0.0);
63   m->inputSpecs()->push_back
64     (ModuleParamSpec(string("endtime"),
65 		     string("time instant until which to calculate "
66 			    "the sum of scalefactors"),
67 		     MAAATE_TYPE_REAL,
68 		     new ModuleParam((double)DBL_MAX), // default
69 		     constraint));
70 
71   // fourth parameter: start subband
72   constraint = new MaaateConstraint();
73   constraint->clear();
74   constraint->addConstraintGreaterThan(0);
75   m->inputSpecs()->push_back
76     (ModuleParamSpec(string("start-subband"),
77 		     string("subband from which to start the sum "
78 			    "of scalefactor calculation"),
79 		     MAAATE_TYPE_INT,
80 		     new ModuleParam(0), // default
81 		     constraint));
82 
83   // fifth parameter: end subband
84   constraint = new MaaateConstraint();
85   constraint->clear();
86   constraint->addConstraintGreaterThan(0);
87   m->inputSpecs()->push_back
88     (ModuleParamSpec(string("end-subband"),
89 		     string("subband at which to end the sum of "
90 			    "scalefactor calculation"),
91 		     MAAATE_TYPE_INT,
92 		     new ModuleParam(0), // default
93 		     constraint));
94 
95   // set up output parameter list
96   m->outputSpecs()->clear();
97 
98   // first parameter: sum of scalefactor curve
99   m->outputSpecs()->push_back
100     (ModuleParamSpec(string("loudness-curve"),
101 		     string("a loudness approximation for the "
102 			    "requested time interval calculated "
103 			    "from the sum of scalefactors"),
104 		     MAAATE_TYPE_SEGMENTDATA,
105 		     new ModuleParam((SegmentData*)NULL)) // default
106      );
107 
108 };
109 
110 
111 // function to suggest parameter values given that some of the input
112 // parameters have already been set; also changes constraints accordingly
113 static void
suggest_sumscf(Module * m,list<ModuleParam> * paramsIn)114 suggest_sumscf (Module * m, list<ModuleParam> * paramsIn) {
115   list<ModuleParam>::iterator iter;
116 
117   // get module's input parameter specifications
118   list<ModuleParamSpec> * inSpecs = m->inputSpecs();
119   list<ModuleParamSpec>::iterator iterSpecs;
120 
121   iter = paramsIn->begin(); // sound file
122   iterSpecs = inSpecs->begin();
123   if (iter == paramsIn->end()) return;
124   SOUNDfile * sf = (*iter).get_sf();
125   if (sf == NULL) return;
126 
127   ++iter; // start time
128   ++iterSpecs;
129   (*iterSpecs).constraint()->clear();
130   (*iterSpecs).constraint()->addConstraintRange(0.0, sf->file_duration());
131   double startTime = (*iter).get_r();
132 
133   ++iter; // end time
134   ++iterSpecs;
135   (*iterSpecs).constraint()->clear();
136   (*iterSpecs).constraint()->addConstraintRange(0.0, sf->file_duration());
137   double endTime = (*iter).get_r();
138   if (endTime < startTime) {
139     endTime = startTime;
140     (*iter).set(startTime);
141   }
142 
143   ++iter; // start subband
144   ++iterSpecs;
145   (*iterSpecs).constraint()->clear();
146   (*iterSpecs).constraint()->addConstraintRange(0, sf->nb_subbands(HIGH)-1);
147 
148   int startSubband = (*iter).get_i();
149 
150   ++iter; // end subband
151   ++iterSpecs;
152   (*iterSpecs).constraint()->clear();
153   (*iterSpecs).constraint()->addConstraintRange(0, sf->nb_subbands(HIGH)-1);
154 
155   // check nr of subbands
156   int endSubband = (*iter).get_i();
157   if (endSubband < startSubband) {
158     endSubband = startSubband;
159     (*iter).set(startSubband);
160   }
161 
162 };
163 
164 // function to work on input parameters and return output parameters
165 static list<ModuleParam> *
apply_sumscf(Module * m,list<ModuleParam> * paramsIn)166 apply_sumscf (Module * m, list<ModuleParam> * paramsIn) {
167   // the output parameter list
168   list<ModuleParam> * mpl = new list<ModuleParam>();
169   list<ModuleParam>::iterator iter;
170 
171   iter = paramsIn->begin(); // sound file
172   if (iter == paramsIn->end()) return mpl;
173 
174   SOUNDfile * sf = (*iter).get_sf();
175   if (sf == NULL) return mpl;
176 
177   ++iter; // start time
178   double startTime = (*iter).get_r();
179 
180   ++iter; // end time
181   double endTime = (*iter).get_r();
182   if (endTime < startTime) {
183     endTime = startTime;
184   }
185 
186   ++iter; // start subband
187   int startSubband = (*iter).get_i();
188 
189   ++iter; // end subband
190   int endSubband = (*iter).get_i();
191   // check nr of subbands depending on layer
192   if (endSubband < startSubband) {
193     endSubband = startSubband;
194   }
195 
196   //convert time into window nb
197   long start = sf->time2window( (float)startTime);
198 
199   long end = sf->time2window( (float)endTime);
200 
201   // go to start window within soundfile
202   if (!sf->seek_window(start)) {
203     cerr << "MaaateM: Error when positioning" << endl;
204     cerr << "         startposition = 0.0" << endl;
205     sf->seek_window(0);
206     start = 0;
207   }
208 
209   // analyse first window
210   if (!sf->next_window(HIGH)) {
211     cerr << "MaaateM: Warning: could not analyse first window." << endl;
212     return mpl;
213   }
214 
215   long columns = end - start;
216   columns = (columns > sf->file_window_number()) ? sf->file_window_number() : columns;
217 
218   SegmentData *result = new SegmentData(startTime,
219 					endTime,
220 					columns,
221 					1);
222 
223   while (sf->at_window() <= end) {
224 
225     double sum=0.0;
226 
227     for (int sb = startSubband; sb <= endSubband; sb++) {
228       sum += sf->subband_scalefactor(sb,HIGH);
229     }
230 
231     // store the sum of subband mean
232     result->data[result->colFilled++][0] = sum;
233     sum=0.0;
234 
235     // analyse next window
236     if (!sf->next_window(HIGH)) {
237       break;
238     }
239 
240   }
241 
242 #ifdef DEBUG
243   cout << "Min sscf: " << result->min() << endl;
244   cout << "Max sscf: " << result->max() << endl;
245   cout << "Sum sscf: " << result->sum() << endl;
246   cout << "Avg sscf: " << result->avg() << endl;
247   cout << "Columns filled:" << result->colFilled << endl;
248   cout << *result;
249 #endif
250 
251   mpl->push_back(ModuleParam(result));
252 
253   return mpl;
254 
255 };
256 
257 
258 Module
loadSumscfModule(void)259 loadSumscfModule (void)
260 {
261   // init_sumscf gets executed during construction of module
262   return Module(init_sumscf,
263 		NULL,
264 		suggest_sumscf,
265 		apply_sumscf,
266 		NULL,
267 		NULL);
268 }
269