www.pudn.com > ssrc-1.30.zip > ssrc.c


#include  
#include  
#include  
#include  
#include  
 
#define NDEBUG 
 
#define VERSION "1.30" 
 
#ifndef HIGHPREC 
typedef float REAL; 
double AA=120; 
double DF=100; 
int FFTFIRLEN=16384; 
#define M 15 
#else 
typedef double REAL; 
double AA=170; 
double DF=100; 
int FFTFIRLEN=65536; 
#define M 15 
#endif 
 
#ifndef M_PI 
#define M_PI 3.1415926535897932384626433832795028842 
#endif 
 
#define RANDBUFLEN 65536 
 
#define RINT(x) ((x) >= 0 ? ((int)((x) + 0.5)) : ((int)((x) - 0.5))) 
 
#if 0 
double fact[M+1]; 
#endif 
 
extern void rdft(int, int, REAL *, int *, REAL *); 
extern double dbesi0(double); 
 
const int scoeffreq[] = {0,48000,44100,37800,32000,22050,48000,44100}; 
 
 
const int scoeflen[] =  {1,16,20,16,16,15,16,15}; 
const int samp[] =  {8,18,27,8,8,8,10,9}; 
 
const double shapercoefs[8][21] = { 
  {-1}, /* triangular dither */ 
 
  {-2.8720729351043701172,   5.0413231849670410156,  -6.2442994117736816406,   5.8483986854553222656, 
   -3.7067542076110839844,   1.0495119094848632812,   1.1830236911773681641,  -2.1126792430877685547, 
    1.9094531536102294922,  -0.99913084506988525391,  0.17090806365013122559,  0.32615602016448974609, 
   -0.39127644896507263184,  0.26876461505889892578, -0.097676105797290802002, 0.023473845794796943665, 
  }, /* 48k, N=16, amp=18 */ 
 
  {-2.6773197650909423828,   4.8308925628662109375,  -6.570110321044921875,    7.4572014808654785156, 
   -6.7263274192810058594,   4.8481650352478027344,  -2.0412089824676513672,  -0.7006359100341796875, 
    2.9537565708160400391,  -4.0800385475158691406,   4.1845216751098632812,  -3.3311812877655029297, 
    2.1179926395416259766,  -0.879302978515625,       0.031759146600961685181, 0.42382788658142089844, 
   -0.47882103919982910156,  0.35490813851356506348, -0.17496839165687561035,  0.060908168554306030273, 
  }, /* 44.1k, N=20, amp=27 */ 
 
  {-1.6335992813110351562,   2.2615492343902587891,  -2.4077029228210449219,   2.6341717243194580078, 
   -2.1440362930297851562,   1.8153258562088012695,  -1.0816224813461303711,   0.70302653312683105469, 
   -0.15991993248462677002, -0.041549518704414367676, 0.29416576027870178223, -0.2518316805362701416, 
    0.27766478061676025391, -0.15785403549671173096,  0.10165894031524658203, -0.016833892092108726501, 
  }, /* 37.8k, N=16 */ 
 
  {-0.82901298999786376953,  0.98922657966613769531, -0.59825712442398071289,  1.0028809309005737305, 
   -0.59938216209411621094,  0.79502451419830322266, -0.42723315954208374023,  0.54492527246475219727, 
   -0.30792605876922607422,  0.36871799826622009277, -0.18792048096656799316,  0.2261127084493637085, 
   -0.10573341697454452515,  0.11435490846633911133, -0.038800679147243499756, 0.040842197835445404053, 
  }, /* 32k, N=16 */ 
 
  {-0.065229974687099456787, 0.54981261491775512695,  0.40278548002243041992,  0.31783768534660339355, 
    0.28201797604560852051,  0.16985194385051727295,  0.15433363616466522217,  0.12507140636444091797, 
    0.08903945237398147583,  0.064410120248794555664, 0.047146003693342208862, 0.032805237919092178345, 
    0.028495194390416145325, 0.011695005930960178375, 0.011831838637590408325, 
  }, /* 22.05k, N=15 */ 
 
  {-2.3925774097442626953,   3.4350297451019287109,  -3.1853709220886230469,   1.8117271661758422852, 
    0.20124770700931549072, -1.4759907722473144531,   1.7210904359817504883,  -0.97746700048446655273, 
    0.13790138065814971924,  0.38185903429985046387, -0.27421241998672485352, -0.066584214568138122559, 
    0.35223302245140075684, -0.37672343850135803223,  0.23964276909828186035, -0.068674825131893157959, 
  }, /* 48k, N=16, amp=10 */ 
 
  {-2.0833916664123535156,   3.0418450832366943359,  -3.2047898769378662109,   2.7571926116943359375, 
   -1.4978630542755126953,   0.3427594602108001709,   0.71733748912811279297, -1.0737057924270629883, 
    1.0225815773010253906,  -0.56649994850158691406,  0.20968692004680633545,  0.065378531813621520996, 
   -0.10322438180446624756,  0.067442022264003753662, 0.00495197344571352005, 
  }, /* 44.1k, N=15, amp=9 */ 
 
#if 0 
  { -3.0259189605712890625,  6.0268716812133789062,  -9.195003509521484375,   11.824929237365722656, 
   -12.767142295837402344,  11.917946815490722656,   -9.1739168167114257812,   5.3712320327758789062, 
    -1.1393624544143676758, -2.4484779834747314453,   4.9719839096069335938,  -6.0392003059387207031, 
     5.9359521865844726562, -4.903278350830078125,    3.5527443885803222656,  -2.1909697055816650391, 
     1.1672389507293701172, -0.4903914332389831543,   0.16519790887832641602, -0.023217858746647834778, 
  }, /* 44.1k, N=20 */ 
#endif 
}; 
 
