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 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #include <float.h>
26 #include "SOUNDfile.H"
27 
28 /*---- put here each library implementing a file format for AllFormat ----*/
29 // this one includes the main header file of libMaaateMPEG
30 #include "MPEGfile.H"
31 
32 
33 /*------------- constructor and destructor ---------------------------*/
34 
35 // this constructor finds the type of the file,
36 // opens it and creates an instance of AllFormat of the right
37 // inherited class
38 CSAPI_TIER1
SOUNDfile(string filestr)39 SOUNDfile::SOUNDfile(string filestr) {
40   which_max    = -1;
41   maxim        = 0.0;
42   format       = 0;
43   filetype     = NOFILE;
44 
45   //try for an MPEG file
46   format = new MPEGfile(filestr);
47   if (format != NULL && format->file_ok()) {
48     // it`s an  MPEGfile!
49     filetype = MPEG;
50     return;
51     //else it`s not!
52   } else if (format != 0 && format != NULL) {
53     delete (MPEGfile *) format;
54   }
55 
56 
57 /*-----  do the same for others file types... ----*/
58 
59   format = 0;
60   //this kind of file cannot be analysed by maaate
61   cerr << "MaaateP: Sorry don't recognise the file format" << endl;
62 
63 return;
64 }
65 
66 
67 // destructor
68 CSAPI_TIER1
~SOUNDfile()69 SOUNDfile::~SOUNDfile() {
70 
71   //if necessary, destroy format
72   if (format) {
73     switch (filetype) {
74     case MPEG:
75       delete (MPEGfile *) format;
76       break;
77 
78 /*---- add here a case for each other file type supported ----*/
79 
80     default: break;
81     }
82   }
83   format=0;
84   return;
85 }
86 
87 /*-------------- About the file -------------------*/
88 // returns the file's name
89 CSAPI_TIER1 string
file()90 SOUNDfile::file() {
91   return format->get_filename();
92 }
93 
94 // returns true if file was opened ok, false otherwise
95 CSAPI_TIER1 bool
file_ok()96 SOUNDfile::file_ok() {
97   return format->file_ok();
98 }
99 
100 // returns the file's tye
101 CSAPI_TIER1 Format
file_type()102 SOUNDfile::file_type() {
103   return filetype;
104 }
105 
106 //is it a stereo file?
107 CSAPI_TIER1 bool
is_stereo()108 SOUNDfile::is_stereo() {
109   return format->is_stereo();
110 }
111 
112 //number of channel
113 CSAPI_TIER1 int
channels()114 SOUNDfile::channels() {
115   return format->channel();
116 }
117 
118 //pcm sampling rate in KHz
119 CSAPI_TIER1 double
sampling_rate()120 SOUNDfile::sampling_rate() {
121   return format->sampling_rate();
122 }
123 
124 
125 
126 /*--------------- time functions --------------------------*/
127 // give the actual time position in sec
128 CSAPI_TIER1 float
at_time()129 SOUNDfile::at_time() {
130   return format->get_windowNo() * format->get_windowDuration();
131 }
132 
133 //give the file duration in sec
134 CSAPI_TIER1 float
file_duration()135 SOUNDfile::file_duration() {
136   return format->get_fileDuration() * format->get_windowDuration();
137 }
138 
139 //give the duration of one subband sample in sec
140 CSAPI_TIER1 float
sample_duration(Resolution res)141 SOUNDfile::sample_duration( Resolution res ) {
142   return format->sample_duration( res );
143 }
144 
145 //go to position corresponding to this time
146 CSAPI_TIER1 bool
seek_time(float t)147 SOUNDfile::seek_time( float t ) {
148   return seek_window( time2window( t ) );
149 }
150 
151 //give the duration of a window in sec
152 CSAPI_TIER1 float
window_duration()153 SOUNDfile::window_duration() {
154   return  format->get_windowDuration();
155 }
156 
157 
158 /*--------------- window functions ----------------------*/
159 //give the position in number of window
160 CSAPI_TIER1 long
at_window()161 SOUNDfile::at_window() {
162   return format->get_windowNo();
163 }
164 
165 //give the number of window in this file
166 CSAPI_TIER1 long
file_window_number()167 SOUNDfile::file_window_number() {
168   return format->get_fileDuration();
169 }
170 
171 //give the nuber of subband samples in one window
172 CSAPI_TIER1 unsigned int
timeticks(Resolution res)173 SOUNDfile::timeticks( Resolution res ) {
174   return format->timeticks( res );
175 }
176 
177 //go to position corresponding to window number w_nb
178 CSAPI_TIER1 bool
seek_window(long w_nb)179 SOUNDfile::seek_window( long w_nb ) {
180   //set which_max as maxim do not contain a meaningful value
181   which_max = -1;
182   return format->seek_window( w_nb );
183 }
184 
185 
186 /*----------- matching functions --------------*/
187 //convert second into window number
188 CSAPI_TIER1 long
time2window(float t)189 SOUNDfile::time2window( float t ) {
190   return (long) ( t / format->get_windowDuration() );
191 }
192 
193 //convert window number into second
194 CSAPI_TIER1 float
window2time(long w_nb)195 SOUNDfile::window2time( long w_nb ) {
196   return format->get_windowDuration() * (float) w_nb;
197 }
198 
199 
200 /*-------------- extract and skip --------------*/
201 //go to next window and analyse it with res
202 CSAPI_TIER1 bool
next_window(Resolution res)203 SOUNDfile::next_window( Resolution res) {
204   //set which_max as maxim do not contain a meaningful value
205   which_max = -1;
206   return format->next_window( res );
207 }
208 
209 //go to next window whitout analysing it
210 CSAPI_TIER1 bool
skip_window()211 SOUNDfile::skip_window() {
212   //set which_max as maxim do not contain a meaningful value
213   which_max = -1;
214   return format->skip_window();
215 }
216 
217 
218 // check if there is any more data available for analysis
219 CSAPI_TIER1 bool
data_available()220 SOUNDfile::data_available() {
221   return format->data_available();
222 }
223 
224 /*--------------- access function ---------------*/
225 //give the value of the subband samples of the current window
226 CSAPI_TIER1 double
freq_value(unsigned int ch,unsigned int sb,unsigned int nb,Resolution res)227 SOUNDfile::freq_value( unsigned int ch, unsigned int sb, unsigned int nb, Resolution res) {
228   return format->freq_value(ch,sb,nb,res);
229 }
230 
231 //give the number of subband at that resolution
232 CSAPI_TIER1 unsigned int
nb_subbands(Resolution res)233 SOUNDfile::nb_subbands( Resolution res ) {
234   return format->nb_subbands( res );
235 }
236 
237 // return the pcm value number no of a channel ch
238 CSAPI_TIER1 short
pcm(unsigned int ch,unsigned int no)239 SOUNDfile::pcm (unsigned int ch, unsigned int no) {
240   return format->pcm(ch, no);
241 }
242 
243 
244 
245 /*------------- Analyse functions ----------------------*/
246 //give the mean of samples nb in subband sb on both channels if available
247 CSAPI_TIER1 double
freqvalue_st_mean(unsigned int sb,unsigned int nb,Resolution res)248 SOUNDfile::freqvalue_st_mean( unsigned int sb, unsigned int nb , Resolution res )
249 {
250 
251   if ( format->is_stereo() ) { // in case of a stereo file it is possible to compute the mean
252     return (fabs(format->freq_value(0,sb,nb,res)) + fabs(format->freq_value(1,sb,nb,res)))/2.0;
253   } else { //just return the value of channel 0
254     return fabs(format->freq_value(0,sb,nb,res));
255   }
256 }
257 
258 //give the rms of samples nb in subband sb on both channels if available
259 CSAPI_TIER1 double
freqvalue_st_rms(unsigned int sb,unsigned int nb,Resolution res)260 SOUNDfile::freqvalue_st_rms( unsigned int sb, unsigned int nb , Resolution res )
261 {
262 
263   if ( format->is_stereo() ) {  // in case of a stereo file it is possible to compute the rms
264     return sqrt(( pow(format->freq_value(0,sb,nb,res), 2) + pow(format->freq_value(1,sb,nb,res), 2) ) / 2.0 );
265   } else { //just return the vakue of channel 0
266     return fabs(format->freq_value(0,sb,nb,res));
267   }
268 }
269 
270 //give the normalised subband energy samples
271 CSAPI_TIER1 double
normalised_sb_nrj(unsigned int sb,unsigned int nb,Resolution res)272 SOUNDfile::normalised_sb_nrj( unsigned int sb, unsigned int nb , Resolution res )
273 {
274   double resu;
275 
276   //find max value over all subbands for that sample number if necessary
277   if (which_max != (int) nb) {
278     int nb_SB = format->nb_subbands(res);
279     maxim = 0.0;
280 
281     //go from one subband to another
282     for (int i = 0; i < nb_SB; i++) {
283       resu = freqvalue_st_mean (i,nb,res);
284       //find max
285       if ( resu > maxim) {
286 	maxim = resu;
287       }
288     }
289 
290     maxim = maxim * maxim;
291 
292     //set which_max as maxim is calculated
293     which_max = nb;
294   }
295 
296   //return the result
297   if (maxim != 0.0) { //division possible
298     resu = freqvalue_st_mean (sb,nb,res);
299     resu = resu * resu;
300     if ( resu == 0.0 ) { // unuseful to calculate anything, just set result as -infinity
301       return - DBL_MAX;
302     } else if ( resu >= maxim ) { //avoid problem of this calculation
303       return 0.0;
304     } else { // resu != 0.0 and resu != maxim
305       return 10.0 * log10 ( resu / maxim); //calculation of subband energies
306     }
307 
308   } else { // division impossible just set result as - infinity
309     return - DBL_MAX;
310   }
311 }
312 
313 
314 //give a coarse and quick idea of the value in that subband
315 CSAPI_TIER1 double
subband_scalefactor(unsigned int sb,Resolution res)316 SOUNDfile::subband_scalefactor ( unsigned int sb, Resolution res )
317 {
318   switch (filetype) {
319   case MPEG:
320     if (((MPEGfile *) format)->layer() != III) {
321       return ((MPEGfile *) format)->scalefactor(0,sb);
322       break;
323     }// else go to default case!
324   default: //find the max of freq_sample over the window in this subband
325     double max = 0;
326     double temp;
327     int ch_max = is_stereo() ? channels() : 1;
328     for (int ch = 0; ch < ch_max; ch++) {
329       for (unsigned int nb = 0; nb < (format->timeticks(res)); nb++) {
330 	temp = fabs(format->freq_value(ch,sb,nb,res));
331 	if ( temp > max ) max = temp;
332       }
333     }
334     return max;
335   }
336 
337 }
338 
339 
340 //give the mean of samples over the current window
341 CSAPI_TIER1 double
subband_mean(unsigned int sb,Resolution res)342 SOUNDfile::subband_mean( unsigned int sb, Resolution res )
343 {
344 
345   int num = format->timeticks(res);
346   double sum = 0.0;
347 
348   //calculate the sum over the window
349   for (int i=0;i<num;i++) {
350     sum += freqvalue_st_mean (sb,i,res);
351   }
352 
353   return (sum/((double) num));
354 }
355 
356 //give the rms of samples over the current window
357 CSAPI_TIER1 double
subband_rms(unsigned int sb,Resolution res)358 SOUNDfile::subband_rms( unsigned int sb, Resolution res )
359 {
360 
361   int num = format->timeticks(res);
362   double sum = 0.0;
363 
364   //calculate the sum of square values over the current window
365   for (int i=0;i<num;i++) {
366     sum += pow( freqvalue_st_mean (sb,i,res) , 2);
367   }
368 
369   return sqrt(sum/((double) num));
370 }
371 
372 //give the normalised subband energy over the current window
373 CSAPI_TIER1 double
subband_nrj(unsigned int sb,Resolution res)374 SOUNDfile::subband_nrj( unsigned int sb, Resolution res )
375 {
376   double resu;
377 
378   //find max value over all subbands for the current window if necessary
379   if (which_max != -2) {
380     int nb_SB = format->nb_subbands(res);
381     maxim = 0.0;
382 
383     //go from one subband to another
384     for (int i = 0; i < nb_SB; i++) {
385       resu = subband_mean (i,res);
386       //find max
387       if ( resu > maxim) {
388 	maxim = resu;
389       }
390     }
391     maxim = maxim * maxim;
392     //set which_max as maxim is calculated for that window
393     which_max = -2;
394   }
395 
396 
397   if (maxim != 0.0) { //division possible
398     resu = subband_mean (sb,res);
399     resu = resu * resu;
400     if ( resu == 0.0) { //unuseful to calculate anything, just set result as -infinity
401       return - DBL_MAX;
402     } else if ( resu >= maxim ) { //due to a problem avoid this calculation
403       return 0.0;
404     } else { //resu != 0 and resu != maxim
405       return 10.0 * log10 ( resu / maxim ); //calculation of subband energies
406     }
407 
408   } else { // division impossible just set result as - infinity
409     return - DBL_MAX;
410   }
411 }
412 
413 
414 /*-------------- pcm decoder -------------------*/
415 //fill buffer with pcm samples corresponding to the "windows"
416 //windows following the current window.
417 //This moves the current position pointer while decoding
418 //and return the number of samples in buffer.
419 
420 CSAPI_TIER1 long
decode(short * buffer,long windows,Channels ch)421 SOUNDfile::decode (short * buffer, long windows, Channels ch) {
422   return format->decode(buffer,windows,ch);
423 }
424