ftp.nice.ch/pub/next/unix/music/clm.d.tar.gz#/cmus.c

This is cmus.c in view mode; [Download] [Up]

/* adjunct to cmus.lisp 
 *
 * the simple cases, both arithmetic and unit-generator, are expanded in-line.
 *
 */

#include <stdio.h>
#include <math.h>
#include "cmus.h"

extern int clm_read(int fd, char *buf, int n);
extern int clm_write(int fd, char *buf, int n);
extern short clm_short(short n);
extern int clm_int(int n);
extern int clm_create(char *name);
extern long clm_seek(int tfd, long offset, int origin);

/* io file structure reflected in datai */
#define io_fd 0
#define io_chans 1
#define io_size 2
#define io_beg 3
#define io_end 4
#define io_bufsiz 5
#define io_data_start 6
#define io_data_end 7
#define io_open_index 8
#define io_dat_A 9
#define io_dat_B 10
#define io_dat_C 11
#define io_dat_D 12
#define io_dir 13
#define io_loc 14
#define io_hdr_end 15

#define c_aref_block 0
#define c_aref_type 1
#define c_aref_size 2
#define c_aref_dims 3
#define c_aref_dim_list_adr 4

#define io_in_f 0
#define io_out_f 1

/* from io.c */
extern cwritez(int fd, int num);
extern crdmono(int fd, int beg, int end, int *buf);
extern cwrtmono(int fd, int beg, int end, int *unpackedbuf);
extern crdstereo(int fd, int beg, int end, int *bufa, int *bufb);
extern cwrtstereo(int fd, int beg, int end, int *unpackedbufa, int *unpackedbufb);
extern crdquad(int fd, int beg, int end, int *bufa, int *bufb, int *bufc, int *bufd);
extern cwrtquad(int fd, int beg, int end, int *unpackedbufa, int *unpackedbufb, int *unpackedbufc, int *unpackedbufd);

/* io support functions translated from io.lisp */

void c_check_stream_indices (int *io)
{
  if ((io[io_data_start] < 0) || (io[io_data_end] < 0)) 
    {
      printf("file buffer index is negative! -- will try to fix it..."); fflush(stdout);
      if (io[io_data_start] < 0) io[io_data_start] = 0; else io[io_data_end] = 0;
    }
}

void c_put_data (int *io)
{
  if (io[io_fd] != -1)               /* -1 -> closed file */
    {
      c_check_stream_indices(io);
      switch (io[io_chans])
	{
	case 0: printf("aw good grief -- no IO buffers!"); fflush(stdout); break; 
	case 1: cwrtmono(io[io_fd],io[io_data_start],io[io_data_end],(int *)io[io_dat_A]); break;
	case 2: cwrtstereo(io[io_fd],io[io_data_start],io[io_data_end],(int *)io[io_dat_A],(int *)io[io_dat_B]); break;
	case 4: cwrtquad(io[io_fd],io[io_data_start],io[io_data_end],(int *)io[io_dat_A],
			 (int *)io[io_dat_B],(int *)io[io_dat_C],(int *)io[io_dat_D]); break;
	}
    }
}

void c_get_data (int *io, int size)
{
  if (size > io[io_bufsiz]) 
    {
      printf("input request is too big: %d", size); fflush(stdout); 
    }
  else
    {
      if (size == 0)
	{
	  printf("get-data asked to read 0 bytes!?"); fflush(stdout); 
	}
      else
	{
	  c_check_stream_indices(io);
	  switch (io[io_chans])
	    {
	    case 0: printf("aw ferchrissake -- no IO channels!"); fflush(stdout); break; 
	    case 1: crdmono(io[io_fd],0,size-1,(int *)io[io_dat_A]); break;
	    case 2: crdstereo(io[io_fd],0,size-1,(int *)io[io_dat_A],(int *)io[io_dat_B]); break;
	    case 4: crdquad(io[io_fd],0,size-1,(int *)io[io_dat_A],
			    (int *)io[io_dat_B],(int *)io[io_dat_C],(int *)io[io_dat_D]); break;
	    }
	}
    }
}

int c_sample_position(int *io, int loc) 
{
  clm_seek(io[io_fd],io[io_hdr_end]+(2*io[io_chans]*loc),0);
  return(loc);
}

void c_io_bufclr (int *io, int beg)
{
  if (io[io_dat_A] == 0) {printf("attempt to clear deallocated IO buffer"); fflush(stdout);} 
  else
    {
      int i,end;
      int *j;
      end=io[io_bufsiz];
      j=((int *)io[io_dat_A]);
      for (i=beg; i<end;i++) j[i]=0;
      if (io[io_chans] > 1)
	{
	  j = (int *)(io[io_dat_B]);
	  for (i=beg; i<end;i++) j[i]=0;
	  if (io[io_chans] > 2)
	    {
	      j = (int *)(io[io_dat_C]);
	      for (i=beg; i<end;i++) j[i]=0;
	      j = (int *)(io[io_dat_D]);
	      for (i=beg; i<end;i++) j[i]=0;
	    }
	}
    }
}

