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

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

#include <math.h>
#include <stdio.h>
#include <fcntl.h>


/* the following procedures are used to allocate and manage the IO buffers and huge delay lines  */
/* used in io.lisp and mus.lisp -- Lisp's garbage collector is not being very smart about these guys */
/* compiled cc io.c -c -O */

/* foreign function tie into clm is in c-io.lisp */

/* all data reads in clm go through clm_read and clm_write */
/* file opens are clm_open_read, clm_reopen_write, and clm_open_write */

#ifdef __LITTLE_ENDIAN__
  #include <architecture/byte_order.h>
  #include <sound/utilsound.h>
  int clm_write(int fd, char *buf, int n)
    {
      int bytes;
      /* SNDSwapHostToSound(buf,buf,(n>>1),1,3); */
      char *i,*j;
      char k;
      int nn;
      for (i=buf,j=(buf+1),nn=0;nn<n;nn+=2,i+=2,j+=2)
	{
	  k=*j;
	  *j = *i;
	  *i = k;
	}
      bytes = write(fd,buf,n);
      return(bytes);
    }
  short clm_short(short n) {return(NXSwapShort(n));}
  int clm_int(int n)       {return(NXSwapInt(n));}
#else
  int clm_write(int fd, char *buf, int n) {return(write(fd,buf,n));}
  short clm_short(short n)                {return(n);}
  int clm_int(int n)                      {return(n);}
#endif

/* for arbitrary sound data formats, we need clm_read, clm_seek as though they were 16-bit */
/* That is, lisp thinks all the data is 16-bit linear, but we provide read translations at the lowest level */

#include "sound_types.h"

/* open might not return a small integer */
#define FILE_DESCRIPTORS 128
#define BASE_FILE_DESCRIPTORS 64
static int clm_datum_format[FILE_DESCRIPTORS];
static int clm_datum_size[FILE_DESCRIPTORS];
static int clm_datum_location[FILE_DESCRIPTORS];
static int clm_files_ready = 0;
static int clm_files[BASE_FILE_DESCRIPTORS];

int convert_fd(int n)
{
  if (n<BASE_FILE_DESCRIPTORS)
    return(n);
  else
    {
      int i;
      for (i=0;i<BASE_FILE_DESCRIPTORS;i++)
	{
	  if (clm_files[i] == n) return(i+BASE_FILE_DESCRIPTORS);
	}
      return(-1);
    }
}

int open_clm_file (int tfd)
{
  int fd;
  if (tfd < BASE_FILE_DESCRIPTORS) return(tfd);
  if (clm_files_ready == 0)
    {
      for (fd=0;fd<BASE_FILE_DESCRIPTORS;fd++) clm_files[fd]=-1;
      clm_files_ready = 1;
    }
  for (fd=0;fd<BASE_FILE_DESCRIPTORS;fd++)
    {
      if (clm_files[fd] == -1)
	{
	  clm_files[fd] = tfd;
	  return(fd+BASE_FILE_DESCRIPTORS);
	}
    }
  return(-1);
}

void open_clm_file_descriptors (int tfd, int df, int ds, int dl)
{ /* transfers header info from functions in header.c back to us for reads here, in fft.c, and in merge.c */
  int fd;
  fd = open_clm_file(tfd);
  clm_datum_format[fd] = df;
  clm_datum_size[fd] = ds;
  clm_datum_location[fd] = dl;
}

void close_clm_file_descriptors(int tfd)
{
  int fd;
  fd = convert_fd(tfd);
  if (fd >= BASE_FILE_DESCRIPTORS)
    clm_files[fd-BASE_FILE_DESCRIPTORS] = -1;
}