double **shapebuf; 
int shaper_type,shaper_len,shaper_clipmin,shaper_clipmax; 
REAL *randbuf; 
int randptr; 
int quiet = 0; 
int lastshowed2; 
time_t starttime,lastshowed; 
 
#define POOLSIZE 97 
 
int init_shaper(int freq,int nch,int min,int max,int dtype,int pdf,double noiseamp) 
{ 
  int i; 
  int pool[POOLSIZE]; 
 
  for(i=1;i<6;i++) if (freq == scoeffreq[i]) break; 
  if ((dtype == 3 || dtype == 4) && i == 6) { 
    fprintf(stderr,"Warning: ATH based noise shaping for destination frequency %dHz is not available, using triangular dither\n",freq); 
  } 
  if (dtype == 2 || i == 6) i = 0; 
  if (dtype == 4 && (i == 1 || i == 2)) i += 5; 
 
  shaper_type = i; 
 
  shapebuf = malloc(sizeof(double *)*nch); 
  shaper_len = scoeflen[shaper_type]; 
 
  for(i=0;i shaper_clipmax) { 
      double d = (double)s/shaper_clipmax; 
      *peak = *peak < d ? d : *peak; 
      s = shaper_clipmax; 
    } 
 
    return RINT(s); 
  } 
 
  h = 0; 
  for(i=0;i=0;i--) shapebuf[ch][i+1] = shapebuf[ch][i]; 
 
  if (s < shaper_clipmin) { 
    double d = (double)s/shaper_clipmin; 
    *peak = *peak < d ? d : *peak; 
    s = shaper_clipmin; 
    shapebuf[ch][0] = s-u; 
 
    if (shapebuf[ch][0] >  1) shapebuf[ch][0] =  1; 
    if (shapebuf[ch][0] < -1) shapebuf[ch][0] = -1; 
  } else if (s > shaper_clipmax) { 
    double d = (double)s/shaper_clipmax; 
    *peak = *peak < d ? d : *peak; 
    s = shaper_clipmax; 
    shapebuf[ch][0] = s-u; 
 
    if (shapebuf[ch][0] >  1) shapebuf[ch][0] =  1; 
    if (shapebuf[ch][0] < -1) shapebuf[ch][0] = -1; 
  } else { 
    s = RINT(s); 
    shapebuf[ch][0] = s-u; 
  } 
 
  return (int)s; 
} 
 
void quit_shaper(int nch) 
{ 
  int i; 
 
  for(i=0;i]  \n"); 
  printf("options : --rate      output sample rate\n"); 
  printf("          --att     attenuate signal\n"); 
  printf("          --bits     output quantization bit length\n"); 
  printf("          --tmpfile       specify temporal file\n"); 
  printf("          --twopass                  two pass processing to avoid clipping\n"); 
  printf("          --normalize                normalize the wave file\n"); 
  printf("          --quiet                    nothing displayed except error\n"); 
  printf("          --dither []          dithering\n"); 
  printf("                                       0 : no dither\n"); 
  printf("                                       1 : no noise shaping\n"); 
  printf("                                       2 : triangular spectral shape\n"); 
  printf("                                       3 : ATH based noise shaping\n"); 
  printf("                                       4 : less dither amplitude than type 3\n"); 
  printf("          --pdf  []       select p.d.f. of noise\n"); 
  printf("                                       0 : rectangular\n"); 
  printf("                                       1 : triangular\n"); 
  printf("                                       2 : Gaussian\n"); 
#ifndef HIGHPREC 
  printf("          --profile            specify profile\n"); 
  printf("                                       standard : the default quality\n"); 
  printf("                                       fast     : fast, not so bad quality\n"); 
#endif 
} 
 
void fmterr(int x) 
{ 
  fprintf(stderr,"unknown error %d\n",x); 
  exit(-1); 
} 
 
void setstarttime(void) 
{ 
  starttime = time(NULL); 
  lastshowed = 0; 
  lastshowed2 = -1; 
} 
 
void showprogress(double p) 
{ 
  int eta,pc; 
  time_t t; 
  if (quiet) return; 
 
  t = time(NULL)-starttime; 
  if (p == 0) eta = 0; else eta = t*(1-p)/p; 
 
  pc = (int)(p*100); 
 
  if (pc != lastshowed2 || t != lastshowed) { 
    printf(" %3d%% processed",pc); 
    lastshowed2 = pc; 
  } 
  if(t != lastshowed) { 
    printf(", ETA =%4dsec",eta); 
    lastshowed = t; 
  } 
  printf("\r"); 
  fflush(stdout); 
} 
 
int gcd(int x, int y) 
{ 
    int t; 
 
    while (y != 0) { 
        t = x % y;  x = y;  y = t; 
    } 
    return x; 
} 
 