void c_flush_snd(int *io)
{
  if ((io[io_fd] != -1) &&
      (io[io_dir] != io_in_f) &&
      (io[io_data_end] != 0) &&
      (io[io_data_start] != io[io_data_end]))
    {
      if (io[io_data_end] > io[io_bufsiz])
	{
	  printf("data end indication in IO buffer is too big: %d > %d",io[io_data_end],io[io_bufsiz]); fflush(stdout);
	}
      else
	{
	  c_sample_position(io,io[io_beg]+io[io_data_start]);
	  c_put_data(io);
	  io[io_data_start] = io[io_data_end];
	  if (io[io_size] < (io[io_beg] + io[io_data_end])) io[io_size] = (io[io_beg] + 1 + io[io_data_end]);
	}
    }
}

void clm_file_reset(int loc0, int *io)
{
  /* called when loc is outside the current in-core frame for the file pointed to by io */
  /* equivalent to the io.lisp function file-check + read-in */

  int file_end,bytes,loc;
  loc = loc0;
  if (io[io_dir] != io_in_f) c_flush_snd(io);
  if ((loc < io[io_beg]) && ((loc + (int)(.9*io[io_bufsiz])) > io[io_beg]))
    {
      if ((loc + 10) > io[io_beg]) loc -= (int)(.75*io[io_bufsiz]);
      if (loc < 0) loc = 0;
      if (io[io_chans] == 1) loc = (2 * (int)(loc / 2));
    }
  file_end = io[io_size];
  bytes = file_end - loc;
  if (bytes > io[io_bufsiz]) bytes=io[io_bufsiz];
  if (bytes < 0)                   /* tried to access beyond current end of file */
    {
      if (io[io_dir] == io_in_f) {printf("attempt to read past EOF"); fflush(stdout);}
      else
	{
	  c_io_bufclr(io,0);
	  bytes = io[io_bufsiz];
	  io[io_data_start] = 0;
	  io[io_data_end] = 0;
	  clm_seek(io[io_fd],0,2);  /* go to end of file */
	  switch (io[io_chans])
	    {
	    case 4: cwritez(io[io_fd],2*(loc-file_end)); io[io_beg]=loc; break;
	    case 2: cwritez(io[io_fd],loc-file_end); io[io_beg]=loc; break;
	    case 1: cwritez(io[io_fd],(int)((loc-file_end)/2)); if ((loc%2)==0) io[io_beg]=loc; else io[io_beg]=loc-1; break;
	    }
	}
    }
  else /* bytes is positive or 0 */
    {
      io[io_beg] = c_sample_position(io,loc);
      if (bytes > 0) c_get_data(io,bytes);
      if (bytes < io[io_bufsiz]) c_io_bufclr(io,bytes);
      io[io_data_start] = 0;
      io[io_data_end] = 0;
      if (io[io_dir] == io_in_f)
	{
	  int bufend,filbytes;
	  bufend = io[io_bufsiz]-1;
	  filbytes = file_end-io[io_beg]-1;
	  if (filbytes < bufend) bufend = filbytes;
	  if (bufend > 0) io[io_data_end] = bufend;
	}
    }
  io[io_end] = io[io_beg]+io[io_bufsiz]-1;
  /* io[io_data_start] = io[io_data_end]; */
  io[io_loc] = (loc0-io[io_beg]);
}

void clm_full_file_reset(int loc, int *io)
{
  /* update data_end before calling clm_file_reset -- we are about to write at loc, so loc-1 is last output */
  /* dangerous assumption!? */
  int lim;
  lim = ((loc - io[io_beg]) - 1);
  if (lim >= io[io_bufsiz]) lim = (io[io_bufsiz]-1);
  if (lim > io[io_data_end]) io[io_data_end] = lim;
  clm_file_reset(loc,io);
}


void c_newline(void) {printf("\n"); fflush(stdout);} 


/* sine wave via table lookup -- normally faster than the built-in sin call */
/* on the Mac, however, the goddam table won't fit */

#ifndef MAC
static float c_sine_table[514];
static float c_sine_table_scaler = (float)(512.0/two_pi);
static int c_sine_table_is_inited = 0;
#endif

c_init_sine (void)
{
#ifndef MAC
  int i;
  float phase,incr;
  if (c_sine_table_is_inited == 0)
    {
      incr = (float)1.0/c_sine_table_scaler;
      for (i=0,phase=0.0;i<514;i++,phase+=incr)
	{
	  c_sine_table[i]=(float)sin((double)phase);
	}
      c_sine_table_is_inited = 1;
    }
#endif
}

float c_sin_lookup(float phase)
{
#ifndef MAC
  /* in-coming phase is in radians, can be anything */
  /* use of sin here was noticeably slower on the 68040 */
  float mag_phase,frac;
  int index;
  float *sint;
  if (phase < 0.0)
    {
      index=(int)(phase*inverse_pi);
      phase+=(float)(((1-index)*(two_pi)));
    }
  mag_phase = phase*c_sine_table_scaler;
  index = (int)mag_phase;
  frac = mag_phase - index;
  index = index%512;         /* % is mod */
  sint = c_sine_table+index;
  return ((*sint + (frac*(*(sint+1)-*sint))));
#else
  return(sin(phase));
#endif
}