long clm_seek(int tfd, long offset, int origin)
{
  int fd,siz;
  fd = convert_fd(tfd);
  siz = clm_datum_size[fd];
  if ((siz == 2) || (origin != 0))
    return(lseek(fd,offset,origin));
  else
    {
      int loc,true_loc,header_end;
      header_end = clm_datum_location[fd];
      loc = offset - header_end;
      switch (siz)
	{
	case 1: 
	  true_loc = lseek(fd,header_end+(loc>>1),origin);
	  /* now pretend we're still in 16-bit land and return where we "actually" are in that region */
	  /* that is, loc (in bytes) = how many (2-byte) samples into the file we want to go, return what we got */
	  return(header_end + ((true_loc - header_end)<<1));
	  break;
	case 3:
	  true_loc = lseek(fd,header_end+loc+(loc>>1),origin);
	  return(true_loc + ((true_loc - header_end)>>1));
	  break;
	case 4:
	  true_loc = lseek(fd,header_end+(loc<<1),origin);
	  return(header_end + ((true_loc - header_end)>>1));
	  break;
	case 8:
	  true_loc = lseek(fd,header_end+(loc<<2),origin);
	  return(header_end + ((true_loc - header_end)>>2));
	  break;
	}
    }
}

/* generated by SNDiMulaw on a NeXT -- see /usr/include/sound/mulaw.h */
static const short mulaw[256] = {
  -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, -23932, -22908, -21884, -20860, 
  -19836, -18812, -17788, -16764, -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, 
  -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, -7932, -7676, -7420, -7164, -6908, 
  -6652, -6396, -6140, -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, -3900, -3772, -3644, 
  -3516, -3388, -3260, -3132, -3004, -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, -1884, 
  -1820, -1756, -1692, -1628, -1564, -1500, -1436, -1372, -1308, -1244, -1180, -1116, -1052, -988, 
  -924, -876, -844, -812, -780, -748, -716, -684, -652, -620, -588, -556, -524, -492, -460, -428, 
  -396, -372, -356, -340, -324, -308, -292, -276, -260, -244, -228, -212, -196, -180, -164, -148, 
  -132, -120, -112, -104, -96, -88, -80, -72, -64, -56, -48, -40, -32, -24, -16, -8, 0, 32124, 31100, 
  30076, 29052, 28028, 27004, 25980, 24956, 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, 
  15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, 11900, 11388, 10876, 10364, 9852, 9340, 
  8828, 8316, 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, 5884, 5628, 5372, 5116, 4860, 4604, 
  4348, 4092, 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, 2876, 2748, 2620, 2492, 2364, 2236, 
  2108, 1980, 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, 1372, 1308, 1244, 1180, 1116, 1052, 
  988, 924, 876, 844, 812, 780, 748, 716, 684, 652, 620, 588, 556, 524, 492, 460, 428, 396, 372, 
  356, 340, 324, 308, 292, 276, 260, 244, 228, 212, 196, 180, 164, 148, 132, 120, 112, 104, 96, 
  88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0};

/* generated from toast_alaw.c */
static const short alaw[256] = {
  5120, -5376, 320, -336, 20480, -21504, 1280, -1344, 2560, -2688, 64, -80, 10240, -10752, 640, 
  -672, 7168, -7424, 448, -464, 28672, -29696, 1792, -1856, 3584, -3712, 192, -208, 14336, -14848, 
  896, -928, 4096, -4352, 256, -272, 16384, -17408, 1024, -1088, 2048, -2176, 0, -16, 8192, -8704, 
  512, -544, 6144, -6400, 384, -400, 24576, -25600, 1536, -1600, 3072, -3200, 128, -144, 12288, 
  -12800, 768, -800, 5632, -5888, 352, -368, 22528, -23552, 1408, -1472, 2816, -2944, 96, -112, 
  11264, -11776, 704, -736, 7680, -7936, 480, -496, 30720, -31744, 1920, -1984, 3840, -3968, 224, 
  -240, 15360, -15872, 960, -992, 4608, -4864, 288, -304, 18432, -19456, 1152, -1216, 2304, -2432, 
  32, -48, 9216, -9728, 576, -608, 6656, -6912, 416, -432, 26624, -27648, 1664, -1728, 3328, -3456, 
  160, -176, 13312, -13824, 832, -864, 5376, -5632, 336, -352, 21504, -22528, 1344, -1408, 2688, 
  -2816, 80, -96, 10752, -11264, 672, -704, 7424, -7680, 464, -480, 29696, -30720, 1856, -1920, 
  3712, -3840, 208, -224, 14848, -15360, 928, -960, 4352, -4608, 272, -288, 17408, -18432, 1088, 
  -1152, 2176, -2304, 16, -32, 8704, -9216, 544, -576, 6400, -6656, 400, -416, 25600, -26624, 1600, 
  -1664, 3200, -3328, 144, -160, 12800, -13312, 800, -832, 5888, -6144, 368, -384, 23552, -24576, 
  1472, -1536, 2944, -3072, 112, -128, 11776, -12288, 736, -768, 7936, -8192, 496, -512, 31744, 
  -32768, 1984, -2048, 3968, -4096, 240, -256, 15872, -16384, 992, -1024, 4864, -5120, 304, -320, 
  19456, -20480, 1216, -1280, 2432, -2560, 48, -64, 9728, -10240, 608, -640, 6912, -7168, 432, 
  -448, 27648, -28672, 1728, -1792, 3456, -3584, 176, -192, 13824, -14336, 864, -896};

