"Fossies" - the Fresh Open Source Software Archive

Member "mp3info-0.8.5a/mp3tech.c" (6 Nov 2006, 10800 Bytes) of package /linux/misc/old/mp3info-0.8.5a.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mp3tech.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2     mp3tech.c - Functions for handling MP3 files and most MP3 data
    3                 structure manipulation.
    4 
    5     Copyright (C) 2000-2006 Cedric Tefft <cedric@phreaker.net>
    6 
    7     This program is free software; you can redistribute it and/or modify
    8     it under the terms of the GNU General Public License as published by
    9     the Free Software Foundation; either version 2 of the License, or
   10     (at your option) any later version.
   11 
   12     This program is distributed in the hope that it will be useful,
   13     but WITHOUT ANY WARRANTY; without even the implied warranty of
   14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15     GNU General Public License for more details.
   16 
   17     You should have received a copy of the GNU General Public License
   18     along with this program; if not, write to the Free Software
   19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   20 
   21   ***************************************************************************
   22 
   23   This file is based in part on:
   24 
   25     * MP3Info 0.5 by Ricardo Cerqueira <rmc@rccn.net>
   26     * MP3Stat 0.9 by Ed Sweetman <safemode@voicenet.com> and 
   27              Johannes Overmann <overmann@iname.com>
   28 
   29 */
   30 
   31 #include "mp3info.h"
   32 
   33 
   34 int layer_tab[4]= {0, 3, 2, 1};
   35 
   36 int frequencies[3][4] = {
   37    {22050,24000,16000,50000},  /* MPEG 2.0 */
   38    {44100,48000,32000,50000},  /* MPEG 1.0 */
   39    {11025,12000,8000,50000}    /* MPEG 2.5 */
   40 };
   41 
   42 int bitrate[2][3][15] = { 
   43   { /* MPEG 2.0 */
   44     {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256},  /* layer 1 */
   45     {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160},       /* layer 2 */
   46     {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160}        /* layer 3 */
   47 
   48   },
   49 
   50   { /* MPEG 1.0 */
   51     {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448}, /* layer 1 */
   52     {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384},    /* layer 2 */
   53     {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320}      /* layer 3 */
   54   }
   55 };
   56 
   57 int frame_size_index[] = {24000, 72000, 72000};
   58 
   59 
   60 char *mode_text[] = {
   61    "stereo", "joint stereo", "dual channel", "mono"
   62 };
   63 
   64 char *emphasis_text[] = {
   65   "none", "50/15 microsecs", "reserved", "CCITT J 17"
   66 };
   67 
   68 
   69 int get_mp3_info(mp3info *mp3,int scantype, int fullscan_vbr)
   70 {
   71   int had_error = 0;
   72   int frame_type[15]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
   73   float seconds=0,total_rate=0;
   74   int frames=0,frame_types=0,frames_so_far=0;
   75   int l,vbr_median=-1;
   76   int bitrate,lastrate;
   77   int counter=0;
   78   mp3header header;
   79   struct stat filestat;
   80   off_t sample_pos,data_start=0;
   81 
   82 
   83   stat(mp3->filename,&filestat);
   84   mp3->datasize=filestat.st_size;
   85   get_id3(mp3);
   86 
   87   if(scantype == SCAN_QUICK) {
   88     if(get_first_header(mp3,0L)) {
   89         data_start=ftell(mp3->file);
   90         lastrate=15-mp3->header.bitrate;
   91         while((counter < NUM_SAMPLES) && lastrate) {
   92             sample_pos=(counter*(mp3->datasize/NUM_SAMPLES+1))+data_start;
   93             if(get_first_header(mp3,sample_pos)) {
   94                 bitrate=15-mp3->header.bitrate;
   95             } else {
   96                 bitrate=-1;
   97             }
   98         
   99             if(bitrate != lastrate) {
  100                 mp3->vbr=1;
  101                 if(fullscan_vbr) {
  102                     counter=NUM_SAMPLES;
  103                     scantype=SCAN_FULL;
  104                 }
  105             }
  106             lastrate=bitrate;
  107             counter++;
  108             
  109         }
  110         if(!(scantype == SCAN_FULL)) {
  111             mp3->frames=(mp3->datasize-data_start)/(l=frame_length(&mp3->header));
  112             mp3->seconds = (int)((float)(frame_length(&mp3->header)*mp3->frames)/
  113                        (float)(header_bitrate(&mp3->header)*125)+0.5);
  114             mp3->vbr_average = (float)header_bitrate(&mp3->header);
  115         }
  116     }
  117 
  118   }
  119 
  120   if(scantype == SCAN_FULL) {
  121     if(get_first_header(mp3,0L)) {
  122         data_start=ftell(mp3->file);
  123         while((bitrate=get_next_header(mp3))) {
  124             frame_type[15-bitrate]++;
  125             frames++;
  126         }
  127         memcpy(&header,&(mp3->header),sizeof(mp3header));
  128         for(counter=0;counter<15;counter++) {
  129             if(frame_type[counter]) {
  130                 frame_types++;
  131                 header.bitrate=counter;
  132                 frames_so_far += frame_type[counter];
  133                 seconds += (float)(frame_length(&header)*frame_type[counter])/
  134                            (float)(header_bitrate(&header)*125);
  135                 total_rate += (float)((header_bitrate(&header))*frame_type[counter]);
  136                 if((vbr_median == -1) && (frames_so_far >= frames/2))
  137                     vbr_median=counter;
  138             }
  139         }
  140         mp3->seconds=(int)(seconds+0.5);
  141         mp3->header.bitrate=vbr_median;
  142         mp3->vbr_average=total_rate/(float)frames;
  143         mp3->frames=frames;
  144         if(frame_types > 1) {
  145             mp3->vbr=1;
  146         }
  147     }
  148   }
  149   return had_error;
  150 }
  151 
  152 
  153 int get_first_header(mp3info *mp3, long startpos) 
  154 {
  155   int k, l=0,c;
  156   mp3header h, h2;
  157   long valid_start=0;
  158   
  159   fseek(mp3->file,startpos,SEEK_SET);
  160   while (1) {
  161      while((c=fgetc(mp3->file)) != 255 && (c != EOF));
  162      if(c == 255) {
  163         ungetc(c,mp3->file);
  164         valid_start=ftell(mp3->file);
  165         if((l=get_header(mp3->file,&h))) {
  166           fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
  167       for(k=1; (k < MIN_CONSEC_GOOD_FRAMES) && (mp3->datasize-ftell(mp3->file) >= FRAME_HEADER_SIZE); k++) {
  168         if(!(l=get_header(mp3->file,&h2))) break;
  169         if(!sameConstant(&h,&h2)) break;
  170         fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
  171       }
  172       if(k == MIN_CONSEC_GOOD_FRAMES) {
  173         fseek(mp3->file,valid_start,SEEK_SET);
  174         memcpy(&(mp3->header),&h2,sizeof(mp3header));
  175         mp3->header_isvalid=1;
  176         return 1;
  177       } 
  178         }
  179      } else {
  180     return 0;
  181      }
  182    }
  183 
  184   return 0;  
  185 }
  186 
  187 /* get_next_header() - read header at current position or look for 
  188    the next valid header if there isn't one at the current position
  189 */
  190 int get_next_header(mp3info *mp3) 
  191 {
  192   int l=0,c,skip_bytes=0;
  193   mp3header h;
  194   
  195    while(1) {
  196      while((c=fgetc(mp3->file)) != 255 && (ftell(mp3->file) < mp3->datasize)) skip_bytes++;
  197      if(c == 255) {
  198         ungetc(c,mp3->file);
  199         if((l=get_header(mp3->file,&h))) {
  200       if(skip_bytes) mp3->badframes++;
  201           fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
  202           return 15-h.bitrate;
  203     } else {
  204         skip_bytes += FRAME_HEADER_SIZE;
  205     }
  206      } else {
  207       if(skip_bytes) mp3->badframes++;
  208           return 0;
  209      }
  210   }
  211 }
  212 
  213 
  214 /* Get next MP3 frame header.
  215    Return codes:
  216    positive value = Frame Length of this header
  217    0 = No, we did not retrieve a valid frame header
  218 */
  219 
  220 int get_header(FILE *file,mp3header *header)
  221 {
  222     unsigned char buffer[FRAME_HEADER_SIZE];
  223     int fl;
  224 
  225     if(fread(&buffer,FRAME_HEADER_SIZE,1,file)<1) {
  226     header->sync=0;
  227     return 0;
  228     }
  229     header->sync=(((int)buffer[0]<<4) | ((int)(buffer[1]&0xE0)>>4));
  230     if(buffer[1] & 0x10) header->version=(buffer[1] >> 3) & 1;
  231                     else header->version=2;
  232     header->layer=(buffer[1] >> 1) & 3;
  233     header->bitrate=(buffer[2] >> 4) & 0x0F;
  234     if((header->sync != 0xFFE) || (header->layer != 1) || (header->bitrate == 0xF)) {
  235     header->sync=0;
  236     return 0;
  237     }
  238     header->crc=buffer[1] & 1;
  239     header->freq=(buffer[2] >> 2) & 0x3;
  240     header->padding=(buffer[2] >>1) & 0x1;
  241     header->extension=(buffer[2]) & 0x1;
  242     header->mode=(buffer[3] >> 6) & 0x3;
  243     header->mode_extension=(buffer[3] >> 4) & 0x3;
  244     header->copyright=(buffer[3] >> 3) & 0x1;
  245     header->original=(buffer[3] >> 2) & 0x1;
  246     header->emphasis=(buffer[3]) & 0x3;
  247 
  248     /* Final sanity checks: bitrate 1111b and frequency 11b are reserved (invalid) */
  249     if (header->bitrate == 0x0F || header->freq == 0x3) {
  250     return 0;
  251     }
  252     
  253     return ((fl=frame_length(header)) >= MIN_FRAME_SIZE ? fl : 0); 
  254 }
  255 
  256 int frame_length(mp3header *header) {
  257     return header->sync == 0xFFE ? 
  258             (frame_size_index[3-header->layer]*((header->version&1)+1)*
  259             header_bitrate(header)/header_frequency(header))+
  260             header->padding : 1;
  261 }
  262 
  263 int header_layer(mp3header *h) {return layer_tab[h->layer];}
  264 
  265 int header_bitrate(mp3header *h) {
  266     return bitrate[h->version & 1][3-h->layer][h->bitrate];
  267 }
  268 
  269 int header_frequency(mp3header *h) {
  270     return frequencies[h->version][h->freq];
  271 }
  272 
  273 char *header_emphasis(mp3header *h) {
  274     return emphasis_text[h->emphasis];
  275 }
  276 
  277 char *header_mode(mp3header *h) {
  278     return mode_text[h->mode];
  279 }
  280 
  281 int sameConstant(mp3header *h1, mp3header *h2) {
  282     if((*(uint*)h1) == (*(uint*)h2)) return 1;
  283 
  284     if((h1->version       == h2->version         ) &&
  285        (h1->layer         == h2->layer           ) &&
  286        (h1->crc           == h2->crc             ) &&
  287        (h1->freq          == h2->freq            ) &&
  288        (h1->mode          == h2->mode            ) &&
  289        (h1->copyright     == h2->copyright       ) &&
  290        (h1->original      == h2->original        ) &&
  291        (h1->emphasis      == h2->emphasis        )) 
  292         return 1;
  293     else return 0;
  294 }
  295 
  296 
  297 int get_id3(mp3info *mp3) {
  298    int retcode=0;
  299    char fbuf[4];
  300 
  301    if(mp3->datasize >= 128) {
  302     if(fseek(mp3->file, -128, SEEK_END )) {
  303        fprintf(stderr,"ERROR: Couldn't read last 128 bytes of %s!!\n",mp3->filename);
  304        retcode |= 4;
  305     } else {
  306        fread(fbuf,1,3,mp3->file); fbuf[3] = '\0';
  307        mp3->id3.genre[0]=255;
  308 
  309 
  310        if (!strcmp((const char *)"TAG",(const char *)fbuf)) {
  311 
  312 
  313           mp3->id3_isvalid=1;
  314           mp3->datasize -= 128;
  315               fseek(mp3->file, -125, SEEK_END);
  316               fread(mp3->id3.title,1,30,mp3->file); mp3->id3.title[30] = '\0';
  317               fread(mp3->id3.artist,1,30,mp3->file); mp3->id3.artist[30] = '\0';
  318               fread(mp3->id3.album,1,30,mp3->file); mp3->id3.album[30] = '\0';
  319               fread(mp3->id3.year,1,4,mp3->file); mp3->id3.year[4] = '\0';
  320               fread(mp3->id3.comment,1,30,mp3->file); mp3->id3.comment[30] = '\0';
  321           if(mp3->id3.comment[28] == '\0') {
  322          mp3->id3.track[0] = mp3->id3.comment[29];
  323           }
  324               fread(mp3->id3.genre,1,1,mp3->file);
  325           unpad(mp3->id3.title);
  326           unpad(mp3->id3.artist);
  327           unpad(mp3->id3.album);
  328           unpad(mp3->id3.year);
  329           unpad(mp3->id3.comment);
  330            }
  331     }
  332    }
  333    return retcode;
  334 
  335 }
  336 
  337 char *pad(char *string, int length) {
  338         int l;
  339 
  340         l=strlen(string);
  341         while(l<length) {
  342                 string[l] = ' ';
  343                 l++;
  344         }
  345 
  346         string[l]='\0';
  347     return string;
  348 }
  349 
  350 /* Remove trailing whitespace from the end of a string */
  351 
  352 char *unpad(char *string) {
  353     char *pos=string+strlen(string)-1;
  354     while(isspace(pos[0])) (pos--)[0]=0;
  355     return string;
  356 }
  357 
  358 /*
  359  * Build an ID3 tag and write it to the file
  360  * Returns positive int on success, 0 on failure
  361  */
  362 
  363 int write_tag(mp3info *mp3) {
  364 
  365     char buf[129];
  366 
  367     strcpy(buf,"TAG");
  368     pad(mp3->id3.title,TEXT_FIELD_LEN);
  369     strncat(buf,mp3->id3.title,TEXT_FIELD_LEN);
  370     pad(mp3->id3.artist,TEXT_FIELD_LEN);
  371     strncat(buf,mp3->id3.artist,TEXT_FIELD_LEN);
  372     pad(mp3->id3.album,TEXT_FIELD_LEN);
  373     strncat(buf,mp3->id3.album,TEXT_FIELD_LEN);
  374     pad(mp3->id3.year,INT_FIELD_LEN);
  375     strncat(buf,mp3->id3.year,INT_FIELD_LEN);
  376     pad(mp3->id3.comment,TEXT_FIELD_LEN);
  377     strncat(buf,mp3->id3.comment,TEXT_FIELD_LEN);
  378     strncat(buf,(char *)&(mp3->id3.genre),1);
  379     if (mp3->id3.track[0] != '\0') {
  380         buf[125]='\0';
  381         buf[126]=mp3->id3.track[0];
  382     }
  383     fseek(mp3->file,-128*mp3->id3_isvalid,SEEK_END);
  384     return (int)fwrite(buf,1,128,mp3->file);
  385 }