#ifndef MAC
/* from Cmix -- appears to be more reliable than the 20 bit form */
static long randx = 1;
#define inverse_rscl .000061035156

float c_frandom(float amp)
{
  int i = ((randx = randx*1103515245 + 12345)>>16) & 077777;
  return(amp * (((float)i)*inverse_rscl - 1.0));
}
#else
float c_frandom(float amp)
{
  int i;
  i = rand();
  return(amp * ((float)(i/16384.0) - 1.0));
}
#endif


void c_fft_window(float *rl, float *win, int size) {int i; for (i=0;i<size;i++) rl[i]=(rl[i]*win[i]);}
void c_clear_block(float *rl, int size) {int i; for (i=0;i<size;i++) rl[i]=0.0;}
void c_blti(int *arr0, int beg, int *arr1, int len) {int i,k; for (i=0,k=beg;i<len;i++,k++) arr0[k]=arr1[i];}
void c_bltf(float *arr0, int beg, float *arr1, int len) {int i,k; for (i=0,k=beg;i<len;i++,k++) arr0[k]=arr1[i];}

double c_gcd(double a, double b)
{
  /* everything double here to mimic main c math libraries */
  double rem;
  if (a == b) return(a);
  else
    {
      if (a>b)
	{
	  rem = fmod(a,b);
	  if (rem == 0.0) return(b);
	  else return(c_gcd(b,rem));
	}
      else return(c_gcd(b,a));
    }
}

double c_lcm(double a, double b)
{
  return((a*b)/c_gcd(a,b));
}


float c_table_interp (float *fn, float xx, int len)
{
  int int_part;
  float frac_part,val0,val1;

  if (xx < 0.0)
    {
      int_part = (int)(xx/len);
      xx += ((1-int_part)*len);
    }
  int_part = (int)(xx);  
  frac_part = xx-(float)int_part;
  if (int_part >= len) int_part = (int_part%len);
  if (frac_part == 0.0) return(fn[int_part]);
  val0 = fn[int_part];
  if (int_part == (len-1)) val1 = fn[0];
  else val1 = fn[int_part+1];
  return (val0 + (frac_part*(val1-val0)));
}

float c_table_lookup (int *tbl, float *datar, float fm)
{
  float *wave;
  float val,freq,phase;
  int size;
  freq = datar[tbl[0]];
  phase = datar[tbl[0]+1];
  wave = (float *)(datar+tbl[1]);
  size = tbl[1+c_aref_size];

  val = c_table_interp(wave,phase,size);
  phase += (freq + fm);
  while (phase >= size) phase -= size;
  while (phase < 0.0) phase += size;
  datar[tbl[0]+1] = phase;
  return(val);
}



float c_direct_flt (int m, float input, float *flt_a, float *flt_b, float *flt_d)
{
  float xout;
  int j;
  xout = 0.0;
  flt_d[0] = input;
  for (j=m;j>=1;j--) 
    {
      xout += flt_d[j]*flt_b[j];
      flt_d[0] -= flt_a[j]*flt_d[j];
      flt_d[j] = flt_d[j-1];
    }
  return(xout+(flt_d[0]*flt_b[0]));
}

float c_lattice_flt (int m, float input, float *flt_a, float *flt_b, float *flt_d)
{
  float xout,inp;
  int i,j;
  xout = 0.0;
  inp = input;
  for (i=m-1,j=m;i>=0;i--,j--)
    {
      inp -= flt_a[i]*flt_d[i];
      flt_d[j] = flt_d[i] + (flt_a[i]*inp);
      xout += flt_d[j]*flt_b[j];
    }
  flt_d[0] = inp;
  return(xout + (inp*flt_b[0]));
}

float c_ladder_flt (int m, float input, float so, float *flt_a, float *flt_b, float *flt_c, float *flt_d)
{
  float xout,inp;
  int i;
  xout = 0.0;
  inp = input;
  for (i=m-1;i>=0;i--)
    {
      flt_d[i+1] = (inp*flt_a[i]) + (flt_d[i]*flt_c[i]);
      inp = (inp*flt_c[i]) - (flt_d[i]*flt_a[i]);
      xout += flt_d[i+1]*flt_b[i+1];
    }
  flt_d[0] = inp;
  return(so*(xout+(flt_d[0]*flt_b[0])));
}


int c_y_or_n_p (void)
{
  int c,i;
  char s[256];
  /* question string has already gone out */
 LOOP:
  i=0;
  while ((i<256) && ((c = getchar()) != '\n') && (c != EOF)) {s[i]=c; i++;}
  if ((s[0] == 'y') || (s[0] == 'Y')) return(1);
  if ((s[0] == 'n') || (s[0] == 'N')) return(0);
  printf("Type \"y\" for yes or \"n\" for no. "); fflush(stdout); 
  goto LOOP;
}
 
int c_yes_or_no_p (void)
{
  int c,i;
  char s[256];
  /* question string has already gone out */
 LOOP:
  i=0;
  while ((i<256) && ((c = getchar()) != '\n') && (c != EOF)) {s[i]=c; i++;}
  if (((s[0] == 'y') || (s[0] == 'Y')) && ((s[1] == 'e') || (s[1] == 'E')) && ((s[2] == 's') || (s[2] == 'S')) && (i == 3)) return(1);
  if (((s[0] == 'n') || (s[0] == 'N')) && ((s[1] == 'o') || (s[1] == 'O')) && (i == 2)) return(0);
  printf("Type \"yes\" or \"no\". "); fflush(stdout); 
  goto LOOP;

}