#define CONVERT_BUF_SIZE 4096
static unsigned char convert_buf[CONVERT_BUF_SIZE];

int clm_read(int tfd, char *buf, long nbytes)
{
  /* read nbytes bytes into buf -- as though data was 16-bit linear -- include any needed conversions */
  int fd;

  fd = convert_fd(tfd);
  if (clm_datum_format[fd] == snd_16_linear)
    {
#ifdef __LITTLE_ENDIAN__
      /*
       * this is just a temporary stop-gap.  We need to figure out what the relation is between
       * the current processor and the data in the sound file and swap whenever that is indicated.
       * This also affects the read loops below for non-8 bit data.
       */
      int bytes; 
      bytes = read(fd,buf,nbytes); 
      /* SNDSwapSoundToHost(buf,buf,(bytes>>1),1,3); */
      /* This is causing clicks */
      {
	char *i,*j;
	char k;
	int nn;
	for (i=buf,j=(buf+1),nn=0;nn<bytes;nn+=2,i+=2,j+=2)
	  {
	    k = *j;
	    *j = *i;
	    *i = k;
	  }
      }
      return(bytes);
#else
      return(read(fd,buf,nbytes));
#endif
    }
  else
    {
      /* read in a buffer's worth, write to buf while converting */
      int bytes,i,j,k,n,total,lim,siz;
      short *m;
      unsigned char *jchar;
      float *jfloat;
      char *jbyte;
      long *jword;
      double *jdouble;

      siz = clm_datum_size[fd];
      switch (siz)
	{
	case 1: bytes = (nbytes>>1); break;
	case 2: bytes = nbytes; break;
	case 3: bytes = (nbytes+(nbytes>>1)); break;
	case 4: bytes = (nbytes<<1); break;
	case 8: bytes = (nbytes<<2); break;
	}
      total=0;
      for (i=0;i<bytes;i+=CONVERT_BUF_SIZE)
	{
	  k=bytes-i;
	  if (k>CONVERT_BUF_SIZE) k=CONVERT_BUF_SIZE;
	  n=read(fd,convert_buf,k);

	  switch (clm_datum_format[fd])
	    {
	    case snd_8_mulaw:   
 
	      for (j=0,jchar=convert_buf,m=(short *)(buf+total);j<n;j++,m++,jchar++) 
		(*m) = mulaw[*jchar];
	      break;

	    case snd_8_alaw:  
   
	      for (j=0,jchar=convert_buf,m=(short *)(buf+total);j<n;j++,m++,jchar++) 
		(*m) = alaw[*jchar];
	      break;

	    case snd_8_linear:  
 
	      for (j=0,jbyte=(char *)convert_buf,m=(short *)(buf+total);j<n;j++,m++,jbyte++) 
		(*m) = (short) ((*jbyte) << 8);
	      break;

	    case snd_8_unsigned: 

	      for (j=0,jchar=convert_buf,m=(short *)(buf+total);j<n;j++,m++,jchar++) 
		(*m) = (short) ((((int)(*jchar))-128) << 8);
	      break;

	    case snd_32_linear:  

	      lim = (n>>2);
	      for (j=0,jword=(long *)convert_buf,m=(short *)(buf+total);j<lim;j++,m++,jword++) 
		(*m) = (short) ((*jword) >> 16);
	      break;

	    case snd_24_linear:  

	      lim = ((n>>1)+(n>>2));
	      for (j=0,k=0,m=(short *)(buf+total);j<lim;j++,m++,k+=3)
		(*m) = (short) ((*((long *)(convert_buf+k))) >> 16); /* extra 8 because we're using (long *) -- low byte is garbage */
	      break;

	    case snd_32_float:  

	      lim = (n>>2);
	      for (j=0,jfloat=(float *)convert_buf,m=(short *)(buf+total);j<lim;j++,m++,jfloat++) 
		(*m) = (short) (32768.0*(*jfloat)); /* DAJ sez float files go from -1.0 to 1.0 */
	      break;

	    case snd_64_double:

	      lim = (n>>3);
	      for (j=0,jdouble=(double *)convert_buf,m=(short *)(buf+total);j<lim;j++,m++,jdouble++) 
		(*m) = (short) (32768.0*(*jdouble));
	      break;

	    }
	  
	  switch (siz)
	    {
	    case 1: total+=(n*2); break;
	    case 2: total+=n; break;
	    case 3: total+=((n>>2)+(n>>1)); break;
	    case 4: total+=(n>>1); break;
	    case 8: total+=(n>>2); break;
	    }
	}
      return(total);
    }
}


