/* 
 * pvfutil.c
 *
 * Contains various small utilities, they get called from pvfmain.c
 *
 */

char pvfutil_c[] = "$Id: pvfutil.c,v 1.10 1995/04/03 15:37:57 marc Exp $";

#include <stdio.h>

#ifndef _NOSTDLIB_H
#include <stdlib.h>
#endif

#include <malloc.h>

#include "../mgetty.h"
#include "pvflib.h"

/* blocksize for reading voice files into memory */
#define BLK 65536

/* decimal point shift for fixed-point arithmetic */
#define SH 12
#define ONE (1<<SH)

int
pvfamp _P2((argc, argv), int argc, char **argv ) {
    FILE *in=stdin, *out=stdout;
    int amp=ONE;

    if( argc>1 && (amp=(int)(ONE*atof(argv[1]))) )
       argc--, argv++;
    if(argc>1) USAGE("<amplification>");
    
    while(1) {
	int d=zget(in);		
	if(feof(in)) break;		
	zput( (d * amp >> SH), out );
    }
    return 0;
}

int
pvfcut _P2((argc, argv), int argc, char **argv ) {
    FILE *in=stdin, *out=stdout;
    int arg=1;
    int len=0, lmax=0, *buf=0;
    int i;
    int head=0, tail=0;
    
    if(argc<2 || argc>3) USAGE("[<head>] <tail>");
    if(argc==3) head=(int)(RATE * atof(argv[arg++]));
    tail=(int)(RATE * atof(argv[arg++]));
    
    while(1) {
	int d;
	d=zget(in);
	if(feof(in)) break;
	if(len>=lmax) {
	    lmax+=BLK;
	    buf=(int*) realloc(buf, lmax*sizeof(int));
	    if(!buf) ERRORRETURN("out of memory");
	}
	buf[len++]=d;
    }
    for(i=head; i<len-tail; i++) {
	int d;
	if(i>=0 && i<len) d=buf[i];
	else d=0;
	zput(d, out);
    }
    return 0;
}

int
pvfecho _P2((argc, argv), int argc, char **argv ) {
    FILE *in=stdin, *out=stdout;
    int arg=1;
    int len=0, lmax=0, *buf=0;
    int i;
    int delay=(int)(0.15 * RATE);
    int vol=(int)(0.3*ONE);
    
    if(argc>3) USAGE("[<delay>] [<volume>]");
    if(argc>=2) delay=(int)(RATE * atof(argv[arg++]));
    if(argc==3) vol=(int)(ONE * atof(argv[arg++]));

    while(1) {
	int d;
	d=zget(in);
	if(feof(in)) break;
	if(len>=lmax) {
	    lmax+=BLK;
	    buf=(int*)realloc(buf, lmax*sizeof(int));
	    if(!buf) ERRORRETURN("out of memory");
	}
	buf[len++]=d;
    }
    for(i=0; i<len; i++) {
	int d, od;
	if(i >= delay)
	    od=buf[i-delay];
	else
	    od=0;		    
	d=(buf[i]*(ONE-vol) + od*vol) >> SH;
	buf[i]=d;
	zput(buf[i], out);
    }
    return 0;
}

int
pvfmix _P2((argc, argv), int argc, char **argv ) {
    FILE *in=stdin, *out=stdout;
    FILE *back;
    int arg=1;
    
    if(argc<2 || argc>2) USAGE("<file>");
    back=fopen( argv[arg++], "r" );
    if(!back) PERROR;
    
    while(1) {
	int d1, d2;
	d1=zget(in);
	if(feof(in)) break;
	d2=zget(back);
	if(!feof(back)) d1+=d2;
	zput( d1, out );
    }
    return 0;
}

int
pvfreverse _P2((argc, argv), int argc, char **argv ) {
    FILE *in=stdin, *out=stdout;
    int len=0, lmax=0, *buf=0;
    int i;
    
    if( argc>1) USAGE("");
    
    while(1) {
	int d;
	d=zget(in);
	if(feof(in)) break;
	if(len>=lmax) {
	    lmax+=BLK;
	    buf=(int*)realloc(buf, lmax*sizeof(int));
	    if(!buf) ERRORRETURN("out of memory");
	}
	buf[len++]=d;
    }
    for(i=len-1; i>=0; i--) {
	zput(buf[i], out);
    }
    return 0;
}

int
pvfspeed _P2((argc, argv), int argc, char **argv ) {
    FILE *in=stdin, *out=stdout;
    int arg=1;
    int speed=ONE;
    int expn=ONE;
    int srate=RATE/10;
    
    if(argc<2 || argc>3) USAGE("<speed> [<exponent>]");
    speed=(int)(ONE*atof(argv[arg++]));
    if(argc==3) expn=(int)(ONE*atof(argv[arg++]));
    
    if(speed <= ONE) {
	/* slow down the sample, create new values using */
	/* simple linear interpolation */
	int a, t;
	int i=0;
	
	a=zget(in);
	if(!feof(in)) zput(a, out);
	t=speed;
	while(1) {
	    int b;
	    b=zget(in);
	    if(feof(in)) break;
	    while(t<=ONE) {
		zput( a + ((b-a)*t >> SH), out );
		t+=speed;
	    }
	    t-=ONE;
	    a=b;
	    if(++i == srate) i-=srate, speed=(speed*expn)>>SH;
	}
    } else {
	/* speed up the sample, use averaging */
	int t=0, sum=0;
	int i=0;
	
	while(1) {
	    int b;
	    
	    b=zget(in);
	    if(feof(in)) break;
	    
	    t += ONE;
	    if(t >= speed) {
		t -= speed;
		sum += b*(ONE-t) >>SH;
		zput( sum*ONE/speed, out );
		sum = b*t >>SH;
	    } else {
		sum += b;
	    }
	    if(++i == srate) i-=srate, speed=(speed*expn)>>SH;
	}
    }
    return 0;
}