/* fft and convolution of real data in zero-based arrays */
/* plus code to tie into clm's convolve generator */


shuffle (float* rl, float* im, int n)
{
  /* bit reversal */

  int i,m,j;
  float tempr,tempi;
  j=0;
  for (i=0;i<n;i++)
    {
      if (j>i)
	{
	  tempr = rl[j];
	  tempi = im[j];
	  rl[j] = rl[i];
	  im[j] = im[i];
	  rl[i] = tempr;
	  im[i] = tempi;
	}
      m = n>>1;
      while ((m>=2) && (j>=m))
	{
	  j -= m;
	  m = m>>1;
	}
      j += m;
    }
}

c_fft (float* rl, float* im, int n, int isign, int ipow)
{
  /* standard fft: real part in rl, imaginary in im,        */
  /* ipow = ceiling (log n / log 2), isign=1 fft, =-1 ifft. */
  /* rl and im are zero-based.                              */
  /*                                                        */
  /* oddly enough, the integer version (using integer ops   */
  /* and "block floating point" scaling) was much slower,   */
  /* and splitting out the no-ops (twiddle factors==0 etc)  */
  /* made no difference at all.                             */

  int mmax,j,pow,prev,lg,i,ii,jj;
  float wrs,wis,tempr,tempi;
  double wr,wi,theta,wtemp,wpr,wpi;

  shuffle(rl,im,n);
  mmax = 2;
  prev = 1;
  pow = n*0.5;
  theta = (one_pi*isign);
  for (lg=0;lg<ipow;lg++)
    {
      wpr = cos(theta);
      wpi = sin(theta);
      wr = 1.0;
      wi = 0.0;
      for (ii=0;ii<prev;ii++)
	{
	  wrs = (float) wr;
	  wis = (float) wi;
	  i = ii;
	  j = ii + prev;
	  for (jj=0;jj<pow;jj++)
	    {
	      tempr = wrs*rl[j] - wis*im[j];
	      tempi = wrs*im[j] + wis*rl[j];
	      rl[j] = rl[i] - tempr;
	      im[j] = im[i] - tempi;
	      rl[i] += tempr;
	      im[i] += tempi;
	      i += mmax;
	      j += mmax;
	    }
	  wtemp = wr;
	  wr = (wr*wpr) - (wi*wpi);
	  wi = (wi*wpr) + (wtemp*wpi);
	}
      pow = pow*0.5;
      prev = mmax;
      theta = theta*0.5;
      mmax = mmax*2;
    }
}
 
convolve (float* rl1, float* rl2, int n, int ipow)
{
  /* convolves two real arrays.                                           */
  /* rl1 and rl2 are assumed to be set up correctly for the convolution   */
  /* (that is, rl1 (the "signal") is zero-padded by length of             */
  /* (non-zero part of) rl2 and rl2 is stored in wrap-around order)       */
  /* We treat rl2 as the imaginary part of the first fft, then do         */
  /* the split, scaling, and (complex) spectral multiply in one step.     */
  /* result in rl1                                                        */

  int j,n2,nn2;
  float rem,rep,aim,aip,invn;

  c_fft(rl1,rl2,n,1,ipow);
  
  n2=n*0.5;
  invn = 0.25/n;
  rl1[0] = ((rl1[0]*rl2[0])/n);
  rl2[0] = 0.0;

  for (j=1;j<=n2;j++)
    {
      nn2 = n-j;
      rep = (rl1[j]+rl1[nn2]);
      rem = (rl1[j]-rl1[nn2]);
      aip = (rl2[j]+rl2[nn2]);
      aim = (rl2[j]-rl2[nn2]);

      rl1[j] = invn*(rep*aip + aim*rem);
      rl1[nn2] = rl1[j];
      rl2[j] = invn*(aim*aip - rep*rem);
      rl2[nn2] = -rl2[j];
    }
  
  c_fft(rl1,rl2,n,-1,ipow);
}



/* now functions to read/write linear 16-bit 1/2 channel sound files converting to/from floats */
floadarray (float* rl0, int rlbeg, int beg, int end, int step, char* data)
{
  char *k;
  float *x;
  float rscl;
  int i,sample;
  rscl = 1.0/32678.0;
  for (i=beg,k=data+beg,x=rl0+rlbeg;i<end;i++,x++,k+=step)
    {
      sample = ( (((*k)<<8)&0xff00) | ((*(k+1))&0xff));
      if ((*k) & 0x8000) sample |= 0xffff0000;
      *x = (float) sample*rscl;
    }
}

fwritearray(int chan, int wrds, float* rl0, int rlbeg, char* buffer)
{
  char *k;
  float *x;
  int i,sample;
  for (i=0,k=buffer,x=rl0+rlbeg;i<wrds;i++,x++,k+=2)
    {
      sample = (int) 32768*(*x);
      *(k+1)=(sample&0xff);
      *k=((sample>>8)&0xff);
    }
  clm_write(chan,buffer,(wrds*2));
}