double upsample(FILE *fpi,FILE *fpo,int nch,int bps,int dbps,int sfrq,int dfrq,double gain,unsigned int chanklen,int twopass,int dither) 
{ 
  int frqgcd,osf,fs1,fs2; 
  REAL **stage1,*stage2; 
  int n1,n1x,n1y,n2,n2b; 
  int filter2len; 
  int *f1order,*f1inc; 
  int *fft_ip = NULL; 
  REAL *fft_w = NULL; 
  unsigned char *rawinbuf,*rawoutbuf; 
  REAL *inbuf,*outbuf; 
  REAL **buf1,**buf2; 
  double peak=0; 
  int spcount = 0; 
  int i,j; 
 
  filter2len = FFTFIRLEN; /* stage 2 filter length */ 
 
  /* Make stage 1 filter */ 
 
  { 
    double aa = AA; /* stop band attenuation(dB) */ 
    double lpf,delta,d,df,alp,iza; 
    double guard = 2; 
 
    frqgcd = gcd(sfrq,dfrq); 
 
    fs1 = sfrq / frqgcd * dfrq; 
 
    if (fs1/dfrq == 1) osf = 1; 
    else if (fs1/dfrq % 2 == 0) osf = 2; 
    else if (fs1/dfrq % 3 == 0) osf = 3; 
    else { 
      fprintf(stderr,"Resampling from %dHz to %dHz is not supported.\n",sfrq,dfrq); 
      fprintf(stderr,"%d/gcd(%d,%d)=%d must be divided by 2 or 3.\n",sfrq,sfrq,dfrq,fs1/dfrq); 
      exit(-1); 
    } 
 
    df = (dfrq*osf/2 - sfrq/2) * 2 / guard; 
    lpf = sfrq/2 + (dfrq*osf/2 - sfrq/2)/guard; 
 
    delta = pow(10,-aa/20); 
    if (aa <= 21) d = 0.9222; else d = (aa-7.95)/14.36; 
 
    n1 = fs1/df*d+1; 
    if (n1 % 2 == 0) n1++; 
 
    alp = alpha(aa); 
    iza = dbesi0(alp); 
    //printf("iza = %g\n",iza); 
 
    n1y = fs1/sfrq; 
    n1x = n1/n1y+1; 
 
    f1order = calloc(n1y*osf,sizeof(int)); 
    for(i=0;i chanklen) { 
	  toberead = chanklen-sumread; 
	} 
 
	nsmplread = fread(rawinbuf,1,bps*nch*toberead,fpi); 
	nsmplread /= bps*nch; 
 
	switch(bps) 
	  { 
	  case 1: 
	    for(i = 0; i < nsmplread * nch; i++) 
	      inbuf[nch * inbuflen + i] = 
		(1 / (REAL)0x7f) * ((REAL)((unsigned char *)rawinbuf)[i]-128); 
	    break; 
 
	  case 2: 
#ifndef BIGENDIAN 
	    for(i=0;i= chanklen; 
 
	//nsmplwrt1 = ((rp-1)*sfrq/fs1+inbuflen-n1x)*dfrq*osf/sfrq; 
	//if (nsmplwrt1 > n2b2) nsmplwrt1 = n2b2; 
	nsmplwrt1 = n2b2; 
 
 
	// apply stage 1 filter 
 
	ip = &inbuf[((sfrq*(rp-1)+fs1)/fs1)*nch]; 
 
	s1p_backup = s1p; 
	ip_backup  = ip; 
	osc_backup = osc; 
 
	for(ch=0;ch 0 ? outbuf[i] : -outbuf[i]; 
	      peak = peak < f ? f : peak; 
	      ((REAL *)rawoutbuf)[i] = outbuf[i]; 
	    } 
	} else { 
	  switch(dbps) 
	    { 
	    case 1: 
	      { 
		REAL gain2 = gain * (REAL)0x7f; 
		ch = 0; 
 
		for(i=0;i>= 8; 
		    ((char *)rawoutbuf)[i*2+1] = s & 255; 
#endif 
		    ch++; 
		    if (ch == nch) ch = 0; 
		  } 
	      } 
	    break; 
 
	    case 3: 
	      { 
		REAL gain2 = gain * (REAL)0x7fffff; 
		ch = 0; 
 
		for(i=0;i>= 8; 
		    ((char *)rawoutbuf)[i*3+1] = s & 255; s >>= 8; 
		    ((char *)rawoutbuf)[i*3+2] = s & 255; 
 
		    ch++; 
		    if (ch == nch) ch = 0; 
		  } 
	      } 
	    break; 
 
#if 0 
	    case 4: 
	      { 
		REAL gain2 = gain * (REAL)0x7fffffff; 
		ch = 0; 
 
		for(i=0;i>= 8; 
		    ((char *)rawoutbuf)[i*4+1] = s & 255; s >>= 8; 
		    ((char *)rawoutbuf)[i*4+2] = s & 255; s >>= 8; 
		    ((char *)rawoutbuf)[i*4+3] = s & 255; 
 
		    ch++; 
		    if (ch == nch) ch = 0; 
		  } 
	      } 
	    break; 
#endif 
	    } 
	} 
 
	if (!init) { 
	  if (ending) { 
	    if ((double)sumread*dfrq/sfrq+2 > sumwrite+nsmplwrt2) { 
	      if (dbps*nch*nsmplwrt2 != fwrite(rawoutbuf,1,dbps*nch*nsmplwrt2,fpo)) { 
		fprintf(stderr,"fwrite error(1).\n"); 
		abort(); 
	      } 
	      sumwrite += nsmplwrt2; 
	    } else { 
	      if (dbps*nch*(floor((double)sumread*dfrq/sfrq)+2-sumwrite) !=  
		  fwrite(rawoutbuf,1,dbps*nch*(floor((double)sumread*dfrq/sfrq)+2-sumwrite),fpo)) { 
		fprintf(stderr,"fwrite error(2).\n"); 
		abort(); 
	      } 
	      break; 
	    } 
	  } else { 
	    if (dbps*nch*nsmplwrt2 != fwrite(rawoutbuf,1,dbps*nch*nsmplwrt2,fpo)) { 
	      fprintf(stderr,"fwrite error(3).\n"); 
	      abort(); 
	    } 
	    sumwrite += nsmplwrt2; 
	  } 
	} else { 
	  int pos,len; 
	  if (nsmplwrt2 < delay) { 
	    delay -= nsmplwrt2; 
	  } else { 
	    if (ending) { 
	      if ((double)sumread*dfrq/sfrq+2 > sumwrite+nsmplwrt2-delay) { 
		if (dbps*nch*(nsmplwrt2-delay) != fwrite(rawoutbuf+dbps*nch*delay,1,dbps*nch*(nsmplwrt2-delay),fpo)) { 
		  fprintf(stderr,"fwrite error(4).\n"); 
		  abort(); 
		} 
		sumwrite += nsmplwrt2-delay; 
	      } else { 
		if (dbps*nch*(floor((double)sumread*dfrq/sfrq)+2-sumwrite-delay) != 
		    fwrite(rawoutbuf+dbps*nch*delay,1,dbps*nch*(floor((double)sumread*dfrq/sfrq)+2-sumwrite-delay),fpo)) { 
		  fprintf(stderr,"fwrite error(5).\n"); 
		  abort(); 
		} 
		break; 
	      } 
	    } else { 
	      if (dbps*nch*(nsmplwrt2-delay) != fwrite(rawoutbuf+dbps*nch*delay,1,dbps*nch*(nsmplwrt2-delay),fpo)) { 
		fprintf(stderr,"fwrite error(6).\n"); 
		abort(); 
	      } 
	      sumwrite += nsmplwrt2-delay; 
	      init = 0; 
	    } 
	  } 
	} 
 
	{ 
	  int ds = (rp-1)/(fs1/sfrq); 
 
	  assert(inbuflen >= ds); 
 
	  memmove(inbuf,inbuf+nch*ds,sizeof(REAL)*nch*(inbuflen-ds)); 
	  inbuflen -= ds; 
	  rp -= ds*(fs1/sfrq); 
	} 
 
	if ((spcount++ & 7) == 7) showprogress((double)sumread / chanklen); 
      } 
  } 
 
  showprogress(1); 
 
  free(f1order); 
  free(f1inc); 
  free(stage1[0]); 
  free(stage1); 
  free(stage2); 
  free(fft_ip); 
  free(fft_w); 
  for(i=0;i chanklen) { 
	  toberead = chanklen-sumread; 
	} 
 
	nsmplread = fread(rawinbuf,1,bps*nch*toberead,fpi); 
	nsmplread /= bps*nch; 
 
	switch(bps) 
	  { 
	  case 1: 
	    for(i = 0; i < nsmplread * nch; i++) 
	      inbuf[nch * inbuflen + i] = 
		(1 / (REAL)0x7f) * ((REAL)((unsigned char *)rawinbuf)[i]-128); 
	    break; 
 
	  case 2: 
#ifndef BIGENDIAN 
	    for(i=0;i= chanklen; 
 
	rps_backup = rps; 
	s2p_backup = s2p; 
 
	for(ch=0;ch 0 ? outbuf[i] : -outbuf[i]; 
	      peak = peak < f ? f : peak; 
	      ((REAL *)rawoutbuf)[i] = outbuf[i]; 
	    } 
	} else { 
	  switch(dbps) 
	    { 
	    case 1: 
	      { 
		REAL gain2 = gain * (REAL)0x7f; 
		ch = 0; 
 
		for(i=0;i>= 8; 
		    ((char *)rawoutbuf)[i*2+1] = s & 255; 
#endif 
 
		    ch++; 
		    if (ch == nch) ch = 0; 
		  } 
	      } 
	    break; 
 
	    case 3: 
	      { 
		REAL gain2 = gain * (REAL)0x7fffff; 
		ch = 0; 
 
		for(i=0;i>= 8; 
		    ((char *)rawoutbuf)[i*3+1] = s & 255; s >>= 8; 
		    ((char *)rawoutbuf)[i*3+2] = s & 255; 
 
		    ch++; 
		    if (ch == nch) ch = 0; 
		  } 
	      } 
	    break; 
 
#if 0 
	    case 4: 
	      { 
		REAL gain2 = gain * (REAL)0x7fffffff; 
		ch = 0; 
 
		for(i=0;i>= 8; 
		    ((char *)rawoutbuf)[i*4+1] = s & 255; s >>= 8; 
		    ((char *)rawoutbuf)[i*4+2] = s & 255; s >>= 8; 
		    ((char *)rawoutbuf)[i*4+3] = s & 255; 
 
		    ch++; 
		    if (ch == nch) ch = 0; 
		  } 
	      } 
	    break; 
#endif 
	    } 
	} 
 
	if (!init) { 
	  if (ending) { 
	    if ((double)sumread*dfrq/sfrq+2 > sumwrite+nsmplwrt2) { 
	      if (dbps*nch*nsmplwrt2 != fwrite(rawoutbuf,1,dbps*nch*nsmplwrt2,fpo)) { 
	      } 
	      sumwrite += nsmplwrt2; 
	    } else { 
	      fwrite(rawoutbuf,1,dbps*nch*(floor((double)sumread*dfrq/sfrq)+2-sumwrite),fpo); 
	      break; 
	    } 
	  } else { 
	    fwrite(rawoutbuf,1,dbps*nch*nsmplwrt2,fpo); 
	    sumwrite += nsmplwrt2; 
	  } 
	} else { 
	  int pos,len; 
	  if (nsmplwrt2 < delay) { 
	    delay -= nsmplwrt2; 
	  } else { 
	    if (ending) { 
	      if ((double)sumread*dfrq/sfrq+2 > sumwrite+nsmplwrt2-delay) { 
		fwrite(rawoutbuf+dbps*nch*delay,1,dbps*nch*(nsmplwrt2-delay),fpo); 
		sumwrite += nsmplwrt2-delay; 
	      } else { 
		fwrite(rawoutbuf+dbps*nch*delay,1,dbps*nch*(floor((double)sumread*dfrq/sfrq)+2-sumwrite-delay),fpo); 
		break; 
	      } 
	    } else { 
	      fwrite(rawoutbuf+dbps*nch*delay,1,dbps*nch*(nsmplwrt2-delay),fpo); 
	      sumwrite += nsmplwrt2-delay; 
	      init = 0; 
	    } 
	  } 
	} 
 
	{ 
	  int ds = (rp2-1)/(fs2/fs1); 
 
	  if (ds > n1b2) ds = n1b2; 
 
	  for(ch=0;ch>= 8; 
	  buf[1] = s & 255; 
	  fwrite(buf,sizeof(char),2,fpo); 
	  break; 
	case 3: 
	  f *= 0x7fffff; 
	  s = dither ? do_shaping(f,&peak,dither,ch) : RINT(f); 
	  buf[0] = s & 255; s >>= 8; 
	  buf[1] = s & 255; s >>= 8; 
	  buf[2] = s & 255; 
	  fwrite(buf,sizeof(char),3,fpo); 
	  break; 
#if 0 
	case 4: 
	  f *= 0x7fffffff; 
	  s = dither ? do_shaping(f,&peak,dither,ch) : RINT(f); 
	  buf[0] = s & 255; s >>= 8; 
	  buf[1] = s & 255; s >>= 8; 
	  buf[2] = s & 255; s >>= 8; 
	  buf[3] = s & 255; 
	  fwrite(buf,sizeof(char),4,fpo); 
	  break; 
#endif 
	}; 
      } else { 
	REAL p = f > 0 ? f : -f; 
	peak = peak < p ? p : peak; 
	fwrite(&f,sizeof(REAL),1,fpo); 
      } 
 
      ch++; 
      if (ch == nch) ch = 0; 
      sumread++; 
 
      if ((sumread & 0x3ffff) == 0) showprogress((double)sumread / (chanklen*nch)); 
    } 
 
  showprogress(1); 
 
  return peak; 
} 
 
