/* 
   GiantDisc-mp3cutter

   (c) Rolf Brugger, 2002



   mp3 frame header doc: http://www.id3.org/mp3frame.html
   
   header format:
   
   f			sync
   f			sync
   f			sync
   id layer prot	id=1: mpeg I, layer="01": layer III
   bitrate              "0001": 32'000 ... "1111": 320'000
   freq pad priv	freq="00": 44'100
   mode modeext		mode="01": joint-stereo
   copy home emph
   
   example: ff fa 92 44
   f (3x)	sync
   a		"1010": mpeg I, layer III, not protected
   9		"1001": 128'000 kb/s 
   2		"0010": samplerate=44'100, padded, not private
   4		"0100": joint stereo, mode extension??
   4		"0100": copy ok, home?, "00": no emphasis method
   
 */

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/stat.h>

int mpg1l3bitrate[] = {0, 32000, 40000, 48000, 56000, 64000, 80000, 96000,
	112000, 128000, 160000, 192000, 224000, 256000, 320000};
int mpg1samprate[] = {44100, 48000, 32000, 0};

char pattern[]=    {0xff,0xfa,0x00};	// mp3-L1 sync byte sequence is 
char patternmask[]={0xff,0xfe,0x00};	// ff-fa or ff-fb

int  writeout=0, percentRead, percentCounter=0, onePercent;
int  mp3fsize;

void condWriteChar(int chrcnt, int frmcnt, int firstframe, int lastframe,
		   int prvchr, FILE *outfptr)
{
  if(chrcnt>0 && (frmcnt>=firstframe) && (frmcnt<=lastframe) && writeout){
    //printf("write %x\n", prvchr);
    putc(prvchr, outfptr);	// write previous character
  }
}


main (int argc, char **argv)
{
  int  pattlen = 2; // Sync sequence length
  char line[500], sqlcmd[500], *infname, *outfname;
  int  chrcnt, prvchr, curchr, frmcnt, frmchr;
  int  bitrate, samplerate, framelen;
  int  firstframe, lastframe;
  FILE *infptr, *outfptr;
  struct stat fileStat;

  lastframe = INT_MAX;
  if(argc!=2 && argc!=5){
    printf("GiantDisc mp3cutter has either 1 or 4 parameters\n\n");
    printf("gdmp3cutter mp3-filename from-frame to-frame output-filename\n  trim the input file\n\n");
    printf("gdmp3cutter mp3-filename\n  prints file statistics without writing an output file\n\n");
    exit (-1);
  }
  infname  = argv[1];
  if (argc==5){
    writeout=1;
    firstframe = atoi(argv[2]);
    lastframe = atoi(argv[3]);
    outfname = argv[4];
  }
  
  //printf ("mp3cutter:  %s from:%i to:%i\n\n", infname, firstframe, lastframe);

  if((infptr =fopen(infname,"r")) == NULL){
    printf("Error: can't open file %s\n", infname);
    exit(0);
  }
  if(writeout && (outfptr=fopen(outfname,"w")) == NULL){
    printf("Error: can't open output file\n");
    exit(0);
  }
  // get in file size
  stat(infname, &fileStat);
  mp3fsize = fileStat.st_size;
  onePercent = (int)(((float)mp3fsize)/100.0);
  printf("reading mp3 file: (%i bytes)\n", mp3fsize);
  
  
    /* *** init variables *** */
    chrcnt  = 1;	// overall byte counter
    frmcnt  = 0;	// frame counter
    frmchr  = 0;	// bytes in current frame counter
    framelen= 0;	// length of frames in input file (without padding)


    /* *** loop through input file *** */
    prvchr = getc(infptr);	// always read one byte ahead
    while((curchr = getc(infptr)) != EOF){
    	
      /* *** Detect frame header *** */
      if (  ( frmchr >= (framelen-2) ) 
          &&( pattern[0]==(patternmask[0] & (char)prvchr))
          &&( pattern[1]==(patternmask[1] & (char)curchr))
         ){

      	/* *** Frame header found *** */
        if(frmcnt == 0){ // *** First frame header?
          int lookahead;
          
          // extract bitrate and samplerate from 3rd byte in header
          lookahead = getc(infptr);
          ungetc(lookahead, infptr);
          bitrate    = mpg1l3bitrate[(lookahead>>4) & 0x000f];
          samplerate = mpg1samprate [(lookahead>>2) & 0x0003];
          framelen = (144*bitrate)/samplerate;
          //printf("bitrate %i, samplerate %i, framelength %i\n", bitrate, samplerate, framelen);
        }
      	//printf("%i ", frmchr);
      	frmcnt++;
      	frmchr  = 0;
      }

      /* *** Write "previous" character to output file *** */
      condWriteChar(chrcnt, frmcnt, firstframe, lastframe, prvchr, outfptr);

      
      chrcnt++;
      frmchr++;
      prvchr = curchr; // set "prev char"
//      if ( percentRead != (chrcnt*100)/mp3fsize ){
      if ( (percentCounter+onePercent) < chrcnt ){
        percentRead = (int)((((double)chrcnt)*100.0)/((double)mp3fsize));
        if (percentRead % 5 == 0){
          printf("reading mp3 file: %i%%\n", percentRead);
          fflush(stdout);
        }
        percentCounter += onePercent;
      }
    }

    /* *** Write last char *** */
      condWriteChar(chrcnt, frmcnt, firstframe, lastframe, prvchr, outfptr);
    
    //printf("exit loop: %i bytes, %i frames\n", chrcnt, frmcnt);
    printf("%i bit/sec\n%i samp/sec\n%i bytes/frame\n", bitrate, samplerate, framelen);
    printf("%i bytes tot\n%i frames\n", chrcnt, frmcnt);
  
  
  fclose( infptr);
  if (writeout) fclose(outfptr);
}