/* convolve either all at once (ipow==allpow) or by overlap-add */
/* filter is assumed to be set up correctly (i.e. in wrap-around order if that is what is wanted) */
/* but in any case, we have to re-set it up in the new (assured-to-be-power-of-2) buffer */

void c_convolve (char *fname, 
           int filec, int filehdr, int filesize,
           int filterc, int filterhdr, int filtersize,
           int start, int fftsize, int ipow, int allpow, int samps, int fullsize, int chans, int chan)
{
#ifndef AKCL
  extern void write_next_header (int chan, int srate, int chans, int loc, int siz, int format, char *comment, int len);
#endif
#ifdef MAC
  #pragma unused(filesize,chan) 
#endif

  float *rl0,*rl1,*temprl,*tempout;
  char *buffer;
  int tempfile,i,readsize,startloc,j,step,fsize,filterwrds,sampctr,fft2,fft4;

  fft2 = (int) fftsize*.5;
  fft4 = (int) fft2*.5;
  step = 2;
  if (chans == 2) step = 4;
  startloc = filehdr + start*step;
  readsize = fftsize*step;
  if (allpow != ipow) readsize = (int) readsize*.5;
  fsize = 2*fullsize;

  /* get to start point in the two sound files */
  lseek(filec,startloc,0);
  lseek(filterc,filterhdr,0);

  rl0 = (float *)calloc(fftsize,sizeof(float));
  rl1 = (float *)calloc(fftsize,sizeof(float));
  buffer = (char *)calloc(readsize,sizeof(char));

  /* read in the filter data */
  clm_read(filterc,buffer,filtersize*2);
  floadarray(rl1,0,0,filtersize,2,buffer);

  /* make sure filter (i.e. impulse response) is in wrap around order in the new array */
  if (filtersize != fftsize)
    {
      filterwrds = (int) filtersize*.5;
      for (i=(fftsize-1),j=(filtersize-1);j>filterwrds;i--,j--) 
	{
	  rl1[i] = rl1[j]; 
	  rl1[j] = 0.0;
	}
    }

  if (allpow != ipow)
    {
      /* save filter samples -- rl1 will be clobbered by the convolution */
      temprl = (float *)calloc(fftsize,sizeof(float));
      for (i=0;i<fftsize;i++) temprl[i] = rl1[i];
      
      /* if overlap-add (since ipow != allpow) create buffer to hold intermediate results */
      tempout = (float *)calloc(fftsize,sizeof(float));
    }

  /* need file to hold convolution output */
  tempfile=clm_create(fname);
  write_next_header(tempfile,22050,1,28,fsize,1,"",0);


  /* split out the easy case (where only one convolution is performed) */
  if (allpow == ipow)
    {
      clm_read(filec,buffer,readsize);
      floadarray(rl0,0,2*(chans-1),fftsize,step,buffer);
      convolve(rl0,rl1,fftsize,ipow);
      fwritearray(tempfile,fftsize,rl0,0,buffer);
    }
  else
    {
      /* the messy case -- here we loop through the signal doing overlap-adds */
      for (sampctr=0;sampctr<samps;sampctr+=fft2)
	{
	  clm_read(filec,buffer,readsize);
	  for (i=0;i<fft4;i++) rl0[i] = 0.0;
	  floadarray(rl0,fft4,2*(chans-1),fft2,step,buffer);
	  for (i=fft2+fft4;i<fftsize;i++) rl0[i] = 0.0;
	  if (sampctr != 0)
	    {
	      for (i=0;i<fftsize;i++) rl1[i] = temprl[i];
	    }
	  convolve(rl0,rl1,fftsize,ipow);
	  for (i=0;i<fftsize;i++) tempout[i] += rl0[i];
	  if (sampctr != 0)
	    {
	      fwritearray(tempfile,fft2,tempout,0,buffer);
	    }
	  else
	    {
	      fwritearray(tempfile,fft4,tempout,fft4,buffer);
	    }
	  for (i=0,j=fft2;i<fft2;i++,j++)
	    {
	      tempout[i] = tempout[j];
	      tempout[j] = 0.0;
	    }
	}     
      fwritearray(tempfile,fft4,tempout,fft2,buffer);

      free(temprl);
      free(tempout);
    }
		
  close(tempfile);

  free(rl0);
  free(rl1);
  free(buffer);
}


#define env_current_value 0
#define env_rate 1
#define env_base 2
#define env_offset 3
#define env_scaler 4
#define env_power 5
#define env_init_y 6
#define env_init_power 7

#define env_type 0
#define env_index 1
#define env_top 2
#define env_pass 3
#define env_end 4
#define env_restart 5

void c_env_restart (float *ef, int *ei, float *data)
{
  int diff,i;
  ef[env_current_value] = ef[env_init_y];
  ef[env_power] = ef[env_init_power];
  ef[env_rate] = 0.0;
  ei[env_index] = 0;
  diff = (ei[env_pass] - ei[env_restart]);
  ei[env_restart] = ei[env_pass];
  ei[env_end] += diff;
  for (i=0;i<ei[env_top];i+=2) data[i] += diff;
}

