
				NOTES


PROGRAM ORGANIZATION:

     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.



NOTES ON COMPILATION:

     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.

     A few minor changes have been made to some of these files since they were
last compiled:
	1. All absolute paths were removed from the Makefiles to make
		adaption to your site less confusing.
	2. The source for the filterkit library was concatinated into one
		file.  The Query(), GetUShort(), GetDouble(), and GetString()
		routines were originally in a separate file "query.c".
	3. "llib-lfilterkit" was modified to reflect the latest change to
		the zerox() routine.  This has not been tested yet.

     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:
	getstr(prompt, defalt, answer)
	char *prompt, *defalt, *answer;
	Getstr() will print the passed "prompt" as a message to the user, and
		wait for the user to type an input string.  The string is
		then copied into "answer".  If the user types just a carriage
		return, then the string "defalt" is copied into "answer".
		"Answer" and "defalt" may be the same string, in which case,
		the default value will be the original contents of "answer".

     Also note that the constants in "resample.h" and the typedefs in
"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.



STRUCTURE OF FILES:

     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:

	File Name: "F" Nmult "T" Nhc ".filter"
		example: "F13T8.filter" and "F27T8.filter"

	Structure of File:
		"ScaleFactor" LpScl
		"Length" Nwing
		"Coeffs:"
		Imp[0]
		Imp[1]
		  :
		Imp[Nwing-1]
		"Differences:"
		ImpD[0]
		ImpD[1]
		  :
		ImpD[Nwing-1]
		EOF

	where:	Something enclosed in "" inicates specific characters found
			in the file.
		Nmult, Nwing, Imp[], and ImpD[] are variables (HWORD)
		Npc is a conversion constant.
		EOF is the end of the file.
	See writeFilter() and readFilter() in "filterkit.c" for more details.


The sound-sample file has the following format:

	File Name: unspecified.
		example: "horn.in", "Cello.adc", etc.

	Structure of File:
		Data[0]
		Data[1]
		  :
		Data[n]
		EOF

	where:	Data[i] is a 16-bit integer in ascii format.  (Example:
			"32767", "-232")
		EOF is the end of the file.
		Note that there is no indication of the length of the
			sample;  the EOF is the only indication that the
			last sample has been reached.



SUGGESTIONS, CORRECTIONS, IMPROVEMENTS:

     The following were assumed to be mistakes in the original SAIL program,
and have been changed in "resample.c" and other related programs:

	1. LpScl was scaled by Factor (when Factor<1.0) only when the filter
		was loaded from a file, but not when the filter was created
		at run-time.
	2. ImpD[Nwing-1] was originally set to Imp[Nwing-1], but in general
		ImpD[i] = ImpD[i+1] - ImpD[i], indicating ImpD[Nwing-1]
		should be set to NEGATIVE Imp[Nwing-1].
	3. To keep the # of multiplies consistant (and odd), I added a check
		near the begining of the Filter() routines to skip the last
		coeff in the right wing when the phase was 180 degrees.
		(The "if (Inc == 1) End--;" clause).
	4. When the phase was zero, and the right-wing Filter() is performed,
		the pointers to the filter coeffs must be incremented to
		keep the pointing to the correct coeff.  (The "if (Ph == 0)
		{ Hp += Npc; Hdp += Npc; }" clause).


     The following were changes made to the basic implementation of the
algorithm:

	1. ImpD[] is now created from the integer Imp[] instead of the
		double ImpR[], in order to avoid problems with rounding.
	2. In SrcUp() and SrcUD(), the order of making guard bits (v>>Nhg)
		and normalizing was switched.  This was done to prevent
		overflow problems.
	3. Rounding was removed from SrcUp() and SrcUD() to get more accurate
		response to a DC input.


     The following are improvements that I recommend be made to various
routines:

	1. Change file format of sound files (and possibly filter files) to
		a binary format.  If you are in a Unix environment, you can
		use the functions read() and write() to perform low-level
		i/o, instead of fprintf() and fscanf().  This would be MUCH
		faster, but I have not made the changes yet because the
		current code is much clearer, and probably easier to port
		to your system and your sound-file format.
	2. I believe the restriction that Nmult must be odd may be removed.
	3. When Filter() is currently called for the right-wing, Xp+1 must
		be passed to it.  This should probably be changed so that
		Filter() adds one to Xp if it is doing the right-wing,
		instead of the user.  This way, that increment would be
		transparent to the user, and provide a more consistent
		interface to these functions.



NOTES ON SPECIFIC FILES:

     "resample.c" - should be a faithful reproduction of the original SAIL
	program in C.

     "warp.c" - I modified SrcUD() to get the current value for Factor from
	the function warpFunction().  WarpFunction() should be changed to
	some form desirable.

     "filterkit.c" - Contains the following useful routines:
	LpFilter() - Calculates the filter coeffs for a Kaiser-windowed
		low-pass filter with a given roll-off frequency.  These
		coeffs are stored into a array of doubles.
	writeFilter() - Writes a filter to a file.
	makeFilter() - A section of the original SAIL program.  Calls 
		LpFilter() to create a filter, then scales the double
		coeffs into a array of half words.
	readFilter() - Reads a filter from a file.
	FilterUp() - Applies a filter to a given sample when up-converting.
	FilterUD() - Applies a filter to a given sample when up- or down-
		converting.  Both are repoductions of the original SAIL
		program.
	initZerox() - Initialization routine for the zerox() function.  Must
		be called before zerox() is called.  This routine loads
		the correct filter so zerox() can use it.
	zerox() - Given a pointer into a sample, finds a zero-crossing on the
		interval [pointer-1:pointer+2] by iteration.
	Query() - Ask the user for a yes/no question with prompt, default, 
		and optional help.
	GetUShort() - Ask the user for a unsigned short with prompt, default,
		and optional help.
	GetDouble() -  Ask the user for a double with prompt, default, and
		optional help.
	GetString() -  Ask the user for a string with prompt, default, and
		optional help.



FURTHER INFORMATION:

     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.
     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

