/* mp3guessenc version 0.2 by Naoki Shibata */ /* This program is still under development. */ #include #include #include #include "VbrTag.h" #define MPG_MD_STEREO 0 #define MPG_MD_JOINT_STEREO 1 #define MPG_MD_DUAL_CHANNEL 2 #define MPG_MD_MONO 3 static long freqs[9] = { 44100, 48000, 32000, 22050, 24000, 16000 , 11025 , 12000 , 8000 }; static int tabsel_123[2][3][16] = { { {128,32,64,96,128,160,192,224,256,288,320,352,384,416,448,}, {128,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,}, {128,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} }, { {128,32,48,56,64,80,96,112,128,144,160,176,192,224,256,}, {128,8,16,24,32,40,48,56,64,80,96,112,128,144,160,}, {128,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} } }; /////////////////////////////////////////////////////// // VBR TAG related routines #define VBRHEADERSIZE (NUMTOCENTRIES+4+4+4+4+4+20) static const char VBRTag[]={"Xing"}; static int ExtractI4(unsigned char *buf) { int x; x = buf[0]; x <<= 8; x |= buf[1]; x <<= 8; x |= buf[2]; x <<= 8; x |= buf[3]; return x; } int GetVbrTag(VBRTAGDATA *pTagData, unsigned char *buf) { int i, head_flags; int h_id, h_mode, h_sr_index; static int sr_table[4] = { 44100, 48000, 32000, 99999 }; pTagData->flags = 0; h_id = (buf[1] >> 3) & 1; h_sr_index = (buf[2] >> 2) & 3; h_mode = (buf[3] >> 6) & 3; if( h_id ) { if( h_mode != 3 ) buf+=(32+4); else buf+=(17+4); } else { if( h_mode != 3 ) buf+=(17+4); else buf+=(9+4); } if( buf[0] != VBRTag[0] ) return 0; if( buf[1] != VBRTag[1] ) return 0; if( buf[2] != VBRTag[2] ) return 0; if( buf[3] != VBRTag[3] ) return 0; buf+=4; pTagData->h_id = h_id; pTagData->samprate = sr_table[h_sr_index]; if( h_id == 0 ) pTagData->samprate >>= 1; head_flags = pTagData->flags = ExtractI4(buf); buf+=4; if( head_flags & FRAMES_FLAG ) { pTagData->frames = ExtractI4(buf); buf+=4; } if( head_flags & BYTES_FLAG ) { pTagData->bytes = ExtractI4(buf); buf+=4; } if( head_flags & TOC_FLAG ) { if( pTagData->toc != NULL ) { for(i=0;itoc[i] = buf[i]; } buf+=NUMTOCENTRIES; } pTagData->vbr_scale = -1; if( head_flags & VBR_SCALE_FLAG ) { pTagData->vbr_scale = ExtractI4(buf); buf+=4; } if (buf[0] == 'L' && buf[1] == 'A' && buf[2] == 'M' && buf[3] == 'E') { for(i=0;i<20;i++) pTagData->lametag[i] = buf[i]; } else { pTagData->lametag[0] = '\0'; } return 1; } int SeekPoint(unsigned char TOC[NUMTOCENTRIES], int file_bytes, float percent) { /* interpolate in TOC to get file seek point in bytes */ int a, seekpoint; float fa, fb, fx; if( percent < (float)0.0 ) percent = (float)0.0; if( percent > (float)100.0 ) percent = (float)100.0; a = (int)percent; if( a > 99 ) a = 99; fa = TOC[a]; if( a < 99 ) { fb = TOC[a+1]; } else { fb = (float)256.0; } fx = fa + (fb-fa)*(percent-a); seekpoint = (int)(((float)(1.0/256.0))*fx*file_bytes); return seekpoint; } /////////////////////////////////////////////////////// int genre_last=147; char *genre_list[]={ "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror", "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop", }; typedef struct id3tag { char tag[3]; char title[30]; char artist[30]; char album[30]; char year[4]; char comment[30]; unsigned char genre; } id3tag; /////////////////////////////////////////////////////// int head_check2(unsigned long head) { int lsf,srate,nch,lay,mpeg25,freq,mode; int padding,bitrate_index,framesize; if ((head & 0xffe00000) != 0xffe00000) return 0; if (!((head>>17)&3)) return 0; if (((head>>12)&0xf) == 0xf) return 0; if (((head>>10)&0x3) == 0x3 ) return 0; //if ((head & 0xffff0000) == 0xfffe0000) return 0; if( head & (1<<20) ) { lsf = (head & (1<<19)) ? 0x0 : 0x1; mpeg25 = 0; } else { lsf = 1; mpeg25 = 1; } if(mpeg25) srate = 6 + ((head>>10)&0x3); else srate = ((head>>10)&0x3) + (lsf*3); bitrate_index = ((head>>12)&0xf); padding = ((head>>9)&0x1); mode = ((head>>6)&0x3); freq = freqs[srate]; nch = (mode == MPG_MD_MONO) ? 1 : 2; lay = 4-((head>>17)&3); if (lay != 3) return 0; if (bitrate_index == 0) return -1; // free format bitstream framesize = tabsel_123[lsf][lay-1][bitrate_index]*144000/(freqs[srate]<fp = fp; fb->nLastBits = 0; fb->location = 8*ftell(fp); } int ftellBits(FILEBITS *fb) { return fb->location; } void fseekBits(FILEBITS *fb,int offset,int whence) { switch(whence) { case SEEK_SET: fb->location = offset; break; case SEEK_CUR: fb->location += offset; break; case SEEK_END: fseek(fb->fp,0,SEEK_END); fb->location = 8*ftell(fb->fp)+offset; break; } fseek(fb->fp,fb->location/8,SEEK_SET); fb->lastBits = getc(fb->fp); fb->nLastBits = 8 - fb->location % 8; } unsigned long int readBits(FILEBITS *fb,int n) { unsigned long int ret = 0; int k; unsigned char c; fb->location += n; while(fb->nLastBits <= 24) { int tmp; tmp = getc(fb->fp); c = tmp; fb->lastBits = fb->lastBits << 8; if (tmp != EOF) fb->lastBits = fb->lastBits | c; fb->nLastBits += 8; } if (n <= fb->nLastBits) k = n; else k = fb->nLastBits; ret = (fb->lastBits >> (fb->nLastBits - k)) & ((1 << k)-1); fb->nLastBits -= k; n -= k; while(fb->nLastBits <= 24) { int tmp; tmp = getc(fb->fp); c = tmp; fb->lastBits = fb->lastBits << 8; if (tmp != EOF) fb->lastBits = fb->lastBits | c; fb->nLastBits += 8; } ret = ret << n; ret = ret | ((fb->lastBits >> (fb->nLastBits - n)) & ((1 << n)-1)); fb->nLastBits -= n; return ret; } /////////////////////////////////////////////////////// /* * you can take 8*511 bit * from the bit reservoir and at most 8*1440 bit from the current * frame (320 kbps, 32 kHz), so 8*1951 bit is the largest possible * value for MPEG1 and 2) */ typedef struct PART23BUF { unsigned char buf[2000]; // 2000 > 1951 int pos,len; } PART23BUF; // In the worst case, 9 bitstream frames have to be received before decoding can start. #define NP23B (9+3) PART23BUF p23b[NP23B]; int p23b_in=0,p23b_out=0,p23b_pos=0; int seek_p23b(int pos) { int i; for(i=0;ifp,fb->location/8,SEEK_SET); fread(p23b[p23b_in].buf,1,len/8+1,fb->fp); fseekBits(fb,p23b[p23b_in].pos-(p23b[p23b_in].pos&7)+p23b[p23b_in].len,SEEK_SET); if (p23b_in == p23b_out) p23b_pos = p23b[p23b_out].pos & 7; p23b_in++; if (p23b_in == NP23B) p23b_in = 0; } unsigned long int readBits_p23b(int n) { unsigned long int ret = 0; if (p23b_in == p23b_out) return 0; while(n) { if (n >= 8 && p23b[p23b_out].len-p23b_pos > 8) { ret = (ret << 8) | (((p23b[p23b_out].buf[p23b_pos>>3] << (p23b_pos & 7)) | (p23b[p23b_out].buf[p23b_pos>>3+1] >> (8-(p23b_pos & 7)))) & 0xff); p23b_pos += 8; n -= 8; } else { int k = p23b[p23b_out].len-p23b_pos; if (n < k) k = n; ret = (ret << k) | (((p23b[p23b_out].buf[p23b_pos>>3] << (p23b_pos & 7)) | (p23b[p23b_out].buf[p23b_pos>>3+1] >> (8-(p23b_pos & 7)))) & (((1 << k)-1) << (7-k))); p23b_pos += k; n -= k; if (p23b_pos == p23b[p23b_out].len) { p23b_out++; if (p23b_out == NP23B) p23b_out = 0; p23b_pos = p23b[p23b_out].pos & 7; if (p23b_in == p23b_out) return ret << n; } } } return ret; } // read byte-aligned 8 bits unsigned char readOneByte_p23b(void) { unsigned char ret = 0; if (p23b_in == p23b_out) return 0; for(;;) { p23b_pos = (p23b_pos+7) & ~7; if (p23b[p23b_out].len-p23b_pos >= 8) { ret = p23b[p23b_out].buf[p23b_pos>>3]; p23b_pos += 8; return ret; } else { p23b_out++; if (p23b_out == NP23B) p23b_out = 0; p23b_pos = p23b[p23b_out].pos & 7; if (p23b_in == p23b_out) return 0; } } return 0; } /////////////////////////////////////////////////////// static unsigned char lame_string[256] = {'\0'}; int extract_lame_string(unsigned char *p,int len) { int i; unsigned char *q,buf[256]; // LAME[0-9]\.[0-9][0-9] \([^()]+\).* strncpy(buf,p,255); buf[255] = '\0'; if (len > 255) len = 255; q = strstr(buf,"LAME"); if (q == NULL) return 0; len -= (q-p); if (lame_string[0] == '\0') strcpy(lame_string,"LAME"); for(i=0;i= lame_string && *q == 'U';q--) *q = '\0'; LSEX_END: {} } /////////////////////////////////////////////////////// int main(int argc,char **argv) { int pos,i; unsigned long len,head; int filesize; int hasID3v2 = 0; int base_freq,base_nch,base_lsf; int id3pos = 0; int bitrateCount[16],modeCount[4]; int totFrameLen=0,totFrameNum=0,nSyncError=0; int copyright,original,emphasis,crc; int usesScfsi=0,usesScalefacScale=0,reservoirMax=0,usesPadding=0; int blockCount[3]; int resync,framenum; char *guess = NULL; FILE *input_file; FILEBITS fb; int startOfFrame,framesize,endOfLastPart3=-1; for(i=0;i<256;i++) lame_string[i] = '\0'; input_file = fopen(argv[1],"rb"); if (input_file == NULL) { printf("Usage: mp3guessenc mp3file\n"); exit(0); } fseek(input_file,0,SEEK_END); filesize = ftell(input_file); fseek(input_file,0,SEEK_SET); pos = 0; // check if this file has ID3 tag. { id3tag id3; unsigned char c1,c2,c3; fseek(input_file,-128,SEEK_END); c1 = getc(input_file); c2 = getc(input_file); c3 = getc(input_file); if (c1 == 'T' && c2 == 'A' && c3 == 'G') { printf("ID3tag found.\n"); id3pos = filesize-128; fseek(input_file,-128,SEEK_END); fread(&id3,sizeof(id3tag),1,input_file); printf(" Title : "); for(i=0;i<30;i++) { if (isprint(id3.title[i])) putchar(id3.title[i]); else putchar('.'); } printf("\n"); printf(" Artist : "); for(i=0;i<30;i++) { if (isprint(id3.artist[i])) putchar(id3.artist[i]); else putchar('.'); } printf("\n"); printf(" Album : "); for(i=0;i<30;i++) { if (isprint(id3.album[i])) putchar(id3.album[i]); else putchar('.'); } printf("\n"); printf(" Year : "); for(i=0;i<4;i++) { if (isprint(id3.year[i])) putchar(id3.year[i]); else putchar('.'); } printf("\n"); printf(" Comment : "); for(i=0;i<30;i++) { if (isprint(id3.comment[i])) putchar(id3.comment[i]); else putchar('.'); } printf("\n"); printf(" Genre : "); if (id3.genre > genre_last) { printf("unknown"); } else { printf("%s",genre_list[id3.genre]); } printf("\n\n"); } } fseek(input_file,0,SEEK_SET); // skip ID3v2 tag { unsigned char c1,c2,c3,c4; c1 = getc(input_file); c2 = getc(input_file); c3 = getc(input_file); c4 = getc(input_file); if (c1 == 'I' && c2 == 'D' && c3 == '3' && c4 == 2) { fseek(input_file,6,SEEK_SET); c1 = getc(input_file); c2 = getc(input_file); c3 = getc(input_file); c4 = getc(input_file); pos = c1*2097152+c2*16384+c3*128+c4; hasID3v2 = 1; printf("ID3tagV2 found. length = %d\n",pos); } } // find first frame pos = resync_mp3(input_file,pos); if (pos == -1) { printf("Cannot find valid mp3 header, scanning failed\n"); fclose(input_file); return; } // read VBR tag { unsigned char buf[VBRHEADERSIZE+36]; VBRTAGDATA TagData; fseek(input_file,pos,SEEK_SET); fread(&buf,1,VBRHEADERSIZE+36,input_file); if (GetVbrTag(&TagData,buf)) { printf("Xing VBR tag found.\n"); if (TagData.flags & BYTES_FLAG ) printf(" File length : %d\n",TagData.bytes); if (TagData.flags & FRAMES_FLAG ) printf(" Number of frames : %d\n",TagData.frames); if (TagData.flags & VBR_SCALE_FLAG) printf(" Vbr quality : %d\n",TagData.vbr_scale); if (TagData.lametag[0] != '\0') { printf(" Lame tag : "); for(i=0;i<20;i++) { if (isprint(TagData.lametag[i])) putchar(TagData.lametag[i]); else putchar('.'); } printf("\n"); extract_lame_string(TagData.lametag,20); } if (TagData.flags & TOC_FLAG ) printf(" Contains TOC\n"); printf("\n"); pos = resync_mp3(input_file,pos+1); if (pos == -1) { printf("Cannot find valid mp3 header, scanning failed\n"); fclose(input_file); return; } } } printf("First frame found at %d\n",pos); { int lsf,srate; fseek(input_file,pos,SEEK_SET); head = 0; head |= getc(input_file); head = head << 8; head |= getc(input_file); head = head << 8; head |= getc(input_file); head = head << 8; head |= getc(input_file); base_nch = ((head>>6)&0x3) == MPG_MD_MONO ? 1 : 2; if( head & (1<<20) ) { lsf = (head & (1<<19)) ? 0x0 : 0x1; srate = ((head>>10)&0x3) + (lsf*3); } else { lsf = 1; srate = 6 + ((head>>10)&0x3); } base_lsf = lsf; base_freq = freqs[srate]; } if (((head>>12)&0xf) == 0) { printf("This file seems to be free format bitstream.\n" "Free format bitstream is not supported.\n" "Sorry.\n"); fclose(input_file); return; } crc = (head >> 16) & 1; copyright = (head >> 3) & 1; original = (head >> 2) & 1; emphasis = head & 3; for(i=0;i<16;i++) bitrateCount[i] = 0; for(i=0;i<4;i++) modeCount[i] = 0; for(i=0;i<3;i++) blockCount[i] = 0; resync = 0; framenum = 0; fseek(input_file,pos,SEEK_SET); initBits(&fb,input_file); for(;;) { int id,idex,protection,bitrate_index,srate,lsf,nch,lay,mpeg25,freq,mode,modeex; int padding; int main_data_begin,pos_main_data_begin; int gr; int part1_length,part2_3_length; if (resync) { nSyncError++; for(i=0;i<65536;i++) { fseekBits(&fb,8*(pos+i),SEEK_SET); ((unsigned char *)&head)[3] = readBits(&fb,8); ((unsigned char *)&head)[2] = readBits(&fb,8); ((unsigned char *)&head)[1] = readBits(&fb,8); ((unsigned char *)&head)[0] = readBits(&fb,8); if (feof(input_file) || head_check2(head)) break; } if (i == 65536 || len == 0) { printf("Failed to resync.\n",i); break; } else { char mes[100]; printf("Resync : skipped %d bytes.\n",i); pos += i; } resync = 0; } startOfFrame = pos*8; fseekBits(&fb,pos*8,SEEK_SET); ((unsigned char *)&head)[3] = readBits(&fb,8); if (feof(input_file)) break; ((unsigned char *)&head)[2] = readBits(&fb,8); ((unsigned char *)&head)[1] = readBits(&fb,8); ((unsigned char *)&head)[0] = readBits(&fb,8); if (feof(input_file)) { printf("The last frame is truncated.\n"); break; } if ((head & 0xffe00000) != 0xffe00000 || !((head>>17)&3) || ((head>>12)&0xf) == 0xf || ((head>>10)&0x3) == 0x3 ) { char mes[100]; if (pos == id3pos) break; printf("sync error at %d(%d%%), frame number %d\n",pos,pos*100/filesize,framenum); resync = 1; continue; } //if ((head & 0xffff0000) == 0xfffe0000) return 0; if( head & (1<<20) ) { lsf = (head & (1<<19)) ? 0x0 : 0x1; mpeg25 = 0; } else { lsf = 1; mpeg25 = 1; } if(mpeg25) srate = 6 + ((head>>10)&0x3); else srate = ((head>>10)&0x3) + (lsf*3); idex = (head >> 20) & 1; id = (head >> 19) & 1; lay = 4-((head>>17)&3); protection = (head >> 16) & 1; bitrate_index = (head >> 12) & 15; padding = (head >> 9) & 1; mode = (head >> 6) & 3; modeex = (head >> 4) & 3; freq = freqs[srate]; nch = (mode == MPG_MD_MONO) ? 1 : 2; if (lay != 3) { char mes[100]; printf("Layer type error at %d(%d%%), frame number %d\n",pos,pos*100/filesize,framenum); resync = 1; pos++; continue; } if (nch != base_nch) { char mes[100]; printf("Channel mode error at %d(%d%%), frame number %d\n",pos,pos*100/filesize,framenum); resync = 1; pos++; continue; } if (freq != base_freq) { char mes[100]; printf("Frequency error at %d(%d%%), frame number %d\n",pos,pos*100/filesize,framenum); resync = 1; pos++; continue; } if (bitrate_index == 0) { char mes[100]; printf("Freeformat frame at %d(%d%%), frame number %d\n",pos,pos*100/filesize,framenum); resync = 1; pos++; continue; } if (!protection) readBits(&fb,16); if (padding) usesPadding = 1; if (id) { main_data_begin = readBits(&fb,9); if (main_data_begin > reservoirMax) reservoirMax = main_data_begin; } else { main_data_begin = readBits(&fb,8); if (main_data_begin > reservoirMax) reservoirMax = main_data_begin; } if (id) { if (mode==3) readBits(&fb,5); // private_bits else readBits(&fb,3); // private_bits } else { if (mode==3) readBits(&fb,1); // private_bits else readBits(&fb,2); // private_bits } if (id == 1) { int ch,scfsi_band; for(ch=0;ch= 8) { unsigned char buf[1024],*p; p = buf; //printf("anc start pos : %d\n",(endOfLastPart3+7)&~7); //printf("ancillary(%d,%d) : ",framenum,((endOfLastPart3+7)&~7)/8); while(pos_main_data_begin-tell_p23b() >= 8) { int c = readOneByte_p23b(); *p++ = c; //if (isprint(c)) putchar(c); else putchar('.'); } extract_lame_string(buf,p-buf); //printf("\n"); } } } endOfLastPart3 = -1; //printf("pos_main_data_begin=%d, part2_3_length=%d\n",pos_main_data_begin,part2_3_length); if (seek_p23b(pos_main_data_begin)) { if (skip_p23b(part2_3_length) == 0) endOfLastPart3 = tell_p23b(); else printf("B!\n"); } else printf("A!\n"); pos += framesize; framenum++; } if (endOfLastPart3 != -1 && seek_p23b(endOfLastPart3)) { // extract ancillary int mdb; seek_p23b(startOfFrame-1); mdb = tell_p23b()+1; //printf("pos*8=%d, mdb=%d\n",pos*8,mdb); //printf("final startOfFrame=%d, endOfLastPart3=%d, anclen : %d\n",startOfFrame,endOfLastPart3,mdb-endOfLastPart3); seek_p23b((endOfLastPart3+7)&~7); if (mdb-tell_p23b() > 8) { unsigned char buf[1024],*p; p = buf; //printf("anc start pos : %d\n",(endOfLastPart3+7)&~7); //printf("ancillary(%d,%d) : ",framenum,((endOfLastPart3+7)&~7)/8); //printf("ancillary(%d) : ",framenum); while(mdb-tell_p23b() > 8) { int c = readOneByte_p23b(); *p++ = c; //if (isprint(c)) putchar(c); else putchar('.'); } extract_lame_string(buf,p-buf); //printf("\n"); } } printf("\n"); printf("File size : %d bytes\n",filesize); printf("Length : %g seconds\n",totFrameNum*576.0*(base_lsf?1:2)/base_freq); printf("%gkbit, %dframes\n",totFrameLen/(totFrameNum*576.0*(base_lsf?1:2)/base_freq)*8/1000,totFrameNum); printf("%dHz %s\n",base_freq,base_nch == 1 ? "Mono" : modeCount[0] == totFrameNum ? "Simple stereo" : "Joint stereo"); printf("Error protection : %s\n",!crc ? "yes":"no"); printf("Copyrighted : %s\n",copyright ? "yes":"no"); printf("Original : %s\n",original ? "yes":"no"); printf("emphasis : %s\n",emphasis == 0 ? "none" : emphasis == 1 ? "50/15ms" : "CCITT"); printf("\n"); if (modeCount[0] != totFrameNum) { printf("%d simple stereo frames\n",modeCount[0]); if (modeCount[1]) { printf("%d intensity stereo frames\n",modeCount[1]); } if (modeCount[2]) { printf("%d mid-side stereo frames\n",modeCount[2]); } if (modeCount[3]) { printf("%d intensity and mid-side stereo frames\n",modeCount[3]); } printf("\n"); } printf("long block granules : %d\n",blockCount[0]); printf("short block granules : %d\n",blockCount[1]); printf("mixed block granules : %d\n\n",blockCount[2]); if (usesPadding) printf("padding is used\n"); if (usesScalefacScale) printf("scalefac_scale is used\n"); if (usesScfsi) printf("scfsi is used\n"); printf("max reservoir : %d\n\n",reservoirMax); for(i=0;i<16;i++) { if (bitrateCount[i] == 0) continue; printf("%d kbps frames : %d(%d%%)\n",tabsel_123[base_lsf][2][i], bitrateCount[i],bitrateCount[i]*100/totFrameNum); } printf("\n"); printf("%d header errors\n",nSyncError); if (lame_string[0] != '\0') { printf("\nlame string : %s\n",lame_string); } if (blockCount[1] == 0) { if (modeCount[1]) { guess = "Xing (very old)"; } else if (usesScfsi) { guess = "Xing (new)"; } else { guess = "Xing (old)"; } } else if (usesScfsi) { if (usesScalefacScale) { guess = "Lame"; } else { guess = "Lame (old) or m3e"; } } else if (usesScalefacScale) { if (usesPadding) { guess = "FhG (l3enc, fastenc or mp3enc)"; } else { guess = "FhG (ACM or producer pro)"; } } else { guess = "dist10 encoder or other encoder"; } printf("\nMaybe this file is encoded by %s\n",guess); fclose(input_file); }