int extract_int(unsigned char *buf) 
{ 
#ifndef BIGENDIAN 
  return *(int *)buf; 
#else 
  return ((int)buf[0]) | (((int)buf[1]) << 8) |  
    (((int)buf[2]) << 16) | (((int)((char *)buf)[3]) << 24); 
#endif 
} 
 
unsigned int extract_uint(unsigned char *buf) 
{ 
#ifndef BIGENDIAN 
  return *(int *)buf; 
#else 
  return ((unsigned int)buf[0]) | (((unsigned int)buf[1]) << 8) |  
    (((unsigned int)buf[2]) << 16) | (((unsigned int)((char *)buf)[3]) << 24); 
#endif 
} 
 
short extract_short(unsigned char *buf) 
{ 
#ifndef BIGENDIAN 
  return *(short *)buf; 
#else 
  return ((short)buf[0]) | (((short)((char *)buf)[1]) << 8); 
#endif 
} 
 
void bury_int(unsigned char *buf,int i) 
{ 
#ifndef BIGENDIAN 
  *(int *)buf = i; 
#else 
  buf[0] = i & 0xff; i >>= 8; 
  buf[1] = i & 0xff; i >>= 8; 
  buf[2] = i & 0xff; i >>= 8; 
  buf[3] = i & 0xff; 
#endif 
} 
 
