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 "MPEGfile.H"
22 #include "SOUNDfile.H"
23
24 #include <float.h>
25
26 using namespace std;
27
28 ///// TODOs: /////
29 // - output time step/resolution for each extracted parameter
30 // - output in xwaves format
31
32
33 // parameters to control what is to be extracted
34 static float from = 0.0; // start at second 0.0
35 static float to = FLT_MAX; // end at end of file
36 static bool verbose = false;
37 static short printHeader = -1; // -1=no 0=first 1=all
38 static short printSideinfo = -1; // -1=no 0=first 1=all
39 static bool printDur = false; // total file duration
40 static short fromSb = 0; // first subband to be extracted
41 static short toSb = 576; // last subband to be extracted
42 static short channels = 1; // mono/stereo processing?
43 static bool wantBitalloc = false; // want bitallocation?
44 static bool wantScf = false; // want scalefactors?
45 static bool wantScfsi = false; // want scalefactor select info?
46 static bool wantValues = false; // want frequency values?
47 static bool wantPcm = false; // want pcm values?
48 static bool wantPcmFile = false; // want pcm output file?
49 static string outfile = string("out.raw"); // name of pcm output file
50 static char *filename = NULL; // mpeg-audio-file
51
52 static FILE *outpcm = NULL;
53 static SOUNDfile *sfile = NULL;
54 static MPEGfile *infile = NULL;
55
56 // prints help information about parameter usage
57 void
PrintUsage(char * prog)58 PrintUsage(char *prog) {
59 cerr << "\nUsage:" << endl;
60 cerr << prog << " [Options] <mpeg-audio-file>" << endl;
61 cerr << "Default Options: -S 0.0 -E eof" << endl;
62 cerr << " (i.e. analyse whole file)" << endl;
63 cerr << endl;
64 cerr << "Possible Options:" << endl;
65 cerr << "-h help=prints this information" << endl;
66 cerr << "-S <from> the second (float) to start analysing from" <<endl;
67 cerr << " Default: 0.0" << endl;
68 cerr << "-E <to> the second (float) to stop analysing at" << endl;
69 cerr << " Default: end of file" << endl;
70 cerr << "-V verbose" << endl;
71 cerr << "-H <0/1> 0=gives header info on first audio frame" << endl;
72 cerr << " 1=gives header info on all audio frames" << endl;
73 cerr << " Default: 0" << endl;
74 cerr << "-I <0/1> 0=gives Layer III side info on first frame" <<endl;
75 cerr << " 1=gives Layer III side info on all frames" << endl;
76 cerr << " Default: 0" << endl;
77 cerr << "-D calculates total duration of audio file" << endl;
78 cerr << "-B <int> <int> subband range that gets extracted" << endl;
79 cerr << " (only required with -X" << endl;
80 cerr << " Default: 0 31 (Layers I, II)" << endl;
81 cerr << " 0 575 (Layer III)" << endl;
82 cerr << "-C <1/2> 1=extract only first channel" << endl;
83 cerr << " 2=extract both channels (if existant)" << endl;
84 cerr << " Default: 1" << endl;
85 cerr << "-X [field] extracts info from fields from audio file" << endl;
86 cerr << " Possible field types depend on the Layer" << endl;
87 cerr << " at which the audio file is encoded:" << endl;
88 cerr << " bitalloc (Layers I, II) -B fromsb tosb -C 1/2" << endl;
89 cerr << " scalefac (Layers I, II, III) -B fromsb tosb -C 1/2" <<endl;
90 cerr << " scfsi (Layers II, III) -B fromsb tosb -C 1/2" << endl;
91 cerr << " freqval (Layers I, II, III) -B fromsb tosb -C 1/2" <<endl;
92 cerr << " pcmval (Layers I, II, III) -C 1/2" << endl;
93 cerr << "-O <file> output pcm samples to file" << endl;
94 cerr << " Default: file=out.raw" << endl;
95 exit (1);
96 }
97
98
99 void
ParseArguments(int argc,char ** argv)100 ParseArguments (int argc, char **argv) {
101 // go through parameters and check values
102 for (int i=1; i<argc; i++) {
103 if (argv[i][0] == '-' && argv[i][1]) {
104 switch (argv[i][1]) {
105 case 'h': // help
106 PrintUsage(argv[0]);
107 break;
108 case 'S': case 's':// second to start from
109 if ((i+1<argc) && !isalpha(argv[i+1][0])) {
110 from = atof(argv[++i]);
111 }
112 break;
113 case 'E': case 'e':// second to end at
114 if ((i+1<argc) && !isalpha(argv[i+1][0])) {
115 to = atof(argv[++i]);
116 }
117 break;
118 case 'V': case 'v':// verbose
119 verbose = true;
120 break;
121 case 'H': // header
122 printHeader = 0;
123 if ((i+1<argc) && !isalpha(argv[i+1][0])) {
124 printHeader = atoi(argv[++i]);
125 }
126 break;
127 case 'I': case 'i':// side information
128 printSideinfo = 0;
129 if ((i+1<argc) && !isalpha(argv[i+1][0])) {
130 printSideinfo = atoi(argv[++i]);
131 }
132 break;
133 case 'D': case 'd':// total duration
134 printDur = true;
135 break;
136 case 'B': case 'b':// subband range
137 if ((i+2<argc) && !isalpha(argv[i+1][0])
138 && !isalpha(argv[i+2][0])) {
139 fromSb = atoi(argv[++i]);
140 toSb = atoi(argv[++i]);
141 } else {
142 cerr << "inspectMPaudio: -B option needs two integers to follow"
143 << endl;
144 exit(1);
145 }
146 break;
147 case 'C': case 'c':// channels
148 if ((i+1<argc) && !isalpha(argv[i+1][0])) {
149 channels = atoi(argv[++i]);
150 }
151 break;
152 case 'X': case 'x':// fields
153 if ((i+1 == argc) || !isalpha(argv[i+1][0])) {
154 cerr << "inspectMPaudio: -X option needs string-argument"
155 << endl;
156 exit(1);
157 } else {
158 if (!strncmp(argv[i+1],"bitalloc",3)) {
159 wantBitalloc = true; i++;
160 } else if (!strncmp(argv[i+1],"scalefac",3)) {
161 wantScf = true; i++;
162 } else if (!strncmp(argv[i+1],"scfsi",3)) {
163 wantScfsi = true; i++;
164 } else if (!strncmp(argv[i+1],"freqval",3)) {
165 wantValues = true; i++;
166 } else if (!strncmp(argv[i+1],"pcmval",3)) {
167 wantPcm = true; i++;
168 } else if (argv[i+1][0] != '-') {
169 cerr << "inspectMPaudio: -X unknown string-argument "
170 << argv[i+1] << endl;
171 exit(1);
172 }
173 }
174 break;
175 case 'O': case 'o': case '0': // output pcm samples to file
176 wantPcmFile = true;
177 if ((i+1<argc) && isalpha(argv[i+1][0])
178 && (argv[i+1][0] != '-')) {
179 outfile = string(argv[++i]);
180 }
181 break;
182 } // switch
183 } else {
184 filename = argv[i];
185 }
186 }
187 }
188
189
190 void
CheckArguments()191 CheckArguments( ) {
192 #ifdef DEBUG
193 cout << "Parameter Settings:" << endl;
194 cout << "From=" << from << endl;
195 cout << "To=" << to << endl;
196 cout << "Verbose=" << verbose << endl;
197 cout << "printHeader=" << printHeader << endl;
198 cout << "printSideinfo=" << printSideinfo << endl;
199 cout << "printDur=" << printDur << endl;
200 cout << "fromSb=" << fromSb << endl;
201 cout << "toSb=" << toSb << endl;
202 cout << "channels=" << channels << endl;
203 cout << "wantBitalloc=" << wantBitalloc << endl;
204 cout << "wantScf=" << wantScf << endl;
205 cout << "wantScfsi=" << wantScfsi << endl;
206 cout << "wantValues=" << wantValues << endl;
207 cout << "wantPcm=" << wantPcm << endl;
208 cout << "wantPcmFile=" << wantPcmFile << endl;
209 cout << "outfile=" << outfile << endl;
210 cout << "filename=" << filename << endl;
211 #endif
212 if (filename == NULL) {
213 cerr << "inspectMPaudio: Mpeg audio filename missing" << endl;
214 exit(1);
215 }
216 if (channels < 1) channels = 1;
217 if (channels > 2) channels = 2;
218 if (fromSb < 0) fromSb = 0;
219 if (toSb < fromSb) toSb = fromSb;
220 if (printSideinfo > 1) printSideinfo = 1;
221 if (printHeader > 1) printHeader = 1;
222 if (from < 0.0) from = 0.0;
223 if (to < from) to = from;
224 }
225
226
227 int
main(int argc,char ** argv)228 main(int argc, char **argv) {
229
230 // check no. of args
231 if (argc < 2) {
232 PrintUsage(argv[0]);
233 }
234
235 // parse arguments
236 ParseArguments (argc, argv);
237
238 // check arguments and correct if appropriate
239 CheckArguments ();
240
241 // open file
242 sfile = new SOUNDfile(filename);
243
244 if (sfile->file_type() == MPEG) {
245 infile = (MPEGfile *) sfile->format;
246 } else {
247 infile = NULL;
248 }
249 if (verbose) {
250 cout << "Audio file opened: " << sfile->file() << endl;
251 }
252
253 // open pcm output file
254 if (wantPcmFile) {
255 outpcm=fopen(outfile.c_str(),"wb");
256 }
257
258 // position at start second
259 if (!sfile->seek_time(from)) {
260 cerr << "inspectMPaudio: error positioning at starting sec ("
261 << from << ") failed." << endl;
262 exit(1);
263 }
264 if (verbose) cout << "starting at " << sfile->at_time() << " s" << endl;
265
266
267 // go through file parsing and displaying
268 int ch = 0;
269
270 while(sfile->data_available() && (sfile->at_time() <= to)) {
271 // parse next frame
272 if ( wantPcm||wantPcmFile) {
273 infile->goTo_nextFrame(PCM);
274 } else {
275 sfile->next_window(PCM);
276 }
277 // print header if requested
278 if (printHeader >= 0 && sfile->file_type() == MPEG) {
279 infile->printheader();
280 if (printHeader == 0) printHeader = -1;
281 }
282
283 // print side info if requested
284 if (printSideinfo >= 0 && sfile->file_type() == MPEG) {
285 infile->printSideinfo();
286 if (printSideinfo == 0) printSideinfo = -1;
287 }
288
289 // check requested subbands for this frame
290 int fromSub = fromSb;
291 int toSub = toSb;
292 if (sfile->file_type() == MPEG) {
293 if (infile->layer() == III) {
294 if (fromSub > 576) fromSub = 576;
295 if (toSub > 576) toSub = 576;
296 } else {
297 if (fromSub > SBLIMIT) fromSub = SBLIMIT;
298 if (toSub > SBLIMIT) toSub = SBLIMIT;
299 }
300 }
301
302 // check channels
303 ch = min ((int) channels, sfile->channels());
304
305 // print requested information:
306
307 // Bitallocation information
308 if (wantBitalloc) {
309 if (sfile->file_type() == MPEG) {
310 if (infile->layer() == III) {
311 cerr << "inspectMPaudio: Layer III has no bitallocation information"
312 << endl;
313 } else {
314 for (int i=fromSub; i<toSub; i++) { // subbands
315 for (int j=0; j<ch; j++) { // channels
316 cout << "Allocation["<<j<<","<<i<<"]="
317 <<infile->bitallocation(j,i)<<endl;
318 }
319 }
320 }
321 } else {
322 cout << "Not an MPEG file: no bitallocation available."<<endl;
323 }
324 }
325
326 // Scalefactors
327 if (wantScf) {
328 if (sfile->file_type() == MPEG) {
329 // print scalefactors
330 for (int i=fromSub; i<toSub; i++) { // subbands
331 for (int j=0; j<ch; j++) { // channels
332 cout << "Scalefactor["<<j<<","<<i<<"]="
333 <<infile->scalefactor(j,i)<<endl;
334 }
335 }
336 } else {
337 cout << "Not an MPEG file: no scakefactors available."<<endl;
338 }
339 }
340
341 // Scalefactor selection information
342 if (wantScfsi) {
343 if (sfile->file_type() == MPEG) {
344 if (infile->layer() == I) {
345 cerr << "inspectMPaudio: Layer I has no scalefactor selection information"
346 << endl;
347 } else {
348 if (infile->layer() != III) {
349 for (int i=fromSub; i<toSub; i++) { // subbands
350 for (int j=0; j<ch; j++) { // channels
351 cout << "Scfsi["<<j<<","<<i<<"]="
352 <<infile->scfsi(j,i)<<endl;
353 }
354 }
355 } else { // layer III
356 for (int i=0; i<4; i++) {
357 for (int j=0; j<ch; j++) { // channels
358 cout << "Scfsi["<<j<<","<<i<<"]="
359 << infile->scfsi(j,i) <<endl;
360 }
361 }
362 }
363 }
364 } else {
365 cout << "Not an MPEG file: no scfis available."<<endl;
366 }
367
368 }
369
370 // Frequency values (spectral values)
371 if (wantValues) {
372 //no. samples
373 for (unsigned int i=0; i<sfile->timeticks(HIGH); i++) {
374 for (int sb=fromSub; sb<toSub; sb++) { //subbands
375 for (int j=0; j<ch; j++) { //channels
376 cout << "FreqVal[ch="<<j<<",sb="<<sb<<",timeticks="
377 <<i<<"]="
378 <<sfile->freq_value(j,sb,i,HIGH)<<endl;
379 }
380 }
381 }
382 /*
383 if (infile->layer() != III) {
384 for (int s=0; s<12; s++) { // no. samples
385 for (int i=fromSub; i<toSub; i++) { // subbands
386 for (int j=0; j<ch; j++) { // channels
387 // cout << "Sample["<<j<<","<<i<<","
388 // <<s<<","<<k<<"]="
389 // <<infile->sample(j,i,s,k)<<endl;
390 cout << "FreqVal["<<j<<","<<i<<","
391 <<s<<"]="
392 <<infile->restored_sample(j,i,s)<<endl;
393 }
394 }
395 }
396 } else { // Layer III (can it be integrated with others?)
397 for (int j=0; j<ch; j++) { // channels
398 for (int sb=fromSub; sb<toSub; sb++) {
399 int subb = sb/SSLIMIT;
400 int ss = sb%SSLIMIT;
401 // cout << "Sample["<<j<<","<<gr<<","
402 // << sb<<"]="
403 // << infile->sample(j,gr,subb,ss)
404 // << endl;
405 cout << "Restored_Sample["<<j<<","
406 << subb<<","<<ss<<"]="
407 << infile->restored_sample(j,subb,ss)
408 << endl;
409 }
410 }
411 }
412 */
413 }
414
415
416
417 // PCM samples
418 if (wantPcm||wantPcmFile) {
419
420 for (unsigned int i=0;
421 i<(sfile->timeticks(HIGH)*sfile->nb_subbands(HIGH));
422 i++) {
423 for (int j=0; j<ch; j++) { //channels
424 cout << "pcm[ch="<<j<<",i="<<i<<"]="
425 <<sfile->pcm(j,i)<<endl;
426 }
427 }
428 }
429
430 /*
431 if (infile->layer() != III) {
432 int kmax=1; // Layer I
433 short sample;
434 if (infile->layer() == II) kmax=3; // Layer II
435 for (int s=0; s<12; s++) { // no. samples
436 for (int k=0; k<kmax; k++) {
437 for (int i=fromSub; i<toSub; i++) { // subbands
438 for (int j=0; j<ch; j++) {
439 if (wantPcm) {
440 cout << "PCM["<<j<<","<<i<<","
441 <<s<<","<<k<<"]="
442 <<infile->pcm_sample(j,i,s,k)<<endl;
443 } else { // wantPcmFile
444 sample = infile->pcm_sample(j,i,s,k);
445 fwrite(&sample, 1, 2, outpcm);
446 }
447 }
448 }
449 }
450 }
451 } else { // Layer III (can it be integrated with others?)
452 short sample;
453 for (int gr=0; gr<(2-infile->version()); gr++) {
454 for (int sb=fromSub; sb<toSub; sb++) {
455 int subb = sb%SBLIMIT;
456 int ss = sb/SBLIMIT;
457 for (int j=0; j<ch; j++) { // channels
458 if (wantPcm) {
459 cout << "PCM_Sample["<<j<<","<<gr<<","
460 <<ss <<","<< subb<<"]="
461 <<infile->pcm_sample(j,gr,subb,ss)<<endl;
462 } else { // wantPcmFile
463 sample = infile->pcm_sample(j,gr,subb,ss);
464 fwrite(&sample, 1, 2, outpcm);
465 }
466 }
467 }
468 }
469 }
470 }
471
472
473 // Layer 3
474 // side information
475 /*
476 for (int ch=0; ch<infile->channels(); ch++) {
477 for (int i=0; i<4; i++) {
478 cout << "Scfsi["<<ch<<","<<i<<"]="
479 << infile->scfsi(ch,i) <<endl;
480 }
481 for (int gr=0; gr<(2-infile->version()); gr++) {
482 cout << "Part2_3_Length["<<ch<<","<<gr<<"]="
483 << infile->part2_3_length(ch,gr) << endl;
484 cout << "Big_Values["<<ch<<","<<gr<<"]="
485 << infile->big_values(ch,gr) << endl;
486 cout << "Global_Gain["<<ch<<","<<gr<<"]="
487 << infile->global_gain(ch,gr) << endl;
488 cout << "Scalefac_Compress["<<ch<<","<<gr<<"]="
489 << infile->scalefac_compress(ch,gr) << endl;
490 cout << "Window_Switching["<<ch<<","<<gr<<"]="
491 << infile->window_switching(ch,gr) << endl;
492 cout << "Block_Type["<<ch<<","<<gr<<"]="
493 << infile->blocktype(ch,gr) << endl;
494 cout << "Mixedblock["<<ch<<","<<gr<<"]="
495 << infile->mixedblock(ch,gr) << endl;
496 for (int j=0; j<3; j++) {
497 cout << "table_select["<<ch<<","<<gr<<","<<j<<"]="
498 << infile->table_select(ch,gr,j) << endl;
499 cout << "subblock_gain["<<ch<<","<<gr<<","<<j<<"]="
500 << infile->subblock_gain(ch,gr,j) << endl;
501 }
502 cout << "preflag["<<ch<<","<<gr<<"]="
503 << infile->preflag(ch,gr) << endl;
504 cout << "Scalefac_Scale["<<ch<<","<<gr<<"]="
505 << infile->scalefac_scale(ch,gr) << endl;
506 cout << "Count1Table_select["<<ch<<","<<gr<<"]="
507 << infile->count1table_select(ch,gr) << endl;
508 cout << "region0_samps["<<ch<<","<<gr<<"]="
509 << infile->region0_samps(ch,gr) << endl;
510 cout << "region1_samps["<<ch<<","<<gr<<"]="
511 << infile->region1_samps(ch,gr) << endl;
512 cout << "region2_samps["<<ch<<","<<gr<<"]="
513 << infile->region2_samps(ch,gr) << endl;
514 }
515 }
516 */
517
518 }
519
520 if (printDur) {
521 cout << "No. of Frames analyzed: " << sfile->at_window() << endl;
522 cout << "stopped at " << sfile->at_time() << " s" << endl;
523 }
524
525
526 // close output sound file
527 if (wantPcmFile) {
528 fclose (outpcm);
529 cout << "PCM file written (16 bit linear, "
530 << sfile->sampling_rate() << " kHz samplingrate, "
531 << ch << " channels): "
532 << outfile.c_str() << endl;
533 }
534
535 exit (0);
536 }
537