#ifndef MAC
int *makearray(len)
{
    int *ip;
    ip = (int *)calloc(len,sizeof(int));   /* returns NULL (i.e. 0) if fails */
    return ip;
}

freearray(int *ip)
{
    free(ip);
}
#endif

int setarray(int *arr, int i, int val)
{
    arr[i]=val;
    return val;
}

int getarray(int *arr, int i)
{
    return arr[i];
}

int incarray(int *arr, int i, int val)
{
   arr[i]+=val;
   return arr[i];
}


cleararray1(int beg, int end, int *arr)
{
    int *i,*last;
    last=arr+end;
    for (i=(arr+beg);i<=last;i++) *i=0;
}

clearchararray1(int beg, int end, char *arr)
{
    char *i,*last;
    last=arr+end;
    for (i=(arr+beg);i<=last;i++) *i=0;
}

int clm_open_read(char *arg) 
{
#ifndef MAC
  return(open (arg, O_RDONLY, 0));
#else
  return(open (arg, O_RDONLY));
#endif
}

int clm_open_write(char *arg)
{
  int fd;
#ifndef MAC
  if ((fd=open(arg,O_RDWR,0))==-1)
    fd=creat(arg,0666);
  else
    lseek(fd,0L,2);
#else
  if ((fd=open(arg,O_RDWR))==-1)
    fd=creat(arg);
  else
    lseek(fd,0L,2);
#endif
  return(fd);
}

int clm_create(char *arg)
{
#ifndef MAC
  return(creat(arg,0666));
#else
  return(creat(arg));
#endif
}

int clm_reopen_write(char *arg)
{
#ifndef MAC
  return(open(arg,O_RDWR,0));
#else
  return(open(arg,O_RDWR));
#endif
}

void clm_close(int fd)
{
  close_clm_file_descriptors(fd);
  close(fd);
}

int clm_true_file_length(char *arg)
{  /* called in headers.lisp and next.lisp for error checks */
    int fd;
    long int rtn;
#ifndef MAC
    fd = open(arg,O_RDONLY,0);
#else
    fd = open(arg,O_RDONLY);
#endif
    rtn = lseek(fd,0L,2);
    close(fd);
    return rtn;
}

#ifndef MAC
#define BUFLIM 512*1024           /* this should be 4 * file-buffer-size in defaults.lisp */
                                  /* or, if quad files are in use, 8 * file-buffer-size  */
#else
#define BUFLIM 16384              /* should be 4 * file-buffer-size in defaults.lisp */
#endif

/* static char charbuf[BUFLIM];  */    /* file I-O buffer */
/* doing it this way makes an enormous io.o file now      */
/* I guess the new c compiler statically allocates it in  */
/* the .o file, unlike the previous compiler.             */
/* Now I wonder whether it matters that we never release  */

#ifndef MAC
static char *charbuf;
static int char_ok = -1;

check_charbuf (void)
{
  if (char_ok == -1)
    charbuf = (char *)calloc((BUFLIM),sizeof(char)); 
  char_ok = 0;
}
#else
static char charbuf[BUFLIM];
check_charbuf (void)
{
}
#endif

int min (int x, int y) 
{
  if (x<y) return(x); 
  return(y); 
}