void bury_uint(unsigned char *buf,unsigned int i) 
{ 
#ifndef BIGENDIAN 
  *(int *)buf = i; 
#else 
  buf[0] = i & 0xff; i >>= 8; 
  buf[1] = i & 0xff; i >>= 8; 
  buf[2] = i & 0xff; i >>= 8; 
  buf[3] = i & 0xff; 
#endif 
} 
 
void bury_short(unsigned char *buf,short s) 
{ 
#ifndef BIGENDIAN 
  *(short *)buf = s; 
#else 
  buf[0] = s & 0xff; s >>= 8; 
  buf[1] = s & 0xff; 
#endif 
} 
 
int fread_int(FILE *fp) 
{ 
#ifndef BIGENDIAN 
  int ret; 
  fread(&ret,4,1,fp); 
 
  return ret; 
#else 
  unsigned char buf[4]; 
  fread(&buf,1,4,fp); 
  return extract_int(buf); 
#endif 
} 
 
unsigned int fread_uint(FILE *fp) 
{ 
#ifndef BIGENDIAN 
  unsigned int ret; 
  fread(&ret,4,1,fp); 
 
  return ret; 
#else 
  unsigned char buf[4]; 
  fread(&buf,1,4,fp); 
  return extract_uint(buf); 
#endif 
} 
 
int fread_short(FILE *fp) 
{ 
#ifndef BIGENDIAN 
  short ret; 
  fread(&ret,2,1,fp); 
  return ret; 
#else 
  unsigned char buf[2]; 
  fread(&buf,1,2,fp); 
  return extract_short(buf); 
#endif 
} 
 
