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 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include "module.H"
27 
28 // copy constructor (XXX is it necessary anyway?)
29 CSAPI_TIER2
ModuleParam(const ModuleParam & mp)30 ModuleParam::ModuleParam (const ModuleParam& mp) {
31   type = mp.getType();
32   switch(type) {
33   case MAAATE_TYPE_SOUNDFILE:
34     sf = mp.get_sf(); break;
35   case MAAATE_TYPE_SEGMENTTABLE:
36     st = mp.get_st(); break;
37   case MAAATE_TYPE_SEGMENTDATA:
38     sd = mp.sd; break;
39   case MAAATE_TYPE_BOOL:
40     b = mp.get_b(); break;
41   case MAAATE_TYPE_INT:
42     i = mp.get_i(); break;
43   case MAAATE_TYPE_REAL:
44     r = mp.get_r(); break;
45   case MAAATE_TYPE_STRING:
46     s = strdup(mp.get_s()); break;
47   }
48 }
49 
50 // overload friend operator <<
51 // main usage: debugging
52 CSAPI_TIER2 ostream&
operator <<(ostream & os,ModuleParam const & mp)53 operator<<(ostream& os, ModuleParam const & mp) {
54   switch (mp.getType()) {
55   case MAAATE_TYPE_SOUNDFILE:
56     if (mp.get_sf() != NULL) {
57       os << mp.get_sf()->file();
58     }
59     break;
60   case MAAATE_TYPE_SEGMENTTABLE:
61     if (mp.get_st() != NULL) {
62       os << mp.get_st();
63     }
64     break;
65   case MAAATE_TYPE_SEGMENTDATA:
66     if (mp.get_sd() != NULL) {
67       os << mp.get_sd();
68     }
69     break;
70   case MAAATE_TYPE_BOOL:
71     os << mp.get_b();
72     break;
73   case MAAATE_TYPE_INT:
74     os << mp.get_i();
75     break;
76   case MAAATE_TYPE_REAL:
77     os << mp.get_r();
78     break;
79   case MAAATE_TYPE_STRING:
80     if (mp.get_s() != NULL) {
81       os << mp.get_s();
82     }
83     break;
84   }
85   return os;
86 }
87 
88 CSAPI_TIER2 bool
operator ==(ModuleParam const & mp1,ModuleParam const & mp2)89 operator== (ModuleParam const & mp1, ModuleParam const & mp2) {
90   if (mp1.getType() != mp2.getType()) return (false);
91 
92   switch(mp1.getType()) {
93   case MAAATE_TYPE_SOUNDFILE:
94     return (mp1.get_sf() == mp2.get_sf());
95   case MAAATE_TYPE_SEGMENTTABLE:
96     return (mp1.get_st() == mp2.get_st());
97   case MAAATE_TYPE_SEGMENTDATA:
98     return (mp1.get_sd() == mp2.get_sd());
99   case MAAATE_TYPE_BOOL:
100     return (mp1.get_b() == mp2.get_b());
101   case MAAATE_TYPE_INT:
102     return (mp1.get_i() == mp2.get_i());
103   case MAAATE_TYPE_REAL:
104     return (mp1.get_r() == mp2.get_r());
105   case MAAATE_TYPE_STRING:
106     return (!strcmp (mp1.get_s(), mp2.get_s()));
107   default:
108     return false;
109   }
110 
111   return false;
112 }
113 
114 CSAPI_TIER2 ModuleParam&
operator =(const ModuleParam & mp)115 ModuleParam::operator= (const ModuleParam & mp) {
116   if (this == &mp)
117     return *this;
118   type = mp.getType();
119   switch(type) {
120   case MAAATE_TYPE_SOUNDFILE:
121     sf = mp.get_sf();
122     break;
123   case MAAATE_TYPE_SEGMENTTABLE:
124     st = mp.get_st();
125     break;
126   case MAAATE_TYPE_SEGMENTDATA:
127     sd = mp.sd;
128     break;
129   case MAAATE_TYPE_BOOL:
130     b = mp.get_b();
131     break;
132   case MAAATE_TYPE_INT:
133     i = mp.get_i();
134     break;
135   case MAAATE_TYPE_REAL:
136     r = mp.get_r();
137     break;
138   case MAAATE_TYPE_STRING:
139     strcpy (s, mp.get_s());
140     break;
141   }
142   return *this;
143 }
144 
145 CSAPI_TIER2 double
operator -(ModuleParam const & mp1,ModuleParam const & mp2)146 operator- (ModuleParam const & mp1, ModuleParam const & mp2) {
147   if (mp1.getType() != mp2.getType()) return (false);
148 
149   switch(mp1.getType()) {
150   case MAAATE_TYPE_SOUNDFILE:
151     return (DBL_MAX);
152   case MAAATE_TYPE_SEGMENTTABLE:
153     return (DBL_MAX);
154   case MAAATE_TYPE_SEGMENTDATA:
155     return (DBL_MAX);
156   case MAAATE_TYPE_BOOL:
157     return (mp1.get_b() == mp2.get_b() ? 0.0 : DBL_MAX);
158   case MAAATE_TYPE_INT:
159     return ((double)(mp1.get_i() - mp2.get_i()));
160   case MAAATE_TYPE_REAL:
161     return (mp1.get_r() - mp2.get_r());
162   case MAAATE_TYPE_STRING:
163     return ((double)strcmp (mp1.get_s(), mp2.get_s()));
164   default:
165     return false;
166   }
167   return false;
168 }
169 
170 CSAPI_TIER2 bool
operator <(ModuleParam const & mp1,ModuleParam const & mp2)171 operator< (ModuleParam const & mp1, ModuleParam const & mp2) {
172   if (mp1.getType() != mp2.getType()) return (false);
173 
174   switch(mp1.getType()) {
175   case MAAATE_TYPE_SOUNDFILE:
176     return (false);
177   case MAAATE_TYPE_SEGMENTTABLE:
178     return (false);
179   case MAAATE_TYPE_SEGMENTDATA:
180     return (false);
181   case MAAATE_TYPE_BOOL:
182     return (mp1.get_b() != mp2.get_b());
183   case MAAATE_TYPE_INT:
184     return (mp1.get_i() < mp2.get_i());
185   case MAAATE_TYPE_REAL:
186     return (mp1.get_r() < mp2.get_r());
187   case MAAATE_TYPE_STRING:
188     return (strcmp (mp1.get_s(), mp2.get_s()) < 0);
189   default:
190     return (false);
191   }
192   return false;
193 }
194 
195 CSAPI_TIER2 bool
operator >(ModuleParam const & mp1,ModuleParam const & mp2)196 operator> (ModuleParam const & mp1, ModuleParam const & mp2) {
197   if (mp1.getType() != mp2.getType()) return (false);
198 
199   switch(mp1.getType()) {
200   case MAAATE_TYPE_SOUNDFILE:
201     return (false);
202   case MAAATE_TYPE_SEGMENTTABLE:
203     return (false);
204   case MAAATE_TYPE_SEGMENTDATA:
205     return (false);
206   case MAAATE_TYPE_BOOL:
207     return (mp1.get_b() != mp2.get_b());
208   case MAAATE_TYPE_INT:
209     return (mp1.get_i() > mp2.get_i());
210   case MAAATE_TYPE_REAL:
211     return (mp1.get_r() > mp2.get_r());
212   case MAAATE_TYPE_STRING:
213     return (strcmp (mp1.get_s(), mp2.get_s()) > 0);
214   default:
215     return false;
216   }
217   return false;
218 }
219 
220 CSAPI_TIER2 bool
operator <=(ModuleParam const & mp1,ModuleParam const & mp2)221 operator<= ( ModuleParam const & mp1, ModuleParam const & mp2) {
222   return ((operator<((const ModuleParam&) mp1,mp2)) || (mp1 == mp2));
223 }
224 
225 CSAPI_TIER2 bool
operator >=(ModuleParam const & mp1,ModuleParam const & mp2)226 operator>= (ModuleParam const & mp1, ModuleParam const & mp2) {
227   return ((mp1 > mp2) || (mp1 == mp2));
228 }
229 
230 CSAPI_TIER2 bool
isZero()231 ModuleParam::isZero () {
232   switch(type) {
233   case MAAATE_TYPE_SOUNDFILE:
234     return (sf == NULL);
235   case MAAATE_TYPE_SEGMENTTABLE:
236     return (st == NULL);
237   case MAAATE_TYPE_SEGMENTDATA:
238     return (sd == NULL);
239   case MAAATE_TYPE_BOOL:
240     return (!b);
241   case MAAATE_TYPE_INT:
242     return (i == 0);
243   case MAAATE_TYPE_REAL:
244     return (r == 0.0);
245   case MAAATE_TYPE_STRING:
246     return (!strcmp (s, ""));
247   default:
248     return (false);
249   }
250   return false;
251 }
252 
253 CSAPI_TIER2 bool
set(SOUNDfile * spf)254 ModuleParam::set (SOUNDfile * spf) {
255   if (type == MAAATE_TYPE_SOUNDFILE) {
256     sf = spf;
257     return true;
258   } else {
259     return false;
260   }
261 }
262 
263 CSAPI_TIER2 bool
set(SegmentTable * sgt)264 ModuleParam::set (SegmentTable * sgt) {
265   if (type == MAAATE_TYPE_SEGMENTTABLE) {
266     st = sgt;
267     return true;
268   } else {
269     return false;
270   }
271 }
272 
273 CSAPI_TIER2 bool
set(SegmentData * sgd)274 ModuleParam::set (SegmentData * sgd) {
275   if (type == MAAATE_TYPE_SEGMENTDATA) {
276     sd = sgd;
277     return true;
278   } else {
279     return false;
280   }
281 }
282 
283 CSAPI_TIER2 bool
set(bool bl)284 ModuleParam::set (bool bl) {
285   if (type == MAAATE_TYPE_BOOL) {
286     b = bl;
287     return true;
288   } else {
289     return false;
290   }
291 }
292 
293 CSAPI_TIER2 bool
set(int it)294 ModuleParam::set (int it) {
295   if (type == MAAATE_TYPE_INT) {
296     i = it;
297     return true;
298   } else {
299     return false;
300   }
301 }
302 
303 CSAPI_TIER2 bool
set(double rl)304 ModuleParam::set (double rl) {
305   if (type == MAAATE_TYPE_REAL) {
306     r = rl;
307     return true;
308   } else {
309     return false;
310   }
311 }
312 
313 CSAPI_TIER2 bool
set(char * sg)314 ModuleParam::set (char * sg) {
315   if (type == MAAATE_TYPE_STRING) {
316     s = strdup(sg);
317     return true;
318   } else {
319     return false;
320   }
321 }
322 
323 // overload friend operator <<
324 // main usage: debugging
325 CSAPI_TIER2 ostream&
operator <<(ostream & os,ModuleParamRange const & mpr)326 operator<<(ostream& os, ModuleParamRange const & mpr) {
327   if (mpr.lowerBound() && mpr.upperBound() && mpr.step()) {
328     os << "[" << mpr.lowerBound() << ";" << mpr.upperBound() << "] step " << mpr.step();
329   } else if (mpr.lowerBound() && mpr.upperBound()) {
330     os << "[" << mpr.lowerBound() << ";" << mpr.upperBound() << "]";
331   } else if (mpr.lowerBound()) {
332     os << "[" << mpr.lowerBound() << ";infinity]";
333   } else if (mpr.upperBound()) {
334     os << "[-infinity;" << mpr.lowerBound() << "]";
335   }
336   return os;
337 }
338 
339 // overload friend operator <<
340 // main usage: debugging
341 CSAPI_TIER2 ostream&
operator <<(ostream & os,ModuleParamConstraint & mpc)342 operator<<(ostream& os, ModuleParamConstraint & mpc) {
343   switch (mpc.Type()) {
344   case MAAATE_CONSTRAINT_NONE:
345     os << "No constraint" << endl;
346     break;
347   case MAAATE_CONSTRAINT_VALUE:
348     os << mpc.Value() << endl;
349     break;
350   case MAAATE_CONSTRAINT_RANGE:
351     os << mpc.Value()->constraintRange() << endl;
352     break;
353   default:
354     break;
355   }
356   return os;
357 }
358 
359 CSAPI_TIER2 bool
within(ModuleParam param)360 ModuleParamConstraint::within (ModuleParam param) {
361   switch (type) {
362   case MAAATE_CONSTRAINT_NONE:
363     return true;
364   case MAAATE_CONSTRAINT_VALUE:
365     if (*(constraint->constraintValue()) == (param)) {
366       return true;
367     }
368     break;
369   case MAAATE_CONSTRAINT_RANGE:
370     if (*(constraint->constraintRange()->lowerBound()) <= (param) &&
371 	*(constraint->constraintRange()->upperBound()) >= (param)) {
372       return true;
373     }
374     break;
375   default:
376     break;
377   }
378   return false;
379 
380 }
381 
382 CSAPI_TIER2 ModuleParam *
closest(ModuleParam param)383 ModuleParamConstraint::closest (ModuleParam param) {
384   if (within(param)) return &param;
385 
386   switch (type) {
387   case MAAATE_CONSTRAINT_VALUE:
388     return constraint->constraintValue();
389   case MAAATE_CONSTRAINT_RANGE:
390     if (param > * (constraint->constraintRange()->upperBound())) {
391       return constraint->constraintRange()->upperBound();
392     } else {
393       return constraint->constraintRange()->lowerBound();
394     }
395     break;
396   default:
397     return NULL;
398   }
399 }
400 
401 CSAPI_TIER2 double
distance(ModuleParam param)402 ModuleParamConstraint::distance (ModuleParam param) {
403   if (within(param)) return 0.0;
404 
405   switch (type) {
406   case MAAATE_CONSTRAINT_VALUE:
407     return abs(param - constraint->constraintValue());
408   case MAAATE_CONSTRAINT_RANGE:
409     if (param > *(constraint->constraintRange()->upperBound())) {
410       return (param - constraint->constraintRange()->upperBound());
411     } else {
412       return (constraint->constraintRange()->lowerBound() - param);
413     }
414     break;
415   default:
416     return DBL_MAX;
417   }
418 }
419 
420 // overload friend operator <<
421 // main usage: debugging
422 CSAPI_TIER2 ostream&
operator <<(ostream & os,MaaateConstraint & mc)423 operator<<(ostream& os, MaaateConstraint & mc) {
424   list<ModuleParamConstraint>::iterator constraintIter;
425 
426   if (mc.getConstraints()->empty()) {
427     return os;
428   }
429 
430   for (constraintIter = mc.getConstraints()->begin();
431        constraintIter != mc.getConstraints()->end();
432        ++constraintIter) {
433     os << *constraintIter;
434   }
435 
436   return os;
437 }
438 
439 CSAPI_TIER2 void
addConstraint(ModuleParam * value)440 MaaateConstraint::addConstraint (ModuleParam * value) {
441   constraints.push_back
442     (ModuleParamConstraint(MAAATE_CONSTRAINT_VALUE,
443 			   new ModuleParamConstraintValue(value)));
444 }
445 
446 CSAPI_TIER2 void
addConstraintRange(ModuleParam * lowerBound,ModuleParam * upperBound,ModuleParam * step)447 MaaateConstraint::addConstraintRange (ModuleParam * lowerBound,
448 				      ModuleParam * upperBound,
449 				      ModuleParam * step)
450 {
451   constraints.push_back
452     (ModuleParamConstraint(MAAATE_CONSTRAINT_RANGE,
453 			   new ModuleParamConstraintValue
454 			   (new ModuleParamRange
455 			    (lowerBound, upperBound,
456 			     ((step == NULL || step->isZero()) ?
457 			      (ModuleParam *)NULL : step)))));
458 }
459 
460 CSAPI_TIER2 void
addConstraintRange(int lowerBound,int upperBound,int step)461 MaaateConstraint::addConstraintRange (int lowerBound,
462 				      int upperBound,
463 				      int step) {
464   addConstraintRange(new ModuleParam(lowerBound),
465 		     new ModuleParam(upperBound),
466 		     (step == 0 ? (ModuleParam *)NULL :
467 		      new ModuleParam(step)));
468 }
469 
470 CSAPI_TIER2 void
addConstraintRange(double lowerBound,double upperBound,double step)471 MaaateConstraint::addConstraintRange (double lowerBound,
472 				      double upperBound,
473 				      double step) {
474   addConstraintRange(new ModuleParam(lowerBound),
475 		     new ModuleParam(upperBound),
476 		     (step == 0.0 ? (ModuleParam *)NULL :
477 		      new ModuleParam(step)));
478 }
479 
480 CSAPI_TIER2 void
addConstraintGreaterThan(int i)481 MaaateConstraint::addConstraintGreaterThan(int i) {
482   addConstraintRange(new ModuleParam(i));
483 }
484 
485 CSAPI_TIER2 void
addConstraintGreaterThan(double d)486 MaaateConstraint::addConstraintGreaterThan(double d) {
487   addConstraintRange(new ModuleParam(d));
488 }
489 
490 CSAPI_TIER2 void
addConstraintLessThan(int i)491 MaaateConstraint::addConstraintLessThan(int i) {
492   addConstraintRange((ModuleParam *)NULL, new ModuleParam(i));
493 }
494 
495 CSAPI_TIER2 void
addConstraintLessThan(double d)496 MaaateConstraint::addConstraintLessThan(double d) {
497   addConstraintRange((ModuleParam *)NULL, new ModuleParam(d));
498 }
499 
500 CSAPI_TIER2 bool
withinConstraints(ModuleParam param)501 MaaateConstraint::withinConstraints (ModuleParam param) {
502   list<ModuleParamConstraint>::iterator constraintIter;
503 
504   if (constraints.empty()) {
505     return true;
506   }
507 
508   for (constraintIter = constraints.begin();
509        constraintIter != constraints.end();
510        ++constraintIter) {
511     if ((*constraintIter).within(param)) {
512       return true;
513     }
514   }
515 
516   return false;
517 }
518 
519 // return NULL if there is no closer value; eg. if value is already
520 // the closest, or if there is no distance function
521 CSAPI_TIER2 ModuleParam *
closestConstraintValue(ModuleParam param)522 MaaateConstraint::closestConstraintValue (ModuleParam param) {
523   MaaateType type;
524   ModuleParam * closest;
525   list<ModuleParamConstraint>::iterator constraintIter;
526   double thisDistance = 0, minDistance = DBL_MAX;
527 
528   // XXX: assume the MaaateType of value is the same as that of the
529   // constraint; constraints.getType() would be better
530   type = param.getType();
531   if (type == MAAATE_TYPE_SOUNDFILE || type == MAAATE_TYPE_SEGMENTTABLE ||
532       type == MAAATE_TYPE_SEGMENTDATA) {
533     return NULL;
534   }
535 
536   if (constraints.size() == 0) {
537     return NULL;
538   }
539 
540   closest = new ModuleParam (param);
541   for (constraintIter = constraints.begin();
542        constraintIter != constraints.end();
543        ++constraintIter) {
544 
545     if ((*constraintIter).within(param)) {
546       return NULL;
547     }
548 
549     thisDistance = (*constraintIter).distance(param);
550     if (thisDistance < minDistance) {
551       closest = (*constraintIter).closest(param);
552       minDistance = thisDistance;
553     }
554   }
555   return closest;
556 
557 }
558 
559 // functions that do nothing for the insane case
560 CSAPI_TIER2
defaultNoop(Module * m)561 list<ModuleParam> * defaultNoop (Module * m) {
562   list<ModuleParam> * result = new list<ModuleParam>();
563   return result;
564 };
565 
566 CSAPI_TIER2
suggestNoop(Module * m,list<ModuleParam> * paramsIn)567 void suggestNoop (Module * m, list<ModuleParam> * paramsIn) {};
applyNoop(Module * m,list<ModuleParam> * params_in)568 list<ModuleParam> * applyNoop (Module * m, list<ModuleParam> * params_in) {
569   list<ModuleParam> * result = new list<ModuleParam>();
570   return result;
571 };
572 
573 CSAPI_TIER2
resetNoop(Module * m)574 void resetNoop (Module * m) {};
575 
576 CSAPI_TIER2
destroyD(Module * m)577 void destroyD (Module * m) {
578   m->inputSpecs()->clear();
579   m->outputSpecs()->clear();
580   //    modParamInSpecs.~list<ModuleParamSpec>();
581   //    modParamOutSpecs.~list<ModuleParamSpec>();
582 };
583 
584 CSAPI_TIER2
585 list<ModuleParam> *
defaultD(Module * m)586 defaultD (Module * m) {
587   list<ModuleParamSpec>::iterator iter;
588   list<ModuleParam> * plist = new list<ModuleParam>();
589   ModuleParam * mp;
590 
591   for (iter = m->inputSpecs()->begin();
592        iter != m->inputSpecs()->end();
593        ++iter) {
594     mp = (*iter).defaultValue();
595     plist->push_back(*mp);
596   }
597 
598   return plist;
599 }
600 
601 CSAPI_TIER2
Module(ModuleInitFunc initF,ModuleDefaultFunc defaultF,ModuleSuggestValues suggestF,ModuleApplyFunc applyF,ModuleResetFunc resetF,ModuleDestroyFunc destroyF)602 Module::Module(ModuleInitFunc      initF,
603 	       ModuleDefaultFunc   defaultF,
604 	       ModuleSuggestValues suggestF,
605 	       ModuleApplyFunc     applyF,
606 	       ModuleResetFunc     resetF,
607 	       ModuleDestroyFunc   destroyF) {
608   // execute init function if supplied
609   if (initF != NULL) {
610     initF(this);
611     // XXX: delete whitespace from modName !!!
612 
613     // set function pointers to other functions
614     defaultM = (defaultF==NULL ? defaultD    : defaultF);
615     suggestM = (suggestF==NULL ? suggestNoop : suggestF);
616     applyM   = (applyF==NULL   ? applyNoop   : applyF);
617     destroyM = (destroyF==NULL ? destroyD    : destroyF);
618 
619     saneM = true;
620   } else {
621     modName = string("Insane_Module");
622     modDesc = string("This module has not been properly initialised.");
623     modAuthor = string("");
624     modCopyright = string("");
625     modUrl = string("");
626     modParamInSpecs.clear();
627     modParamOutSpecs.clear();
628 
629     defaultM = defaultNoop;
630     suggestM = suggestNoop;
631     applyM   = applyNoop;
632     destroyM = NULL;
633 
634     saneM = false;
635   }
636 }
637 
638 // returns true if params got changed; false otherwise
639 CSAPI_TIER2 bool
checkConstraints(list<ModuleParam> * paramsIn)640 Module::checkConstraints (list<ModuleParam> * paramsIn) {
641   list<ModuleParamSpec>::iterator specIter;
642   list<ModuleParam>::iterator paramIter;
643   MaaateConstraint * constraint;
644   ModuleParam * suggest;
645   bool change = false;
646 
647   for (specIter = modParamInSpecs.begin(), paramIter = paramsIn->begin();
648        specIter != modParamInSpecs.end() && paramIter != paramsIn->end();
649        ++specIter, ++paramIter) {
650     constraint = (*specIter).constraint();
651 
652     if (!constraint || constraint->withinConstraints (*paramIter)) {
653       continue;
654     }
655 
656     suggest = constraint->closestConstraintValue (*paramIter);
657     if (suggest != NULL) {
658       *paramIter = *suggest;
659       change = true;
660     }
661   }
662   return change;
663 }
664