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