void fwrite_int(FILE *fp,int i) 
{ 
#ifndef BIGENDIAN 
  fwrite(&i,4,1,fp); 
#else 
  unsigned char buf[4]; 
  bury_int(buf,i); 
  fwrite(&buf,1,4,fp); 
#endif 
} 
 
void fwrite_uint(FILE *fp,unsigned int i) 
{ 
#ifndef BIGENDIAN 
  fwrite(&i,4,1,fp); 
#else 
  unsigned char buf[4]; 
  bury_uint(buf,i); 
  fwrite(&buf,1,4,fp); 
#endif 
} 
 
void fwrite_short(FILE *fp,short s) 
{ 
#ifndef BIGENDIAN 
  fwrite(&s,2,1,fp); 
#else 
  unsigned char buf[4]; 
  bury_int(buf,s); 
  fwrite(&buf,1,2,fp); 
#endif 
} 
 
int main(int argc,char **argv) 
{ 
  char *sfn,*dfn,*tmpfn=NULL; 
  FILE *fpi,*fpo,*fpt; 
  int twopass,normalize,dither,pdf,samp; 
  int nch,bps; 
  unsigned int length; 
  int sfrq,dfrq,dbps; 
  double att,peak,noiseamp; 
  int i,j; 
 
  // parse command line options 
 
  dfrq = -1; 
  att = 0; 
  dbps = -1; 
  twopass = 0; 
  normalize = 0; 
  dither = 0; 
  pdf = 0; 
  noiseamp = 0.18; 
 
  for(i=1;i 4) { 
	    fprintf(stderr,"unrecognized dither type : %s\n",argv[i+1]); 
	    exit(-1); 
	  } 
	  i++; 
	} else dither = -1; 
	continue; 
      } 
 
      if (strcmp(argv[i],"--pdf") == 0) { 
	char *endptr; 
	pdf = strtol(argv[i+1],&endptr,10); 
	if (*endptr == '\0') { 
	  if (pdf < 0 || pdf > 2) { 
	    fprintf(stderr,"unrecognized p.d.f. type : %s\n",argv[i+1]); 
	    exit(-1); 
	  } 
	  i++; 
	} else { 
	  fprintf(stderr,"unrecognized p.d.f. type : %s\n",argv[i+1]); 
	  exit(-1); 
	} 
 
	noiseamp = strtod(argv[i+1],&endptr); 
	if (*endptr == '\0') { 
	  i++; 
	} else { 
	  static double presets[] = {0.7,0.9,0.18}; 
	  noiseamp = presets[pdf]; 
	} 
 
	continue; 
      } 
 
      if (strcmp(argv[i],"--quiet") == 0) { 
	quiet = 1; 
	continue; 
      } 
 
      if (strcmp(argv[i],"--tmpfile") == 0) { 
	tmpfn = argv[++i]; 
	continue; 
      } 
 
#ifndef HIGHPREC 
      if (strcmp(argv[i],"--profile") == 0) { 
	if (strcmp(argv[i+1],"fast") == 0) { 
	  AA = 96; 
	  DF = 8000; 
	  FFTFIRLEN = 1024; 
	} else if (strcmp(argv[i+1],"standard") == 0) { 
	  /* nothing to do */ 
	} else { 
	  fprintf(stderr,"unrecognized profile : %s\n",argv[i+1]); 
	  exit(-1); 
	} 
	i++; 
	continue; 
      } 
#else 
      if (strcmp(argv[i],"--profile") == 0) { 
	fprintf(stderr,"Warning : --profile option is ignored.\n"); 
	i++; 
	continue; 
      } 
#endif 
 
      fprintf(stderr,"unrecognized option : %s\n",argv[i]); 
      exit(-1); 
    } 
 
#ifndef HIGHPREC 
  if (!quiet) printf("Shibatch sampling rate converter version " VERSION "\n\n"); 
#else 
  if (!quiet) printf("Shibatch sampling rate converter version " VERSION "(high precision)\n\n"); 