#ifdef MAC

float c_env (float *ef, int *ei, float *data)
{
  int loc,passpt;
  float val;
  loc = ei[env_index];
  val = ef[env_current_value];
  passpt = data[loc];  /* believe it or not, (int) here, which goddam well ought to be a no-op causes the  */
                       /* the result to be 4 times the true value as an integer!  There are lots more bugs */
                       /* along these lines in MPW C -- surely the worst implementation of C on the planet */
  if ((loc < ei[env_top]) && (ei[env_pass] >= passpt))
    {
      ef[env_rate] = data[loc+1];
      ei[env_index] += 2;
    }
  ei[env_pass] += 1;
  if (ei[env_pass]<=ei[env_end])
    {
      if (ei[env_type] == 0)
	{  /* line-segment or step envelope */
	  if (ef[env_base] != 0.0) 
	    ef[env_current_value] += ef[env_rate];
	  else ef[env_current_value] = ef[env_rate];
	}
      else /* exponential envelope */
	{
	  if (ef[env_rate] != 0.0)
	    {
	      ef[env_power] += ef[env_rate];
 	      ef[env_current_value] = (ef[env_offset] + (ef[env_scaler] * (exp(ef[env_base]*ef[env_power]) - 1.0)));
	    }
	}
    }
  return(val);
}

#endif



#ifndef __LITTLE_ENDIAN__
#ifndef MAC

/* exp from Jos Vermaseren */
/* on the NeXT this code is about 4 times as fast as the equivalent call on the libm version of exp */
/* on little endian machines this code dies because it assumes big endian IEEE format */

double jv_exp(double x)
{
/*
	routine for the evaluation of the exp (IEEE)
	Method:
		1: y = x/log(2)  -> exp(x) = 2^y;
		2: z = n+y, -0.5 <= y < 0.5
		3: exp(x) = exp(z*log(2))*2^n
	For the last series we need only terms till 13!
	Routine made by J.A.M.Vermaseren 20-apr-1992
*/
	double y,z,scr;
	long n;
	int m,sflag;
	y = x*(1.0/0.6931471805599453094);
	if ( y < 0 ) { sflag = 1; y = -y; }
	else sflag = 0;
	scr = y + 0.5;
	n = *((long *)(&scr));
	m = (n >> 20) - 0x3FF;
	if ( m > 7 ) {
		fprintf(stderr,"Overflow in exponent of %e\n",x);
		exit(-1);
	}
	n &= 0xFFFFF;
	n |= 0x100000;
	n >>= (20-m);
	z = (y - n)*0.6931471805599453094;
	if ( sflag ) { n = -n; z = -z; }
	scr = 0.99999999999999999693+z*(
          0.99999999999999999850+z*(
          0.50000000000000183922+z*(
          0.16666666666666701804+z*(
          0.04166666666648804594+z*(
          0.00833333333330984930+z*(
          0.00138888889523274996+z*(
          0.00019841269908532560+z*(
          0.00002480148546912669+z*(
          0.00000275572255877329+z*(
          0.00000027632644397330+z*(
          0.00000002511466084085)))))))))));
	n <<= 20;
	*((long *)(&scr)) += n;
	return(scr);
}
#else
  double jv_exp(double x) {return(exp(x));}
#endif
#else
  double jv_exp(double x) {return(exp(x));}
#endif



/* RUN-BLOCK */

#define blk_loc 0
#define blk_siz 1

#define blk_ctr 0

float c_run_block (int *blk, float *fblk, float *buf)
{
  int loc,i,j;
  float val;
  loc = blk[blk_loc];
  if (loc < blk[blk_siz]) val = buf[loc];
  else val = 0.0;
  loc++;
  if (loc >= fblk[blk_ctr])
    {
      if (loc < blk[blk_siz])
	{
	  for (i=0;i<loc;i++) buf[i]=0.0;
	  for (i=0,j=loc;j<blk[blk_siz];i++,j++) 
	    {
	      buf[i]=buf[j];
	      buf[j]=0.0;
	    }
	}
      else
	{
	  for (i=0;i<blk[blk_siz];i++) buf[i]=0.0;
	}
    fblk[blk_ctr] -= loc;
    blk[blk_loc] = 0;
    }
  else blk[blk_loc] = loc;
  return(val);
}

void c_base_run_block (int *blk, float *fblk, float *buf)
{
  int loc,i,j;
  loc = blk[blk_loc];
  if (loc < blk[blk_siz])
    {
      for (i=0;i<loc;i++) buf[i]=0.0;
      for (i=0,j=loc;j<blk[blk_siz];i++,j++) 
	{
	  buf[i]=buf[j];
	  buf[j]=0.0;
	}
    }
  else
    {
      for (i=0;i<blk[blk_siz];i++) buf[i]=0.0;
    }
  fblk[blk_ctr] -= loc;
  blk[blk_loc] = 0;
}



/* READIN */

