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