#endif 
 
  if (argc-i != 2) {usage(); exit(-1);} 
 
  sfn = argv[i]; 
  dfn = argv[i+1]; 
 
  fpi = fopen(sfn,"rb"); 
 
  if (!fpi) {fprintf(stderr,"cannot open input file.\n"); exit(-1);} 
 
  /* read wav header */ 
 
  { 
    unsigned char ibuf[576*2*2]; 
    short word; 
    int dword; 
 
    if (getc(fpi) != 'R') fmterr(1); 
    if (getc(fpi) != 'I') fmterr(1); 
    if (getc(fpi) != 'F') fmterr(1); 
    if (getc(fpi) != 'F') fmterr(1); 
 
    dword = fread_int(fpi); 
 
    if (getc(fpi) != 'W') fmterr(2); 
    if (getc(fpi) != 'A') fmterr(2); 
    if (getc(fpi) != 'V') fmterr(2); 
    if (getc(fpi) != 'E') fmterr(2); 
    if (getc(fpi) != 'f') fmterr(2); 
    if (getc(fpi) != 'm') fmterr(2); 
    if (getc(fpi) != 't') fmterr(2); 
    if (getc(fpi) != ' ') fmterr(2); 
 
    dword = fread_int(fpi); 
    fread(ibuf,dword,1,fpi); 
 
    if (extract_short(&ibuf[0]) != 1) { 
      fprintf(stderr,"Error: Only PCM is supported.\n"); 
      exit(-1); 
    } 
    nch = extract_short(&ibuf[2]); 
    sfrq = extract_int(&ibuf[4]); 
    bps = extract_int(&ibuf[8]); 
    if ((int)bps % sfrq*nch != 0) fmterr(4); 
 
    bps /= sfrq*nch; 
 
    for(;;) 
      { 
	char buf[4]; 
	buf[0] = getc(fpi); 
	buf[1] = getc(fpi); 
	buf[2] = getc(fpi); 
	buf[3] = getc(fpi); 
	length = fread_uint(fpi); 
	if (buf[0] == 'd' && buf[1] == 'a' && buf[2] == 't' && buf[3] == 'a') break; 
	if (feof(fpi)) break; 
	fseek(fpi,length,SEEK_CUR); 
      } 
    if (feof(fpi)) { 
      fprintf(stderr,"Couldn't find data chank\n"); 
      exit(-1); 
    } 
  } 
 
  if (bps != 1 && bps != 2 && bps != 3 && bps != 4) { 
    fprintf(stderr,"Error : Only 8bit, 16bit, 24bit and 32bit PCM are supported.\n"); 
    exit(-1); 
  } 
 
  if (dbps == -1) { 
    if (bps != 1) dbps = bps; 
    else dbps = 2; 
    if (dbps == 4) dbps = 3; 
  } 
 
  if (dfrq == -1) dfrq = sfrq; 
 
  if (dither == -1) { 
    if (dbps < bps) { 
      if (dbps == 1) dither = 4; else dither = 3; 
    } else { 
      dither = 1; 
    } 
  } 
 
  if (!quiet) { 
    const char *dtype[] = { 
      "none","no noise shaping","triangular spectral shape","ATH based noise shaping","ATH based noise shaping(less amplitude)" 
    }; 
    const char *ptype[] = { 
      "rectangular","triangular","gaussian" 
    }; 
    printf("frequency : %d -> %d\n",sfrq,dfrq); 
    printf("attenuation : %gdB\n",att); 
    printf("bits per sample : %d -> %d\n",bps*8,dbps*8); 
    printf("nchannels : %d\n",nch); 
    printf("length : %d bytes, %g secs\n",length,(double)length/bps/nch/sfrq); 
    if (dither == 0) { 
      printf("dither type : none\n"); 
    } else { 
      printf("dither type : %s, %s p.d.f, amp = %g\n",dtype[dither],ptype[pdf],noiseamp); 
    } 
    printf("\n"); 
  } 
 
  if (twopass) { 
    if (tmpfn) { 
      fpt = fopen(tmpfn,"w+b"); 
    } else { 
      fpt = tmpfile(); 
    } 
    if (!fpt) {fprintf(stderr,"cannot open temporary file.\n"); exit(-1);} 
  } 
 
  fpo = fopen(dfn,"wb"); 
 
  if (!fpo) {fprintf(stderr,"cannot open output file.\n"); exit(-1);} 
 
  /* generate wav header */ 
 
  { 
    short word; 
    int dword; 
 
    fwrite("RIFF",4,1,fpo); 
    dword = 0; 
    fwrite_int(fpo,dword); 
 
    fwrite("WAVEfmt ",8,1,fpo); 
    dword = 16; 
    fwrite_int(fpo,dword); 
    word = 1; 
    fwrite_short(fpo,word); /* format category, PCM */ 
    word = nch; 
    fwrite_short(fpo,word); /* channels */ 
    dword = dfrq; 
    fwrite_int(fpo,dword); /* sampling rate */ 
    dword = dfrq*nch*dbps; 
    fwrite_int(fpo,dword); /* bytes per sec */ 
    word = dbps*nch; 
    fwrite_short(fpo,word); /* block alignment */ 
    word = dbps*8; 
    fwrite_short(fpo,word); /* bits per sample */ 
 
    fwrite("data",4,1,fpo); 
    dword = 0; 
    fwrite_int(fpo,dword); 
  } 
 
#if 0 
  { 
    int i,j; 
 
    for(i=0;i<=M;i++) 
      { 
	fact[i] = 1; 
	for(j=1;j<=i;j++) fact[i] *= j; 
      } 
  } 