float c_readin (int *rd, int *io)
{
  float val;
  if ((rd[0] >= 0) && (rd[0] < io[io_size]))
    {
      if ((rd[0] < io[io_beg]) || (rd[0] > io[io_end])) clm_file_reset(rd[0],io);
      val = (float)(_sndflt_ * (((int *)(io[io_dat_A+rd[2]]))[rd[0] - io[io_beg]]));
    }
  else val = 0.0;
  rd[0] += rd[1];
  return(val);
}



/* SRC */

float sinc(float x)
{
  float pi_x;
  if (x == 0.0)
    return 1.0;
  else
    {
      pi_x = x * one_pi;
      return(c_sin_lookup(pi_x) / pi_x);
    }
}

float smoothed_table (float *data, float x, int size)
{
  int i;
  float sum;
  if (size == 1)
    return x;
  else
    {
      size -= 1;
      for (i=0;i<size;i++) data[i]=data[i+1];
      data[size]=x;
      sum = 0.5*(data[0]+x);
      for (i=1;i<size;i++) sum += data[i];
      return (sum/(float)size);
    }
}

#define src_x 0
#define src_incr 1
#define src_offset 2

#define src_left 0
#define src_right 1
#define src_width 2
#define src_use_filter 3
#define src_filter_size 4

float c_src(int *rd, int *rio, float *srf, int *sri, float *data, float *filt, float fm)
{
  float sum,start_x;
  int loc,lim,fsx,i,k,right;
  right=sri[src_right];
  lim=2*sri[src_width];
  start_x=srf[src_x]+srf[src_offset]-sri[src_width];
  fsx=0;
  loc=0;
  if (start_x > 1.0) fsx=(int)start_x;
  if ((sri[src_left] < fsx) || ((fsx+lim) > right))
    {
      if (fsx <= right)
	{
	  for (i=fsx,k=(lim-(right-fsx));i<=right;i++,k++) 
	    {
	      data[loc]=data[k];
	      loc++;
	    }
	}
      else
	if (right != -1) rd[0] += (fsx-right); /* just flush these samples */
      if (sri[src_use_filter] != 0)
	{
	  for (i=loc;i<=lim;i++) data[i]=smoothed_table(filt,c_readin(rd,rio),sri[src_filter_size]);
	}
      else
	for (i=loc;i<=lim;i++) data[i]=c_readin(rd,rio);
    }
  sri[src_left]=fsx;
  sri[src_right]=fsx+lim;
  start_x=(sri[src_left]-srf[src_x])-srf[src_offset];
  sum = 0.0;
  for (i=0;i<=lim;i++)
    {
      sum += data[i]*sinc(start_x);
      start_x+=1.0; /* bizarre -- this is implicit in the mus.lisp loop */
                    /* the 56k version windows the sinc with a hamming window */
    }
  srf[src_x] += (fm+srf[src_incr]);
  if (srf[src_x] > 1024.0) {srf[src_offset] += 1024.0; srf[src_x] -= 1024.0;}
  return(sum);
}



/* EXPAND */

#define spd_len 0
#define spd_rmp 1
#define spd_in_spd 2
#define spd_out_spd 3
#define spd_cur_in 4
#define spd_cur_out 5
#define spd_s20 6
#define spd_s50 7
#define spd_ctr 8

#define spd_amp 0

void shift_block_back (int *spidat, float *b)
{
  int start,end,i,j;
  start=spidat[spd_cur_out];
  end=spidat[spd_len]-start;
  for (i=0,j=start;i<end;i++,j++) b[i]=b[j];
  for (i=end;i<spidat[spd_len];i++) b[i]=0.0;
}

void add_one_segment (int *rd, int *spidat, float *spfdat, int *rio, float *b)
{
  float curamp,incr;
  int i,k,steady_time,ramp_time;
  curamp = 0.0;
  ramp_time = spidat[spd_rmp];
  incr = spfdat[spd_amp] / (float)ramp_time;
  steady_time = spidat[spd_len] - (2*ramp_time);
  k=0;
  for (i=0;i<ramp_time;i++,k++)
    {
      b[k] += (curamp * c_readin(rd,rio));
      curamp += incr;
    }
  for (i=0;i<steady_time;i++,k++)
    {
      b[k] += (curamp * c_readin(rd,rio));
    }
  for (i=0;i<ramp_time;i++,k++)
    {
      b[k] += (curamp * c_readin(rd,rio));
      curamp -= incr;
    }
}  

void set_expansion_triggers (int *rddat, int *spidat)
{
  spidat[spd_ctr] -= spidat[spd_cur_out];
  spidat[spd_cur_out] = (spidat[spd_out_spd] + (int)c_frandom((float)spidat[spd_s20]));
  rddat[0] = spidat[spd_cur_in] + (int)c_frandom((float)spidat[spd_s50]);
  spidat[spd_cur_in] += spidat[spd_in_spd];
}

float c_spd (int *rddat, int *spidat, float *spfdat, int *io, float *b)
{
  float val;
  val=b[spidat[spd_ctr]];
  spidat[spd_ctr]++;
  if (spidat[spd_ctr] >= spidat[spd_cur_out])
    {
      shift_block_back(spidat,b);
      add_one_segment(rddat,spidat,spfdat,io,b);
      set_expansion_triggers(rddat,spidat);
    }
  return(val);
}



      
/* FFT-FILTER */