int ceiling (float x) 
{
  int y; 
  y=x; 
  if ((x-y)==0.0) 
    return(y); 
  return(y+1);
}


#ifndef MAC
int checked_write(int fd, char *buf, int chars)
{
  long lisp_call(int index);
  extern void perror(const char *);
  /* see /usr/include/sys/errno.h for actual errno values */

  if (clm_write(fd,buf,chars) != chars)
    {
      perror("clm");
#ifndef AKCL
      lisp_call(7);       /* see next56.lisp for the table of these constants -- 7=fatal write error */
#endif
      return -1;
    }
  return 0;
}
#else
int checked_write(int fd, char *buf, int chars)
{
  clm_write(fd,buf,chars);
  return 0;
}
#endif

cwritez(int fd, int num)
{
    int i,k,lim,curnum;
    check_charbuf();
    lim=num*4;
    k=ceiling(lim/(BUFLIM));
    curnum=min(lim,BUFLIM);
    clearchararray1(0,curnum-1,charbuf);
    for (i=0;i<=k;i++)
      {
	checked_write(fd,charbuf,curnum);
	lim=lim-(BUFLIM);
	curnum=min(lim,BUFLIM);
      }
}


/* assume data is stored as follows (32 bit words here, 8 bit bytes):
/*    high low high low
/*    A1       A2
/*    A1       B1
*/

crdmono(int fd, int beg, int end, int *buf)
{
    int *i,*last;
    short *ii;
    int num,rtn;
    check_charbuf();
    num=(end-beg+1)*2;   /* file is packed, two samples per word */
    rtn=clm_read(fd,charbuf,num);
    last=buf+beg+(rtn>>1);
    for (i=(buf+beg),ii=(short *)charbuf;i<last;i++,ii++)
      {
	*i = (int) (*ii);
      }
    if (rtn<num) 
      {
	last=buf+end;
	for (;i<=last;i++)
	  *i = 0;
      }
}

cwrtmono(int fd, int beg, int end, int *unpackedbuf)
{
    int *i,*last;
    short *j;
    int num,lim;
    check_charbuf();
    lim=(end-beg+1);
    num=lim*2;
    last=unpackedbuf+end;
    for (i=(unpackedbuf+beg),j=(short *)charbuf;i<=last;i++,j++)
      {
	(*j) = (short)(*i);
      }
    checked_write(fd,charbuf,num);
}

crdstereo(int fd, int beg, int end, int *bufa, int *bufb)
{
    int *ia,*ib,*last;
    short *j,*k;
    int num,rtn;
    check_charbuf();
    num=(end-beg+1)*4;
    rtn=clm_read(fd,charbuf,num);
    last=bufa+beg+(rtn>>2);
    for (ia=(bufa+beg),ib=(bufb+beg),j=(short *)charbuf,k=(short *)(charbuf+2);
	 ia<last;
	 ia++,ib++,j+=2,k+=2)
      {
	*ia= (int) (*j);
	*ib= (int) (*k);
      }
    if (rtn<num)
      {
	last=bufa+end;
	for (;ia<=last;ia++,ib++)
	  {
	    *ia=0;
	    *ib=0;
	  }
      }
}

cwrtstereo(int fd, int beg, int end, int *unpackedbufa, int *unpackedbufb)
{
    int *ia,*ib,*last;
    short *j,*k;
    int num,lim;
    check_charbuf();
    lim=(end-beg+1);
    num=lim*4;
    last=unpackedbufa+end;
    for (ia=(unpackedbufa+beg),ib=(unpackedbufb+beg),j=(short *)charbuf,k=(short *)(charbuf+2);
	 ia<=last;
	 ia++,ib++,j+=2,k+=2)
      {
	(*j) = (short)(*ia);
	(*k) = (short)(*ib);
      }
    checked_write(fd,charbuf,num);
}