#endif 
 
  if (dither) { 
    int min,max; 
    if (dbps == 1) {min = -0x80; max = 0x7f;} 
    if (dbps == 2) {min = -0x8000; max = 0x7fff;} 
    if (dbps == 3) {min = -0x800000; max = 0x7fffff;} 
    if (dbps == 4) {min = -0x80000000; max = 0x7fffffff;} 
 
    samp = init_shaper(dfrq,nch,min,max,dither,pdf,noiseamp); 
  } 
 
  if (twopass) { 
    REAL gain; 
    int ch=0; 
    unsigned int fptlen,sumread; 
 
    if (!quiet) printf("Pass 1\n"); 
 
    if (normalize) { 
      if (sfrq < dfrq) peak = upsample(fpi,fpt,nch,bps,sizeof(REAL),sfrq,dfrq,1,length/bps/nch,twopass,dither); 
      else if (sfrq > dfrq) peak = downsample(fpi,fpt,nch,bps,sizeof(REAL),sfrq,dfrq,1,length/bps/nch,twopass,dither); 
      else peak = no_src(fpi,fpt,nch,bps,sizeof(REAL),1,length/bps/nch,twopass,dither); 
    } else { 
      if (sfrq < dfrq) peak = upsample(fpi,fpt,nch,bps,sizeof(REAL),sfrq,dfrq,pow(10,-att/20),length/bps/nch,twopass,dither); 
      else if (sfrq > dfrq) peak = downsample(fpi,fpt,nch,bps,sizeof(REAL),sfrq,dfrq,pow(10,-att/20),length/bps/nch,twopass,dither); 
      else peak = no_src(fpi,fpt,nch,bps,sizeof(REAL),pow(10,-att/20),length/bps/nch,twopass,dither); 
    } 
 
    if (!quiet) printf("\npeak : %gdB\n",20*log10(peak)); 
 
    if (!normalize) { 
      if (peak < pow(10,-att/20)) peak = 1; 
      else peak *= pow(10,att/20); 
    } else peak *= pow(10,att/20); 
 
    if (!quiet) printf("\nPass 2\n"); 
     
    if (dither) { 
      switch(dbps) 
	{ 
	case 1: 
	  gain = (normalize || peak >= (0x7f-samp)/(double)0x7f) ? 1/peak*(0x7f-samp) : 1/peak*0x7f; 
	  break; 
	case 2: 
	  gain = (normalize || peak >= (0x7fff-samp)/(double)0x7fff) ? 1/peak*(0x7fff-samp) : 1/peak*0x7fff; 
	  break; 
	case 3: 
	  gain = (normalize || peak >= (0x7fffff-samp)/(double)0x7fffff) ? 1/peak*(0x7fffff-samp) : 1/peak*0x7fffff; 
	  break; 
#if 0 
	case 4: 
	  gain = (normalize || peak >= (0x7fffffff-samp)/(double)0x7fffffff) ? 1/peak*(0x7fffffff-samp) : 1/peak*0x7fffffff; 
	  break; 
#endif 
	} 
    } else { 
      switch(dbps) 
	{ 
	case 1: 
	  gain = 1/peak * 0x7f; 
	  break; 
	case 2: 
	  gain = 1/peak * 0x7fff; 
	  break; 
	case 3: 
	  gain = 1/peak * 0x7fffff; 
	  break; 
#if 0 
	case 4: 
	  gain = 1/peak * 0x7fffffff; 
	  break; 
#endif 
	} 
    } 
    randptr = 0; 
 
    setstarttime(); 
 
    fptlen = ftell(fpt) / sizeof(REAL); 
    sumread = 0; 
 
    fseek(fpt,0,SEEK_SET); 
    for(;;) 
      { 
	REAL f; 
	int s; 
 
	if (fread(&f,sizeof(REAL),1,fpt) == 0) break; 
	f *= gain; 
	sumread++; 
 
	switch(dbps) { 
	case 1: 
	  { 
	    unsigned char buf[1]; 
	    s = dither ? do_shaping(f,&peak,dither,ch) : RINT(f); 
 
	    buf[0] = s + 128; 
 
	    fwrite(buf,sizeof(char),1,fpo); 
	  } 
	  break; 
	case 2: 
	  { 
	    char buf[2]; 
	    s = dither ? do_shaping(f,&peak,dither,ch) : RINT(f); 
 
	    buf[0] = s & 255; s >>= 8; 
	    buf[1] = s & 255; 
 
	    fwrite(buf,sizeof(char),2,fpo); 
	  } 
	  break; 
	case 3: 
	  { 
	    char buf[3]; 
	    s = dither ? do_shaping(f,&peak,dither,ch) : RINT(f); 
 
	    buf[0] = s & 255; s >>= 8; 
	    buf[1] = s & 255; s >>= 8; 
	    buf[2] = s & 255; 
 
	    fwrite(buf,sizeof(char),3,fpo); 
	  } 
	  break; 
#if 0 
	case 4: 
	  { 
	    char buf[4]; 
	    s = dither ? do_shaping(f,&peak,dither,ch) : RINT(f); 
 
	    buf[0] = s & 255; s >>= 8; 
	    buf[1] = s & 255; s >>= 8; 
	    buf[2] = s & 255; s >>= 8; 
	    buf[3] = s & 255; 
 
	    fwrite(buf,sizeof(char),4,fpo); 
	  } 
	  break; 
#endif 
	} 
 
	ch++; 
	if (ch == nch) ch = 0; 
 
	if ((sumread & 0x3ffff) == 0) showprogress((double)sumread / fptlen); 
      } 
    showprogress(1); 
    if (!quiet) printf("\n"); 
    fclose(fpt); 
    if (tmpfn != NULL) { 
      if (remove(tmpfn)) 
	fprintf(stderr,"Failed to remove %s\n",tmpfn); 
    } 
  } else { 
    if (sfrq < dfrq) peak = upsample(fpi,fpo,nch,bps,dbps,sfrq,dfrq,pow(10,-att/20),length/bps/nch,twopass,dither); 
    else if (sfrq > dfrq) peak = downsample(fpi,fpo,nch,bps,dbps,sfrq,dfrq,pow(10,-att/20),length/bps/nch,twopass,dither); 
    else peak = no_src(fpi,fpo,nch,bps,dbps,pow(10,-att/20),length/bps/nch,twopass,dither); 
    if (!quiet) printf("\n"); 
  } 
 
  if (dither) { 
    quit_shaper(nch); 
  } 
 
  if (!twopass && peak > 1) { 
    if (!quiet) printf("clipping detected : %gdB\n",20*log10(peak)); 
  } 
 
  { 
    short word; 
    int dword; 
    int len; 
 
    fseek(fpo,0,SEEK_END); 
    len = ftell(fpo); 
 
    fseek(fpo,4,SEEK_SET); 
    dword = len-8; 
    fwrite_int(fpo,dword); 
 
    fseek(fpo,40,SEEK_SET); 
    dword = len-44; 
    fwrite_int(fpo,dword); 
  } 
 
  exit(0); 
}