/* echoplex.c - echo generator
**
** Copyright (C) 1989 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
*/

#include <stdio.h>
#include "libst.h"

#define abs(a) ((a) >= 0 ? (a) : -(a))

#define FADE_THRESH 30
#define MYBUFSIZ 256
#define DELAYBUFSIZ ( 50 * SAMPLES_PER_SECOND )
#define MAXDELAYS 1000

main( argc, argv )
int argc;
char *argv[];
    {
    FILE *f;
    char mybuf[MYBUFSIZ];
    int argn, numdelays;
    register int i, j, c, lc, plc, pplc, ppplc;
    static int delaybuf[DELAYBUFSIZ];
    float delay[MAXDELAYS], atten[MAXDELAYS];
    int samples[MAXDELAYS], maxsamples;
    double atof();
    char *usage = "usage:  %s <delay> <atten> [<delay> <atten>] ... [<file>]\n";

    argn = 1;
    numdelays = 0;
    maxsamples = 0;

    while ( argn + 1 < argc )
	{
	delay[numdelays] = atof( argv[argn++] );
	atten[numdelays] = atof( argv[argn++] );
	samples[numdelays] = delay[numdelays] * SAMPLES_PER_SECOND;
	if ( samples[numdelays] < 1 )
	    {
	    fprintf( stderr, "%s: delay must positive, aye!\n", argv[0] );
	    exit( 1 );
	    }
	if ( samples[numdelays] > DELAYBUFSIZ )
	    {
	    fprintf(
		stderr, "%s: delay must be less than %g seconds\n",
		argv[0], DELAYBUFSIZ / (float) SAMPLES_PER_SECOND );
	    exit( 1 );
	    }
	if ( atten[numdelays] < 0.0 )
	    {
	    fprintf( stderr, "%s: attenuation must positive, aye!\n", argv[0] );
	    exit( 1 );
	    }
	if ( samples[numdelays] > maxsamples )
	    maxsamples = samples[numdelays];
	++numdelays;
	}

    if ( argn == argc )
	f = stdin;
    else
	{
	f = fopen( argv[argn], "r" );
	if ( f == NULL )
	    {
	    perror( argv[argn] );
	    exit( 1 );
	    }
	++argn;
	}

    if ( argn != argc )
	{
	fprintf( stderr, usage, argv[0] );
	exit( 1 );
	}


    setbuffer( stdout, mybuf, MYBUFSIZ );

    for ( i = 0; i < maxsamples; ++i )
	delaybuf[i] = 0;

    for ( i = 0; (c = getc( f )) != EOF; i = ( i + 1 ) % maxsamples )
	{
	lc = st_ulaw_to_linear( c );
	for ( j = 0; j < numdelays; ++j )
	    lc = lc + delaybuf[( i + maxsamples - samples[j] ) % maxsamples] * atten[j];
	LINCLIP( lc );
	delaybuf[i] = lc;
	putchar( st_linear_to_ulaw( lc ) );
	}

    for ( ppplc = pplc = plc = MAXLIN;
	  abs(lc) + abs(plc) + abs(pplc) + abs(ppplc) > FADE_THRESH / 4;
	  i = ( i + 1 ) % maxsamples )
	{
	lc = 0;
	for ( j = 0; j < numdelays; ++j )
	    lc = lc + delaybuf[( i + maxsamples - samples[j] ) % maxsamples] * atten[j];
	LINCLIP( lc );
	delaybuf[i] = lc;
	putchar( st_linear_to_ulaw( lc ) );
	ppplc = pplc;
	pplc = plc;
	plc = lc;
	}

    exit( 0 );
    }
