home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume26
/
filterkit
/
part01
next >
Wrap
Text File
|
1993-04-15
|
90KB
|
2,602 lines
Newsgroups: comp.sources.unix
From: cf0v@andrew.cmu.edu (Christopher Lee Fraley)
Subject: v26i166: filterkit - a collection of audio filters and resamplers, Part01/01
Sender: unix-sources-moderator@vix.com
Approved: paul@vix.com
Submitted-By: cf0v@andrew.cmu.edu (Christopher Lee Fraley)
Posting-Number: Volume 26, Issue 166
Archive-Name: filterkit/part01
The original SAIL resampling program is now located among four files:
"filterkit.c", "makefilter.c", "resample.c", and "resample.h". These files
contain:
filterkit.c - The source code for the library. Contains routines
to calculate filter coeff's, convert these to a 16-bit
integer format, write a filter file, read a filter file,
apply the filter when up-sampling, apply the filter when
up-/down-sampling, and apply the filter to find a zero-
crossing.
makefilter.c - Routines to design and write a filter to a file.
Creates a Kaiser-windowed lowpass filter based upon routines
found in the filterkit library.
resample.c - The original resampling program stripped down to the
part that does the actual resampling. Designing a filter
was moved to "makefilter.c", the conversion constants
were moved into "resample.c", and various general filter
routines were moved into the filterkit library.
resample.h - Contains the resampling conversion constants. These
constants govern such things as the number of bits in the
input sample & filter coeff's, the number of bits to the
right of the binary-point for fixed-point math, etc.
Other programs included in this package are the Makefiles for each of
the programs (and the filterkit library), the needed headerfiles, and a
human-readable copy of the lint version of the filterkit library:
warp.c - Very similar to "resample.c", except is modified to allow
the conversion factor to change on a sample-by-sample basis,
currently using sinusiods. This program can be used to add
vibrato or other pitch-shifting effects to a sample.
stdefs.h - Contains the definitions for words and halfwords, which
can change from machine to machine. Also, useful constants
are defined, as well as a few useful macros.
filterkit.h - Contains the declarations of each of the functions in
the filterkit library. Must be included by any program using
any of the filterkit routines.
llib-lfilterkit - A human-readble version of the lint-library for
filterkit. Simply defines the type of each function and
the routine's formal parameters, so lint can check programs
which use the filterkit library. The compact version of this
file is created via the -C option of lint. See the filterkit
Makefile for details.
For further information on any of the files, look in the comments and
help strings contained within that file. Also I can be contacted at:
cf0v@spice.cs.cmu.edu, or
cf0v@andrew.cmu.edu.
--Christopher Lee Fraley
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 1 (of 1)."
# Contents: MANIFEST Makefile Notes README.filterkit README.resample
# filterkit.c filterkit.h kaiser.c makefilter.c protos.h resample.c
# resample.h stdefs.h warp.c
# Wrapped by vixie@gw.home.vix.com on Thu Apr 15 18:45:31 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'MANIFEST' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(548 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X File Name Archive # Description
X-----------------------------------------------------------
X MANIFEST 1 This shipping list
X Makefile 1
X Notes 1
X README.filterkit 1
X README.resample 1
X filterkit.c 1
X filterkit.h 1
X kaiser.c 1
X makefilter.c 1
X protos.h 1
X resample.c 1
X resample.h 1
X stdefs.h 1
X warp.c 1
END_OF_FILE
if test 548 -ne `wc -c <'MANIFEST'`; then
echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(954 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
SRC = kaiser.c filterkit.c makefilter.c resample.c warp.c
OBJ = kaiser.o filterkit.o makefilter.o resample.o warp.o
BIN = kaiser makefilter resample warp
X
XFILES = Readme Notes Makefile filterkit.h protos.h resample.h stdefs.h $(SRC)
X
INSTALLDIR = /usr/local/bin
X
all: $(BIN)
X
install: $(BIN)
X cp $(BIN) "$(INSTALLDIR)"
X
kaiser: kaiser.c filterkit.c
X rm -f kaiser
X $(CC) $(CFLAGS) kaiser.c filterkit.c -o kaiser -lm
X
makefilter: makefilter.c filterkit.c
X rm -f makefilter
X $(CC) $(CFLAGS) makefilter.c filterkit.c -o makefilter -lm
X
resample: resample.c filterkit.c
X rm -f resample
X $(CC) $(CFLAGS) resample.c filterkit.c -o resample -lm
X
warp: warp.c filterkit.c
X rm -f warp
X $(CC) $(CFLAGS) warp.c filterkit.c -o warp -lm
X
X$(SRC): filterkit.h stdefs.h
resample.c: resample.h
X
X# Shar: -F (prefix all lines with X),
X# -s addr (set return addr of poster)
shar: $(FILES)
X /usr2/tools/shar/shar -F -l 50 -o shar -n resample -s thinman@netcom.com $(FILES)
END_OF_FILE
if test 954 -ne `wc -c <'Makefile'`; then
echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'Notes' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Notes'\"
else
echo shar: Extracting \"'Notes'\" \(9614 characters\)
sed "s/^X//" >'Notes' <<'END_OF_FILE'
X
X NOTES
X
X
PROGRAM ORGANIZATION:
X
X The original SAIL resampling program is now located among four files:
X"filterkit.c", "makefilter.c", "resample.c", and "resample.h". These files
contain:
X
X filterkit.c - The source code for the library. Contains routines
X to calculate filter coeff's, convert these to a 16-bit
X integer format, write a filter file, read a filter file,
X apply the filter when up-sampling, apply the filter when
X up-/down-sampling, and apply the filter to find a zero-
X crossing.
X
X makefilter.c - Routines to design and write a filter to a file.
X Creates a Kaiser-windowed lowpass filter based upon routines
X found in the filterkit library.
X
X resample.c - The original resampling program stripped down to the
X part that does the actual resampling. Designing a filter
X was moved to "makefilter.c", the conversion constants
X were moved into "resample.c", and various general filter
X routines were moved into the filterkit library.
X
X resample.h - Contains the resampling conversion constants. These
X constants govern such things as the number of bits in the
X input sample & filter coeff's, the number of bits to the
X right of the binary-point for fixed-point math, etc.
X
X Other programs included in this package are the Makefiles for each of
the programs (and the filterkit library), the needed headerfiles, and a
human-readable copy of the lint version of the filterkit library:
X
X warp.c - Very similar to "resample.c", except is modified to allow
X the conversion factor to change on a sample-by-sample basis,
X currently using sinusiods. This program can be used to add
X vibrato or other pitch-shifting effects to a sample.
X
X stdefs.h - Contains the definitions for words and halfwords, which
X can change from machine to machine. Also, useful constants
X are defined, as well as a few useful macros.
X
X filterkit.h - Contains the declarations of each of the functions in
X the filterkit library. Must be included by any program using
X any of the filterkit routines.
X
X llib-lfilterkit - A human-readble version of the lint-library for
X filterkit. Simply defines the type of each function and
X the routine's formal parameters, so lint can check programs
X which use the filterkit library. The compact version of this
X file is created via the -C option of lint. See the filterkit
X Makefile for details.
X
X
X
NOTES ON COMPILATION:
X
X All of the modules should compile without any problems, although search
paths will have to be set up correctly so "cc" can find all of the proper
include and library files. Alternatively, one could also explicly cite an
absolute file path for each of the files.
X
X A few minor changes have been made to some of these files since they were
last compiled:
X 1. All absolute paths were removed from the Makefiles to make
X adaption to your site less confusing.
X 2. The source for the filterkit library was concatinated into one
X file. The Query(), GetUShort(), GetDouble(), and GetString()
X routines were originally in a separate file "query.c".
X 3. "llib-lfilterkit" was modified to reflect the latest change to
X the zerox() routine. This has not been tested yet.
X
X The routines originally in "query.c" may have to be modified slightly
to get them to compile. Apparently, the getstr() routine (which is used in
each of these routines) is not a part of the standard C library on all Unix
systems. Its specification is:
X getstr(prompt, defalt, answer)
X char *prompt, *defalt, *answer;
X Getstr() will print the passed "prompt" as a message to the user, and
X wait for the user to type an input string. The string is
X then copied into "answer". If the user types just a carriage
X return, then the string "defalt" is copied into "answer".
X "Answer" and "defalt" may be the same string, in which case,
X the default value will be the original contents of "answer".
X
X Also note that the constants in "resample.h" and the typedefs in
X"stdefs.h" may need to be changed to reflect the word-size of the machine
the program will be running on. These files currently reflect a word-size
of 32-bits.
X
X
X
STRUCTURE OF FILES:
X
X There are two types of files used to pass information from one program
the the next: the filter file and a sound-sample file. The filter file
has the following format:
X
X File Name: "F" Nmult "T" Nhc ".filter"
X example: "F13T8.filter" and "F27T8.filter"
X
X Structure of File:
X "ScaleFactor" LpScl
X "Length" Nwing
X "Coeffs:"
X Imp[0]
X Imp[1]
X :
X Imp[Nwing-1]
X "Differences:"
X ImpD[0]
X ImpD[1]
X :
X ImpD[Nwing-1]
X EOF
X
X where: Something enclosed in "" inicates specific characters found
X in the file.
X Nmult, Nwing, Imp[], and ImpD[] are variables (HWORD)
X Npc is a conversion constant.
X EOF is the end of the file.
X See writeFilter() and readFilter() in "filterkit.c" for more details.
X
X
The sound-sample file has the following format:
X
X File Name: unspecified.
X example: "horn.in", "Cello.adc", etc.
X
X Structure of File:
X Data[0]
X Data[1]
X :
X Data[n]
X EOF
X
X where: Data[i] is a 16-bit integer in ascii format. (Example:
X "32767", "-232")
X EOF is the end of the file.
X Note that there is no indication of the length of the
X sample; the EOF is the only indication that the
X last sample has been reached.
X
X
X
SUGGESTIONS, CORRECTIONS, IMPROVEMENTS:
X
X The following were assumed to be mistakes in the original SAIL program,
and have been changed in "resample.c" and other related programs:
X
X 1. LpScl was scaled by Factor (when Factor<1.0) only when the filter
X was loaded from a file, but not when the filter was created
X at run-time.
X 2. ImpD[Nwing-1] was originally set to Imp[Nwing-1], but in general
X ImpD[i] = ImpD[i+1] - ImpD[i], indicating ImpD[Nwing-1]
X should be set to NEGATIVE Imp[Nwing-1].
X 3. To keep the # of multiplies consistant (and odd), I added a check
X near the begining of the Filter() routines to skip the last
X coeff in the right wing when the phase was 180 degrees.
X (The "if (Inc == 1) End--;" clause).
X 4. When the phase was zero, and the right-wing Filter() is performed,
X the pointers to the filter coeffs must be incremented to
X keep the pointing to the correct coeff. (The "if (Ph == 0)
X { Hp += Npc; Hdp += Npc; }" clause).
X
X
X The following were changes made to the basic implementation of the
algorithm:
X
X 1. ImpD[] is now created from the integer Imp[] instead of the
X double ImpR[], in order to avoid problems with rounding.
X 2. In SrcUp() and SrcUD(), the order of making guard bits (v>>Nhg)
X and normalizing was switched. This was done to prevent
X overflow problems.
X 3. Rounding was removed from SrcUp() and SrcUD() to get more accurate
X response to a DC input.
X
X
X The following are improvements that I recommend be made to various
routines:
X
X 1. Change file format of sound files (and possibly filter files) to
X a binary format. If you are in a Unix environment, you can
X use the functions read() and write() to perform low-level
X i/o, instead of fprintf() and fscanf(). This would be MUCH
X faster, but I have not made the changes yet because the
X current code is much clearer, and probably easier to port
X to your system and your sound-file format.
X 2. I believe the restriction that Nmult must be odd may be removed.
X 3. When Filter() is currently called for the right-wing, Xp+1 must
X be passed to it. This should probably be changed so that
X Filter() adds one to Xp if it is doing the right-wing,
X instead of the user. This way, that increment would be
X transparent to the user, and provide a more consistent
X interface to these functions.
X
X
X
NOTES ON SPECIFIC FILES:
X
X "resample.c" - should be a faithful reproduction of the original SAIL
X program in C.
X
X "warp.c" - I modified SrcUD() to get the current value for Factor from
X the function warpFunction(). WarpFunction() should be changed to
X some form desirable.
X
X "filterkit.c" - Contains the following useful routines:
X LpFilter() - Calculates the filter coeffs for a Kaiser-windowed
X low-pass filter with a given roll-off frequency. These
X coeffs are stored into a array of doubles.
X writeFilter() - Writes a filter to a file.
X makeFilter() - A section of the original SAIL program. Calls
X LpFilter() to create a filter, then scales the double
X coeffs into a array of half words.
X readFilter() - Reads a filter from a file.
X FilterUp() - Applies a filter to a given sample when up-converting.
X FilterUD() - Applies a filter to a given sample when up- or down-
X converting. Both are repoductions of the original SAIL
X program.
X initZerox() - Initialization routine for the zerox() function. Must
X be called before zerox() is called. This routine loads
X the correct filter so zerox() can use it.
X zerox() - Given a pointer into a sample, finds a zero-crossing on the
X interval [pointer-1:pointer+2] by iteration.
X Query() - Ask the user for a yes/no question with prompt, default,
X and optional help.
X GetUShort() - Ask the user for a unsigned short with prompt, default,
X and optional help.
X GetDouble() - Ask the user for a double with prompt, default, and
X optional help.
X GetString() - Ask the user for a string with prompt, default, and
X optional help.
X
X
X
XFURTHER INFORMATION:
X
X Any printf()'s that start with a "|" as the first character in the
control string are used for debugging to to alert the user of an error
condition.
X For further information on any of the files, look in the comments and
help strings contained within that file. Also I can be contacted at:
X cf0v@spice.cs.cmu.edu, or
X cf0v@andrew.cmu.edu.
X
X --Christopher Lee Fraley
X
END_OF_FILE
if test 9614 -ne `wc -c <'Notes'`; then
echo shar: \"'Notes'\" unpacked with wrong size!
fi
# end of 'Notes'
fi
if test -f 'README.filterkit' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README.filterkit'\"
else
echo shar: Extracting \"'README.filterkit'\" \(459 characters\)
sed "s/^X//" >'README.filterkit' <<'END_OF_FILE'
X
X
XFilterkit is a C translation of an old SAIL program (SAIL =
Stanford AI Lab) which does FIR filtering with sample rate
changing on the fly.
X
Christopher Fraley @CMU did the translation and split it up
into a toolkit. Being ignorant, I've glommed some of the pieces
together into a program that performs straight filtering on
a sound sample file of signed words.
X
The warp program in particular looks very promising; I haven't
used it yet.
X
X Lance Norskog
END_OF_FILE
if test 459 -ne `wc -c <'README.filterkit'`; then
echo shar: \"'README.filterkit'\" unpacked with wrong size!
fi
# end of 'README.filterkit'
fi
if test -f 'README.resample' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README.resample'\"
else
echo shar: Extracting \"'README.resample'\" \(1605 characters\)
sed "s/^X//" >'README.resample' <<'END_OF_FILE'
X(Message inbox:3096)
Received: from netcom4.netcom.com by charon.cwi.nl with SMTP
X id AA27402 (5.65b/3.8/CWI-Amsterdam); Mon, 8 Mar 1993 22:46:14 +0100
Received: by netcom4.netcom.com (5.65/SMI-4.1/Netcom)
X id AA04106; Mon, 8 Mar 93 13:45:12 -0800
Date: Mon, 8 Mar 93 13:45:12 -0800
XFrom: thinman@netcom.com (Technically Sweet)
Message-Id: <9303082145.AA04106@netcom4.netcom.com>
In-Reply-To: Guido.van.Rossum@cwi.nl
X "Re: SOX wav.c patch" (Mar 8, 10:07pm)
XX-Mailer: Mail User's Shell (7.2.3 5/22/91)
To: Guido.van.Rossum@cwi.nl
Subject: resampler part 1 of 2
X
Here it is. Now I realise there's no help.
X
X'kaiser' reads and writes signed 16-bit samples, but
doesn't care about sampling rates.
X
X'kaiser 2.0' doubles the sampling rate.
X'kaiser 0.5 [ 0.5 ]' cuts the sampling rate in 1/2.
X'kaiser 0.5 0.7' does the same, but with a more gradual slope.
X
I checked this out with the FFT analyzer in MixVIew,
and it really does better than interpolating.
Interp upward reflects the base sound in the higher
frequencies. This doesn't.
X
X(Message inbox:3097)
Received: from netcom4.netcom.com by charon.cwi.nl with SMTP
X id AA27418 (5.65b/3.8/CWI-Amsterdam); Mon, 8 Mar 1993 22:46:30 +0100
Received: by netcom4.netcom.com (5.65/SMI-4.1/Netcom)
X id AA04154; Mon, 8 Mar 93 13:45:29 -0800
Date: Mon, 8 Mar 93 13:45:29 -0800
XFrom: thinman@netcom.com (Technically Sweet)
Message-Id: <9303082145.AA04154@netcom4.netcom.com>
In-Reply-To: Guido.van.Rossum@cwi.nl
X "Re: SOX wav.c patch" (Mar 8, 10:07pm)
XX-Mailer: Mail User's Shell (7.2.3 5/22/91)
To: Guido.van.Rossum@cwi.nl
Subject: resample part 2 of 2
X
END_OF_FILE
if test 1605 -ne `wc -c <'README.resample'`; then
echo shar: \"'README.resample'\" unpacked with wrong size!
fi
# end of 'README.resample'
fi
if test -f 'filterkit.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'filterkit.c'\"
else
echo shar: Extracting \"'filterkit.c'\" \(16885 characters\)
sed "s/^X//" >'filterkit.c' <<'END_OF_FILE'
X
X/*
X * FILE: filterkit.c (source for library "filterkit.a")
X * BY: Christopher Lee Fraley (cf0v@andrew.cmu.edu)
X * DESC: Makes a Kaiser-windowed low-pass filter.
X * DATE: 7-JUN-88
X */
X
char filterkitVERSION[] = "2.0 (7-JUN-88 3:30pm)";
X
X/* filterkit.c
X *
X * The function makeFilter(), FilterUp(), and FilterUD(), were originally
X * written by Julius O. Smith in SAIL, and were translated into C.
X *
X * LpFilter() - Calculates the filter coeffs for a Kaiser-windowed low-pass
X * filter with a given roll-off frequency. These coeffs
X * are stored into a array of doubles.
X * writeFilter() - Writes a filter to a file.
X * makeFilter() - Calls LpFilter() to create a filter, then scales the double
X * coeffs into an array of half words.
X * readFilter() - Reads a filter from a file.
X * FilterUp() - Applies a filter to a given sample when up-converting.
X * FilterUD() - Applies a filter to a given sample when up- or down-
X * converting.
X * initZerox() - Initialization routine for the zerox() function. Must
X * be called before zerox() is called. This routine loads
X * the correct filter so zerox() can use it.
X * zerox() - Given a pointer into a sample, finds a zero-crossing on the
X * interval [pointer-1:pointer+2] by iteration.
X * Query() - Ask the user for a yes/no question with prompt, default,
X * and optional help.
X * GetUShort() - Ask the user for a unsigned short with prompt, default,
X * and optional help.
X * GetDouble() - Ask the user for a double with prompt, default, and
X * optional help.
X * GetString() - Ask the user for a string with prompt, default, and
X * optional help.
X */
X
X
X#include <stdio.h>
X#include <math.h>
X#include <string.h>
X#include "stdefs.h"
X#include "resample.h"
X#include "filterkit.h"
X#include "protos.h"
X
X
X
X/* LpFilter()
X *
X * reference: "Digital Filters, 2nd edition"
X * R.W. Hamming, pp. 178-179
X *
X * Izero() computes the 0th order modified bessel function of the first kind.
X * (Needed to compute Kaiser window).
X *
X * LpFilter() computes the coeffs of a Kaiser-windowed low pass filter with
X * the following characteristics:
X *
X * c[] = array in which to store computed coeffs
X * frq = roll-off frequency of filter
X * N = Half the window length in number of coeffs
X * Beta = parameter of Kaiser window
X * Num = number of coeffs before 1/frq
X *
X * Beta trades the rejection of the lowpass filter against the transition
X * width from passband to stopband. Larger Beta means a slower
X * transition and greater stopband rejection. See Rabiner and Gold
X * (Theory and Application of DSP) under Kaiser windows for more about
X * Beta. The following table from Rabiner and Gold gives some feel
X * for the effect of Beta:
X *
X * All ripples in dB, width of transition band = D*N where N = window length
X *
X * BETA D PB RIP SB RIP
X * 2.120 1.50 +-0.27 -30
X * 3.384 2.23 0.0864 -40
X * 4.538 2.93 0.0274 -50
X * 5.658 3.62 0.00868 -60
X * 6.764 4.32 0.00275 -70
X * 7.865 5.0 0.000868 -80
X * 8.960 5.7 0.000275 -90
X * 10.056 6.4 0.000087 -100
X */
X
X
X
X#define IzeroEPSILON 1E-21 /* Max error acceptable in Izero */
X
double Izero(x)
double x;
X{
X double sum, u, halfx, temp;
X int n;
X
X sum = u = n = 1;
X halfx = x/2.0;
X do {
X temp = halfx/(double)n;
X n += 1;
X temp *= temp;
X u *= temp;
X sum += u;
X } while (u >= IzeroEPSILON*sum);
X return(sum);
X}
X
X
void LpFilter(c,N,frq,Beta,Num)
double c[], frq, Beta;
int N, Num;
X{
X double IBeta, temp;
X int i;
X
X /* Calculate filter coeffs: */
X c[0] = 2.0*frq;
X for (i=1; i<N; i++)
X {
X temp = PI*(double)i/(double)Num;
X c[i] = sin(2.0*temp*frq)/temp;
X }
X
X /* Calculate and Apply Kaiser window to filter coeffs: */
X IBeta = 1.0/Izero(Beta);
X for (i=1; i<N; i++)
X {
X temp = (double)i / ((double)N * (double)1.0);
X c[i] *= Izero(Beta*sqrt(1.0-temp*temp)) * IBeta;
X }
X}
X
X
X
X/* Write a filter to a file
X * Filter file format:
X * file name: "F" Nmult "T" Nhc ".filter"
X * 1st line: the string "ScaleFactor" followed by its value.
X * 2nd line: the string "Length" followed by Nwing's value.
X * 3rd line: the string "Coeffs:" on a separate line.
X * following lines: Nwing number of 16-bit impulse response values
X * in the right wing of the impulse response (the Imp[] array).
X * (Nwing is equal to Npc*(Nmult+1)/2+1, where Npc is defined in the
X * file "resample.h".) Each coefficient is on a separate line.
X * next line: the string "Differences:" on a separate line.
X * following lines: Nwing number of 16-bit impulse-response
X * successive differences: ImpD[i] = Imp[i+1] - Imp[i].
X * ERROR codes:
X * 0 - no error
X * 1 - could not open file
X */
X
int writeFilter(Imp, ImpD, LpScl, Nmult, Nwing)
HWORD Imp[], ImpD[];
UHWORD LpScl, Nmult, Nwing;
X{
X char fname[30];
X FILE *fp;
X int i;
X
X sprintf(fname, "F%dT%d.filter", Nmult, Nhc);
X fp = fopen(fname, "w");
X if (!fp)
X return(1);
X fprintf(fp, "ScaleFactor %d\n", LpScl);
X fprintf(fp, "Length %d\n", Nwing);
X fprintf(fp, "Coeffs:\n");
X for (i=0; i<Nwing; i++) /* Put array of 16-bit filter coefficients */
X fprintf(fp, "%d\n", Imp[i]);
X fprintf(fp, "Differences:\n");
X for (i=0; i<Nwing; i++) /* Put array of 16-bit filter coeff differences */
X fprintf(fp, "%d\n", ImpD[i]);
X fclose(fp);
X return(0);
X}
X
X
X
X/* ERROR return codes:
X * 0 - no error
X * 1 - Nwing too large (Nwing is > MAXNWING)
X * 2 - Froll is not in interval [0:1)
X * 3 - Beta is < 1.0
X * 4 - LpScl will not fit in 16-bits
X *
X * Made following global to avoid stack problems in Sun3 compilation: */
static double ImpR[MAXNWING];
X
int makeFilter(Imp, ImpD, LpScl, Nwing, Froll, Beta)
HWORD Imp[], ImpD[];
UHWORD *LpScl, Nwing;
double Froll, Beta;
X{
X double DCgain, Scl, Maxh;
X HWORD Dh;
X int i, temp;
X
X if (Nwing > MAXNWING) /* Check for valid parameters */
X return(1);
X if ((Froll<=0) || (Froll>1))
X return(2);
X if (Beta < 1)
X return(3);
X
X LpFilter(ImpR, (int)Nwing, Froll, Beta, Npc); /* Design a Kaiser-window */
X /* Sinc low-pass filter */
X
X /* Compute the DC gain of the lowpass filter, and its maximum coefficient
X * magnitude. Scale the coefficients so that the maximum coeffiecient just
X * fits in Nh-bit fixed-point, and compute LpScl as the NLpScl-bit (signed)
X * scale factor which when multiplied by the output of the lowpass filter
X * gives unity gain. */
X DCgain = 0;
X Dh = Npc; /* Filter sampling period for factors>=1 */
X for (i=Dh; i<Nwing; i+=Dh)
X DCgain += ImpR[i];
X DCgain = 2*DCgain + ImpR[0]; /* DC gain of real coefficients */
X
X for (Maxh=i=0; i<Nwing; i++)
X Maxh = MAX(Maxh, fabs(ImpR[i]));
X
X Scl = ((1<<(Nh-1))-1)/Maxh; /* Map largest coeff to 16-bit maximum */
X temp = fabs((1<<(NLpScl+Nh))/(DCgain*Scl));
X if (temp >= 1<<16)
X return(4); /* Filter scale factor overflows UHWORD */
X *LpScl = temp;
X
X /* Scale filter coefficients for Nh bits and convert to integer */
X if (ImpR[0] < 0) /* Need pos 1st value for LpScl storage */
X Scl = -Scl;
X for (i=0; i<Nwing; i++) /* Scale them */
X ImpR[i] *= Scl;
X for (i=0; i<Nwing; i++) /* Round them */
X Imp[i] = ImpR[i] + 0.5;
X
X /* ImpD makes linear interpolation of the filter coefficients faster */
X for (i=0; i<Nwing-1; i++)
X ImpD[i] = Imp[i+1] - Imp[i];
X ImpD[Nwing-1] = - Imp[Nwing-1]; /* Last coeff. not interpolated */
X
X return(0);
X}
X
X
X
X/* Read-in a filter
X * Filter file format:
X * file name: "F" Nmult "T" Nhc ".filter"
X * 1st line: the string "ScaleFactor" followed by its value.
X * 2nd line: the string "Length" followed by Nwing's value.
X * 3rd line: the string "Coeffs:" on separate line.
X * Nwing number of 16-bit impulse response values in the right
X * wing of the impulse response. (Length=Npc*(Nmult+1)/2+1,
X * where originally Npc=2^9, and Nmult=13.) Each on separate line.
X * The string "Differences:" on separate line.
X * Nwing number of 16-bit impulse-response successive differences:
X * ImpDiff[i] = Imp[i+1] - Imp[i].
X *
X * ERROR return codes:
X * 0 - no error
X * 1 - file not found
X * 2 - invalid ScaleFactor in file
X * 3 - invalid Length in file
X */
int readFilter(Imp, ImpD, LpScl, Nmult, Nwing)
HWORD Imp[], ImpD[];
UHWORD *LpScl, Nmult, *Nwing;
X{
X char fname[30];
X FILE *fp;
X int i, temp;
X
X sprintf(fname, "F%dT%d.filter", Nmult, Nhc);
X fp = fopen(fname, "r");
X if (fp == NULL)
X return(1);
X
X fscanf(fp, "ScaleFactor ");
X if (1 != fscanf(fp,"%d",&temp))
X return(2);
X *LpScl = temp;
X
X fscanf(fp, "\nLength ");
X if (1 != fscanf(fp,"%d",&temp))
X return(3);
X *Nwing = temp;
X
X fscanf(fp, "\nCoeffs:\n");
X for (i=0; i<*Nwing; i++) /* Get array of 16-bit filter coefficients */
X fscanf(fp, "%d\n", &Imp[i]);
X
X fscanf(fp, "\nDifferences:\n");
X for (i=0; i<*Nwing; i++) /* Get array of 16-bit filter coeff differences */
X fscanf(fp, "%d\n", &ImpD[i]);
X
X fclose(fp);
X return(0);
X}
X
X
X
X
WORD FilterUp(Imp, ImpD, Nwing, Interp, Xp, Ph, Inc)
HWORD Imp[], ImpD[], *Xp, Inc, Ph;
UHWORD Nwing;
BOOL Interp;
X{
X HWORD a, *Hp, *Hdp, *End;
X WORD v, t;
X
X v=0;
X Hp = &Imp[Ph>>Na];
X End = &Imp[Nwing];
X if (Interp)
X {
X Hdp = &ImpD[Ph>>Na];
X a = Ph & Amask;
X }
X if (Inc == 1) /* If doing right wing... */
X { /* ...drop extra coeff, so when Ph is */
X End--; /* 0.5, we don't do too many mult's */
X if (Ph == 0) /* If the phase is zero... */
X { /* ...then we've already skipped the */
X Hp += Npc; /* first sample, so we must also */
X Hdp += Npc; /* skip ahead in Imp[] and ImpD[] */
X }
X }
X while (Hp < End)
X {
X t = *Hp; /* Get filter coeff */
X if (Interp)
X {
X t += (((WORD)*Hdp)*a)>>Na; /* t is now interp'd filter coeff */
X Hdp += Npc; /* Filter coeff differences step */
X }
X t *= *Xp; /* Mult coeff by input sample */
X if (t & 1<<(Nhxn-1)) /* Round, if needed */
X t += 1<<(Nhxn-1);
X t >>= Nhxn; /* Leave some guard bits, but come back some */
X v += t; /* The filter output */
X Hp += Npc; /* Filter coeff step */
X Xp += Inc; /* Input signal step. NO CHECK ON ARRAY BOUNDS */
X }
X return(v);
X}
X
X
X
X
WORD FilterUD(Imp, ImpD, Nwing, Interp, Xp, Ph, Inc, dhb)
HWORD Imp[], ImpD[], *Xp, Ph, Inc;
UHWORD Nwing, dhb;
BOOL Interp;
X{
X HWORD a, *Hp, *Hdp, *End;
X WORD v, t;
X UWORD Ho;
X
X v=0;
X Ho = (Ph*(UWORD)dhb)>>Np;
X End = &Imp[Nwing];
X if (Inc == 1) /* If doing right wing... */
X { /* ...drop extra coeff, so when Ph is */
X End--; /* 0.5, we don't do too many mult's */
X if (Ph == 0) /* If the phase is zero... */
X Ho += dhb; /* ...then we've already skipped the */
X } /* first sample, so we must also */
X /* skip ahead in Imp[] and ImpD[] */
X while ((Hp = &Imp[Ho>>Na]) < End)
X {
X t = *Hp; /* Get IR sample */
X if (Interp)
X {
X Hdp = &ImpD[Ho>>Na]; /* get interp (lower Na) bits from diff table */
X a = Ho & Amask; /* a is logically between 0 and 1 */
X t += (((WORD)*Hdp)*a)>>Na; /* t is now interp'd filter coeff */
X }
X t *= *Xp; /* Mult coeff by input sample */
X if (t & 1<<(Nhxn-1)) /* Round, if needed */
X t += 1<<(Nhxn-1);
X t >>= Nhxn; /* Leave some guard bits, but come back some */
X v += t; /* The filter output */
X Ho += dhb; /* IR step */
X Xp += Inc; /* Input signal step. NO CHECK ON ARRAY BOUNDS */
X }
X return(v);
X}
X
X
X
X/*
X * double zerox(Data, Factor)
X * HWORD *Data;
X * double Factor;
X * Given a pointer into a sound sample, this function uses a low-pass
X * filter to estimate the x coordinate of the zero-crossing which must ocurr
X * between Data[0] and Data[1]. This value is returned as the value of the
X * function. A return value of -100 indicates there was no zero-crossing in
X * the x interval [-1,2]. Factor is the resampling factor: Rate(out) /
X * Rate(in). Nmult (which determines which filter is used) is passed the
X * zerox's initialization routine: initZerox(Nmult)
X * UHWORD Nmult;
X */
X
static UHWORD LpScl, Nmult, Nwing;
static HWORD Imp[MAXNWING];
static HWORD ImpD[MAXNWING];
X
X/* ERROR return values:
X * 0 - no error
X * 1 - Nmult is even (should be odd)
X * 2 - filter file not found
X * 3 - invalid ScaleFactor in input file
X * 4 - invalid Length in file
X */
int initZerox(tempNmult)
UHWORD tempNmult;
X{
X int err;
X
X /* Check for illegal input values */
X if (!(tempNmult % 2))
X return(1);
X if (err = readFilter(Imp, ImpD, &LpScl, tempNmult, &Nwing))
X return(1+err);
X
X Nmult = tempNmult;
X return(0);
X}
X
X
X
X#define MAXITER 64
X#define ZeroxEPSILON (1E-4)
X#define ZeroxMAXERROR (5.0)
X
double zerox(Data, Factor)
HWORD *Data;
double Factor;
X{
X double x, out;
X double lo, hi;
X double dh;
X UWORD dhb;
X WORD v;
X int i;
X
X if (!Data[0])
X return (0.0);
X if (!Data[1])
X return (1.0);
X
X if (Data[0] < Data[1])
X {
X lo = -1.0;
X hi = 2.0;
X }
X else
X {
X lo = 2.0;
X hi = -1.0;
X }
X dh = (Factor<1) ? (Factor*Npc) : (Npc);
X dhb = dh * (1<<Na) + 0.5;
X
X for (i=0; i<MAXITER; i++)
X {
X x = (hi+lo)/2.0;
X v = FilterUD(Imp,ImpD,Nwing,TRUE,Data, (HWORD)(x*Pmask), -1,dhb);
X v += FilterUD(Imp,ImpD,Nwing,TRUE,Data+1,(HWORD)((1-x)*Pmask), 1,dhb);
X v >>= Nhg;
X v *= LpScl;
X out = (double)v / (double)(1<<NLpScl);
X if (out < 0.0)
X lo = x;
X else
X hi = x;
X if (ABS(out) <= ZeroxEPSILON)
X return(x);
X }
X printf("|ZeroX Error| x:%g, \t Data[x]:%d, \t Data[x+1]:%d\n",
X x, *Data, *(Data+1));
X printf("|\tABS(out):%g \t EPSILON:%g\n", ABS(out),ZeroxEPSILON);
X if (ABS(out) <= ZeroxMAXERROR)
X return(x);
X return(-100.0);
X}
X
X
X
X
BOOL Query(prompt, deflt, help)
char *help, *prompt;
BOOL deflt;
X{
X char s[80];
X
X while (TRUE)
X {
X sprintf(s,"\n%s%s", prompt, (*help) ? " (Type ? for help)" : "");
X getstr(s,(deflt)?"yes":"no",s);
X if (*s=='?' && *help)
X printf(help);
X if (*s=='Y' || *s=='y')
X return(TRUE);
X if (*s=='N' || *s=='n')
X return(FALSE);
X }
X}
X
X
char *GetString(prompt, deflt, help)
char *help, *prompt, *deflt;
X{
X char s[80];
X
X while (TRUE)
X {
X sprintf(s,"\n%s%s",prompt, (*help) ? " (Type ? for Help)" : "");
X getstr(s,deflt,s);
X if (*s=='?' && *help)
X printf(help);
X else
X return(s);
X }
X}
X
getstr(s1, deflt, s2)
char *s1, *deflt, *s2;
X{
X write(1, s1, strlen(s1));
X read(0, s2, 80);
X}
X
X
X
double GetDouble(title, deflt, help)
char *help, *title;
double deflt;
X{
X char s[80],sdeflt[80];
X double newval;
X
X while (TRUE)
X {
X sprintf(s,"\n%s:%s",title, (*help) ? " (Type ? for Help)" : "");
X sprintf(sdeflt,"%g",deflt);
X getstr(s,sdeflt,s);
X if (*s=='?' && *help)
X printf(help);
X else
X {
X if (!sscanf(s,"%lf",&newval))
X return(deflt);
X return(newval);
X }
X }
X}
X
X
unsigned short GetUShort(title, deflt, help)
char *help, *title;
unsigned short deflt;
X{
X char s[80],sdeflt[80];
X int newval;
X
X while (TRUE)
X {
X sprintf(s,"\n%s:%s",title, (*help) ? " (Type ? for Help)" : "");
X sprintf(sdeflt,"%d",deflt);
X getstr(s,sdeflt,s);
X if (*s=='?' && *help)
X printf(help);
X else
X {
X if (!sscanf(s,"%d",&newval))
X printf("unchanged (%d)\n",(newval=deflt));
X if (newval < 0)
X printf("Error: value must be >= zero\n");
X else
X return(newval);
X }
X }
X}
X
X
END_OF_FILE
if test 16885 -ne `wc -c <'filterkit.c'`; then
echo shar: \"'filterkit.c'\" unpacked with wrong size!
fi
# end of 'filterkit.c'
fi
if test -f 'filterkit.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'filterkit.h'\"
else
echo shar: Extracting \"'filterkit.h'\" \(380 characters\)
sed "s/^X//" >'filterkit.h' <<'END_OF_FILE'
X
X/*
X * FILE:filterkit.h
X * BY: Christopher Lee Fraley (cf0v@andrew.cmu.edu)
X * DATE: 17-JUN-88
X * VERS: 1.0 (20-JUN-88, 3:10pm)
X */
X
void LpFilter();
int writeFilter(), readFilter(), makeFilter();
WORD FilterUp(), FilterUD();
double GetDouble();
unsigned short GetUShort();
char *GetString();
BOOL Query();
double cubic(), zerox();
X
X#define GetUHWORD(x,y,z) GetUShort(x,y,z)
X
END_OF_FILE
if test 380 -ne `wc -c <'filterkit.h'`; then
echo shar: \"'filterkit.h'\" unpacked with wrong size!
fi
# end of 'filterkit.h'
fi
if test -f 'kaiser.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'kaiser.c'\"
else
echo shar: Extracting \"'kaiser.c'\" \(12170 characters\)
sed "s/^X//" >'kaiser.c' <<'END_OF_FILE'
X
X
X/*
X * FILE: resample.c
X * BY: Julius Smith (at CCRMA, Stanford U)
X * C BY: translated from SAIL to C by Christopher Lee Fraley
X * (cf0v@spice.cs.cmu.edu or @andrew.cmu.edu)
X * DATE: 7-JUN-88
X *
X * HACKED: Lance Norskog, Dec. 28, 1991, to make sealed resampler for SoundKit
X */
X
char resampleVERSION[] = "1.3 (24-JUN-88, 3:00pm)";
X
X/*
X * The original version of this program in SAIL may be found in:
X * /../s/usr/mhs/resample or /../x/usr/rbd/src/resample
X *
X * Implement sampling rate conversions by (almost) arbitrary factors.
X * Based on SRCONV.SAI[SYS,MUS] with new algorithm by JOS&PG.
X * The program internally uses 16-bit data and 16-bit filter
X * coefficients.
X *
X * Reference: "A Flexible Sampling-Rate Conversion Method,"
X * J. O. Smith and P. Gossett, ICASSP, San Diego, 1984, Pgs 19.4.
X *
X * * Need overflow detection in Filter() routines. Also, we want
X * to saturate instead of wrap-around and report number of clipped
X * samples.
X */
X
X/* CHANGES from original SAIL program:
X *
X * 1. LpScl is scaled by Factor (when Factor<1) in resample() so this is
X * done whether the filter was loaded or created.
X * 2. makeFilter() - ImpD[] is created from Imp[] instead of ImpR[], to avoid
X * problems with round-off errors.
X * 3. makeFilter() - ImpD[Nwing-1] gets NEGATIVE Imp[Nwing-1].
X * 4. SrcU/D() - Switched order of making guard bits (v>>Nhg) and
X * normalizing. This was done to prevent overflow.
X */
X
X/* LIBRARIES needed:
X *
X * 1. filterkit
X * readFilter() - reads standard filter file
X * FilterUp() - applies filter to sample when Factor >= 1
X * FilterUD() - applies filter to sample for any Factor
X * Query() - prompt user for y/n answer with help.
X * GetDouble() - prompt user for a double with help.
X * GetUShort() - prompt user for a UHWORD with help.
X *
X * 2. math
X */
X
X
X
X
X#include <stdio.h>
X#include <math.h>
X#include <string.h>
X#include "stdefs.h"
X#include "filterkit.h"
X#include "resample.h"
X#include "protos.h"
X
X#define IBUFFSIZE 1024 /* Input buffer size */
X#define OBUFFSIZE (IBUFFSIZE*MAXFACTOR+2) /* Calc'd out buffer size */
X
fail(s)
char *s;
X{
X fprintf(stderr, "kaiser: %s\n\n", s); /* Display error message */
X exit(1); /* Exit, indicating error */
X}
X
fails(s,s2)
char *s, *s2;
X{
X fprintf(stderr, "kaiser: "); /* Display error message */
X fprintf(stderr, s,s2);
X fprintf(stderr, "\n\n");
X exit(1); /* Exit, indicating error */
X}
X
X
X
X
X/* Help Declarations */
X
X/* Global file pointers: */
XFILE *fin, *fout;
X
closeData()
X{
X (void) fclose(fin);
X (void) fclose(fout);
X}
X
X
int readData(Data, DataArraySize, Xoff) /* return: 0 - notDone */
HWORD Data[]; /* >0 - index of last sample */
int DataArraySize, Xoff;
X{
X int Nsamps, Scan;
X short val;
X HWORD *DataStart;
X
X DataStart = Data;
X Nsamps = DataArraySize - Xoff; /* Calculate number of samples to get */
X Data += Xoff; /* Start at designated sample number */
X for (; Nsamps>0; Nsamps--)
X {
X Scan = fread(&val, 1, 2, fin); /* Read in Nsamps samples */
X if (Scan==EOF || Scan==0) /* unless read error or EOF */
X break; /* in which case we exit and */
X *Data++ = val;
X }
X if (Nsamps > 0)
X {
X val = Data - DataStart; /* (Calc return value) */
X while (--Nsamps >= 0) /* fill unread spaces with 0's */
X *Data++ = 0; /* and return FALSE */
X return(val);
X }
X return(0);
X}
X
X
X
writeData(Nout, Data)
int Nout;
HWORD Data[];
X{
X short s;
X /* Write Nout samples to ascii file */
X while (--Nout >= 0) {
X s = *Data++;
X fwrite(&s, 1, 2, fout);
X }
X}
X
X
X
X
getparams(argc, argv, Factor, Froll)
int argc;
char **argv;
double *Factor, *Froll;
X{
X if ((argc != 2) && (argc != 3))
X fail("format is 'resample factor [ rolloff ]'");
X if ((*Factor = atof(argv[1])) < 0.01)
X fail("conversion factor no good");
X if (argc == 2)
X *Froll = 0.5;
X else if ((*Froll = atof(argv[2])) < 0.01)
X fail("rolloff factor no good");
X fin = stdin;
X fout = stdout;
X
X /* Check for illegal constants */
X if (Np >= 16)
X fail("Error: Np>=16");
X if (Nb+Nhg+NLpScl >= 32)
X fail("Error: Nb+Nhg+NLpScl>=32");
X if (Nh+Nb > 32)
X fail("Error: Nh+Nb>32");
X}
X
X
X
X/* Sampling rate up-conversion only subroutine;
X * Slightly faster than down-conversion;
X */
SrcUp(X, Y, Factor, Time, Nx, Nwing, LpScl, Imp, ImpD, Interp)
HWORD X[], Y[], Imp[], ImpD[];
UHWORD Nx, Nwing, LpScl;
UWORD *Time;
double Factor;
BOOL Interp;
X{
X HWORD *Xp, *Ystart;
X WORD v;
X
X double dt; /* Step through input signal */
X UWORD dtb; /* Fixed-point version of Dt */
X UWORD endTime; /* When Time reaches EndTime, return to user */
X
X dt = 1.0/Factor; /* Output sampling period */
X dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */
X
X Ystart = Y;
X endTime = *Time + (1<<Np)*(WORD)Nx;
X while (*Time < endTime)
X {
X Xp = &X[*Time>>Np]; /* Ptr to current input sample */
X v = FilterUp(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),
X -1); /* Perform left-wing inner product */
X v += FilterUp(Imp, ImpD, Nwing, Interp, Xp+1, (HWORD)((-*Time)&Pmask),
X 1); /* Perform right-wing inner product */
X v >>= Nhg; /* Make guard bits */
X v *= LpScl; /* Normalize for unity filter gain */
X *Y++ = v>>NLpScl; /* Deposit output */
X *Time += dtb; /* Move to next sample by time increment */
X }
X return (Y - Ystart); /* Return the number of output samples */
X}
X
X
X
X/* Sampling rate conversion subroutine */
X
SrcUD(X, Y, Factor, Time, Nx, Nwing, LpScl, Imp, ImpD, Interp)
HWORD X[], Y[], Imp[], ImpD[];
UHWORD Nx, Nwing, LpScl;
UWORD *Time;
double Factor;
BOOL Interp;
X{
X HWORD *Xp, *Ystart;
X WORD v;
X
X double dh; /* Step through filter impulse response */
X double dt; /* Step through input signal */
X UWORD endTime; /* When Time reaches EndTime, return to user */
X UWORD dhb, dtb; /* Fixed-point versions of Dh,Dt */
X
X dt = 1.0/Factor; /* Output sampling period */
X dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */
X
X dh = MIN(Npc, Factor*Npc); /* Filter sampling period */
X dhb = dh*(1<<Na) + 0.5; /* Fixed-point representation */
X
X Ystart = Y;
X endTime = *Time + (1<<Np)*(WORD)Nx;
X while (*Time < endTime)
X {
X Xp = &X[*Time>>Np]; /* Ptr to current input sample */
X v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),
X -1, dhb); /* Perform left-wing inner product */
X v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1, (HWORD)((-*Time)&Pmask),
X 1, dhb); /* Perform right-wing inner product */
X v >>= Nhg; /* Make guard bits */
X v *= LpScl; /* Normalize for unity filter gain */
X *Y++ = v>>NLpScl; /* Deposit output */
X *Time += dtb; /* Move to next sample by time increment */
X }
X return (Y - Ystart); /* Return the number of output samples */
X}
X
X
X
int resample(Imp, ImpD, LpScl, Nmult, Nwing, Factor, InterpFilt)
HWORD Imp[], ImpD[];
UHWORD LpScl, Nmult, Nwing;
double Factor;
BOOL InterpFilt;
X{
X UWORD Time; /* Current time/pos in input sample */
X UHWORD Xp, Ncreep, Xoff, Xread;
X HWORD X[IBUFFSIZE], Y[OBUFFSIZE]; /* I/O buffers */
X UHWORD Nout, Nx;
X int i, Ycount, last;
X
X /* Account for increased filter gain when using Factors less than 1 */
X if (Factor < 1)
X LpScl = LpScl*Factor + 0.5;
X /* Calc reach of LP filter wing & give some creeping room */
X Xoff = ((Nmult+1)/2.0) * MAX(1.0,1.0/Factor) + 10;
X if (IBUFFSIZE < 2*Xoff) /* Check input buffer size */
X fail("IBUFFSIZE (or Factor) is too small");
X Nx = IBUFFSIZE - 2*Xoff; /* # of samples to proccess each iteration */
X
X last = FALSE; /* Have not read last input sample yet */
X Ycount = 0; /* Current sample and length of output file */
X Xp = Xoff; /* Current "now"-sample pointer for input */
X Xread = Xoff; /* Position in input array to read into */
X Time = (Xoff<<Np); /* Current-time pointer for converter */
X
X for (i=0; i<Xoff; X[i++]=0); /* Need Xoff zeros at begining of sample */
X
X do {
X if (!last) /* If haven't read last sample yet */
X {
X last = readData(X, IBUFFSIZE, (int)Xread); /* Fill input buffer */
X if (last && (last+Xoff<Nx)) /* If last sample has been read... */
X Nx = last + Xoff; /* ...calc last sample affected by filter */
X }
X if (Factor >= 1) /* Resample stuff in input buffer */
X Ycount += Nout = SrcUp(X,Y,Factor,&Time,Nx,Nwing,LpScl,Imp,ImpD,
X InterpFilt); /* SrcUp() is faster if we can use it */
X else
X Ycount += Nout = SrcUD(X,Y,Factor,&Time,Nx,Nwing,LpScl,Imp,ImpD,
X InterpFilt);
X Time -= (Nx<<Np); /* Move converter Nx samples back in time */
X Xp += Nx; /* Advance by number of samples processed */
X Ncreep = (Time>>Np) - Xoff; /* Calc time accumulation in Time */
X if (Ncreep)
X {
X Time -= (Ncreep<<Np); /* Remove time accumulation */
X Xp += Ncreep; /* and add it to read pointer */
X }
X for (i=0; i<IBUFFSIZE-Xp+Xoff; i++) /* Copy portion of input signal */
X X[i] = X[i+Xp-Xoff]; /* That must be re-used */
X if (last) /* If near end of sample... */
X {
X last -= Xp; /* ...keep track were it ends */
X if (!last) /* Lengthen input by 1 sample if... */
X last++; /* ...needed to keep flag TRUE */
X }
X Xread = i; /* Pos in input buff to read new data into */
X Xp = Xoff;
X
X if (Nout > OBUFFSIZE) /* Check to see if output buff overflowed */
X fail("Output array overflow");
X
X writeData((int)Nout ,Y); /* Write data in output buff to file */
X } while (last >= 0); /* Continue until done processing samples */
X return(Ycount); /* Return # of samples in output file */
X}
X
X
X
X
main(argc, argv)
int argc;
char *argv[];
X{
X double Factor; /* Factor = Fout/Fin */
X double Froll; /* roll-off frequency */
X BOOL InterpFilt = TRUE; /* TRUE means interpolate filter coeffs */
X UHWORD LpScl, Nmult, Nwing;
X HWORD Imp[MAXNWING]; /* Filter coefficients */
X HWORD ImpD[MAXNWING]; /* ImpD[n] = Imp[n+1]-Imp[n] */
X int outCount;
X
X Nmult = 37;
X getparams(argc, argv, &Factor, &Froll);
X genFilter(Imp, ImpD, &LpScl, Nmult, &Nwing, Froll);
X resample(Imp, ImpD, LpScl, Nmult, Nwing, Factor, InterpFilt);
X closeData();
X}
X
char *cantmake[5] = {
X"0 - no error",
X"1 - Nwing too large (Nwing is > MAXNWING)",
X"2 - Froll is not in interval [0:1)",
X"3 - Beta is < 1.0",
X"4 - LpScl will not fit in 16-bits"
X};
X
genFilter(Imp, ImpD, LpScl, Nmult, Nwing, Froll)
HWORD Imp[MAXNWING]; /* Filter coefficients */
HWORD ImpD[MAXNWING]; /* ImpD[i] = ImpD[i+1] - ImpD[i] */
UHWORD Nmult, *LpScl, *Nwing;
double Froll;
X{
X double Beta = 2.120;
X int err;
X
X *Nwing = Npc*(Nmult+1)/2; /* # of filter coeffs in right wing */
X *Nwing += Npc/2 + 1; /* This prevents just missing last coeff */
X /* for integer conversion factors */
X if ((Froll<=0) || (Froll>1))
X fail("Error: Roll-off freq must be 0<Factor<=1\n");
X if (err = makeFilter(Imp, ImpD, LpScl, *Nwing, Froll, Beta))
X fails("Error: Unable to make filter: %s\n", cantmake[err]);
X}
X
END_OF_FILE
if test 12170 -ne `wc -c <'kaiser.c'`; then
echo shar: \"'kaiser.c'\" unpacked with wrong size!
fi
# end of 'kaiser.c'
fi
if test -f 'makefilter.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'makefilter.c'\"
else
echo shar: Extracting \"'makefilter.c'\" \(4633 characters\)
sed "s/^X//" >'makefilter.c' <<'END_OF_FILE'
X
X/*
X * FILE: makefilter.c
X * BY: Christopher Lee Fraley (cf0v@spice.cmu.edu or cf0v@andrew.cmu.edu)
X * DESC: Makes a Kaiser-windowed low-pass filter.
X * DATE: 7-JUN-88
X */
X
char makefilterVERSION[] = "2.0 (17-JUN-88 3:00pm)";
X
X#include <stdio.h>
X#include <math.h>
X#include "stdefs.h"
X#include "resample.h"
X#include "filterkit.h"
X
X/* LIBRARIES needed:
X *
X * 1. filterkit
X * makeFilter() - designs a Kaiser-windowed low-pass filter
X * writeFilter() - writes a filter to a standard filter file
X * GetUShort() - prompt user for a UHWORD with help
X * GetDouble() - prompt user for a double with help
X *
X * 2. math
X */
X
X
X
char NmultHelp[] =
X "\n Nmult is the length of the symmetric FIR lowpass filter used\
X \n by the sampling rate converter. It must be odd.\
X \n This is the number of multiplies per output sample for\
X \n up-conversions (Factor>1), and is the number of multiplies\
X \n per input sample for down-conversions (Factor<1). Thus if\
X \n the rate conversion is Srate2 = Factor*Srate1, then you have\
X \n Nmult*Srate1*MAXof(Factor,1) multiplies per second of real time.\
X \n Naturally, higher Nmult gives better lowpass-filtering at the\
X \n expense of longer compute times. Nmult should be odd because\
X \n it is the length of a symmetric FIR filter, and the current\
X \n implementation requires a coefficient at the time origin.\n";
X
char FrollHelp[] =
X "\n Froll determines the frequency at which the lowpass filter begins to\
X \n roll-off. If Froll=1, then there is no 'guard zone' and the filter\
X \n roll-off region will be aliased. If Froll is 0.85, for example, then\
X \n the filter begins rolling off at 0.85*Srate/2, so that by Srate/2,\
X \n the filter is well down and aliasing is reduced. Since aliasing\
X \n distortion is worse by far than loss of the high-frequency spectral\
X \n amplitude, Froll<1 is highly recommended. The default of 0.85\
X \n sacrifices the upper 15% of the spectrum as an anti-aliasing guard\
X \n zone.\n";
X
char BetaHelp[] =
X "\n Beta trades the rejection of the lowpass filter against the\
X \n transition width from passband to stopband. Larger Beta means\
X \n a slower transition and greater stopband rejection. See Rabiner\
X \n and Gold (Th. and App. of DSP) under Kaiser windows for more about\
X \n Beta. The following table from Rabiner and Gold gives some feel\
X \n for the effect of Beta:\
X \n\
X \nAll ripples in dB, width of transition band =D*N, where N= window length\
X \n\
X \n BETA D PB RIP SB RIP\
X \n 2.120 1.50 +-0.27 -30\
X \n 3.384 2.23 0.0864 -40\
X \n 4.538 2.93 0.0274 -50\
X \n 5.658 3.62 0.00868 -60\
X \n 6.764 4.32 0.00275 -70\
X \n 7.865 5.0 0.000868 -80\
X \n 8.960 5.7 0.000275 -90\
X \n 10.056 6.4 0.000087 -100\n";
X
X
X
main()
X{
X HWORD Imp[MAXNWING]; /* Filter coefficients */
X HWORD ImpD[MAXNWING]; /* ImpD[i] = ImpD[i+1] - ImpD[i] */
X double Froll, Beta;
X UHWORD Nmult, Nwing, LpScl;
X int err;
X
X printf("\nKaiser-windowed FIR Filter Design\n");
X printf("Written by: Chritopher Lee Fraley\n");
X printf("Version %s\n", makefilterVERSION);
X
X Nmult = 13;
X Froll = 0.425;
X Beta = 5.7;
X while (TRUE)
X {
X Nmult = GetUHWORD("(Odd) Filter length 'Nmult'", Nmult, NmultHelp);
X Nwing = Npc*(Nmult+1)/2; /* # of filter coeffs in right wing */
X Nwing += Npc/2 + 1; /* This prevents just missing last coeff */
X /* for integer conversion factors */
X Froll = GetDouble("Normalized Roll-off freq (0<Froll<=1)",
X Froll, FrollHelp);
X Beta = GetDouble("Beta", Beta, BetaHelp);
X printf("\n");
X if (!(Nmult % 2))
X printf("Error: Nmult must be odd and greater than zero\n");
X else if (Nwing > MAXNWING)
X printf("Error: Nmult too large for current MAXNWING\n");
X else if ((Froll<=0) || (Froll>1))
X printf("Error: Roll-off freq must be 0<Froll<=1\n");
X else if (Beta < 1)
X printf("Error: Beta must be greater or equal to 1\n");
X else if (err = makeFilter(Imp, ImpD, &LpScl, Nwing, Froll, Beta))
X printf("Error: Unable to make filter, err=%d\n", err);
X else if (err = writeFilter(Imp, ImpD, LpScl, Nmult, Nwing))
X printf("Error: Unable to write filter, err=%d\n", err);
X else
X break;
X }
X}
X
END_OF_FILE
if test 4633 -ne `wc -c <'makefilter.c'`; then
echo shar: \"'makefilter.c'\" unpacked with wrong size!
fi
# end of 'makefilter.c'
fi
if test -f 'protos.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'protos.h'\"
else
echo shar: Extracting \"'protos.h'\" \(3396 characters\)
sed "s/^X//" >'protos.h' <<'END_OF_FILE'
X#if defined(__STDC__) || defined(__cplusplus)
X# define P_(s) s
X#else
X# define P_(s) ()
X#endif
X
X
X/* filterkit.c */
double Izero P_((double x));
void LpFilter P_((double c[], int N, double frq, double Beta, int Num));
int writeFilter P_((HWORD Imp[], HWORD ImpD[], UHWORD LpScl, UHWORD Nmult, UHWORD Nwing));
int makeFilter P_((HWORD Imp[], HWORD ImpD[], UHWORD *LpScl, UHWORD Nwing, double Froll, double Beta));
int readFilter P_((HWORD Imp[], HWORD ImpD[], UHWORD *LpScl, UHWORD Nmult, UHWORD *Nwing));
WORD FilterUp P_((HWORD Imp[], HWORD ImpD[], UHWORD Nwing, BOOL Interp, HWORD *Xp, HWORD Ph, HWORD Inc));
WORD FilterUD P_((HWORD Imp[], HWORD ImpD[], UHWORD Nwing, BOOL Interp, HWORD *Xp, HWORD Ph, HWORD Inc, UHWORD dhb));
int initZerox P_((UHWORD tempNmult));
double zerox P_((HWORD *Data, double Factor));
BOOL Query P_((char *prompt, BOOL deflt, char *help));
char *GetString P_((char *prompt, char *deflt, char *help));
int getstr P_((char *s1, char *deflt, char *s2));
double GetDouble P_((char *title, double deflt, char *help));
unsigned short GetUShort P_((char *title, unsigned int deflt, char *help));
X
X/* makefilter.c */
int main P_((void));
X
X/* nres.c */
int fail P_((char *s));
int fails P_((char *s, char *s2));
int closeData P_((void));
int readData P_((HWORD Data[], int DataArraySize, int Xoff));
int writeData P_((int Nout, HWORD Data[]));
int getparams P_((int argc, char **argv, double *Factor, double *Froll));
int SrcUp P_((HWORD X[], HWORD Y[], double Factor, UWORD *Time, UHWORD Nx, UHWORD Nwing, UHWORD LpScl, HWORD Imp[], HWORD ImpD[], BOOL Interp));
int SrcUD P_((HWORD X[], HWORD Y[], double Factor, UWORD *Time, UHWORD Nx, UHWORD Nwing, UHWORD LpScl, HWORD Imp[], HWORD ImpD[], BOOL Interp));
int resample P_((HWORD Imp[], HWORD ImpD[], UHWORD LpScl, UHWORD Nmult, UHWORD Nwing, double Factor, BOOL InterpFilt));
int main P_((int argc, char *argv[]));
int genFilter P_((HWORD Imp[MAXNWING ], HWORD ImpD[MAXNWING ], UHWORD *LpScl, UHWORD Nmult, UHWORD *Nwing, double Froll));
X
X/* resample.c */
int fail P_((char *s));
int fails P_((char *s, char *s2));
int openData P_((int argc, char *argv[]));
int closeData P_((void));
int readData P_((HWORD Data[], int DataArraySize, int Xoff));
int writeData P_((int Nout, HWORD Data[]));
int getparams P_((double *Factor, BOOL *InterpFilt, UHWORD *Nmult));
int SrcUp P_((HWORD X[], HWORD Y[], double Factor, UWORD *Time, UHWORD Nx, UHWORD Nwing, UHWORD LpScl, HWORD Imp[], HWORD ImpD[], BOOL Interp));
int SrcUD P_((HWORD X[], HWORD Y[], double Factor, UWORD *Time, UHWORD Nx, UHWORD Nwing, UHWORD LpScl, HWORD Imp[], HWORD ImpD[], BOOL Interp));
int resample P_((HWORD Imp[], HWORD ImpD[], UHWORD LpScl, UHWORD Nmult, UHWORD Nwing, double Factor, BOOL InterpFilt));
int main P_((int argc, char *argv[]));
X
X/* warp.c */
int fail P_((char *s));
int fails P_((char *s, char *s2));
int openData P_((int argc, char *argv[]));
int closeData P_((void));
int readData P_((HWORD Data[], int DataArraySize, int Xoff));
int writeData P_((int Nout, HWORD Data[]));
int check P_((void));
int initWarp P_((void));
double warpFunction P_((UWORD Time));
int SrcUD P_((HWORD X[], HWORD Y[], UWORD *Time, UHWORD Nx, UHWORD Nwing, UHWORD LpScl, HWORD Imp[], HWORD ImpD[], BOOL Interp));
int resample P_((HWORD Imp[], HWORD ImpD[], UHWORD LpScl, UHWORD Nmult, UHWORD Nwing, BOOL InterpFilt));
int main P_((int argc, char *argv[]));
X
X#undef P_
END_OF_FILE
if test 3396 -ne `wc -c <'protos.h'`; then
echo shar: \"'protos.h'\" unpacked with wrong size!
fi
# end of 'protos.h'
fi
if test -f 'resample.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'resample.c'\"
else
echo shar: Extracting \"'resample.c'\" \(13378 characters\)
sed "s/^X//" >'resample.c' <<'END_OF_FILE'
X
X/*
X * FILE: resample.c
X * BY: Julius Smith (at CCRMA, Stanford U)
X * C BY: translated from SAIL to C by Christopher Lee Fraley
X * (cf0v@spice.cs.cmu.edu or @andrew.cmu.edu)
X * DATE: 7-JUN-88
X */
X
char resampleVERSION[] = "1.3 (24-JUN-88, 3:00pm)";
X
X/*
X * The original version of this program in SAIL may be found in:
X * /../s/usr/mhs/resample or /../x/usr/rbd/src/resample
X *
X * Implement sampling rate conversions by (almost) arbitrary factors.
X * Based on SRCONV.SAI[SYS,MUS] with new algorithm by JOS&PG.
X * The program internally uses 16-bit data and 16-bit filter
X * coefficients.
X *
X * Reference: "A Flexible Sampling-Rate Conversion Method,"
X * J. O. Smith and P. Gossett, ICASSP, San Diego, 1984, Pgs 19.4.
X *
X * * Need overflow detection in Filter() routines. Also, we want
X * to saturate instead of wrap-around and report number of clipped
X * samples.
X */
X
X/* CHANGES from original SAIL program:
X *
X * 1. LpScl is scaled by Factor (when Factor<1) in resample() so this is
X * done whether the filter was loaded or created.
X * 2. makeFilter() - ImpD[] is created from Imp[] instead of ImpR[], to avoid
X * problems with round-off errors.
X * 3. makeFilter() - ImpD[Nwing-1] gets NEGATIVE Imp[Nwing-1].
X * 4. SrcU/D() - Switched order of making guard bits (v>>Nhg) and
X * normalizing. This was done to prevent overflow.
X */
X
X/* LIBRARIES needed:
X *
X * 1. filterkit
X * readFilter() - reads standard filter file
X * FilterUp() - applies filter to sample when Factor >= 1
X * FilterUD() - applies filter to sample for any Factor
X * Query() - prompt user for y/n answer with help.
X * GetDouble() - prompt user for a double with help.
X * GetUShort() - prompt user for a UHWORD with help.
X *
X * 2. math
X */
X
X
X
X
X#include <stdio.h>
X#include <math.h>
X#include <string.h>
X#include "stdefs.h"
X#include "filterkit.h"
X#include "resample.h"
X
X#define IBUFFSIZE 1024 /* Input buffer size */
X#define OBUFFSIZE (IBUFFSIZE*MAXFACTOR+2) /* Calc'd out buffer size */
X
X
fail(s)
char *s;
X{
X printf("resample: %s\n\n", s); /* Display error message */
X exit(1); /* Exit, indicating error */
X}
X
fails(s,s2)
char *s, *s2;
X{
X printf("resample: "); /* Display error message */
X printf(s,s2);
X printf("\n\n");
X exit(1); /* Exit, indicating error */
X}
X
X
X
X
X/* Help Declarations */
char FactorHelp[] =
X "\n Factor is the amount by which the sampling rate is changed.\
X \n If the sampling rate of the input signal is Srate1, then the\
X \n sampling rate of the output is Factor*Srate1.\n";
X
char NmultHelp[] =
X "\n Nmult is the length of the symmetric FIR lowpass filter used\
X \n by the sampling rate converter. It must be odd.\
X \n This is the number of multiplies per output sample for\
X \n up-conversions (Factor>1), and is the number of multiplies\
X \n per input sample for down-conversions (Factor<1). Thus if\
X \n the rate conversion is Srate2 = Factor*Srate1, then you have\
X \n Nmult*Srate1*MAXof(Factor,1) multiplies per second of real time.\
X \n Naturally, higher Nmult gives better lowpass-filtering at the\
X \n expense of longer compute times. Nmult should be odd because\
X \n it is the length of a symmetric FIR filter, and the current\
X \n implementation requires a coefficient at the time origin.\n";
X
char InterpFiltHelp[] =
X "\n By electing to interpolate the filter look-up table,\
X \n execution is slowed down but the quality of filtering\
X \n is higher. Interpolation results in twice as many\
X \n multiply-adds per sample of output.\n";
X
X
X
X/* Global file pointers: */
XFILE *fin, *fout;
X
X
openData(argc,argv)
int argc;
char *argv[];
X{
X if (argc != 3)
X fail("format is 'resample <filein> <fileout>'");
X if (NULL == (fin = fopen(*++argv,"r")))
X fails("could not open input file '%s'",*argv);
X if (NULL == (fout = fopen(*++argv,"w")))
X fails("could not open output file '%s'",*argv);
X}
X
X
closeData()
X{
X (void) fclose(fin);
X (void) fclose(fout);
X}
X
X
int readData(Data, DataArraySize, Xoff) /* return: 0 - notDone */
HWORD Data[]; /* >0 - index of last sample */
int DataArraySize, Xoff;
X{
X int Nsamps, Scan;
X short val;
X HWORD *DataStart;
X
X DataStart = Data;
X Nsamps = DataArraySize - Xoff; /* Calculate number of samples to get */
X Data += Xoff; /* Start at designated sample number */
X for (; Nsamps>0; Nsamps--)
X {
X Scan = fread(&val, 1, 2, fin); /* Read in Nsamps samples */
X if (Scan==EOF || Scan==0) /* unless read error or EOF */
X break; /* in which case we exit and */
X *Data++ = val;
X }
X if (Nsamps > 0)
X {
X val = Data - DataStart; /* (Calc return value) */
X while (--Nsamps >= 0) /* fill unread spaces with 0's */
X *Data++ = 0; /* and return FALSE */
X return(val);
X }
X return(0);
X}
X
X
X
writeData(Nout, Data)
int Nout;
HWORD Data[];
X{
X short s;
X /* Write Nout samples to ascii file */
X while (--Nout >= 0) {
X s = *Data++;
X fwrite(&s, 1, 2, fout);
X }
X}
X
X
X
X
getparams(Factor, InterpFilt, Nmult)
double *Factor;
BOOL *InterpFilt;
UHWORD *Nmult;
X{
X /* Check for illegal constants */
X if (Np >= 16)
X fail("Error: Np>=16");
X if (Nb+Nhg+NLpScl >= 32)
X fail("Error: Nb+Nhg+NLpScl>=32");
X if (Nh+Nb > 32)
X fail("Error: Nh+Nb>32");
X
X /* Default conversion parameters */
X *Factor = 2;
X *InterpFilt = TRUE;
X
X /* Set up conversion parameters */
X while (TRUE)
X {
X *Factor =
X GetDouble("Sampling-rate conversion factor",*Factor,FactorHelp);
X if (*Factor <= MAXFACTOR)
X break;
X printf("Error: Factor must be <= %g to prevent out buffer overflow",
X MAXFACTOR);
X *Factor = MAXFACTOR;
X }
X *Nmult = GetUHWORD("Nmult",*Nmult,NmultHelp);
X *InterpFilt = Query("Interpolate filter?", *InterpFilt, InterpFiltHelp);
X}
X
X
X
X/* Sampling rate up-conversion only subroutine;
X * Slightly faster than down-conversion;
X */
SrcUp(X, Y, Factor, Time, Nx, Nwing, LpScl, Imp, ImpD, Interp)
HWORD X[], Y[], Imp[], ImpD[];
UHWORD Nx, Nwing, LpScl;
UWORD *Time;
double Factor;
BOOL Interp;
X{
X HWORD *Xp, *Ystart;
X WORD v;
X
X double dt; /* Step through input signal */
X UWORD dtb; /* Fixed-point version of Dt */
X UWORD endTime; /* When Time reaches EndTime, return to user */
X
X dt = 1.0/Factor; /* Output sampling period */
X dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */
X
X Ystart = Y;
X endTime = *Time + (1<<Np)*(WORD)Nx;
X while (*Time < endTime)
X {
X Xp = &X[*Time>>Np]; /* Ptr to current input sample */
X v = FilterUp(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),
X -1); /* Perform left-wing inner product */
X v += FilterUp(Imp, ImpD, Nwing, Interp, Xp+1, (HWORD)((-*Time)&Pmask),
X 1); /* Perform right-wing inner product */
X v >>= Nhg; /* Make guard bits */
X v *= LpScl; /* Normalize for unity filter gain */
X *Y++ = v>>NLpScl; /* Deposit output */
X *Time += dtb; /* Move to next sample by time increment */
X }
X return (Y - Ystart); /* Return the number of output samples */
X}
X
X
X
X/* Sampling rate conversion subroutine */
X
SrcUD(X, Y, Factor, Time, Nx, Nwing, LpScl, Imp, ImpD, Interp)
HWORD X[], Y[], Imp[], ImpD[];
UHWORD Nx, Nwing, LpScl;
UWORD *Time;
double Factor;
BOOL Interp;
X{
X HWORD *Xp, *Ystart;
X WORD v;
X
X double dh; /* Step through filter impulse response */
X double dt; /* Step through input signal */
X UWORD endTime; /* When Time reaches EndTime, return to user */
X UWORD dhb, dtb; /* Fixed-point versions of Dh,Dt */
X
X dt = 1.0/Factor; /* Output sampling period */
X dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */
X
X dh = MIN(Npc, Factor*Npc); /* Filter sampling period */
X dhb = dh*(1<<Na) + 0.5; /* Fixed-point representation */
X
X Ystart = Y;
X endTime = *Time + (1<<Np)*(WORD)Nx;
X while (*Time < endTime)
X {
X Xp = &X[*Time>>Np]; /* Ptr to current input sample */
X v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),
X -1, dhb); /* Perform left-wing inner product */
X v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1, (HWORD)((-*Time)&Pmask),
X 1, dhb); /* Perform right-wing inner product */
X v >>= Nhg; /* Make guard bits */
X v *= LpScl; /* Normalize for unity filter gain */
X *Y++ = v>>NLpScl; /* Deposit output */
X *Time += dtb; /* Move to next sample by time increment */
X }
X return (Y - Ystart); /* Return the number of output samples */
X}
X
X
X
int resample(Imp, ImpD, LpScl, Nmult, Nwing, Factor, InterpFilt)
HWORD Imp[], ImpD[];
UHWORD LpScl, Nmult, Nwing;
double Factor;
BOOL InterpFilt;
X{
X UWORD Time; /* Current time/pos in input sample */
X UHWORD Xp, Ncreep, Xoff, Xread;
X HWORD X[IBUFFSIZE], Y[OBUFFSIZE]; /* I/O buffers */
X UHWORD Nout, Nx;
X int i, Ycount, last;
X
X /* Account for increased filter gain when using Factors less than 1 */
X if (Factor < 1)
X LpScl = LpScl*Factor + 0.5;
X /* Calc reach of LP filter wing & give some creeping room */
X Xoff = ((Nmult+1)/2.0) * MAX(1.0,1.0/Factor) + 10;
X if (IBUFFSIZE < 2*Xoff) /* Check input buffer size */
X fail("IBUFFSIZE (or Factor) is too small");
X Nx = IBUFFSIZE - 2*Xoff; /* # of samples to proccess each iteration */
X
X last = FALSE; /* Have not read last input sample yet */
X Ycount = 0; /* Current sample and length of output file */
X Xp = Xoff; /* Current "now"-sample pointer for input */
X Xread = Xoff; /* Position in input array to read into */
X Time = (Xoff<<Np); /* Current-time pointer for converter */
X
X for (i=0; i<Xoff; X[i++]=0); /* Need Xoff zeros at begining of sample */
X
X do {
X if (!last) /* If haven't read last sample yet */
X {
X last = readData(X, IBUFFSIZE, (int)Xread); /* Fill input buffer */
X if (last && (last+Xoff<Nx)) /* If last sample has been read... */
X Nx = last + Xoff; /* ...calc last sample affected by filter */
X }
X if (Factor >= 1) /* Resample stuff in input buffer */
X Ycount += Nout = SrcUp(X,Y,Factor,&Time,Nx,Nwing,LpScl,Imp,ImpD,
X InterpFilt); /* SrcUp() is faster if we can use it */
X else
X Ycount += Nout = SrcUD(X,Y,Factor,&Time,Nx,Nwing,LpScl,Imp,ImpD,
X InterpFilt);
X Time -= (Nx<<Np); /* Move converter Nx samples back in time */
X Xp += Nx; /* Advance by number of samples processed */
X Ncreep = (Time>>Np) - Xoff; /* Calc time accumulation in Time */
X if (Ncreep)
X {
X Time -= (Ncreep<<Np); /* Remove time accumulation */
X Xp += Ncreep; /* and add it to read pointer */
X }
X for (i=0; i<IBUFFSIZE-Xp+Xoff; i++) /* Copy portion of input signal */
X X[i] = X[i+Xp-Xoff]; /* That must be re-used */
X if (last) /* If near end of sample... */
X {
X last -= Xp; /* ...keep track were it ends */
X if (!last) /* Lengthen input by 1 sample if... */
X last++; /* ...needed to keep flag TRUE */
X }
X Xread = i; /* Pos in input buff to read new data into */
X Xp = Xoff;
X
X if (Nout > OBUFFSIZE) /* Check to see if output buff overflowed */
X fail("Output array overflow");
X
X writeData((int)Nout ,Y); /* Write data in output buff to file */
X } while (last >= 0); /* Continue until done processing samples */
X return(Ycount); /* Return # of samples in output file */
X}
X
X
X
X
main(argc, argv)
int argc;
char *argv[];
X{
X double Factor; /* Factor = Fout/Fin */
X BOOL InterpFilt; /* TRUE means interpolate filter coeffs */
X UHWORD LpScl, Nmult, Nwing;
X HWORD Imp[MAXNWING]; /* Filter coefficients */
X HWORD ImpD[MAXNWING]; /* ImpD[n] = Imp[n+1]-Imp[n] */
X int outCount;
X
X Nmult = 13;
X printf("\nSampling Rate Conversion Program\n");
X printf("Written by: Julius O. Smith (CCRMA)\n");
X printf("Translated to C by: Christopher Lee Fraley (cf0v@spice.cs.cmu.edu)\n");
X printf("Version %s\n", resampleVERSION);
X openData(argc, argv); /* Interp arguments and open i&o files */
X getparams(&Factor, &InterpFilt, &Nmult);
X if (readFilter(Imp, ImpD, &LpScl, Nmult, &Nwing))
X fail("could not find filter file, or syntax error in filter file");
X printf("\nStarting Conversion...\n");
X outCount = resample(Imp, ImpD, LpScl, Nmult, Nwing, Factor, InterpFilt);
X closeData();
X
X printf("...Conversion Finished: %d output samples.\n\n",outCount);
X}
X
END_OF_FILE
if test 13378 -ne `wc -c <'resample.c'`; then
echo shar: \"'resample.c'\" unpacked with wrong size!
fi
# end of 'resample.c'
fi
if test -f 'resample.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'resample.h'\"
else
echo shar: Extracting \"'resample.h'\" \(2942 characters\)
sed "s/^X//" >'resample.h' <<'END_OF_FILE'
X
X/*
X * FILE: resample.h
X * BY: Julius Smith (at CCRMA, Stanford U)
X * C BY: translated from SAIL to C by Christopher Lee Fraley
X * (cf0v@andrew.cmu.edu)
X * DATE: 7-JUN-88
X * VERS: 2.0 (17-JUN-88, 3:00pm)
X */
X
X#define MAXNWING 5122
X#define MAXFACTOR 4 /* Maximum Factor without output buff overflow */
X
X
X
X/* Conversion constants */
X#define Nhc 8
X#define Na 7
X#define Np (Nhc+Na)
X#define Npc (1<<Nhc)
X#define Amask ((1<<Na)-1)
X#define Pmask ((1<<Np)-1)
X#define Nh 16
X#define Nb 16
X#define Nhxn 14
X#define Nhg (Nh-Nhxn)
X#define NLpScl 13
X
X/* Description of constants:
X *
X * Npc - is the number of look-up values available for the lowpass filter
X * between the beginning of its impulse response and the "cutoff time"
X * of the filter. The cutoff time is defined as the reciprocal of the
X * lowpass-filter cut off frequence in Hz. For example, if the
X * lowpass filter were a sinc function, Npc would be the index of the
X * impulse-response lookup-table corresponding to the first zero-
X * crossing of the sinc function. (The inverse first zero-crossing
X * time of a sinc function equals its nominal cutoff frequency in Hz.)
X * Npc must be a power of 2 due to the details of the current
X * implementation. The default value of 512 is sufficiently high that
X * using linear interpolation to fill in between the table entries
X * gives approximately 16-bit accuracy in filter coefficients.
X *
X * Nhc - is log base 2 of Npc.
X *
X * Na - is the number of bits devoted to linear interpolation of the
X * filter coefficients.
X *
X * Np - is Na + Nhc, the number of bits to the right of the binary point
X * in the integer "time" variable. To the left of the point, it indexes
X * the input array (X), and to the right, it is interpreted as a number
X * between 0 and 1 sample of the input X. Np must be less than 16 in
X * this implementation.
X *
X * Nh - is the number of bits in the filter coefficients. The sum of Nh and
X * the number of bits in the input data (typically 16) cannot exceed 32.
X * Thus Nh should be 16. The largest filter coefficient should nearly
X * fill 16 bits (32767).
X *
X * Nb - is the number of bits in the input data. The sum of Nb and Nh cannot
X * exceed 32.
X *
X * Nhxn - is the number of bits to right shift after multiplying each input
X * sample times a filter coefficient. It can be as great as Nh and as
X * small as 0. Nhxn = Nh-2 gives 2 guard bits in the multiply-add
X * accumulation. If Nhxn=0, the accumulation will soon overflow 32 bits.
X *
X * Nhg - is the number of guard bits in mpy-add accumulation (equal to Nh-Nhxn).
X *
X * NLpScl - is the number of bits allocated to the unity-gain normalization
X * factor. The output of the lowpass filter is multiplied by LpScl and
X * then right-shifted NLpScl bits. To avoid overflow, we must have
X * Nb+Nhg+NLpScl < 32.
X */
X
END_OF_FILE
if test 2942 -ne `wc -c <'resample.h'`; then
echo shar: \"'resample.h'\" unpacked with wrong size!
fi
# end of 'resample.h'
fi
if test -f 'stdefs.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'stdefs.h'\"
else
echo shar: Extracting \"'stdefs.h'\" \(699 characters\)
sed "s/^X//" >'stdefs.h' <<'END_OF_FILE'
X
X/*
X * FILE: stdefs.h
X * BY: Christopher Lee Fraley
X * DESC: Defines standard stuff for inclusion in C programs.
X * DATE: 6-JUN-88
X * VERS: 1.0 (6-JUN-88, 2:00pm)
X */
X
X
X#define TRUE 1
X#define FALSE 0
X
X#define PI (3.14159265358979232846)
X#define PI2 (6.28318530717958465692)
X#define D2R (0.01745329348) /* (2*pi)/360 */
X#define R2D (57.29577951) /* 360/(2*pi) */
X
X#define MAX(x,y) ((x)>(y) ?(x):(y))
X#define MIN(x,y) ((x)<(y) ?(x):(y))
X#define ABS(x) ((x)<0 ?(-(x)):(x))
X#define SGN(x) ((x)<0 ?(-1):((x)==0?(0):(1)))
X
typedef char BOOL;
typedef short HWORD;
typedef unsigned short UHWORD;
typedef int WORD;
typedef unsigned int UWORD;
X
END_OF_FILE
if test 699 -ne `wc -c <'stdefs.h'`; then
echo shar: \"'stdefs.h'\" unpacked with wrong size!
fi
# end of 'stdefs.h'
fi
if test -f 'warp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'warp.c'\"
else
echo shar: Extracting \"'warp.c'\" \(10961 characters\)
sed "s/^X//" >'warp.c' <<'END_OF_FILE'
X
X/*
X * FILE: warp.c
X * BY: Christopher Lee Fraley (cf0v@spice.cs.cmu.edu)
X * NOTE: Based upon SAIL program by Julius O. Smith (CCRMA, Stanford U)
X * DATE: 17-JUN-88
X */
X
char warpVERSION[] = "1.0 24-JUN-88, 4:20pm";
X
X/*
X * The original SAIL program on which this is based may be found in
X * /../s/usr/mhs/resample or /../x/usr/rbd/src/resample
X *
X * Implement dynamic sampling-rate changes; uses a second file to
X * indicate where periods should fall. This program may be used to add
X * or remove vibrato and micro pitch variations from a sound sample.
X * Based on SRCONV.SAI[SYS,MUS] with new algorithm by JOS&PG.
X * The program internally uses 16-bit data and 16-bit filter
X * coefficients.
X *
X * Reference: "A Flexible Sampling-Rate Conversion Method,"
X * J. O. Smith and P. Gossett, ICASSP, San Diego, 1984, Pgs 19.4.
X *
X * * Need overflow detection in Filter() routines. Also, we want
X * to saturate instead of wrap-around and report number of clipped
X * samples.
X */
X
X/* CHANGES from original SAIL program:
X *
X * 1. SrcUD() - Switched order of making guard bits (v>>Nhg) and
X * normalizing. This was done to prevent overflow.
X */
X
X/* LIBRARIES needed:
X *
X * 1. filterkit
X * readFilter() - reads standard filter file.
X * FilterUD() - applies filter to sample for any Factor.
X * GetDouble() - prompt user for a double with help.
X *
X * 2. math
X */
X
X
X
X
X#include <stdio.h>
X#include <math.h>
X#include <string.h>
X#include "stdefs.h"
X#include "filterkit.h"
X#include "resample.h"
X
X#define IBUFFSIZE 1024 /* Input buffer size */
X#define OBUFFSIZE (IBUFFSIZE*MAXFACTOR+2) /* Calc'd out buffer size */
X
X
fail(s)
char *s;
X{
X printf("warp: %s\n\n", s); /* Display error message */
X exit(1); /* Exit, indicating error */
X}
X
fails(s,s2)
char *s, *s2;
X{
X printf("warp: "); /* Display error message */
X printf(s, s2);
X printf("\n\n");
X exit(1); /* Exit, indicating error */
X}
X
X
X
X/* Global file pointers: */
XFILE *fin, *fout;
X
X
int openData(argc, argv)
int argc;
char *argv[];
X{
X if (argc != 3)
X fail("format is 'warp <file-in> <file-out>'");
X if (NULL == (fin = fopen(*++argv,"r")))
X fails("could not open <file-in> file '%s'",*argv);
X if (NULL == (fout = fopen(*++argv,"w")))
X fails("could not open <file-out> file '%s'",*argv);
X}
X
X
closeData()
X{
X (void) fclose(fin);
X (void) fclose(fout);
X}
X
X
X
int readData(Data, DataArraySize, Xoff) /* return: 0 - notDone */
HWORD Data[]; /* >0 - index of last sample */
int DataArraySize, Xoff;
X{
X int Nsamps, Scan, val;
X HWORD *DataStart;
X
X DataStart = Data;
X Nsamps = DataArraySize - Xoff; /* Calculate number of samples to get */
X Data += Xoff; /* Start at designated sample number */
X for (; Nsamps>0; Nsamps--)
X {
X Scan = fscanf(fin, "%d", &val); /* Read in Nsamps samples */
X if (Scan==EOF || Scan==0) /* unless read error or EOF */
X break; /* in which case we exit and */
X *Data++ = val;
X }
X if (Nsamps > 0)
X {
X val = Data - DataStart; /* (Calc return value) */
X while (--Nsamps >= 0) /* fill unread spaces with 0's */
X *Data++ = 0; /* and return FALSE */
X return(val);
X }
X return(0);
X}
X
X
X
writeData(Nout, Data)
int Nout;
HWORD Data[];
X{
X while (--Nout >= 0) /* Write Nout samples to ascii file */
X fprintf(fout, "%d\n", *Data++);
X}
X
X
X
X
check()
X{
X /* Check for illegal constants */
X if (Np >= 16)
X fail("Error: Np>=16");
X if (Nb+Nhg+NLpScl >= 32)
X fail("Error: Nb+Nhg+NLpScl>=32");
X if (Nh+Nb > 32)
X fail("Error: Nh+Nb>32");
X}
X
X
X/* Globals for warping frequency */
double a,b,c,d,e,f,Total;
int Acc;
X
initWarp()
X{
X Total = GetDouble("\n# of input samples",12000.0,"");
X
X printf("Warping function: Fout/Fin = w(n)\n");
X printf(" w(n) = off + [amp * sin(ph1+frq1*n/N) * sin(ph2+frq2*n/N)]\n");
X printf(" where: off,amp,ph1 - parameters\n");
X printf(" frq1,ph2,frq2 - more parameters\n");
X printf(" n - current input sample number\n");
X printf(" N - total number of input samples\n");
X
X a = GetDouble("off",1.5,"");
X b = GetDouble("amp",-0.5,"");
X c = D2R * GetDouble("ph1 (degrees)",-90.0,"");
X d = GetDouble("frq1",1.0,"");
X e = D2R * GetDouble("ph2 (degrees)",90.0,"");
X f = GetDouble("frq2",0.0,"");
X}
X
X
double warpFunction(Time)
UWORD Time;
X{
X double fTime,t;
X
X /* Calc absolute position in input file: */
X fTime = (double)Time / (double)(1<<Np) + (double)Acc;
X /* Calc fraction of file processed: */
X t = fTime/Total;
X /* Return warp factor: */
X return (1.0 / (a + b*sin(c+PI2*d*t)*sin(e+PI2*f*t)));
X}
X
X
X/* Sampling rate conversion subroutine */
X
SrcUD(X, Y, Time, Nx, Nwing, LpScl, Imp, ImpD, Interp)
HWORD X[], Y[], Imp[], ImpD[];
UHWORD Nx, Nwing, LpScl;
UWORD *Time;
BOOL Interp;
X{
X HWORD *Xp, *Ystart;
X WORD v;
X
X UHWORD NewScl; /* Unity gain scale factor */
X double dh; /* Step through filter impulse response */
X double dt; /* Step through input signal */
X UWORD endTime; /* When Time reaches EndTime, return to user */
X UWORD dhb, dtb; /* Fixed-point versions of Dh,Dt */
X double Factor; /* Current resampling factor */
X
X Ystart = Y;
X endTime = *Time + (1<<Np)*(WORD)Nx;
X while (*Time < endTime)
X {
X Factor = warpFunction(*Time); /* Get new conversion Factor */
X NewScl = LpScl * Factor; /* Calc new normalizing scalar */
X dt = 1.0 / Factor; /* New output sampling period */
X dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */
X dh = MIN(Npc, Factor * Npc); /* New filter sampling period */
X dhb = dh*(1<<Na) + 0.5; /* Fixed-point representation */
X Xp = &X[*Time>>Np]; /* Ptr to current input sample */
X v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),
X -1, dhb); /* Perform left-wing inner product */
X v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1, (HWORD)((-*Time)&Pmask),
X 1, dhb); /* Perform right-wing inner product */
X v >>= Nhg; /* Make guard bits */
X v *= NewScl; /* Normalize for unity filter gain */
X *Y++ = v>>NLpScl; /* Deposit output */
X *Time += dtb; /* Move to next sample by time inc */
X }
X return (Y - Ystart); /* Return the # of output samples */
X}
X
X
X
int resample(Imp, ImpD, LpScl, Nmult, Nwing, InterpFilt)
HWORD Imp[], ImpD[];
UHWORD LpScl, Nmult, Nwing;
BOOL InterpFilt;
X{
X UWORD Time; /* Current time/pos in input sample */
X UHWORD Xp, Xread, Ncreep, Xoff;
X HWORD X[IBUFFSIZE], Y[OBUFFSIZE]; /* I/O buffers */
X UHWORD Nout, Nx;
X int i, Ycount, last;
X
X /* Calc reach of LP filter wing & give some creeping room */
X Xoff = ((Nmult+1)/2.0) * MAX(1.0,1.0*MAXFACTOR) + 10;
X if (IBUFFSIZE < 2*Xoff) /* Check input buffer size */
X fail("IBUFFSIZE (or Factor) is too small");
X Nx = IBUFFSIZE - 2*Xoff; /* # of samples to proccess each iteration */
X
X last = FALSE; /* Have we read last input sample yet? */
X Ycount = 0; /* Output sample # and length of out file */
X Xp = Xoff; /* Current position in input buffer */
X Xread = Xoff; /* Position in input array to read into */
X Time = (Xoff<<Np); /* Current-time pointer for converter */
X Acc = -Xoff; /* Acc + int(Time) = index into input file */
X
X for (i=0; i<Xoff; X[i++]=0); /* Need Xoff zeros at begining of sample */
X
X do {
X if (!last) /* If haven't read last sample yet */
X {
X last = readData(X, IBUFFSIZE, (int)Xread); /* Fill input buffer */
X if (last && (last+Xoff<Nx)) /* If last sample has been read... */
X Nx = last + Xoff; /* ...calc last sample affected by filter */
X }
X Ycount += Nout = SrcUD(X,Y,&Time,Nx,Nwing,LpScl,Imp,ImpD,InterpFilt);
X Time -= (Nx<<Np); /* Move converter Nx samples back in time */
X Xp += Nx; /* Advance by number of samples processed */
X Acc += Nx; /* We moved Nx samples in the input file */
X Ncreep = (Time>>Np) - Xoff; /* Calc time accumulation in Time */
X if (Ncreep)
X {
X Time -= (Ncreep<<Np); /* Remove time accumulation */
X Xp += Ncreep; /* and add it to read pointer */
X Acc += Ncreep;
X }
X for (i=0; i<IBUFFSIZE-Xp+Xoff; i++) /* Copy portion of input signal */
X X[i] = X[i+Xp-Xoff]; /* that must be re-used */
X if (last) /* If near end of sample... */
X {
X last -= Xp; /* ...keep track were it ends */
X if (!last) /* Lengthen input by 1 sample */
X last++; /* if needed to keep flag TRUE */
X }
X Xread = i; /* Pos in input buff to read new data into */
X Xp = Xoff;
X
X if (Nout > OBUFFSIZE) /* Check to see if output buff overflowed */
X fail("Output array overflow");
X
X writeData((int)Nout, Y); /* Write data in output buff to file */
X } while (last >= 0); /* Continue until done processing samples */
X return(Ycount); /* Return # of samples in output file */
X}
X
X
X
X
main(argc,argv)
int argc;
char *argv[];
X{
X BOOL InterpFilt; /* TRUE means interpolate filter coeffs */
X UHWORD LpScl, Nmult, Nwing;
X HWORD Imp[MAXNWING]; /* Filter coefficients */
X HWORD ImpD[MAXNWING]; /* ImpD[n] = Imp[n+1]-Imp[n] */
X int outCount;
X
X Nmult = 13;
X InterpFilt = TRUE;
X printf("\nDynamic Rate Resampling Program (for interesting effects)\n");
X printf("Written by: Christopher Lee Fraley (cf0v@spice.cs.cmu.edu)\n");
X printf("Based upon SAIL program by Julius O. Smith (CCRMA)\n");
X printf("Version %s\n", warpVERSION);
X check(); /* Check constants for validity */
X openData(argc, argv); /* Interp arguments and open i&o files */
X initWarp(); /* Set up the warp function's parameters */
X if (readFilter(Imp, ImpD, &LpScl, Nmult, &Nwing))
X fail("could not open Filter file, or syntax error in filter file");
X printf("\nWarp Speed Full Ahead...\n");
X outCount = resample(Imp, ImpD, LpScl, Nmult, Nwing, InterpFilt);
X closeData();
X
X printf("...Returning To Ion Drive: %d output samples.\n\n", outCount);
X}
X
END_OF_FILE
if test 10961 -ne `wc -c <'warp.c'`; then
echo shar: \"'warp.c'\" unpacked with wrong size!
fi
# end of 'warp.c'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have the archive.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0