#define fftf_siz 0
#define fftf_hop 1
#define fftf_half_siz 2
#define fftf_pow 3

void readin_data (int *rddat, int *fftdat, int *rio, float *datar, float *datai)
{
  int start,amount,i,k;
  float scaler;
  start=(int)(fftdat[fftf_siz]/4);
  amount=fftdat[fftf_half_siz];
  scaler = 1.0/(float)fftdat[fftf_siz];
  for (i=0,k=start+amount;i<start;i++,k++)
    {
      datar[i]=0.0;
      datai[i]=0.0;
      datar[k]=0.0;
      datai[k]=0.0;
    }
  if ((rio != NULL) && (rio[io_fd] != -1))
    {
      for (k=0,i=start;k<amount;k++,i++)
	{
	  datar[i]=(scaler * c_readin(rddat,rio));
	  datai[i]=0.0;
	}
    }
  else
    {
      for (k=0,i=start;k<amount;k++,i++) 
	{
	  datar[i]=c_frandom(scaler);
	  datai[i]=0.0;
	}
    }
}

void apply_envelope_and_shift(int *fftdat, float *datar, float *datai, float *fenv)
{
  int i,k,lim,mid;
  float val;
  lim=fftdat[fftf_siz]-1;
  mid=fftdat[fftf_half_siz];
  for (i=0,k=lim;i<mid;i++,k--)
    {
      val=fenv[i];
      datar[i]=(datar[i]*val);
      datai[i]=(datai[i]*val);
      datar[k]=(datar[k]*val);
      datai[k]=(datai[k]*val);
    }
}

void readout_first_data(int *fftdat, float *runbuf, float *datar)
{
  int start,amount,i,k;
  start=(int)(fftdat[fftf_siz]/4);
  amount=start*3;
  for (i=0,k=start;i<amount;i++,k++)
    {
      runbuf[i]=datar[k];
    }
}

void readout_data(int *fftdat, float *runbuf, float *datar)
{
  int stop,i,k;
  stop=fftdat[fftf_hop];
  for (i=0;i<stop;i++) runbuf[i] += datar[i];
  for (i=0,k=stop;i<stop;i++,k++) runbuf[k] = datar[k];
}

float c_fft_filter (int *rddat, int *io, int *runblk, float *fblk, int *fftdat,
		   float *runbuf, float *datar, float *datai, float *fenv)
{
  if (runblk[blk_loc] == 0)
    {
      readin_data(rddat,fftdat,io,datar,datai);
      c_fft(datar,datai,fftdat[fftf_siz],1,fftdat[fftf_pow]);
      apply_envelope_and_shift(fftdat,datar,datai,fenv);
      c_fft(datar,datai,fftdat[fftf_siz],-1,fftdat[fftf_pow]);
      if (fftdat[fftf_hop] < 0)
	{
	  fftdat[fftf_hop] = fftdat[fftf_half_siz];
	  fblk[blk_ctr] = (float)(fftdat[fftf_siz]/4);
	  readout_first_data(fftdat,runbuf,datar);
	}
      else
	{
	  readout_data(fftdat,runbuf,datar);
	  fblk[blk_ctr] = (float)fftdat[fftf_hop];
	}
    }
  return(c_run_block(runblk,fblk,runbuf));
}




load_one_sine (float partial, float amp, float *table, int table_size, float phase)
{
  float angle,freq;
  int i;
  if (amp != 0.0)
    {
      freq = (partial*two_pi)/((float)table_size);
      for (i=0,angle=phase;i<table_size;i++,angle+=freq)
	table[i]+=amp*sin(angle);
    }
}

float c_convolve_or_readin (int *rddat, int *io, int *runblk, float *fblk, int *fftdat,
			    float *runbuf, float *datar, float *datai, float *filtr, float *filti)
{
  /* can be just a readin call if two very large files were convolved into a temp */
  if (filtr == NULL)
    {
      return(c_readin(rddat,io));
    }
  else
    {
      if (runblk[blk_loc] == 0)
	{
	  float scale,temp;
	  int i;
	  readin_data(rddat,fftdat,io,datar,datai);
	  c_fft(datar,datai,fftdat[fftf_siz],1,fftdat[fftf_pow]);
	  scale = (float)(1.0/fftdat[fftf_siz]);
	  for (i=0;i<fftdat[fftf_siz];i++)
	    {
	      temp=datar[i];
	      datar[i]=scale*((datar[i]*filtr[i]) - (datai[i]*filti[i]));
	      datai[i]=scale*((temp*filti[i]) + (datai[i]*filtr[i]));
	    }
	  c_fft(datar,datai,fftdat[fftf_siz],-1,fftdat[fftf_pow]);
	  if (fftdat[fftf_hop] < 0)
	    {
	      fftdat[fftf_hop] = fftdat[fftf_half_siz];
	      fblk[blk_ctr] = (float)(fftdat[fftf_siz]/4);
	      readout_first_data(fftdat,runbuf,datar);
	    }
	  else
	    {
	      readout_data(fftdat,runbuf,datar);
	      fblk[blk_ctr] = (float)fftdat[fftf_hop];
	    }
	}
      return(c_run_block(runblk,fblk,runbuf));
    }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.