crdquad(int fd, int beg, int end, int *bufa, int *bufb, int *bufc, int *bufd)
{
    int *ia,*ib,*ic,*id,*last;
    short *j,*k,*l,*m;
    int num,rtn;
    check_charbuf();
    num=(end-beg+1)*8;
    rtn=clm_read(fd,charbuf,num);
    last=bufa+beg+(rtn>>3);
    for (ia=(bufa+beg),ib=(bufb+beg),ic=(bufc+beg),id=(bufd+beg),
	 j=(short *)charbuf,k=(short *)(charbuf+2),l=(short *)(charbuf+4),m=(short *)(charbuf+6);
	 ia<last;
	 ia++,ib++,ic++,id++,j+=4,k+=4,l+=4,m+=4)
      {
	(*ia)=(int)(*j);
	(*ib)=(int)(*k);
	(*ic)=(int)(*l);
	(*id)=(int)(*m);
      }
    if (rtn<num)
      {
	last=bufa+end;
	for (;ia<=last;ia++,ib++,ic++,id++)
	  {
	    *ia=0;
	    *ib=0;
	    *ic=0;
	    *id=0;
	  }
      }
}

cwrtquad(int fd, int beg, int end, int *unpackedbufa, int *unpackedbufb, int *unpackedbufc, int *unpackedbufd)
{
    int *ia,*ib,*ic,*id,*last;
    short *j,*k,*l,*m;
    int num,lim;
    check_charbuf();
    lim=(end-beg+1);
    num=lim*8;
    last=unpackedbufa+end;
    for (ia=(unpackedbufa+beg),
	 ib=(unpackedbufb+beg),
	 ic=(unpackedbufc+beg),
	 id=(unpackedbufd+beg),
	 j=(short *)charbuf,
	 k=(short *)(charbuf+2),
	 l=(short *)(charbuf+4),
	 m=(short *)(charbuf+6);
	 ia<=last;
	 ia++,ib++,ic++,id++,j+=4,k+=4,l+=4,m+=4)
      {
	(*j)=(short)(*ia);
	(*k)=(short)(*ib);
	(*l)=(short)(*ic);
	(*m)=(short)(*id);
      }
    checked_write(fd,charbuf,num);
}



float absf(float x) 
{
  if (x>=0.0) return x; 
  return(0.0-x);
}

float maxmagn(float x, float y) 
{
  if (x>absf(y)) return x; 
  return (absf(y));
}

float maxamparray(int size, float *arr)
{
    float *i,*last;
    float maxa;
    maxa=arr[0];
    last=arr+size;
    for (i=(arr+1);i<last;i++)
      maxa=maxmagn(maxa,*i);
    return maxa;
}

normarray(int size, float *arr)
{
    float maxa;
    float *i,*last;
    maxa=maxamparray(size,arr);
    if (maxa==0.0) return;
    if (maxa==1.0) return;
    maxa=1.0/maxa;
    last=arr+size;
    for (i=arr;i<last;i++) *i=((*i)*maxa);
}

arrblt(int beg, int end, int newbeg, int *arr)
{
    int *i,*j,*first;
    first=arr+end;
    for (i=(arr+beg),j=(arr+newbeg);i>=first;i--,j--) (*j)=(*i);
}

int absmaxarr(int beg, int end, int *arr)
{
  int maxA,val;
  int *i,*last;
  last = arr+end;
  maxA = 0;
  for (i=arr+beg;i<=last;i++)
    {
      val = ((*i) & 0xffff);
      if (val & 0x8000) val = (65536 - val);
      if (val > maxA) maxA = val;
    }
  return maxA;
}

int last_time = 0;

int get_last_time(void)
{
  return last_time;
}

int timedabsmaxarr(int beg, int end, int *arr)
{
  int j,maxA,val;
  int *i,*last;
  last = arr+end;
  maxA = 0;
  for (i=arr+beg,j=beg;i<=last;i++,j++)
    {
      val = ((*i) & 0xffff);
      if (val & 0x8000) val = (65536 - val);
      if (val > maxA)
	{
	  maxA = val;
	  last_time=j;
	}
    }
  return maxA;
}

int newtimedabsmaxarr(int beg, int end, int maxA, int *arr)
{
  int minA;
  int *i,*first,*last;
  last = arr+end;
  first = arr+beg;
  minA = -maxA;
  for (i=first;i<=last;i++)
    {
      if (((*i) > maxA) || ((*i) < minA))
	{
	  maxA = (*i);
	  if (maxA < 0.0) maxA = -maxA;
	  minA = -maxA;
	  last_time=(i-first);
	}
    }
  return maxA;
}

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