home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume26 / filterkit / part01 next >
Text File  |  1993-04-15  |  90KB  |  2,602 lines

  1. Newsgroups: comp.sources.unix
  2. From: cf0v@andrew.cmu.edu (Christopher Lee Fraley)
  3. Subject: v26i166: filterkit - a collection of audio filters and resamplers, Part01/01
  4. Sender: unix-sources-moderator@vix.com
  5. Approved: paul@vix.com
  6.  
  7. Submitted-By: cf0v@andrew.cmu.edu (Christopher Lee Fraley)
  8. Posting-Number: Volume 26, Issue 166
  9. Archive-Name: filterkit/part01
  10.  
  11.      The original SAIL resampling program is now located among four files:
  12. "filterkit.c", "makefilter.c", "resample.c", and "resample.h".  These files
  13. contain:
  14.  
  15.     filterkit.c - The source code for the library.  Contains routines
  16.         to calculate filter coeff's, convert these to a 16-bit
  17.         integer format, write a filter file, read a filter file,
  18.         apply the filter when up-sampling, apply the filter when
  19.         up-/down-sampling, and apply the filter to find a zero-
  20.         crossing.
  21.  
  22.     makefilter.c - Routines to design and write a filter to a file.
  23.         Creates a Kaiser-windowed lowpass filter based upon routines
  24.         found in the filterkit library.
  25.  
  26.     resample.c - The original resampling program stripped down to the
  27.             part that does the actual resampling.  Designing a filter
  28.             was moved to "makefilter.c", the conversion constants
  29.         were moved into "resample.c", and various general filter
  30.         routines were moved into the filterkit library.
  31.  
  32.     resample.h - Contains the resampling conversion constants.  These
  33.         constants govern such things as the number of bits in the
  34.         input sample & filter coeff's, the number of bits to the
  35.         right of the binary-point for fixed-point math, etc.
  36.  
  37.      Other programs included in this package are the Makefiles for each of
  38. the programs (and the filterkit library), the needed headerfiles, and a
  39. human-readable copy of the lint version of the filterkit library:
  40.  
  41.     warp.c - Very similar to "resample.c", except is modified to allow
  42.         the conversion factor to change on a sample-by-sample basis,
  43.         currently using sinusiods.  This program can be used to add
  44.         vibrato or other pitch-shifting effects to a sample.
  45.  
  46.     stdefs.h - Contains the definitions for words and halfwords, which
  47.         can change from machine to machine.  Also, useful constants
  48.         are defined, as well as a few useful macros.
  49.  
  50.     filterkit.h - Contains the declarations of each of the functions in
  51.         the filterkit library.  Must be included by any program using
  52.         any of the filterkit routines.
  53.  
  54.     llib-lfilterkit - A human-readble version of the lint-library for
  55.         filterkit.  Simply defines the type of each function and
  56.         the routine's formal parameters, so lint can check programs
  57.         which use the filterkit library.  The compact version of this
  58.         file is created via the -C option of lint.  See the filterkit
  59.         Makefile for details.
  60.  
  61.      For further information on any of the files, look in the comments and
  62. help strings contained within that file.  Also I can be contacted at:
  63.     cf0v@spice.cs.cmu.edu, or
  64.     cf0v@andrew.cmu.edu.
  65.  
  66.      --Christopher Lee Fraley
  67.  
  68. #! /bin/sh
  69. # This is a shell archive.  Remove anything before this line, then unpack
  70. # it by saving it into a file and typing "sh file".  To overwrite existing
  71. # files, type "sh file -c".  You can also feed this as standard input via
  72. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  73. # will see the following message at the end:
  74. #        "End of archive 1 (of 1)."
  75. # Contents:  MANIFEST Makefile Notes README.filterkit README.resample
  76. #   filterkit.c filterkit.h kaiser.c makefilter.c protos.h resample.c
  77. #   resample.h stdefs.h warp.c
  78. # Wrapped by vixie@gw.home.vix.com on Thu Apr 15 18:45:31 1993
  79. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  80. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  81.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  82. else
  83. echo shar: Extracting \"'MANIFEST'\" \(548 characters\)
  84. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  85. X   File Name        Archive #    Description
  86. X-----------------------------------------------------------
  87. X MANIFEST                   1    This shipping list
  88. X Makefile                   1    
  89. X Notes                      1    
  90. X README.filterkit           1    
  91. X README.resample            1    
  92. X filterkit.c                1    
  93. X filterkit.h                1    
  94. X kaiser.c                   1    
  95. X makefilter.c               1    
  96. X protos.h                   1    
  97. X resample.c                 1    
  98. X resample.h                 1    
  99. X stdefs.h                   1    
  100. X warp.c                     1    
  101. END_OF_FILE
  102. if test 548 -ne `wc -c <'MANIFEST'`; then
  103.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  104. fi
  105. # end of 'MANIFEST'
  106. fi
  107. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  108.   echo shar: Will not clobber existing file \"'Makefile'\"
  109. else
  110. echo shar: Extracting \"'Makefile'\" \(954 characters\)
  111. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  112. SRC = kaiser.c filterkit.c makefilter.c resample.c warp.c
  113. OBJ = kaiser.o filterkit.o makefilter.o resample.o warp.o
  114. BIN = kaiser makefilter resample warp
  115. X
  116. XFILES = Readme Notes Makefile filterkit.h protos.h resample.h stdefs.h $(SRC) 
  117. X
  118. INSTALLDIR = /usr/local/bin
  119. X
  120. all: $(BIN)
  121. X
  122. install: $(BIN)
  123. X    cp $(BIN) "$(INSTALLDIR)"
  124. X
  125. kaiser: kaiser.c filterkit.c
  126. X    rm -f kaiser
  127. X    $(CC) $(CFLAGS) kaiser.c filterkit.c -o kaiser -lm
  128. X
  129. makefilter: makefilter.c filterkit.c
  130. X    rm -f makefilter
  131. X    $(CC) $(CFLAGS) makefilter.c filterkit.c -o makefilter -lm
  132. X
  133. resample: resample.c filterkit.c
  134. X    rm -f resample
  135. X    $(CC) $(CFLAGS) resample.c filterkit.c -o resample -lm
  136. X
  137. warp: warp.c filterkit.c
  138. X    rm -f warp
  139. X    $(CC) $(CFLAGS) warp.c filterkit.c -o warp -lm
  140. X
  141. X$(SRC): filterkit.h stdefs.h
  142. resample.c: resample.h
  143. X
  144. X# Shar: -F (prefix all lines with X), 
  145. X#     -s addr (set return addr of poster)
  146. shar: $(FILES)
  147. X    /usr2/tools/shar/shar -F -l 50 -o shar -n resample -s thinman@netcom.com $(FILES)
  148. END_OF_FILE
  149. if test 954 -ne `wc -c <'Makefile'`; then
  150.     echo shar: \"'Makefile'\" unpacked with wrong size!
  151. fi
  152. # end of 'Makefile'
  153. fi
  154. if test -f 'Notes' -a "${1}" != "-c" ; then 
  155.   echo shar: Will not clobber existing file \"'Notes'\"
  156. else
  157. echo shar: Extracting \"'Notes'\" \(9614 characters\)
  158. sed "s/^X//" >'Notes' <<'END_OF_FILE'
  159. X
  160. X                NOTES
  161. X
  162. X
  163. PROGRAM ORGANIZATION:
  164. X
  165. X     The original SAIL resampling program is now located among four files:
  166. X"filterkit.c", "makefilter.c", "resample.c", and "resample.h".  These files
  167. contain:
  168. X
  169. X    filterkit.c - The source code for the library.  Contains routines
  170. X        to calculate filter coeff's, convert these to a 16-bit
  171. X        integer format, write a filter file, read a filter file,
  172. X        apply the filter when up-sampling, apply the filter when
  173. X        up-/down-sampling, and apply the filter to find a zero-
  174. X        crossing.
  175. X
  176. X    makefilter.c - Routines to design and write a filter to a file.
  177. X        Creates a Kaiser-windowed lowpass filter based upon routines
  178. X        found in the filterkit library.
  179. X
  180. X    resample.c - The original resampling program stripped down to the
  181. X            part that does the actual resampling.  Designing a filter
  182. X            was moved to "makefilter.c", the conversion constants
  183. X        were moved into "resample.c", and various general filter
  184. X        routines were moved into the filterkit library.
  185. X
  186. X    resample.h - Contains the resampling conversion constants.  These
  187. X        constants govern such things as the number of bits in the
  188. X        input sample & filter coeff's, the number of bits to the
  189. X        right of the binary-point for fixed-point math, etc.
  190. X
  191. X     Other programs included in this package are the Makefiles for each of
  192. the programs (and the filterkit library), the needed headerfiles, and a
  193. human-readable copy of the lint version of the filterkit library:
  194. X
  195. X    warp.c - Very similar to "resample.c", except is modified to allow
  196. X        the conversion factor to change on a sample-by-sample basis,
  197. X        currently using sinusiods.  This program can be used to add
  198. X        vibrato or other pitch-shifting effects to a sample.
  199. X
  200. X    stdefs.h - Contains the definitions for words and halfwords, which
  201. X        can change from machine to machine.  Also, useful constants
  202. X        are defined, as well as a few useful macros.
  203. X
  204. X    filterkit.h - Contains the declarations of each of the functions in
  205. X        the filterkit library.  Must be included by any program using
  206. X        any of the filterkit routines.
  207. X
  208. X    llib-lfilterkit - A human-readble version of the lint-library for
  209. X        filterkit.  Simply defines the type of each function and
  210. X        the routine's formal parameters, so lint can check programs
  211. X        which use the filterkit library.  The compact version of this
  212. X        file is created via the -C option of lint.  See the filterkit
  213. X        Makefile for details.
  214. X
  215. X
  216. X
  217. NOTES ON COMPILATION:
  218. X
  219. X     All of the modules should compile without any problems, although search
  220. paths will have to be set up correctly so "cc" can find all of the proper
  221. include and library files.  Alternatively, one could also explicly cite an
  222. absolute file path for each of the files.
  223. X
  224. X     A few minor changes have been made to some of these files since they were
  225. last compiled:
  226. X    1. All absolute paths were removed from the Makefiles to make
  227. X        adaption to your site less confusing.
  228. X    2. The source for the filterkit library was concatinated into one
  229. X        file.  The Query(), GetUShort(), GetDouble(), and GetString()
  230. X        routines were originally in a separate file "query.c".
  231. X    3. "llib-lfilterkit" was modified to reflect the latest change to
  232. X        the zerox() routine.  This has not been tested yet.
  233. X
  234. X     The routines originally in "query.c" may have to be modified slightly
  235. to get them to compile.  Apparently, the getstr() routine (which is used in
  236. each of these routines) is not a part of the standard C library on all Unix
  237. systems.  Its specification is:
  238. X    getstr(prompt, defalt, answer)
  239. X    char *prompt, *defalt, *answer;
  240. X    Getstr() will print the passed "prompt" as a message to the user, and
  241. X        wait for the user to type an input string.  The string is
  242. X        then copied into "answer".  If the user types just a carriage
  243. X        return, then the string "defalt" is copied into "answer".
  244. X        "Answer" and "defalt" may be the same string, in which case,
  245. X        the default value will be the original contents of "answer".
  246. X
  247. X     Also note that the constants in "resample.h" and the typedefs in
  248. X"stdefs.h" may need to be changed to reflect the word-size of the machine
  249. the program will be running on.  These files currently reflect a word-size
  250. of 32-bits.
  251. X
  252. X
  253. X
  254. STRUCTURE OF FILES:
  255. X
  256. X     There are two types of files used to pass information from one program
  257. the the next: the filter file and a sound-sample file.  The filter file
  258. has the following format:
  259. X
  260. X    File Name: "F" Nmult "T" Nhc ".filter"
  261. X        example: "F13T8.filter" and "F27T8.filter"
  262. X
  263. X    Structure of File:
  264. X        "ScaleFactor" LpScl
  265. X        "Length" Nwing
  266. X        "Coeffs:"
  267. X        Imp[0]
  268. X        Imp[1]
  269. X          :
  270. X        Imp[Nwing-1]
  271. X        "Differences:"
  272. X        ImpD[0]
  273. X        ImpD[1]
  274. X          :
  275. X        ImpD[Nwing-1]
  276. X        EOF
  277. X
  278. X    where:    Something enclosed in "" inicates specific characters found
  279. X            in the file.
  280. X        Nmult, Nwing, Imp[], and ImpD[] are variables (HWORD)
  281. X        Npc is a conversion constant.
  282. X        EOF is the end of the file.
  283. X    See writeFilter() and readFilter() in "filterkit.c" for more details.
  284. X
  285. X
  286. The sound-sample file has the following format:
  287. X
  288. X    File Name: unspecified.
  289. X        example: "horn.in", "Cello.adc", etc.
  290. X
  291. X    Structure of File:
  292. X        Data[0]
  293. X        Data[1]
  294. X          :
  295. X        Data[n]
  296. X        EOF
  297. X
  298. X    where:    Data[i] is a 16-bit integer in ascii format.  (Example:
  299. X            "32767", "-232")
  300. X        EOF is the end of the file.
  301. X        Note that there is no indication of the length of the
  302. X            sample;  the EOF is the only indication that the
  303. X            last sample has been reached.
  304. X
  305. X
  306. X
  307. SUGGESTIONS, CORRECTIONS, IMPROVEMENTS:
  308. X
  309. X     The following were assumed to be mistakes in the original SAIL program,
  310. and have been changed in "resample.c" and other related programs:
  311. X
  312. X    1. LpScl was scaled by Factor (when Factor<1.0) only when the filter
  313. X        was loaded from a file, but not when the filter was created
  314. X        at run-time.
  315. X    2. ImpD[Nwing-1] was originally set to Imp[Nwing-1], but in general
  316. X        ImpD[i] = ImpD[i+1] - ImpD[i], indicating ImpD[Nwing-1]
  317. X        should be set to NEGATIVE Imp[Nwing-1].
  318. X    3. To keep the # of multiplies consistant (and odd), I added a check
  319. X        near the begining of the Filter() routines to skip the last
  320. X        coeff in the right wing when the phase was 180 degrees.
  321. X        (The "if (Inc == 1) End--;" clause).
  322. X    4. When the phase was zero, and the right-wing Filter() is performed,
  323. X        the pointers to the filter coeffs must be incremented to
  324. X        keep the pointing to the correct coeff.  (The "if (Ph == 0)
  325. X        { Hp += Npc; Hdp += Npc; }" clause).
  326. X
  327. X
  328. X     The following were changes made to the basic implementation of the
  329. algorithm:
  330. X
  331. X    1. ImpD[] is now created from the integer Imp[] instead of the
  332. X        double ImpR[], in order to avoid problems with rounding.
  333. X    2. In SrcUp() and SrcUD(), the order of making guard bits (v>>Nhg)
  334. X        and normalizing was switched.  This was done to prevent
  335. X        overflow problems.
  336. X    3. Rounding was removed from SrcUp() and SrcUD() to get more accurate
  337. X        response to a DC input.
  338. X
  339. X
  340. X     The following are improvements that I recommend be made to various
  341. routines:
  342. X
  343. X    1. Change file format of sound files (and possibly filter files) to
  344. X        a binary format.  If you are in a Unix environment, you can
  345. X        use the functions read() and write() to perform low-level
  346. X        i/o, instead of fprintf() and fscanf().  This would be MUCH
  347. X        faster, but I have not made the changes yet because the
  348. X        current code is much clearer, and probably easier to port
  349. X        to your system and your sound-file format.
  350. X    2. I believe the restriction that Nmult must be odd may be removed.
  351. X    3. When Filter() is currently called for the right-wing, Xp+1 must
  352. X        be passed to it.  This should probably be changed so that
  353. X        Filter() adds one to Xp if it is doing the right-wing,
  354. X        instead of the user.  This way, that increment would be
  355. X        transparent to the user, and provide a more consistent
  356. X        interface to these functions.
  357. X
  358. X
  359. X
  360. NOTES ON SPECIFIC FILES:
  361. X
  362. X     "resample.c" - should be a faithful reproduction of the original SAIL
  363. X    program in C.
  364. X
  365. X     "warp.c" - I modified SrcUD() to get the current value for Factor from
  366. X    the function warpFunction().  WarpFunction() should be changed to
  367. X    some form desirable.
  368. X
  369. X     "filterkit.c" - Contains the following useful routines:
  370. X    LpFilter() - Calculates the filter coeffs for a Kaiser-windowed
  371. X        low-pass filter with a given roll-off frequency.  These
  372. X        coeffs are stored into a array of doubles.
  373. X    writeFilter() - Writes a filter to a file.
  374. X    makeFilter() - A section of the original SAIL program.  Calls 
  375. X        LpFilter() to create a filter, then scales the double
  376. X        coeffs into a array of half words.
  377. X    readFilter() - Reads a filter from a file.
  378. X    FilterUp() - Applies a filter to a given sample when up-converting.
  379. X    FilterUD() - Applies a filter to a given sample when up- or down-
  380. X        converting.  Both are repoductions of the original SAIL
  381. X        program.
  382. X    initZerox() - Initialization routine for the zerox() function.  Must
  383. X        be called before zerox() is called.  This routine loads
  384. X        the correct filter so zerox() can use it.
  385. X    zerox() - Given a pointer into a sample, finds a zero-crossing on the
  386. X        interval [pointer-1:pointer+2] by iteration.
  387. X    Query() - Ask the user for a yes/no question with prompt, default, 
  388. X        and optional help.
  389. X    GetUShort() - Ask the user for a unsigned short with prompt, default,
  390. X        and optional help.
  391. X    GetDouble() -  Ask the user for a double with prompt, default, and
  392. X        optional help.
  393. X    GetString() -  Ask the user for a string with prompt, default, and
  394. X        optional help.
  395. X
  396. X
  397. X
  398. XFURTHER INFORMATION:
  399. X
  400. X     Any printf()'s that start with a "|" as the first character in the
  401. control string are used for debugging to to alert the user of an error
  402. condition.
  403. X     For further information on any of the files, look in the comments and
  404. help strings contained within that file.  Also I can be contacted at:
  405. X    cf0v@spice.cs.cmu.edu, or
  406. X    cf0v@andrew.cmu.edu.
  407. X
  408. X     --Christopher Lee Fraley
  409. X
  410. END_OF_FILE
  411. if test 9614 -ne `wc -c <'Notes'`; then
  412.     echo shar: \"'Notes'\" unpacked with wrong size!
  413. fi
  414. # end of 'Notes'
  415. fi
  416. if test -f 'README.filterkit' -a "${1}" != "-c" ; then 
  417.   echo shar: Will not clobber existing file \"'README.filterkit'\"
  418. else
  419. echo shar: Extracting \"'README.filterkit'\" \(459 characters\)
  420. sed "s/^X//" >'README.filterkit' <<'END_OF_FILE'
  421. X
  422. X
  423. XFilterkit is a C translation of an old SAIL program (SAIL =
  424. Stanford AI Lab) which does FIR filtering with sample rate
  425. changing on the fly.
  426. X
  427. Christopher Fraley @CMU did the translation and split it up
  428. into a toolkit.  Being ignorant, I've glommed some of the pieces 
  429. together into a program that performs straight filtering on
  430. a sound sample file of signed words.
  431. X
  432. The warp program in particular looks very promising; I haven't
  433. used it yet.
  434. X
  435. X    Lance Norskog
  436. END_OF_FILE
  437. if test 459 -ne `wc -c <'README.filterkit'`; then
  438.     echo shar: \"'README.filterkit'\" unpacked with wrong size!
  439. fi
  440. # end of 'README.filterkit'
  441. fi
  442. if test -f 'README.resample' -a "${1}" != "-c" ; then 
  443.   echo shar: Will not clobber existing file \"'README.resample'\"
  444. else
  445. echo shar: Extracting \"'README.resample'\" \(1605 characters\)
  446. sed "s/^X//" >'README.resample' <<'END_OF_FILE'
  447. X(Message inbox:3096)
  448. Received: from netcom4.netcom.com by charon.cwi.nl with SMTP
  449. X    id AA27402 (5.65b/3.8/CWI-Amsterdam); Mon, 8 Mar 1993 22:46:14 +0100
  450. Received: by netcom4.netcom.com (5.65/SMI-4.1/Netcom)
  451. X    id AA04106; Mon, 8 Mar 93 13:45:12 -0800
  452. Date: Mon, 8 Mar 93 13:45:12 -0800
  453. XFrom: thinman@netcom.com (Technically Sweet)
  454. Message-Id: <9303082145.AA04106@netcom4.netcom.com>
  455. In-Reply-To: Guido.van.Rossum@cwi.nl
  456. X       "Re: SOX wav.c patch" (Mar  8, 10:07pm)
  457. XX-Mailer: Mail User's Shell (7.2.3 5/22/91)
  458. To: Guido.van.Rossum@cwi.nl
  459. Subject: resampler part 1 of 2
  460. X
  461. Here it is.  Now I realise there's no help.
  462. X
  463. X'kaiser' reads and writes signed 16-bit samples, but
  464. doesn't care about sampling rates.
  465. X
  466. X'kaiser 2.0' doubles the sampling rate.
  467. X'kaiser 0.5 [ 0.5 ]' cuts the sampling rate in 1/2.
  468. X'kaiser 0.5 0.7' does the same, but with a more gradual slope.
  469. X
  470. I checked this out with the FFT analyzer in MixVIew,
  471. and it really does better than interpolating.
  472. Interp upward reflects the base sound in the higher
  473. frequencies.  This doesn't.
  474. X
  475. X(Message inbox:3097)
  476. Received: from netcom4.netcom.com by charon.cwi.nl with SMTP
  477. X    id AA27418 (5.65b/3.8/CWI-Amsterdam); Mon, 8 Mar 1993 22:46:30 +0100
  478. Received: by netcom4.netcom.com (5.65/SMI-4.1/Netcom)
  479. X    id AA04154; Mon, 8 Mar 93 13:45:29 -0800
  480. Date: Mon, 8 Mar 93 13:45:29 -0800
  481. XFrom: thinman@netcom.com (Technically Sweet)
  482. Message-Id: <9303082145.AA04154@netcom4.netcom.com>
  483. In-Reply-To: Guido.van.Rossum@cwi.nl
  484. X       "Re: SOX wav.c patch" (Mar  8, 10:07pm)
  485. XX-Mailer: Mail User's Shell (7.2.3 5/22/91)
  486. To: Guido.van.Rossum@cwi.nl
  487. Subject: resample part 2 of 2
  488. X
  489. END_OF_FILE
  490. if test 1605 -ne `wc -c <'README.resample'`; then
  491.     echo shar: \"'README.resample'\" unpacked with wrong size!
  492. fi
  493. # end of 'README.resample'
  494. fi
  495. if test -f 'filterkit.c' -a "${1}" != "-c" ; then 
  496.   echo shar: Will not clobber existing file \"'filterkit.c'\"
  497. else
  498. echo shar: Extracting \"'filterkit.c'\" \(16885 characters\)
  499. sed "s/^X//" >'filterkit.c' <<'END_OF_FILE'
  500. X
  501. X/*
  502. X * FILE: filterkit.c (source for library "filterkit.a")
  503. X *   BY: Christopher Lee Fraley (cf0v@andrew.cmu.edu)
  504. X * DESC: Makes a Kaiser-windowed low-pass filter.
  505. X * DATE: 7-JUN-88
  506. X */
  507. X
  508. char filterkitVERSION[] = "2.0  (7-JUN-88  3:30pm)";
  509. X
  510. X/* filterkit.c
  511. X *
  512. X *      The function makeFilter(), FilterUp(), and FilterUD(), were originally
  513. X * written by Julius O. Smith in SAIL, and were translated into C.
  514. X *
  515. X * LpFilter() - Calculates the filter coeffs for a Kaiser-windowed low-pass
  516. X *                   filter with a given roll-off frequency.  These coeffs
  517. X *                   are stored into a array of doubles.
  518. X * writeFilter() - Writes a filter to a file.
  519. X * makeFilter() - Calls LpFilter() to create a filter, then scales the double
  520. X *                   coeffs into an array of half words.
  521. X * readFilter() - Reads a filter from a file.
  522. X * FilterUp() - Applies a filter to a given sample when up-converting.
  523. X * FilterUD() - Applies a filter to a given sample when up- or down-
  524. X *                   converting.
  525. X * initZerox() - Initialization routine for the zerox() function.  Must
  526. X *                   be called before zerox() is called.  This routine loads
  527. X *                   the correct filter so zerox() can use it.
  528. X * zerox() - Given a pointer into a sample, finds a zero-crossing on the
  529. X *                   interval [pointer-1:pointer+2] by iteration.
  530. X * Query() - Ask the user for a yes/no question with prompt, default, 
  531. X *                   and optional help.
  532. X * GetUShort() - Ask the user for a unsigned short with prompt, default,
  533. X *                   and optional help.
  534. X * GetDouble() - Ask the user for a double with prompt, default, and
  535. X *                   optional help.
  536. X * GetString() - Ask the user for a string with prompt, default, and
  537. X *                   optional help.
  538. X */
  539. X
  540. X
  541. X#include <stdio.h>
  542. X#include <math.h>
  543. X#include <string.h>
  544. X#include "stdefs.h"
  545. X#include "resample.h"
  546. X#include "filterkit.h"
  547. X#include "protos.h"
  548. X
  549. X
  550. X
  551. X/* LpFilter()
  552. X *
  553. X * reference: "Digital Filters, 2nd edition"
  554. X *            R.W. Hamming, pp. 178-179
  555. X *
  556. X * Izero() computes the 0th order modified bessel function of the first kind.
  557. X *    (Needed to compute Kaiser window).
  558. X *
  559. X * LpFilter() computes the coeffs of a Kaiser-windowed low pass filter with
  560. X *    the following characteristics:
  561. X *
  562. X *       c[]  = array in which to store computed coeffs
  563. X *       frq  = roll-off frequency of filter
  564. X *       N    = Half the window length in number of coeffs
  565. X *       Beta = parameter of Kaiser window
  566. X *       Num  = number of coeffs before 1/frq
  567. X *
  568. X * Beta trades the rejection of the lowpass filter against the transition
  569. X *    width from passband to stopband.  Larger Beta means a slower
  570. X *    transition and greater stopband rejection.  See Rabiner and Gold
  571. X *    (Theory and Application of DSP) under Kaiser windows for more about
  572. X *    Beta.  The following table from Rabiner and Gold gives some feel
  573. X *    for the effect of Beta:
  574. X *
  575. X * All ripples in dB, width of transition band = D*N where N = window length
  576. X *
  577. X *               BETA    D       PB RIP   SB RIP
  578. X *               2.120   1.50  +-0.27      -30
  579. X *               3.384   2.23    0.0864    -40
  580. X *               4.538   2.93    0.0274    -50
  581. X *               5.658   3.62    0.00868   -60
  582. X *               6.764   4.32    0.00275   -70
  583. X *               7.865   5.0     0.000868  -80
  584. X *               8.960   5.7     0.000275  -90
  585. X *               10.056  6.4     0.000087  -100
  586. X */
  587. X
  588. X
  589. X
  590. X#define IzeroEPSILON 1E-21               /* Max error acceptable in Izero */
  591. X
  592. double Izero(x)
  593. double x;
  594. X{
  595. X   double sum, u, halfx, temp;
  596. X   int n;
  597. X
  598. X   sum = u = n = 1;
  599. X   halfx = x/2.0;
  600. X   do {
  601. X      temp = halfx/(double)n;
  602. X      n += 1;
  603. X      temp *= temp;
  604. X      u *= temp;
  605. X      sum += u;
  606. X      } while (u >= IzeroEPSILON*sum);
  607. X   return(sum);
  608. X}
  609. X
  610. X
  611. void LpFilter(c,N,frq,Beta,Num)
  612. double c[], frq, Beta;
  613. int N, Num;
  614. X{
  615. X   double IBeta, temp;
  616. X   int i;
  617. X
  618. X   /* Calculate filter coeffs: */
  619. X   c[0] = 2.0*frq;
  620. X   for (i=1; i<N; i++)
  621. X      {
  622. X      temp = PI*(double)i/(double)Num;
  623. X      c[i] = sin(2.0*temp*frq)/temp;
  624. X      }
  625. X
  626. X   /* Calculate and Apply Kaiser window to filter coeffs: */
  627. X   IBeta = 1.0/Izero(Beta);
  628. X   for (i=1; i<N; i++)
  629. X      {
  630. X      temp = (double)i / ((double)N * (double)1.0);
  631. X      c[i] *= Izero(Beta*sqrt(1.0-temp*temp)) * IBeta;
  632. X      }
  633. X}
  634. X
  635. X
  636. X
  637. X/* Write a filter to a file
  638. X *    Filter file format:
  639. X *       file name: "F" Nmult "T" Nhc ".filter"
  640. X *       1st line:  the string "ScaleFactor" followed by its value.
  641. X *       2nd line:  the string "Length" followed by Nwing's value.
  642. X *       3rd line:  the string "Coeffs:" on a separate line.
  643. X *       following lines:  Nwing number of 16-bit impulse response values
  644. X *          in the right wing of the impulse response (the Imp[] array).
  645. X *         (Nwing is equal to Npc*(Nmult+1)/2+1, where Npc is defined in the
  646. X *         file "resample.h".)  Each coefficient is on a separate line.
  647. X *       next line:  the string "Differences:" on a separate line.
  648. X *       following lines:  Nwing number of 16-bit impulse-response
  649. X *          successive differences:  ImpD[i] = Imp[i+1] - Imp[i].
  650. X * ERROR codes:
  651. X *   0 - no error
  652. X *   1 - could not open file
  653. X */
  654. X
  655. int writeFilter(Imp, ImpD, LpScl, Nmult, Nwing)
  656. HWORD Imp[], ImpD[];
  657. UHWORD LpScl, Nmult, Nwing;
  658. X{
  659. X   char fname[30];
  660. X   FILE *fp;
  661. X   int i;
  662. X
  663. X   sprintf(fname, "F%dT%d.filter", Nmult, Nhc);
  664. X   fp = fopen(fname, "w");
  665. X   if (!fp)
  666. X      return(1);
  667. X   fprintf(fp, "ScaleFactor %d\n", LpScl);
  668. X   fprintf(fp, "Length %d\n", Nwing);
  669. X   fprintf(fp, "Coeffs:\n");
  670. X   for (i=0; i<Nwing; i++)   /* Put array of 16-bit filter coefficients */
  671. X      fprintf(fp, "%d\n", Imp[i]);
  672. X   fprintf(fp, "Differences:\n");
  673. X   for (i=0; i<Nwing; i++)   /* Put array of 16-bit filter coeff differences */
  674. X      fprintf(fp, "%d\n", ImpD[i]);
  675. X   fclose(fp);
  676. X   return(0);
  677. X}
  678. X
  679. X
  680. X
  681. X/* ERROR return codes:
  682. X *    0 - no error
  683. X *    1 - Nwing too large (Nwing is > MAXNWING)
  684. X *    2 - Froll is not in interval [0:1)
  685. X *    3 - Beta is < 1.0
  686. X *    4 - LpScl will not fit in 16-bits
  687. X *
  688. X * Made following global to avoid stack problems in Sun3 compilation: */
  689. static double ImpR[MAXNWING];
  690. X
  691. int makeFilter(Imp, ImpD, LpScl, Nwing, Froll, Beta)
  692. HWORD Imp[], ImpD[];
  693. UHWORD *LpScl, Nwing;
  694. double Froll, Beta;
  695. X{
  696. X   double DCgain, Scl, Maxh;
  697. X   HWORD Dh;
  698. X   int i, temp;
  699. X
  700. X   if (Nwing > MAXNWING)                      /* Check for valid parameters */
  701. X      return(1);
  702. X   if ((Froll<=0) || (Froll>1))
  703. X      return(2);
  704. X   if (Beta < 1)
  705. X      return(3);
  706. X
  707. X   LpFilter(ImpR, (int)Nwing, Froll, Beta, Npc); /* Design a Kaiser-window */
  708. X                                                 /* Sinc low-pass filter */
  709. X
  710. X   /* Compute the DC gain of the lowpass filter, and its maximum coefficient
  711. X    * magnitude. Scale the coefficients so that the maximum coeffiecient just
  712. X    * fits in Nh-bit fixed-point, and compute LpScl as the NLpScl-bit (signed)
  713. X    * scale factor which when multiplied by the output of the lowpass filter
  714. X    * gives unity gain. */
  715. X   DCgain = 0;
  716. X   Dh = Npc;                       /* Filter sampling period for factors>=1 */
  717. X   for (i=Dh; i<Nwing; i+=Dh)
  718. X      DCgain += ImpR[i];
  719. X   DCgain = 2*DCgain + ImpR[0];    /* DC gain of real coefficients */
  720. X
  721. X   for (Maxh=i=0; i<Nwing; i++)
  722. X      Maxh = MAX(Maxh, fabs(ImpR[i]));
  723. X
  724. X   Scl = ((1<<(Nh-1))-1)/Maxh;     /* Map largest coeff to 16-bit maximum */
  725. X   temp = fabs((1<<(NLpScl+Nh))/(DCgain*Scl));
  726. X   if (temp >= 1<<16)
  727. X      return(4);                   /* Filter scale factor overflows UHWORD */
  728. X   *LpScl = temp;
  729. X
  730. X   /* Scale filter coefficients for Nh bits and convert to integer */
  731. X   if (ImpR[0] < 0)                /* Need pos 1st value for LpScl storage */
  732. X      Scl = -Scl;
  733. X   for (i=0; i<Nwing; i++)         /* Scale them */
  734. X      ImpR[i] *= Scl;
  735. X   for (i=0; i<Nwing; i++)         /* Round them */
  736. X      Imp[i] = ImpR[i] + 0.5;
  737. X
  738. X   /* ImpD makes linear interpolation of the filter coefficients faster */
  739. X   for (i=0; i<Nwing-1; i++)
  740. X      ImpD[i] = Imp[i+1] - Imp[i];
  741. X   ImpD[Nwing-1] = - Imp[Nwing-1];      /* Last coeff. not interpolated */
  742. X
  743. X   return(0);
  744. X}
  745. X
  746. X
  747. X
  748. X/* Read-in a filter
  749. X *    Filter file format:
  750. X *       file name: "F" Nmult "T" Nhc ".filter"
  751. X *       1st line:  the string "ScaleFactor" followed by its value.
  752. X *       2nd line:  the string "Length" followed by Nwing's value.
  753. X *       3rd line:  the string "Coeffs:" on separate line.
  754. X *       Nwing number of 16-bit impulse response values in the right
  755. X *          wing of the impulse response.  (Length=Npc*(Nmult+1)/2+1,
  756. X *          where originally Npc=2^9, and Nmult=13.)   Each on separate line.
  757. X *       The string "Differences:" on separate line.
  758. X *       Nwing number of 16-bit impulse-response successive differences:
  759. X *          ImpDiff[i] = Imp[i+1] - Imp[i].
  760. X *
  761. X * ERROR return codes:
  762. X *    0 - no error
  763. X *    1 - file not found
  764. X *    2 - invalid ScaleFactor in file
  765. X *    3 - invalid Length in file
  766. X */
  767. int readFilter(Imp, ImpD, LpScl, Nmult, Nwing)
  768. HWORD Imp[], ImpD[];
  769. UHWORD *LpScl, Nmult, *Nwing;
  770. X{
  771. X   char fname[30];
  772. X   FILE *fp;
  773. X   int i, temp;
  774. X
  775. X   sprintf(fname, "F%dT%d.filter", Nmult, Nhc);
  776. X   fp = fopen(fname, "r");
  777. X   if (fp == NULL)
  778. X      return(1);
  779. X
  780. X   fscanf(fp, "ScaleFactor ");
  781. X   if (1 != fscanf(fp,"%d",&temp))
  782. X      return(2);
  783. X   *LpScl = temp;
  784. X
  785. X   fscanf(fp, "\nLength ");
  786. X   if (1 != fscanf(fp,"%d",&temp))
  787. X      return(3);
  788. X   *Nwing = temp;
  789. X
  790. X   fscanf(fp, "\nCoeffs:\n");
  791. X   for (i=0; i<*Nwing; i++)  /* Get array of 16-bit filter coefficients */
  792. X      fscanf(fp, "%d\n", &Imp[i]);
  793. X
  794. X   fscanf(fp, "\nDifferences:\n");
  795. X   for (i=0; i<*Nwing; i++)  /* Get array of 16-bit filter coeff differences */
  796. X      fscanf(fp, "%d\n", &ImpD[i]);
  797. X
  798. X   fclose(fp);
  799. X   return(0);
  800. X}
  801. X
  802. X
  803. X
  804. X
  805. WORD FilterUp(Imp, ImpD, Nwing, Interp, Xp, Ph, Inc)
  806. HWORD Imp[], ImpD[], *Xp, Inc, Ph;
  807. UHWORD Nwing;
  808. BOOL Interp;
  809. X{
  810. X   HWORD a, *Hp, *Hdp, *End;
  811. X   WORD v, t;
  812. X
  813. X   v=0;
  814. X   Hp = &Imp[Ph>>Na];
  815. X   End = &Imp[Nwing];
  816. X   if (Interp)
  817. X      {
  818. X      Hdp = &ImpD[Ph>>Na];
  819. X      a = Ph & Amask;
  820. X      }
  821. X   if (Inc == 1)                     /* If doing right wing...              */
  822. X      {                              /* ...drop extra coeff, so when Ph is  */
  823. X      End--;                         /*    0.5, we don't do too many mult's */
  824. X      if (Ph == 0)                   /* If the phase is zero...           */
  825. X         {                           /* ...then we've already skipped the */
  826. X         Hp += Npc;                  /*    first sample, so we must also  */
  827. X         Hdp += Npc;                 /*    skip ahead in Imp[] and ImpD[] */
  828. X         }
  829. X      }
  830. X   while (Hp < End)
  831. X      {
  832. X      t = *Hp;                       /* Get filter coeff */
  833. X      if (Interp)
  834. X         {
  835. X         t += (((WORD)*Hdp)*a)>>Na;  /* t is now interp'd filter coeff */
  836. X         Hdp += Npc;                 /* Filter coeff differences step */
  837. X     }
  838. X      t *= *Xp;      /* Mult coeff by input sample */
  839. X      if (t & 1<<(Nhxn-1))  /* Round, if needed */
  840. X         t += 1<<(Nhxn-1);
  841. X      t >>= Nhxn;    /* Leave some guard bits, but come back some */
  842. X      v += t;        /* The filter output */
  843. X      Hp += Npc;     /* Filter coeff step */
  844. X      Xp += Inc;     /* Input signal step. NO CHECK ON ARRAY BOUNDS */
  845. X      }
  846. X   return(v);
  847. X}
  848. X
  849. X
  850. X
  851. X
  852. WORD FilterUD(Imp, ImpD, Nwing, Interp, Xp, Ph, Inc, dhb)
  853. HWORD Imp[], ImpD[], *Xp, Ph, Inc;
  854. UHWORD Nwing, dhb;
  855. BOOL Interp;
  856. X{
  857. X   HWORD a, *Hp, *Hdp, *End;
  858. X   WORD v, t;
  859. X   UWORD Ho;
  860. X
  861. X   v=0;
  862. X   Ho = (Ph*(UWORD)dhb)>>Np;
  863. X   End = &Imp[Nwing];
  864. X   if (Inc == 1)                     /* If doing right wing...              */
  865. X      {                              /* ...drop extra coeff, so when Ph is  */
  866. X      End--;                         /*    0.5, we don't do too many mult's */
  867. X      if (Ph == 0)                   /* If the phase is zero...           */
  868. X         Ho += dhb;                  /* ...then we've already skipped the */
  869. X      }                              /*    first sample, so we must also  */
  870. X                                     /*    skip ahead in Imp[] and ImpD[] */
  871. X   while ((Hp = &Imp[Ho>>Na]) < End)
  872. X      {
  873. X      t = *Hp;       /* Get IR sample */
  874. X      if (Interp)
  875. X         {
  876. X         Hdp = &ImpD[Ho>>Na]; /* get interp (lower Na) bits from diff table */
  877. X         a = Ho & Amask;                  /* a is logically between 0 and 1 */
  878. X         t += (((WORD)*Hdp)*a)>>Na;       /* t is now interp'd filter coeff */
  879. X     }
  880. X      t *= *Xp;      /* Mult coeff by input sample */
  881. X      if (t & 1<<(Nhxn-1))  /* Round, if needed */
  882. X         t += 1<<(Nhxn-1);
  883. X      t >>= Nhxn;    /* Leave some guard bits, but come back some */
  884. X      v += t;        /* The filter output */
  885. X      Ho += dhb;     /* IR step */
  886. X      Xp += Inc;     /* Input signal step. NO CHECK ON ARRAY BOUNDS */
  887. X      }
  888. X   return(v);
  889. X}
  890. X
  891. X
  892. X
  893. X/*
  894. X * double zerox(Data, Factor)
  895. X * HWORD *Data;
  896. X * double Factor;
  897. X *    Given a pointer into a sound sample, this function uses a low-pass
  898. X * filter to estimate the x coordinate of the zero-crossing which must ocurr
  899. X * between Data[0] and Data[1].  This value is returned as the value of the
  900. X * function.  A return value of -100 indicates there was no zero-crossing in
  901. X * the x interval [-1,2].  Factor is the resampling factor: Rate(out) /
  902. X * Rate(in).  Nmult (which determines which filter is used) is passed the
  903. X * zerox's initialization routine: initZerox(Nmult)
  904. X *                                 UHWORD Nmult;
  905. X */
  906. X
  907. static UHWORD LpScl, Nmult, Nwing;
  908. static HWORD Imp[MAXNWING];
  909. static HWORD ImpD[MAXNWING];
  910. X
  911. X/* ERROR return values:
  912. X *   0 - no error
  913. X *   1 - Nmult is even (should be odd)
  914. X *   2 - filter file not found
  915. X *   3 - invalid ScaleFactor in input file
  916. X *   4 - invalid Length in file
  917. X */
  918. int initZerox(tempNmult)
  919. UHWORD tempNmult;
  920. X{
  921. X   int err;
  922. X
  923. X   /* Check for illegal input values */
  924. X   if (!(tempNmult % 2))
  925. X      return(1);
  926. X   if (err = readFilter(Imp, ImpD, &LpScl, tempNmult, &Nwing))
  927. X      return(1+err);
  928. X
  929. X   Nmult = tempNmult;
  930. X   return(0);
  931. X}
  932. X
  933. X
  934. X
  935. X#define MAXITER 64
  936. X#define ZeroxEPSILON (1E-4)
  937. X#define ZeroxMAXERROR (5.0)
  938. X
  939. double zerox(Data, Factor)
  940. HWORD *Data;
  941. double Factor;
  942. X{
  943. X   double x, out;
  944. X   double lo, hi;
  945. X   double dh;
  946. X   UWORD dhb;
  947. X   WORD v;
  948. X   int i;
  949. X
  950. X   if (!Data[0])
  951. X      return (0.0);
  952. X   if (!Data[1])
  953. X      return (1.0);
  954. X
  955. X   if (Data[0] < Data[1])
  956. X      {
  957. X      lo = -1.0;
  958. X      hi =  2.0;
  959. X      }
  960. X   else
  961. X      {
  962. X      lo =  2.0;
  963. X      hi = -1.0;
  964. X      }
  965. X   dh = (Factor<1) ? (Factor*Npc) : (Npc);
  966. X   dhb = dh * (1<<Na) + 0.5;
  967. X
  968. X   for (i=0; i<MAXITER; i++)
  969. X      {
  970. X      x = (hi+lo)/2.0;
  971. X      v  = FilterUD(Imp,ImpD,Nwing,TRUE,Data,  (HWORD)(x*Pmask),    -1,dhb);
  972. X      v += FilterUD(Imp,ImpD,Nwing,TRUE,Data+1,(HWORD)((1-x)*Pmask), 1,dhb);
  973. X      v >>= Nhg;
  974. X      v *= LpScl;
  975. X      out = (double)v / (double)(1<<NLpScl);
  976. X      if (out < 0.0)
  977. X         lo = x;
  978. X      else
  979. X         hi = x;
  980. X      if (ABS(out) <= ZeroxEPSILON)
  981. X         return(x);
  982. X      }
  983. X   printf("|ZeroX Error| x:%g, \t Data[x]:%d, \t Data[x+1]:%d\n",
  984. X      x, *Data, *(Data+1));
  985. X   printf("|\tABS(out):%g \t EPSILON:%g\n", ABS(out),ZeroxEPSILON);
  986. X   if (ABS(out) <= ZeroxMAXERROR)
  987. X      return(x);
  988. X   return(-100.0);
  989. X}
  990. X
  991. X
  992. X
  993. X
  994. BOOL Query(prompt, deflt, help)
  995. char *help, *prompt;
  996. BOOL deflt;
  997. X{
  998. X   char s[80];
  999. X
  1000. X   while (TRUE)
  1001. X      {
  1002. X      sprintf(s,"\n%s%s", prompt, (*help) ? " (Type ? for help)" : "");
  1003. X      getstr(s,(deflt)?"yes":"no",s);
  1004. X      if (*s=='?' && *help)
  1005. X         printf(help);
  1006. X      if (*s=='Y' || *s=='y')
  1007. X         return(TRUE);
  1008. X      if (*s=='N' || *s=='n')
  1009. X         return(FALSE);
  1010. X      }
  1011. X}
  1012. X
  1013. X
  1014. char *GetString(prompt, deflt, help)
  1015. char *help, *prompt, *deflt;
  1016. X{
  1017. X   char s[80];
  1018. X
  1019. X   while (TRUE)
  1020. X      {
  1021. X      sprintf(s,"\n%s%s",prompt, (*help) ? " (Type ? for Help)" : "");
  1022. X      getstr(s,deflt,s);
  1023. X      if (*s=='?' && *help)
  1024. X         printf(help);
  1025. X      else
  1026. X         return(s);
  1027. X      }
  1028. X}
  1029. X
  1030. getstr(s1, deflt, s2)
  1031. char *s1, *deflt, *s2;
  1032. X{
  1033. X    write(1, s1, strlen(s1));
  1034. X    read(0, s2, 80);
  1035. X}
  1036. X
  1037. X
  1038. X
  1039. double GetDouble(title, deflt, help)
  1040. char *help, *title;
  1041. double deflt;
  1042. X{
  1043. X   char s[80],sdeflt[80];
  1044. X   double newval;
  1045. X
  1046. X   while (TRUE)
  1047. X      {
  1048. X      sprintf(s,"\n%s:%s",title, (*help) ? " (Type ? for Help)" : "");
  1049. X      sprintf(sdeflt,"%g",deflt);
  1050. X      getstr(s,sdeflt,s);
  1051. X      if (*s=='?' && *help)
  1052. X         printf(help);
  1053. X      else
  1054. X         {
  1055. X         if (!sscanf(s,"%lf",&newval))
  1056. X            return(deflt);
  1057. X         return(newval);
  1058. X     }
  1059. X      }
  1060. X}
  1061. X
  1062. X
  1063. unsigned short GetUShort(title, deflt, help)
  1064. char *help, *title;
  1065. unsigned short deflt;
  1066. X{
  1067. X   char s[80],sdeflt[80];
  1068. X   int newval;
  1069. X
  1070. X   while (TRUE)
  1071. X      {
  1072. X      sprintf(s,"\n%s:%s",title, (*help) ? " (Type ? for Help)" : "");
  1073. X      sprintf(sdeflt,"%d",deflt);
  1074. X      getstr(s,sdeflt,s);
  1075. X      if (*s=='?' && *help)
  1076. X         printf(help);
  1077. X      else
  1078. X         {
  1079. X         if (!sscanf(s,"%d",&newval))
  1080. X            printf("unchanged (%d)\n",(newval=deflt));
  1081. X         if (newval < 0)
  1082. X            printf("Error: value must be >= zero\n");
  1083. X         else
  1084. X            return(newval);
  1085. X     }
  1086. X      }
  1087. X}
  1088. X
  1089. X
  1090. END_OF_FILE
  1091. if test 16885 -ne `wc -c <'filterkit.c'`; then
  1092.     echo shar: \"'filterkit.c'\" unpacked with wrong size!
  1093. fi
  1094. # end of 'filterkit.c'
  1095. fi
  1096. if test -f 'filterkit.h' -a "${1}" != "-c" ; then 
  1097.   echo shar: Will not clobber existing file \"'filterkit.h'\"
  1098. else
  1099. echo shar: Extracting \"'filterkit.h'\" \(380 characters\)
  1100. sed "s/^X//" >'filterkit.h' <<'END_OF_FILE'
  1101. X
  1102. X/*
  1103. X * FILE:filterkit.h
  1104. X *   BY: Christopher Lee Fraley (cf0v@andrew.cmu.edu)
  1105. X * DATE: 17-JUN-88
  1106. X * VERS: 1.0  (20-JUN-88, 3:10pm)
  1107. X */
  1108. X
  1109. void LpFilter();
  1110. int writeFilter(),  readFilter(), makeFilter();
  1111. WORD FilterUp(), FilterUD();
  1112. double GetDouble();
  1113. unsigned short GetUShort();
  1114. char *GetString();
  1115. BOOL Query();
  1116. double cubic(), zerox();
  1117. X
  1118. X#define GetUHWORD(x,y,z) GetUShort(x,y,z)
  1119. X
  1120. END_OF_FILE
  1121. if test 380 -ne `wc -c <'filterkit.h'`; then
  1122.     echo shar: \"'filterkit.h'\" unpacked with wrong size!
  1123. fi
  1124. # end of 'filterkit.h'
  1125. fi
  1126. if test -f 'kaiser.c' -a "${1}" != "-c" ; then 
  1127.   echo shar: Will not clobber existing file \"'kaiser.c'\"
  1128. else
  1129. echo shar: Extracting \"'kaiser.c'\" \(12170 characters\)
  1130. sed "s/^X//" >'kaiser.c' <<'END_OF_FILE'
  1131. X
  1132. X
  1133. X/*
  1134. X * FILE: resample.c
  1135. X *   BY: Julius Smith (at CCRMA, Stanford U)
  1136. X * C BY: translated from SAIL to C by Christopher Lee Fraley
  1137. X *          (cf0v@spice.cs.cmu.edu or @andrew.cmu.edu)
  1138. X * DATE: 7-JUN-88
  1139. X *
  1140. X * HACKED: Lance Norskog, Dec. 28, 1991, to make sealed resampler for SoundKit
  1141. X */
  1142. X
  1143. char resampleVERSION[] = "1.3  (24-JUN-88, 3:00pm)";
  1144. X
  1145. X/*
  1146. X *      The original version of this program in SAIL may be found in:
  1147. X *      /../s/usr/mhs/resample  or  /../x/usr/rbd/src/resample
  1148. X *
  1149. X *      Implement sampling rate conversions by (almost) arbitrary factors.
  1150. X *      Based on SRCONV.SAI[SYS,MUS] with new algorithm by JOS&PG.
  1151. X *      The program internally uses 16-bit data and 16-bit filter
  1152. X *      coefficients.
  1153. X *
  1154. X *      Reference: "A Flexible Sampling-Rate Conversion Method,"
  1155. X *      J. O. Smith and P. Gossett, ICASSP, San Diego, 1984, Pgs 19.4.
  1156. X *
  1157. X *      * Need overflow detection in Filter() routines.  Also, we want
  1158. X *        to saturate instead of wrap-around and report number of clipped
  1159. X *        samples.
  1160. X */
  1161. X
  1162. X/* CHANGES from original SAIL program:
  1163. X *
  1164. X * 1. LpScl is scaled by Factor (when Factor<1) in resample() so this is
  1165. X *       done whether the filter was loaded or created.
  1166. X * 2. makeFilter() - ImpD[] is created from Imp[] instead of ImpR[], to avoid
  1167. X *       problems with round-off errors.
  1168. X * 3. makeFilter() - ImpD[Nwing-1] gets NEGATIVE Imp[Nwing-1].
  1169. X * 4. SrcU/D() - Switched order of making guard bits (v>>Nhg) and
  1170. X *       normalizing.  This was done to prevent overflow.
  1171. X */
  1172. X
  1173. X/* LIBRARIES needed:
  1174. X *
  1175. X * 1. filterkit
  1176. X *       readFilter() - reads standard filter file
  1177. X *       FilterUp()   - applies filter to sample when Factor >= 1
  1178. X *       FilterUD()   - applies filter to sample for any Factor
  1179. X *       Query()      - prompt user for y/n answer with help.
  1180. X *       GetDouble()  - prompt user for a double with help.
  1181. X *       GetUShort()  - prompt user for a UHWORD with help.
  1182. X *
  1183. X * 2. math
  1184. X */
  1185. X
  1186. X
  1187. X
  1188. X
  1189. X#include <stdio.h>
  1190. X#include <math.h>
  1191. X#include <string.h>
  1192. X#include "stdefs.h"
  1193. X#include "filterkit.h"
  1194. X#include "resample.h"
  1195. X#include "protos.h"
  1196. X
  1197. X#define IBUFFSIZE 1024                         /* Input buffer size */
  1198. X#define OBUFFSIZE (IBUFFSIZE*MAXFACTOR+2)      /* Calc'd out buffer size */
  1199. X
  1200. fail(s)
  1201. char *s;
  1202. X{
  1203. X   fprintf(stderr, "kaiser: %s\n\n", s);  /* Display error message  */
  1204. X   exit(1);                        /* Exit, indicating error */
  1205. X}
  1206. X
  1207. fails(s,s2)
  1208. char *s, *s2;
  1209. X{
  1210. X   fprintf(stderr, "kaiser: ");           /* Display error message  */
  1211. X   fprintf(stderr, s,s2);
  1212. X   fprintf(stderr, "\n\n");
  1213. X   exit(1);                        /* Exit, indicating error */
  1214. X}
  1215. X
  1216. X
  1217. X
  1218. X
  1219. X/* Help Declarations */
  1220. X
  1221. X/* Global file pointers: */
  1222. XFILE *fin, *fout;
  1223. X
  1224. closeData()
  1225. X{
  1226. X   (void) fclose(fin);
  1227. X   (void) fclose(fout);
  1228. X}
  1229. X
  1230. X
  1231. int readData(Data, DataArraySize, Xoff)  /* return: 0 - notDone */
  1232. HWORD Data[];                            /*        >0 - index of last sample */
  1233. int DataArraySize, Xoff;
  1234. X{
  1235. X   int Nsamps, Scan;
  1236. X   short val;
  1237. X   HWORD *DataStart;
  1238. X
  1239. X   DataStart = Data;
  1240. X   Nsamps = DataArraySize - Xoff;   /* Calculate number of samples to get */
  1241. X   Data += Xoff;                    /* Start at designated sample number */
  1242. X   for (; Nsamps>0; Nsamps--)
  1243. X      {
  1244. X      Scan = fread(&val, 1, 2, fin);      /* Read in Nsamps samples */
  1245. X      if (Scan==EOF || Scan==0)            /*   unless read error or EOF */
  1246. X         break;                            /*   in which case we exit and */
  1247. X      *Data++ = val;
  1248. X      }
  1249. X   if (Nsamps > 0)
  1250. X      {
  1251. X      val = Data - DataStart;              /* (Calc return value) */
  1252. X      while (--Nsamps >= 0)                /*   fill unread spaces with 0's */
  1253. X         *Data++ = 0;                      /*   and return FALSE */
  1254. X      return(val);
  1255. X      }
  1256. X   return(0);
  1257. X}
  1258. X
  1259. X
  1260. X
  1261. writeData(Nout, Data)
  1262. int Nout;
  1263. HWORD Data[];
  1264. X{
  1265. X   short s;
  1266. X   /* Write Nout samples to ascii file */
  1267. X   while (--Nout >= 0) {
  1268. X      s = *Data++;
  1269. X      fwrite(&s, 1, 2, fout);
  1270. X   }
  1271. X}
  1272. X
  1273. X
  1274. X
  1275. X
  1276. getparams(argc, argv, Factor, Froll)
  1277. int argc;
  1278. char **argv;
  1279. double *Factor, *Froll;
  1280. X{
  1281. X   if ((argc != 2) && (argc != 3))
  1282. X      fail("format is 'resample factor [ rolloff ]'");
  1283. X   if ((*Factor = atof(argv[1])) < 0.01)
  1284. X      fail("conversion factor no good");
  1285. X   if (argc == 2)
  1286. X      *Froll = 0.5;
  1287. X   else if ((*Froll = atof(argv[2])) < 0.01)
  1288. X      fail("rolloff factor no good");
  1289. X   fin = stdin;
  1290. X   fout = stdout;
  1291. X
  1292. X   /* Check for illegal constants */
  1293. X   if (Np >= 16)
  1294. X      fail("Error: Np>=16");
  1295. X   if (Nb+Nhg+NLpScl >= 32)
  1296. X      fail("Error: Nb+Nhg+NLpScl>=32");
  1297. X   if (Nh+Nb > 32)
  1298. X      fail("Error: Nh+Nb>32");
  1299. X}
  1300. X
  1301. X
  1302. X
  1303. X/* Sampling rate up-conversion only subroutine;
  1304. X * Slightly faster than down-conversion;
  1305. X */
  1306. SrcUp(X, Y, Factor, Time, Nx, Nwing, LpScl, Imp, ImpD, Interp)
  1307. HWORD X[], Y[], Imp[], ImpD[];
  1308. UHWORD Nx, Nwing, LpScl;
  1309. UWORD *Time;
  1310. double Factor;
  1311. BOOL Interp;
  1312. X{
  1313. X   HWORD *Xp, *Ystart;
  1314. X   WORD v;
  1315. X
  1316. X   double dt;                  /* Step through input signal */ 
  1317. X   UWORD dtb;                  /* Fixed-point version of Dt */
  1318. X   UWORD endTime;              /* When Time reaches EndTime, return to user */
  1319. X
  1320. X   dt = 1.0/Factor;            /* Output sampling period */
  1321. X   dtb = dt*(1<<Np) + 0.5;     /* Fixed-point representation */
  1322. X
  1323. X   Ystart = Y;
  1324. X   endTime = *Time + (1<<Np)*(WORD)Nx;
  1325. X   while (*Time < endTime)
  1326. X      {
  1327. X      Xp = &X[*Time>>Np];      /* Ptr to current input sample */
  1328. X      v = FilterUp(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),
  1329. X         -1);                  /* Perform left-wing inner product */
  1330. X      v += FilterUp(Imp, ImpD, Nwing, Interp, Xp+1, (HWORD)((-*Time)&Pmask),
  1331. X         1);                   /* Perform right-wing inner product */
  1332. X      v >>= Nhg;               /* Make guard bits */
  1333. X      v *= LpScl;              /* Normalize for unity filter gain */
  1334. X      *Y++ = v>>NLpScl;        /* Deposit output */
  1335. X      *Time += dtb;            /* Move to next sample by time increment */
  1336. X      }
  1337. X   return (Y - Ystart);        /* Return the number of output samples */
  1338. X}
  1339. X
  1340. X
  1341. X
  1342. X/* Sampling rate conversion subroutine */
  1343. X
  1344. SrcUD(X, Y, Factor, Time, Nx, Nwing, LpScl, Imp, ImpD, Interp)
  1345. HWORD X[], Y[], Imp[], ImpD[];
  1346. UHWORD Nx, Nwing, LpScl;
  1347. UWORD *Time;
  1348. double Factor;
  1349. BOOL Interp;
  1350. X{
  1351. X   HWORD *Xp, *Ystart;
  1352. X   WORD v;
  1353. X
  1354. X   double dh;                  /* Step through filter impulse response */
  1355. X   double dt;                  /* Step through input signal */
  1356. X   UWORD endTime;              /* When Time reaches EndTime, return to user */
  1357. X   UWORD dhb, dtb;             /* Fixed-point versions of Dh,Dt */
  1358. X
  1359. X   dt = 1.0/Factor;            /* Output sampling period */
  1360. X   dtb = dt*(1<<Np) + 0.5;     /* Fixed-point representation */
  1361. X
  1362. X   dh = MIN(Npc, Factor*Npc);  /* Filter sampling period */
  1363. X   dhb = dh*(1<<Na) + 0.5;     /* Fixed-point representation */
  1364. X
  1365. X   Ystart = Y;
  1366. X   endTime = *Time + (1<<Np)*(WORD)Nx;
  1367. X   while (*Time < endTime)
  1368. X      {
  1369. X      Xp = &X[*Time>>Np];      /* Ptr to current input sample */
  1370. X      v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),
  1371. X          -1, dhb);            /* Perform left-wing inner product */
  1372. X      v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1, (HWORD)((-*Time)&Pmask),
  1373. X           1, dhb);            /* Perform right-wing inner product */
  1374. X      v >>= Nhg;               /* Make guard bits */
  1375. X      v *= LpScl;              /* Normalize for unity filter gain */
  1376. X      *Y++ = v>>NLpScl;        /* Deposit output */
  1377. X      *Time += dtb;            /* Move to next sample by time increment */
  1378. X      }
  1379. X   return (Y - Ystart);        /* Return the number of output samples */
  1380. X}
  1381. X
  1382. X
  1383. X
  1384. int resample(Imp, ImpD, LpScl, Nmult, Nwing, Factor, InterpFilt)
  1385. HWORD Imp[], ImpD[];
  1386. UHWORD LpScl, Nmult, Nwing;
  1387. double Factor;
  1388. BOOL InterpFilt;
  1389. X{
  1390. X   UWORD Time;                       /* Current time/pos in input sample */
  1391. X   UHWORD Xp, Ncreep, Xoff, Xread;
  1392. X   HWORD X[IBUFFSIZE], Y[OBUFFSIZE]; /* I/O buffers */
  1393. X   UHWORD Nout, Nx;
  1394. X   int i, Ycount, last;
  1395. X
  1396. X   /* Account for increased filter gain when using Factors less than 1 */
  1397. X   if (Factor < 1)
  1398. X      LpScl = LpScl*Factor + 0.5;
  1399. X   /* Calc reach of LP filter wing & give some creeping room */
  1400. X   Xoff = ((Nmult+1)/2.0) * MAX(1.0,1.0/Factor) + 10;
  1401. X   if (IBUFFSIZE < 2*Xoff)      /* Check input buffer size */
  1402. X      fail("IBUFFSIZE (or Factor) is too small");
  1403. X   Nx = IBUFFSIZE - 2*Xoff;     /* # of samples to proccess each iteration */
  1404. X
  1405. X   last = FALSE;                /* Have not read last input sample yet */
  1406. X   Ycount = 0;                  /* Current sample and length of output file */
  1407. X   Xp = Xoff;                   /* Current "now"-sample pointer for input */
  1408. X   Xread = Xoff;                /* Position in input array to read into */
  1409. X   Time = (Xoff<<Np);           /* Current-time pointer for converter */
  1410. X
  1411. X   for (i=0; i<Xoff; X[i++]=0); /* Need Xoff zeros at begining of sample */
  1412. X     
  1413. X   do {
  1414. X      if (!last)                /* If haven't read last sample yet */
  1415. X         {
  1416. X         last = readData(X, IBUFFSIZE, (int)Xread); /* Fill input buffer */
  1417. X         if (last && (last+Xoff<Nx))  /* If last sample has been read... */
  1418. X            Nx = last + Xoff;   /* ...calc last sample affected by filter */
  1419. X     }
  1420. X      if (Factor >= 1)          /* Resample stuff in input buffer */
  1421. X         Ycount += Nout = SrcUp(X,Y,Factor,&Time,Nx,Nwing,LpScl,Imp,ImpD,
  1422. X            InterpFilt);        /* SrcUp() is faster if we can use it */
  1423. X      else
  1424. X         Ycount += Nout = SrcUD(X,Y,Factor,&Time,Nx,Nwing,LpScl,Imp,ImpD,
  1425. X            InterpFilt);
  1426. X      Time -= (Nx<<Np);           /* Move converter Nx samples back in time */
  1427. X      Xp += Nx;                   /* Advance by number of samples processed */
  1428. X      Ncreep = (Time>>Np) - Xoff; /* Calc time accumulation in Time */
  1429. X      if (Ncreep)
  1430. X         {
  1431. X         Time -= (Ncreep<<Np);    /* Remove time accumulation */
  1432. X         Xp += Ncreep;            /* and add it to read pointer */
  1433. X         }
  1434. X      for (i=0; i<IBUFFSIZE-Xp+Xoff; i++)   /* Copy portion of input signal */
  1435. X         X[i] = X[i+Xp-Xoff];               /* That must be re-used */
  1436. X      if (last)                             /* If near end of sample... */
  1437. X         {
  1438. X         last -= Xp;             /* ...keep track were it ends */
  1439. X         if (!last)              /* Lengthen input by 1 sample if... */
  1440. X            last++;              /* ...needed to keep flag TRUE */
  1441. X     }
  1442. X      Xread = i;                 /* Pos in input buff to read new data into */
  1443. X      Xp = Xoff;
  1444. X
  1445. X      if (Nout > OBUFFSIZE)      /* Check to see if output buff overflowed */
  1446. X         fail("Output array overflow");
  1447. X
  1448. X      writeData((int)Nout ,Y);   /* Write data in output buff to file */
  1449. X      } while (last >= 0);       /* Continue until done processing samples */
  1450. X   return(Ycount);               /* Return # of samples in output file */
  1451. X}
  1452. X
  1453. X
  1454. X
  1455. X
  1456. main(argc, argv)
  1457. int argc;
  1458. char *argv[];
  1459. X{
  1460. X   double Factor;               /* Factor = Fout/Fin */
  1461. X   double Froll;        /* roll-off frequency */
  1462. X   BOOL InterpFilt = TRUE;      /* TRUE means interpolate filter coeffs */
  1463. X   UHWORD LpScl, Nmult, Nwing;  
  1464. X   HWORD Imp[MAXNWING];         /* Filter coefficients */
  1465. X   HWORD ImpD[MAXNWING];        /* ImpD[n] = Imp[n+1]-Imp[n] */
  1466. X   int outCount;
  1467. X
  1468. X   Nmult = 37;
  1469. X   getparams(argc, argv, &Factor, &Froll);
  1470. X   genFilter(Imp, ImpD, &LpScl, Nmult, &Nwing, Froll);
  1471. X   resample(Imp, ImpD, LpScl, Nmult, Nwing, Factor, InterpFilt);
  1472. X   closeData();
  1473. X}
  1474. X
  1475. char *cantmake[5] = {
  1476. X"0 - no error",
  1477. X"1 - Nwing too large (Nwing is > MAXNWING)",
  1478. X"2 - Froll is not in interval [0:1)",
  1479. X"3 - Beta is < 1.0",
  1480. X"4 - LpScl will not fit in 16-bits"
  1481. X};
  1482. X
  1483. genFilter(Imp, ImpD, LpScl, Nmult, Nwing, Froll)
  1484. HWORD Imp[MAXNWING];               /* Filter coefficients */
  1485. HWORD ImpD[MAXNWING];              /* ImpD[i] = ImpD[i+1] - ImpD[i] */
  1486. UHWORD Nmult, *LpScl, *Nwing;
  1487. double Froll;
  1488. X{
  1489. X   double Beta = 2.120;
  1490. X   int err;
  1491. X
  1492. X   *Nwing = Npc*(Nmult+1)/2;     /* # of filter coeffs in right wing */
  1493. X   *Nwing += Npc/2 + 1;          /* This prevents just missing last coeff */
  1494. X                                   /*   for integer conversion factors  */
  1495. X   if ((Froll<=0) || (Froll>1))
  1496. X         fail("Error: Roll-off freq must be 0<Factor<=1\n");
  1497. X   if (err = makeFilter(Imp, ImpD, LpScl, *Nwing, Froll, Beta))
  1498. X         fails("Error: Unable to make filter: %s\n", cantmake[err]);
  1499. X}
  1500. X
  1501. END_OF_FILE
  1502. if test 12170 -ne `wc -c <'kaiser.c'`; then
  1503.     echo shar: \"'kaiser.c'\" unpacked with wrong size!
  1504. fi
  1505. # end of 'kaiser.c'
  1506. fi
  1507. if test -f 'makefilter.c' -a "${1}" != "-c" ; then 
  1508.   echo shar: Will not clobber existing file \"'makefilter.c'\"
  1509. else
  1510. echo shar: Extracting \"'makefilter.c'\" \(4633 characters\)
  1511. sed "s/^X//" >'makefilter.c' <<'END_OF_FILE'
  1512. X
  1513. X/*
  1514. X * FILE: makefilter.c
  1515. X *   BY: Christopher Lee Fraley (cf0v@spice.cmu.edu or cf0v@andrew.cmu.edu)
  1516. X * DESC: Makes a Kaiser-windowed low-pass filter.
  1517. X * DATE: 7-JUN-88
  1518. X */
  1519. X
  1520. char makefilterVERSION[] = "2.0  (17-JUN-88  3:00pm)";
  1521. X
  1522. X#include <stdio.h>
  1523. X#include <math.h>
  1524. X#include "stdefs.h"
  1525. X#include "resample.h"
  1526. X#include "filterkit.h"
  1527. X
  1528. X/* LIBRARIES needed:
  1529. X *
  1530. X * 1. filterkit
  1531. X *       makeFilter()  - designs a Kaiser-windowed low-pass filter
  1532. X *       writeFilter() - writes a filter to a standard filter file
  1533. X *       GetUShort()   - prompt user for a UHWORD with help
  1534. X *       GetDouble()   - prompt user for a double with help
  1535. X *
  1536. X * 2. math
  1537. X */
  1538. X
  1539. X
  1540. X
  1541. char NmultHelp[] =
  1542. X  "\n   Nmult is the length of the symmetric FIR lowpass filter used\
  1543. X   \n   by the sampling rate converter. It must be odd.\
  1544. X   \n   This is the number of multiplies per output sample for\
  1545. X   \n   up-conversions (Factor>1), and is the number of multiplies\
  1546. X   \n   per input sample for down-conversions (Factor<1). Thus if\
  1547. X   \n   the rate conversion is Srate2 = Factor*Srate1, then you have\
  1548. X   \n   Nmult*Srate1*MAXof(Factor,1) multiplies per second of real time.\
  1549. X   \n   Naturally, higher Nmult gives better lowpass-filtering at the\
  1550. X   \n   expense of longer compute times. Nmult should be odd because\
  1551. X   \n   it is the length of a symmetric FIR filter, and the current\
  1552. X   \n   implementation requires a coefficient at the time origin.\n";      
  1553. X
  1554. char FrollHelp[] =
  1555. X  "\n   Froll determines the frequency at which the lowpass filter begins to\
  1556. X   \n   roll-off. If Froll=1, then there is no 'guard zone' and the filter\
  1557. X   \n   roll-off region will be aliased. If Froll is 0.85, for example, then\
  1558. X   \n   the filter begins rolling off at 0.85*Srate/2, so that by Srate/2,\
  1559. X   \n   the filter is well down and aliasing is reduced.  Since aliasing\
  1560. X   \n   distortion is worse by far than loss of the high-frequency spectral\
  1561. X   \n   amplitude, Froll<1 is highly recommended. The default of 0.85\
  1562. X   \n   sacrifices the upper 15% of the spectrum as an anti-aliasing guard\
  1563. X   \n   zone.\n";
  1564. X
  1565. char BetaHelp[] =
  1566. X  "\n   Beta trades the rejection of the lowpass filter against the\
  1567. X   \n   transition width from passband to stopband. Larger Beta means\
  1568. X   \n   a slower transition and greater stopband rejection. See Rabiner\
  1569. X   \n   and Gold (Th. and App. of DSP) under Kaiser windows for more about\
  1570. X   \n   Beta. The following table from Rabiner and Gold gives some feel\
  1571. X   \n   for the effect of Beta:\
  1572. X   \n\
  1573. X   \nAll ripples in dB, width of transition band =D*N, where N= window length\
  1574. X   \n\
  1575. X   \n               BETA    D       PB RIP   SB RIP\
  1576. X   \n               2.120   1.50  +-0.27      -30\
  1577. X   \n               3.384   2.23    0.0864    -40\
  1578. X   \n               4.538   2.93    0.0274    -50\
  1579. X   \n               5.658   3.62    0.00868   -60\
  1580. X   \n               6.764   4.32    0.00275   -70\
  1581. X   \n               7.865   5.0     0.000868  -80\
  1582. X   \n               8.960   5.7     0.000275  -90\
  1583. X   \n               10.056  6.4     0.000087  -100\n";
  1584. X
  1585. X
  1586. X
  1587. main()
  1588. X{
  1589. X   HWORD Imp[MAXNWING];               /* Filter coefficients */
  1590. X   HWORD ImpD[MAXNWING];              /* ImpD[i] = ImpD[i+1] - ImpD[i] */
  1591. X   double Froll, Beta;
  1592. X   UHWORD Nmult, Nwing, LpScl;
  1593. X   int err;
  1594. X
  1595. X   printf("\nKaiser-windowed FIR Filter Design\n");
  1596. X   printf("Written by:  Chritopher Lee Fraley\n");
  1597. X   printf("Version %s\n", makefilterVERSION);
  1598. X
  1599. X   Nmult = 13;
  1600. X   Froll = 0.425;
  1601. X   Beta  = 5.7;
  1602. X   while (TRUE)
  1603. X      {
  1604. X      Nmult = GetUHWORD("(Odd) Filter length 'Nmult'", Nmult, NmultHelp);
  1605. X      Nwing = Npc*(Nmult+1)/2;     /* # of filter coeffs in right wing */
  1606. X      Nwing += Npc/2 + 1;          /* This prevents just missing last coeff */
  1607. X                                   /*   for integer conversion factors  */
  1608. X      Froll = GetDouble("Normalized Roll-off freq (0<Froll<=1)",
  1609. X         Froll, FrollHelp);
  1610. X      Beta = GetDouble("Beta", Beta, BetaHelp);
  1611. X      printf("\n");
  1612. X      if (!(Nmult % 2))
  1613. X         printf("Error: Nmult must be odd and greater than zero\n");
  1614. X      else if (Nwing > MAXNWING)
  1615. X         printf("Error: Nmult too large for current MAXNWING\n");
  1616. X      else if ((Froll<=0) || (Froll>1))
  1617. X         printf("Error: Roll-off freq must be 0<Froll<=1\n");
  1618. X      else if (Beta < 1)
  1619. X         printf("Error: Beta must be greater or equal to 1\n");
  1620. X      else if (err = makeFilter(Imp, ImpD, &LpScl, Nwing, Froll, Beta))
  1621. X         printf("Error: Unable to make filter, err=%d\n", err);
  1622. X      else if (err = writeFilter(Imp, ImpD, LpScl, Nmult, Nwing))
  1623. X         printf("Error: Unable to write filter, err=%d\n", err);
  1624. X      else
  1625. X         break;
  1626. X      }
  1627. X}
  1628. X
  1629. END_OF_FILE
  1630. if test 4633 -ne `wc -c <'makefilter.c'`; then
  1631.     echo shar: \"'makefilter.c'\" unpacked with wrong size!
  1632. fi
  1633. # end of 'makefilter.c'
  1634. fi
  1635. if test -f 'protos.h' -a "${1}" != "-c" ; then 
  1636.   echo shar: Will not clobber existing file \"'protos.h'\"
  1637. else
  1638. echo shar: Extracting \"'protos.h'\" \(3396 characters\)
  1639. sed "s/^X//" >'protos.h' <<'END_OF_FILE'
  1640. X#if defined(__STDC__) || defined(__cplusplus)
  1641. X# define P_(s) s
  1642. X#else
  1643. X# define P_(s) ()
  1644. X#endif
  1645. X
  1646. X
  1647. X/* filterkit.c */
  1648. double Izero P_((double x));
  1649. void LpFilter P_((double c[], int N, double frq, double Beta, int Num));
  1650. int writeFilter P_((HWORD Imp[], HWORD ImpD[], UHWORD LpScl, UHWORD Nmult, UHWORD Nwing));
  1651. int makeFilter P_((HWORD Imp[], HWORD ImpD[], UHWORD *LpScl, UHWORD Nwing, double Froll, double Beta));
  1652. int readFilter P_((HWORD Imp[], HWORD ImpD[], UHWORD *LpScl, UHWORD Nmult, UHWORD *Nwing));
  1653. WORD FilterUp P_((HWORD Imp[], HWORD ImpD[], UHWORD Nwing, BOOL Interp, HWORD *Xp, HWORD Ph, HWORD Inc));
  1654. WORD FilterUD P_((HWORD Imp[], HWORD ImpD[], UHWORD Nwing, BOOL Interp, HWORD *Xp, HWORD Ph, HWORD Inc, UHWORD dhb));
  1655. int initZerox P_((UHWORD tempNmult));
  1656. double zerox P_((HWORD *Data, double Factor));
  1657. BOOL Query P_((char *prompt, BOOL deflt, char *help));
  1658. char *GetString P_((char *prompt, char *deflt, char *help));
  1659. int getstr P_((char *s1, char *deflt, char *s2));
  1660. double GetDouble P_((char *title, double deflt, char *help));
  1661. unsigned short GetUShort P_((char *title, unsigned int deflt, char *help));
  1662. X
  1663. X/* makefilter.c */
  1664. int main P_((void));
  1665. X
  1666. X/* nres.c */
  1667. int fail P_((char *s));
  1668. int fails P_((char *s, char *s2));
  1669. int closeData P_((void));
  1670. int readData P_((HWORD Data[], int DataArraySize, int Xoff));
  1671. int writeData P_((int Nout, HWORD Data[]));
  1672. int getparams P_((int argc, char **argv, double *Factor, double *Froll));
  1673. int SrcUp P_((HWORD X[], HWORD Y[], double Factor, UWORD *Time, UHWORD Nx, UHWORD Nwing, UHWORD LpScl, HWORD Imp[], HWORD ImpD[], BOOL Interp));
  1674. int SrcUD P_((HWORD X[], HWORD Y[], double Factor, UWORD *Time, UHWORD Nx, UHWORD Nwing, UHWORD LpScl, HWORD Imp[], HWORD ImpD[], BOOL Interp));
  1675. int resample P_((HWORD Imp[], HWORD ImpD[], UHWORD LpScl, UHWORD Nmult, UHWORD Nwing, double Factor, BOOL InterpFilt));
  1676. int main P_((int argc, char *argv[]));
  1677. int genFilter P_((HWORD Imp[MAXNWING ], HWORD ImpD[MAXNWING ], UHWORD *LpScl, UHWORD Nmult, UHWORD *Nwing, double Froll));
  1678. X
  1679. X/* resample.c */
  1680. int fail P_((char *s));
  1681. int fails P_((char *s, char *s2));
  1682. int openData P_((int argc, char *argv[]));
  1683. int closeData P_((void));
  1684. int readData P_((HWORD Data[], int DataArraySize, int Xoff));
  1685. int writeData P_((int Nout, HWORD Data[]));
  1686. int getparams P_((double *Factor, BOOL *InterpFilt, UHWORD *Nmult));
  1687. int SrcUp P_((HWORD X[], HWORD Y[], double Factor, UWORD *Time, UHWORD Nx, UHWORD Nwing, UHWORD LpScl, HWORD Imp[], HWORD ImpD[], BOOL Interp));
  1688. int SrcUD P_((HWORD X[], HWORD Y[], double Factor, UWORD *Time, UHWORD Nx, UHWORD Nwing, UHWORD LpScl, HWORD Imp[], HWORD ImpD[], BOOL Interp));
  1689. int resample P_((HWORD Imp[], HWORD ImpD[], UHWORD LpScl, UHWORD Nmult, UHWORD Nwing, double Factor, BOOL InterpFilt));
  1690. int main P_((int argc, char *argv[]));
  1691. X
  1692. X/* warp.c */
  1693. int fail P_((char *s));
  1694. int fails P_((char *s, char *s2));
  1695. int openData P_((int argc, char *argv[]));
  1696. int closeData P_((void));
  1697. int readData P_((HWORD Data[], int DataArraySize, int Xoff));
  1698. int writeData P_((int Nout, HWORD Data[]));
  1699. int check P_((void));
  1700. int initWarp P_((void));
  1701. double warpFunction P_((UWORD Time));
  1702. int SrcUD P_((HWORD X[], HWORD Y[], UWORD *Time, UHWORD Nx, UHWORD Nwing, UHWORD LpScl, HWORD Imp[], HWORD ImpD[], BOOL Interp));
  1703. int resample P_((HWORD Imp[], HWORD ImpD[], UHWORD LpScl, UHWORD Nmult, UHWORD Nwing, BOOL InterpFilt));
  1704. int main P_((int argc, char *argv[]));
  1705. X
  1706. X#undef P_
  1707. END_OF_FILE
  1708. if test 3396 -ne `wc -c <'protos.h'`; then
  1709.     echo shar: \"'protos.h'\" unpacked with wrong size!
  1710. fi
  1711. # end of 'protos.h'
  1712. fi
  1713. if test -f 'resample.c' -a "${1}" != "-c" ; then 
  1714.   echo shar: Will not clobber existing file \"'resample.c'\"
  1715. else
  1716. echo shar: Extracting \"'resample.c'\" \(13378 characters\)
  1717. sed "s/^X//" >'resample.c' <<'END_OF_FILE'
  1718. X
  1719. X/*
  1720. X * FILE: resample.c
  1721. X *   BY: Julius Smith (at CCRMA, Stanford U)
  1722. X * C BY: translated from SAIL to C by Christopher Lee Fraley
  1723. X *          (cf0v@spice.cs.cmu.edu or @andrew.cmu.edu)
  1724. X * DATE: 7-JUN-88
  1725. X */
  1726. X
  1727. char resampleVERSION[] = "1.3  (24-JUN-88, 3:00pm)";
  1728. X
  1729. X/*
  1730. X *      The original version of this program in SAIL may be found in:
  1731. X *      /../s/usr/mhs/resample  or  /../x/usr/rbd/src/resample
  1732. X *
  1733. X *      Implement sampling rate conversions by (almost) arbitrary factors.
  1734. X *      Based on SRCONV.SAI[SYS,MUS] with new algorithm by JOS&PG.
  1735. X *      The program internally uses 16-bit data and 16-bit filter
  1736. X *      coefficients.
  1737. X *
  1738. X *      Reference: "A Flexible Sampling-Rate Conversion Method,"
  1739. X *      J. O. Smith and P. Gossett, ICASSP, San Diego, 1984, Pgs 19.4.
  1740. X *
  1741. X *      * Need overflow detection in Filter() routines.  Also, we want
  1742. X *        to saturate instead of wrap-around and report number of clipped
  1743. X *        samples.
  1744. X */
  1745. X
  1746. X/* CHANGES from original SAIL program:
  1747. X *
  1748. X * 1. LpScl is scaled by Factor (when Factor<1) in resample() so this is
  1749. X *       done whether the filter was loaded or created.
  1750. X * 2. makeFilter() - ImpD[] is created from Imp[] instead of ImpR[], to avoid
  1751. X *       problems with round-off errors.
  1752. X * 3. makeFilter() - ImpD[Nwing-1] gets NEGATIVE Imp[Nwing-1].
  1753. X * 4. SrcU/D() - Switched order of making guard bits (v>>Nhg) and
  1754. X *       normalizing.  This was done to prevent overflow.
  1755. X */
  1756. X
  1757. X/* LIBRARIES needed:
  1758. X *
  1759. X * 1. filterkit
  1760. X *       readFilter() - reads standard filter file
  1761. X *       FilterUp()   - applies filter to sample when Factor >= 1
  1762. X *       FilterUD()   - applies filter to sample for any Factor
  1763. X *       Query()      - prompt user for y/n answer with help.
  1764. X *       GetDouble()  - prompt user for a double with help.
  1765. X *       GetUShort()  - prompt user for a UHWORD with help.
  1766. X *
  1767. X * 2. math
  1768. X */
  1769. X
  1770. X
  1771. X
  1772. X
  1773. X#include <stdio.h>
  1774. X#include <math.h>
  1775. X#include <string.h>
  1776. X#include "stdefs.h"
  1777. X#include "filterkit.h"
  1778. X#include "resample.h"
  1779. X
  1780. X#define IBUFFSIZE 1024                         /* Input buffer size */
  1781. X#define OBUFFSIZE (IBUFFSIZE*MAXFACTOR+2)      /* Calc'd out buffer size */
  1782. X
  1783. X
  1784. fail(s)
  1785. char *s;
  1786. X{
  1787. X   printf("resample: %s\n\n", s);  /* Display error message  */
  1788. X   exit(1);                        /* Exit, indicating error */
  1789. X}
  1790. X
  1791. fails(s,s2)
  1792. char *s, *s2;
  1793. X{
  1794. X   printf("resample: ");           /* Display error message  */
  1795. X   printf(s,s2);
  1796. X   printf("\n\n");
  1797. X   exit(1);                        /* Exit, indicating error */
  1798. X}
  1799. X
  1800. X
  1801. X
  1802. X
  1803. X/* Help Declarations */
  1804. char FactorHelp[] =
  1805. X  "\n   Factor is the amount by which the sampling rate is changed.\
  1806. X   \n   If the sampling rate of the input signal is Srate1, then the\
  1807. X   \n   sampling rate of the output is Factor*Srate1.\n";
  1808. X
  1809. char NmultHelp[] =
  1810. X  "\n   Nmult is the length of the symmetric FIR lowpass filter used\
  1811. X   \n   by the sampling rate converter. It must be odd.\
  1812. X   \n   This is the number of multiplies per output sample for\
  1813. X   \n   up-conversions (Factor>1), and is the number of multiplies\
  1814. X   \n   per input sample for down-conversions (Factor<1). Thus if\
  1815. X   \n   the rate conversion is Srate2 = Factor*Srate1, then you have\
  1816. X   \n   Nmult*Srate1*MAXof(Factor,1) multiplies per second of real time.\
  1817. X   \n   Naturally, higher Nmult gives better lowpass-filtering at the\
  1818. X   \n   expense of longer compute times. Nmult should be odd because\
  1819. X   \n   it is the length of a symmetric FIR filter, and the current\
  1820. X   \n   implementation requires a coefficient at the time origin.\n";      
  1821. X
  1822. char InterpFiltHelp[] =
  1823. X  "\n   By electing to interpolate the filter look-up table,\
  1824. X   \n   execution is slowed down but the quality of filtering\
  1825. X   \n   is higher. Interpolation results in twice as many\
  1826. X   \n   multiply-adds per sample of output.\n";
  1827. X
  1828. X
  1829. X
  1830. X/* Global file pointers: */
  1831. XFILE *fin, *fout;
  1832. X
  1833. X
  1834. openData(argc,argv)
  1835. int argc;
  1836. char *argv[];
  1837. X{
  1838. X   if (argc != 3)
  1839. X      fail("format is 'resample <filein> <fileout>'");
  1840. X   if (NULL == (fin = fopen(*++argv,"r")))
  1841. X      fails("could not open input file '%s'",*argv);
  1842. X   if (NULL == (fout = fopen(*++argv,"w")))
  1843. X      fails("could not open output file '%s'",*argv);
  1844. X}
  1845. X
  1846. X
  1847. closeData()
  1848. X{
  1849. X   (void) fclose(fin);
  1850. X   (void) fclose(fout);
  1851. X}
  1852. X
  1853. X
  1854. int readData(Data, DataArraySize, Xoff)  /* return: 0 - notDone */
  1855. HWORD Data[];                            /*        >0 - index of last sample */
  1856. int DataArraySize, Xoff;
  1857. X{
  1858. X   int Nsamps, Scan;
  1859. X   short val;
  1860. X   HWORD *DataStart;
  1861. X
  1862. X   DataStart = Data;
  1863. X   Nsamps = DataArraySize - Xoff;   /* Calculate number of samples to get */
  1864. X   Data += Xoff;                    /* Start at designated sample number */
  1865. X   for (; Nsamps>0; Nsamps--)
  1866. X      {
  1867. X      Scan = fread(&val, 1, 2, fin);      /* Read in Nsamps samples */
  1868. X      if (Scan==EOF || Scan==0)            /*   unless read error or EOF */
  1869. X         break;                            /*   in which case we exit and */
  1870. X      *Data++ = val;
  1871. X      }
  1872. X   if (Nsamps > 0)
  1873. X      {
  1874. X      val = Data - DataStart;              /* (Calc return value) */
  1875. X      while (--Nsamps >= 0)                /*   fill unread spaces with 0's */
  1876. X         *Data++ = 0;                      /*   and return FALSE */
  1877. X      return(val);
  1878. X      }
  1879. X   return(0);
  1880. X}
  1881. X
  1882. X
  1883. X
  1884. writeData(Nout, Data)
  1885. int Nout;
  1886. HWORD Data[];
  1887. X{
  1888. X   short s;
  1889. X   /* Write Nout samples to ascii file */
  1890. X   while (--Nout >= 0) {
  1891. X      s = *Data++;
  1892. X      fwrite(&s, 1, 2, fout);
  1893. X   }
  1894. X}
  1895. X
  1896. X
  1897. X
  1898. X
  1899. getparams(Factor, InterpFilt, Nmult)
  1900. double *Factor;
  1901. BOOL *InterpFilt;
  1902. UHWORD *Nmult;
  1903. X{
  1904. X   /* Check for illegal constants */
  1905. X   if (Np >= 16)
  1906. X      fail("Error: Np>=16");
  1907. X   if (Nb+Nhg+NLpScl >= 32)
  1908. X      fail("Error: Nb+Nhg+NLpScl>=32");
  1909. X   if (Nh+Nb > 32)
  1910. X      fail("Error: Nh+Nb>32");
  1911. X
  1912. X   /* Default conversion parameters */
  1913. X   *Factor = 2;
  1914. X   *InterpFilt = TRUE;
  1915. X
  1916. X   /* Set up conversion parameters */
  1917. X   while (TRUE)
  1918. X      {
  1919. X      *Factor =
  1920. X         GetDouble("Sampling-rate conversion factor",*Factor,FactorHelp);
  1921. X      if (*Factor <= MAXFACTOR)
  1922. X         break;
  1923. X      printf("Error: Factor must be <= %g to prevent out buffer overflow",
  1924. X         MAXFACTOR);
  1925. X      *Factor = MAXFACTOR;
  1926. X      }
  1927. X   *Nmult = GetUHWORD("Nmult",*Nmult,NmultHelp);
  1928. X   *InterpFilt = Query("Interpolate filter?", *InterpFilt, InterpFiltHelp);
  1929. X}
  1930. X
  1931. X
  1932. X
  1933. X/* Sampling rate up-conversion only subroutine;
  1934. X * Slightly faster than down-conversion;
  1935. X */
  1936. SrcUp(X, Y, Factor, Time, Nx, Nwing, LpScl, Imp, ImpD, Interp)
  1937. HWORD X[], Y[], Imp[], ImpD[];
  1938. UHWORD Nx, Nwing, LpScl;
  1939. UWORD *Time;
  1940. double Factor;
  1941. BOOL Interp;
  1942. X{
  1943. X   HWORD *Xp, *Ystart;
  1944. X   WORD v;
  1945. X
  1946. X   double dt;                  /* Step through input signal */ 
  1947. X   UWORD dtb;                  /* Fixed-point version of Dt */
  1948. X   UWORD endTime;              /* When Time reaches EndTime, return to user */
  1949. X
  1950. X   dt = 1.0/Factor;            /* Output sampling period */
  1951. X   dtb = dt*(1<<Np) + 0.5;     /* Fixed-point representation */
  1952. X
  1953. X   Ystart = Y;
  1954. X   endTime = *Time + (1<<Np)*(WORD)Nx;
  1955. X   while (*Time < endTime)
  1956. X      {
  1957. X      Xp = &X[*Time>>Np];      /* Ptr to current input sample */
  1958. X      v = FilterUp(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),
  1959. X         -1);                  /* Perform left-wing inner product */
  1960. X      v += FilterUp(Imp, ImpD, Nwing, Interp, Xp+1, (HWORD)((-*Time)&Pmask),
  1961. X         1);                   /* Perform right-wing inner product */
  1962. X      v >>= Nhg;               /* Make guard bits */
  1963. X      v *= LpScl;              /* Normalize for unity filter gain */
  1964. X      *Y++ = v>>NLpScl;        /* Deposit output */
  1965. X      *Time += dtb;            /* Move to next sample by time increment */
  1966. X      }
  1967. X   return (Y - Ystart);        /* Return the number of output samples */
  1968. X}
  1969. X
  1970. X
  1971. X
  1972. X/* Sampling rate conversion subroutine */
  1973. X
  1974. SrcUD(X, Y, Factor, Time, Nx, Nwing, LpScl, Imp, ImpD, Interp)
  1975. HWORD X[], Y[], Imp[], ImpD[];
  1976. UHWORD Nx, Nwing, LpScl;
  1977. UWORD *Time;
  1978. double Factor;
  1979. BOOL Interp;
  1980. X{
  1981. X   HWORD *Xp, *Ystart;
  1982. X   WORD v;
  1983. X
  1984. X   double dh;                  /* Step through filter impulse response */
  1985. X   double dt;                  /* Step through input signal */
  1986. X   UWORD endTime;              /* When Time reaches EndTime, return to user */
  1987. X   UWORD dhb, dtb;             /* Fixed-point versions of Dh,Dt */
  1988. X
  1989. X   dt = 1.0/Factor;            /* Output sampling period */
  1990. X   dtb = dt*(1<<Np) + 0.5;     /* Fixed-point representation */
  1991. X
  1992. X   dh = MIN(Npc, Factor*Npc);  /* Filter sampling period */
  1993. X   dhb = dh*(1<<Na) + 0.5;     /* Fixed-point representation */
  1994. X
  1995. X   Ystart = Y;
  1996. X   endTime = *Time + (1<<Np)*(WORD)Nx;
  1997. X   while (*Time < endTime)
  1998. X      {
  1999. X      Xp = &X[*Time>>Np];      /* Ptr to current input sample */
  2000. X      v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),
  2001. X          -1, dhb);            /* Perform left-wing inner product */
  2002. X      v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1, (HWORD)((-*Time)&Pmask),
  2003. X           1, dhb);            /* Perform right-wing inner product */
  2004. X      v >>= Nhg;               /* Make guard bits */
  2005. X      v *= LpScl;              /* Normalize for unity filter gain */
  2006. X      *Y++ = v>>NLpScl;        /* Deposit output */
  2007. X      *Time += dtb;            /* Move to next sample by time increment */
  2008. X      }
  2009. X   return (Y - Ystart);        /* Return the number of output samples */
  2010. X}
  2011. X
  2012. X
  2013. X
  2014. int resample(Imp, ImpD, LpScl, Nmult, Nwing, Factor, InterpFilt)
  2015. HWORD Imp[], ImpD[];
  2016. UHWORD LpScl, Nmult, Nwing;
  2017. double Factor;
  2018. BOOL InterpFilt;
  2019. X{
  2020. X   UWORD Time;                       /* Current time/pos in input sample */
  2021. X   UHWORD Xp, Ncreep, Xoff, Xread;
  2022. X   HWORD X[IBUFFSIZE], Y[OBUFFSIZE]; /* I/O buffers */
  2023. X   UHWORD Nout, Nx;
  2024. X   int i, Ycount, last;
  2025. X
  2026. X   /* Account for increased filter gain when using Factors less than 1 */
  2027. X   if (Factor < 1)
  2028. X      LpScl = LpScl*Factor + 0.5;
  2029. X   /* Calc reach of LP filter wing & give some creeping room */
  2030. X   Xoff = ((Nmult+1)/2.0) * MAX(1.0,1.0/Factor) + 10;
  2031. X   if (IBUFFSIZE < 2*Xoff)      /* Check input buffer size */
  2032. X      fail("IBUFFSIZE (or Factor) is too small");
  2033. X   Nx = IBUFFSIZE - 2*Xoff;     /* # of samples to proccess each iteration */
  2034. X
  2035. X   last = FALSE;                /* Have not read last input sample yet */
  2036. X   Ycount = 0;                  /* Current sample and length of output file */
  2037. X   Xp = Xoff;                   /* Current "now"-sample pointer for input */
  2038. X   Xread = Xoff;                /* Position in input array to read into */
  2039. X   Time = (Xoff<<Np);           /* Current-time pointer for converter */
  2040. X
  2041. X   for (i=0; i<Xoff; X[i++]=0); /* Need Xoff zeros at begining of sample */
  2042. X     
  2043. X   do {
  2044. X      if (!last)                /* If haven't read last sample yet */
  2045. X         {
  2046. X         last = readData(X, IBUFFSIZE, (int)Xread); /* Fill input buffer */
  2047. X         if (last && (last+Xoff<Nx))  /* If last sample has been read... */
  2048. X            Nx = last + Xoff;   /* ...calc last sample affected by filter */
  2049. X     }
  2050. X      if (Factor >= 1)          /* Resample stuff in input buffer */
  2051. X         Ycount += Nout = SrcUp(X,Y,Factor,&Time,Nx,Nwing,LpScl,Imp,ImpD,
  2052. X            InterpFilt);        /* SrcUp() is faster if we can use it */
  2053. X      else
  2054. X         Ycount += Nout = SrcUD(X,Y,Factor,&Time,Nx,Nwing,LpScl,Imp,ImpD,
  2055. X            InterpFilt);
  2056. X      Time -= (Nx<<Np);           /* Move converter Nx samples back in time */
  2057. X      Xp += Nx;                   /* Advance by number of samples processed */
  2058. X      Ncreep = (Time>>Np) - Xoff; /* Calc time accumulation in Time */
  2059. X      if (Ncreep)
  2060. X         {
  2061. X         Time -= (Ncreep<<Np);    /* Remove time accumulation */
  2062. X         Xp += Ncreep;            /* and add it to read pointer */
  2063. X         }
  2064. X      for (i=0; i<IBUFFSIZE-Xp+Xoff; i++)   /* Copy portion of input signal */
  2065. X         X[i] = X[i+Xp-Xoff];               /* That must be re-used */
  2066. X      if (last)                             /* If near end of sample... */
  2067. X         {
  2068. X         last -= Xp;             /* ...keep track were it ends */
  2069. X         if (!last)              /* Lengthen input by 1 sample if... */
  2070. X            last++;              /* ...needed to keep flag TRUE */
  2071. X     }
  2072. X      Xread = i;                 /* Pos in input buff to read new data into */
  2073. X      Xp = Xoff;
  2074. X
  2075. X      if (Nout > OBUFFSIZE)      /* Check to see if output buff overflowed */
  2076. X         fail("Output array overflow");
  2077. X
  2078. X      writeData((int)Nout ,Y);   /* Write data in output buff to file */
  2079. X      } while (last >= 0);       /* Continue until done processing samples */
  2080. X   return(Ycount);               /* Return # of samples in output file */
  2081. X}
  2082. X
  2083. X
  2084. X
  2085. X
  2086. main(argc, argv)
  2087. int argc;
  2088. char *argv[];
  2089. X{
  2090. X   double Factor;               /* Factor = Fout/Fin */
  2091. X   BOOL InterpFilt;             /* TRUE means interpolate filter coeffs */
  2092. X   UHWORD LpScl, Nmult, Nwing;  
  2093. X   HWORD Imp[MAXNWING];         /* Filter coefficients */
  2094. X   HWORD ImpD[MAXNWING];        /* ImpD[n] = Imp[n+1]-Imp[n] */
  2095. X   int outCount;
  2096. X
  2097. X   Nmult = 13;
  2098. X   printf("\nSampling Rate Conversion Program\n");
  2099. X   printf("Written by:  Julius O. Smith (CCRMA)\n");
  2100. X   printf("Translated to C by: Christopher Lee Fraley (cf0v@spice.cs.cmu.edu)\n");
  2101. X   printf("Version %s\n", resampleVERSION);
  2102. X   openData(argc, argv);         /* Interp arguments and open i&o files */
  2103. X   getparams(&Factor, &InterpFilt, &Nmult);
  2104. X   if (readFilter(Imp, ImpD, &LpScl, Nmult, &Nwing))
  2105. X      fail("could not find filter file, or syntax error in filter file");
  2106. X   printf("\nStarting Conversion...\n");
  2107. X   outCount = resample(Imp, ImpD, LpScl, Nmult, Nwing, Factor, InterpFilt);
  2108. X   closeData();
  2109. X
  2110. X   printf("...Conversion Finished:  %d output samples.\n\n",outCount);
  2111. X}
  2112. X
  2113. END_OF_FILE
  2114. if test 13378 -ne `wc -c <'resample.c'`; then
  2115.     echo shar: \"'resample.c'\" unpacked with wrong size!
  2116. fi
  2117. # end of 'resample.c'
  2118. fi
  2119. if test -f 'resample.h' -a "${1}" != "-c" ; then 
  2120.   echo shar: Will not clobber existing file \"'resample.h'\"
  2121. else
  2122. echo shar: Extracting \"'resample.h'\" \(2942 characters\)
  2123. sed "s/^X//" >'resample.h' <<'END_OF_FILE'
  2124. X
  2125. X/*
  2126. X * FILE: resample.h
  2127. X *   BY: Julius Smith (at CCRMA, Stanford U)
  2128. X * C BY: translated from SAIL to C by Christopher Lee Fraley
  2129. X *          (cf0v@andrew.cmu.edu)
  2130. X * DATE: 7-JUN-88
  2131. X * VERS: 2.0  (17-JUN-88, 3:00pm)
  2132. X */
  2133. X
  2134. X#define MAXNWING  5122
  2135. X#define MAXFACTOR 4       /* Maximum Factor without output buff overflow */
  2136. X
  2137. X
  2138. X
  2139. X/* Conversion constants */
  2140. X#define Nhc       8
  2141. X#define Na        7
  2142. X#define Np       (Nhc+Na)
  2143. X#define Npc      (1<<Nhc)
  2144. X#define Amask    ((1<<Na)-1)
  2145. X#define Pmask    ((1<<Np)-1)
  2146. X#define Nh       16
  2147. X#define Nb       16
  2148. X#define Nhxn     14
  2149. X#define Nhg      (Nh-Nhxn)
  2150. X#define NLpScl   13
  2151. X
  2152. X/* Description of constants:
  2153. X *
  2154. X * Npc - is the number of look-up values available for the lowpass filter
  2155. X *    between the beginning of its impulse response and the "cutoff time"
  2156. X *    of the filter.  The cutoff time is defined as the reciprocal of the
  2157. X *    lowpass-filter cut off frequence in Hz.  For example, if the
  2158. X *    lowpass filter were a sinc function, Npc would be the index of the
  2159. X *    impulse-response lookup-table corresponding to the first zero-
  2160. X *    crossing of the sinc function.  (The inverse first zero-crossing
  2161. X *    time of a sinc function equals its nominal cutoff frequency in Hz.)
  2162. X *    Npc must be a power of 2 due to the details of the current
  2163. X *    implementation. The default value of 512 is sufficiently high that
  2164. X *    using linear interpolation to fill in between the table entries
  2165. X *    gives approximately 16-bit accuracy in filter coefficients.
  2166. X *
  2167. X * Nhc - is log base 2 of Npc.
  2168. X *
  2169. X * Na - is the number of bits devoted to linear interpolation of the
  2170. X *    filter coefficients.
  2171. X *
  2172. X * Np - is Na + Nhc, the number of bits to the right of the binary point
  2173. X *    in the integer "time" variable. To the left of the point, it indexes
  2174. X *    the input array (X), and to the right, it is interpreted as a number
  2175. X *    between 0 and 1 sample of the input X.  Np must be less than 16 in
  2176. X *    this implementation.
  2177. X *
  2178. X * Nh - is the number of bits in the filter coefficients. The sum of Nh and
  2179. X *    the number of bits in the input data (typically 16) cannot exceed 32.
  2180. X *    Thus Nh should be 16.  The largest filter coefficient should nearly
  2181. X *    fill 16 bits (32767).
  2182. X *
  2183. X * Nb - is the number of bits in the input data. The sum of Nb and Nh cannot
  2184. X *    exceed 32.
  2185. X *
  2186. X * Nhxn - is the number of bits to right shift after multiplying each input
  2187. X *    sample times a filter coefficient. It can be as great as Nh and as
  2188. X *    small as 0. Nhxn = Nh-2 gives 2 guard bits in the multiply-add
  2189. X *    accumulation.  If Nhxn=0, the accumulation will soon overflow 32 bits.
  2190. X *
  2191. X * Nhg - is the number of guard bits in mpy-add accumulation (equal to Nh-Nhxn).
  2192. X *
  2193. X * NLpScl - is the number of bits allocated to the unity-gain normalization
  2194. X *    factor.  The output of the lowpass filter is multiplied by LpScl and
  2195. X *    then right-shifted NLpScl bits. To avoid overflow, we must have 
  2196. X *    Nb+Nhg+NLpScl < 32.
  2197. X */
  2198. X
  2199. END_OF_FILE
  2200. if test 2942 -ne `wc -c <'resample.h'`; then
  2201.     echo shar: \"'resample.h'\" unpacked with wrong size!
  2202. fi
  2203. # end of 'resample.h'
  2204. fi
  2205. if test -f 'stdefs.h' -a "${1}" != "-c" ; then 
  2206.   echo shar: Will not clobber existing file \"'stdefs.h'\"
  2207. else
  2208. echo shar: Extracting \"'stdefs.h'\" \(699 characters\)
  2209. sed "s/^X//" >'stdefs.h' <<'END_OF_FILE'
  2210. X
  2211. X/*
  2212. X * FILE: stdefs.h
  2213. X *   BY: Christopher Lee Fraley
  2214. X * DESC: Defines standard stuff for inclusion in C programs.
  2215. X * DATE: 6-JUN-88
  2216. X * VERS: 1.0  (6-JUN-88, 2:00pm)
  2217. X */
  2218. X
  2219. X
  2220. X#define TRUE  1
  2221. X#define FALSE 0
  2222. X
  2223. X#define PI (3.14159265358979232846)
  2224. X#define PI2 (6.28318530717958465692)
  2225. X#define D2R (0.01745329348)          /* (2*pi)/360 */
  2226. X#define R2D (57.29577951)            /* 360/(2*pi) */
  2227. X
  2228. X#define MAX(x,y) ((x)>(y) ?(x):(y))
  2229. X#define MIN(x,y) ((x)<(y) ?(x):(y))
  2230. X#define ABS(x)   ((x)<0   ?(-(x)):(x))
  2231. X#define SGN(x)   ((x)<0   ?(-1):((x)==0?(0):(1)))
  2232. X
  2233. typedef char           BOOL;
  2234. typedef short          HWORD;
  2235. typedef unsigned short UHWORD;
  2236. typedef int            WORD;
  2237. typedef unsigned int   UWORD;
  2238. X
  2239. END_OF_FILE
  2240. if test 699 -ne `wc -c <'stdefs.h'`; then
  2241.     echo shar: \"'stdefs.h'\" unpacked with wrong size!
  2242. fi
  2243. # end of 'stdefs.h'
  2244. fi
  2245. if test -f 'warp.c' -a "${1}" != "-c" ; then 
  2246.   echo shar: Will not clobber existing file \"'warp.c'\"
  2247. else
  2248. echo shar: Extracting \"'warp.c'\" \(10961 characters\)
  2249. sed "s/^X//" >'warp.c' <<'END_OF_FILE'
  2250. X
  2251. X/*
  2252. X * FILE: warp.c
  2253. X *   BY: Christopher Lee Fraley (cf0v@spice.cs.cmu.edu)
  2254. X * NOTE: Based upon SAIL program by Julius O. Smith (CCRMA, Stanford U)
  2255. X * DATE: 17-JUN-88
  2256. X */
  2257. X
  2258. char warpVERSION[] = "1.0  24-JUN-88, 4:20pm";
  2259. X
  2260. X/*
  2261. X *      The original SAIL program on which this is based may be found in
  2262. X *      /../s/usr/mhs/resample  or  /../x/usr/rbd/src/resample
  2263. X *
  2264. X *      Implement dynamic sampling-rate changes; uses a second file to
  2265. X *      indicate where periods should fall.  This program may be used to add
  2266. X *      or remove vibrato and micro pitch variations from a sound sample.
  2267. X *      Based on SRCONV.SAI[SYS,MUS] with new algorithm by JOS&PG.
  2268. X *      The program internally uses 16-bit data and 16-bit filter
  2269. X *      coefficients.
  2270. X *
  2271. X *      Reference: "A Flexible Sampling-Rate Conversion Method,"
  2272. X *      J. O. Smith and P. Gossett, ICASSP, San Diego, 1984, Pgs 19.4.
  2273. X *
  2274. X *      * Need overflow detection in Filter() routines.  Also, we want
  2275. X *        to saturate instead of wrap-around and report number of clipped
  2276. X *        samples.
  2277. X */
  2278. X
  2279. X/* CHANGES from original SAIL program:
  2280. X *
  2281. X * 1. SrcUD() - Switched order of making guard bits (v>>Nhg) and
  2282. X *       normalizing.  This was done to prevent overflow.
  2283. X */
  2284. X
  2285. X/* LIBRARIES needed:
  2286. X *
  2287. X * 1. filterkit
  2288. X *       readFilter() - reads standard filter file.
  2289. X *       FilterUD()   - applies filter to sample for any Factor.
  2290. X *       GetDouble()  - prompt user for a double with help.
  2291. X *
  2292. X * 2. math
  2293. X */
  2294. X
  2295. X
  2296. X
  2297. X
  2298. X#include <stdio.h>
  2299. X#include <math.h>
  2300. X#include <string.h>
  2301. X#include "stdefs.h"
  2302. X#include "filterkit.h"
  2303. X#include "resample.h"
  2304. X
  2305. X#define IBUFFSIZE 1024                         /* Input buffer size */
  2306. X#define OBUFFSIZE (IBUFFSIZE*MAXFACTOR+2)      /* Calc'd out buffer size */
  2307. X
  2308. X
  2309. fail(s)
  2310. char *s;
  2311. X{
  2312. X   printf("warp: %s\n\n", s);     /* Display error message  */
  2313. X   exit(1);                       /* Exit, indicating error */
  2314. X}
  2315. X
  2316. fails(s,s2)
  2317. char *s, *s2;
  2318. X{
  2319. X   printf("warp: ");              /* Display error message  */
  2320. X   printf(s, s2);
  2321. X   printf("\n\n");
  2322. X   exit(1);                       /* Exit, indicating error */
  2323. X}
  2324. X
  2325. X
  2326. X
  2327. X/* Global file pointers: */
  2328. XFILE *fin, *fout;
  2329. X
  2330. X
  2331. int openData(argc, argv)
  2332. int argc;
  2333. char *argv[];
  2334. X{
  2335. X   if (argc != 3)
  2336. X      fail("format is 'warp <file-in> <file-out>'");
  2337. X   if (NULL == (fin = fopen(*++argv,"r")))
  2338. X      fails("could not open <file-in> file '%s'",*argv);
  2339. X   if (NULL == (fout = fopen(*++argv,"w")))
  2340. X      fails("could not open <file-out> file '%s'",*argv);
  2341. X}
  2342. X
  2343. X
  2344. closeData()
  2345. X{
  2346. X   (void) fclose(fin);
  2347. X   (void) fclose(fout);
  2348. X}
  2349. X
  2350. X
  2351. X
  2352. int readData(Data, DataArraySize, Xoff)  /* return: 0 - notDone */
  2353. HWORD Data[];                            /*        >0 - index of last sample */
  2354. int DataArraySize, Xoff;
  2355. X{
  2356. X   int Nsamps, Scan, val;
  2357. X   HWORD *DataStart;
  2358. X
  2359. X   DataStart = Data;
  2360. X   Nsamps = DataArraySize - Xoff;   /* Calculate number of samples to get */
  2361. X   Data += Xoff;                    /* Start at designated sample number */
  2362. X   for (; Nsamps>0; Nsamps--)
  2363. X      {
  2364. X      Scan = fscanf(fin, "%d", &val);      /* Read in Nsamps samples */
  2365. X      if (Scan==EOF || Scan==0)            /*   unless read error or EOF */
  2366. X         break;                            /*   in which case we exit and */
  2367. X      *Data++ = val;
  2368. X      }
  2369. X   if (Nsamps > 0)
  2370. X      {
  2371. X      val = Data - DataStart;              /* (Calc return value) */
  2372. X      while (--Nsamps >= 0)                /*   fill unread spaces with 0's */
  2373. X         *Data++ = 0;                      /*   and return FALSE */
  2374. X      return(val);
  2375. X      }
  2376. X   return(0);
  2377. X}
  2378. X
  2379. X
  2380. X
  2381. writeData(Nout, Data)
  2382. int Nout;
  2383. HWORD Data[];
  2384. X{
  2385. X   while (--Nout >= 0)                  /* Write Nout samples to ascii file */
  2386. X      fprintf(fout, "%d\n", *Data++);
  2387. X}
  2388. X
  2389. X
  2390. X
  2391. X
  2392. check()
  2393. X{
  2394. X   /* Check for illegal constants */
  2395. X   if (Np >= 16)
  2396. X      fail("Error: Np>=16");
  2397. X   if (Nb+Nhg+NLpScl >= 32)
  2398. X      fail("Error: Nb+Nhg+NLpScl>=32");
  2399. X   if (Nh+Nb > 32)
  2400. X      fail("Error: Nh+Nb>32");
  2401. X}
  2402. X
  2403. X
  2404. X/* Globals for warping frequency */
  2405. double a,b,c,d,e,f,Total;
  2406. int Acc;
  2407. X
  2408. initWarp()
  2409. X{
  2410. X   Total = GetDouble("\n# of input samples",12000.0,"");
  2411. X
  2412. X   printf("Warping function:  Fout/Fin = w(n)\n");
  2413. X   printf("  w(n) = off + [amp * sin(ph1+frq1*n/N) * sin(ph2+frq2*n/N)]\n");
  2414. X   printf("  where: off,amp,ph1   - parameters\n");
  2415. X   printf("         frq1,ph2,frq2 - more parameters\n");
  2416. X   printf("         n             - current input sample number\n");
  2417. X   printf("         N             - total number of input samples\n");
  2418. X
  2419. X   a = GetDouble("off",1.5,"");
  2420. X   b = GetDouble("amp",-0.5,"");
  2421. X   c = D2R * GetDouble("ph1 (degrees)",-90.0,"");
  2422. X   d = GetDouble("frq1",1.0,"");
  2423. X   e = D2R * GetDouble("ph2 (degrees)",90.0,"");
  2424. X   f = GetDouble("frq2",0.0,"");
  2425. X}
  2426. X
  2427. X
  2428. double warpFunction(Time)
  2429. UWORD Time;
  2430. X{
  2431. X   double fTime,t;
  2432. X
  2433. X   /* Calc absolute position in input file: */
  2434. X   fTime = (double)Time / (double)(1<<Np) + (double)Acc;
  2435. X   /* Calc fraction of file processed: */
  2436. X   t = fTime/Total;
  2437. X   /* Return warp factor: */
  2438. X   return (1.0 / (a + b*sin(c+PI2*d*t)*sin(e+PI2*f*t)));
  2439. X}
  2440. X
  2441. X
  2442. X/* Sampling rate conversion subroutine */
  2443. X
  2444. SrcUD(X, Y, Time, Nx, Nwing, LpScl, Imp, ImpD, Interp)
  2445. HWORD X[], Y[], Imp[], ImpD[];
  2446. UHWORD Nx, Nwing, LpScl;
  2447. UWORD *Time;
  2448. BOOL Interp;
  2449. X{
  2450. X   HWORD *Xp, *Ystart;
  2451. X   WORD v;
  2452. X
  2453. X   UHWORD NewScl;              /* Unity gain scale factor */
  2454. X   double dh;                  /* Step through filter impulse response */
  2455. X   double dt;                  /* Step through input signal */
  2456. X   UWORD endTime;              /* When Time reaches EndTime, return to user */
  2457. X   UWORD dhb, dtb;             /* Fixed-point versions of Dh,Dt */
  2458. X   double Factor;              /* Current resampling factor */
  2459. X
  2460. X   Ystart = Y;
  2461. X   endTime = *Time + (1<<Np)*(WORD)Nx;
  2462. X   while (*Time < endTime)
  2463. X      {
  2464. X      Factor = warpFunction(*Time);     /* Get new conversion Factor */
  2465. X      NewScl = LpScl * Factor;          /* Calc new normalizing scalar */
  2466. X      dt = 1.0 / Factor;                /* New output sampling period */
  2467. X      dtb = dt*(1<<Np) + 0.5;           /* Fixed-point representation */
  2468. X      dh = MIN(Npc, Factor * Npc);      /* New filter sampling period */
  2469. X      dhb = dh*(1<<Na) + 0.5;           /* Fixed-point representation */
  2470. X      Xp = &X[*Time>>Np];               /* Ptr to current input sample */
  2471. X      v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),
  2472. X          -1, dhb);                     /* Perform left-wing inner product */
  2473. X      v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1, (HWORD)((-*Time)&Pmask),
  2474. X           1, dhb);                     /* Perform right-wing inner product */
  2475. X      v >>= Nhg;                        /* Make guard bits */
  2476. X      v *= NewScl;                      /* Normalize for unity filter gain */
  2477. X      *Y++ = v>>NLpScl;                 /* Deposit output */
  2478. X      *Time += dtb;                     /* Move to next sample by time inc */
  2479. X      }
  2480. X   return (Y - Ystart);                 /* Return the # of output samples */
  2481. X}
  2482. X
  2483. X
  2484. X
  2485. int resample(Imp, ImpD, LpScl, Nmult, Nwing, InterpFilt)
  2486. HWORD Imp[], ImpD[];
  2487. UHWORD LpScl, Nmult, Nwing;
  2488. BOOL InterpFilt;
  2489. X{
  2490. X   UWORD Time;                       /* Current time/pos in input sample */
  2491. X   UHWORD Xp, Xread, Ncreep, Xoff;
  2492. X   HWORD X[IBUFFSIZE], Y[OBUFFSIZE]; /* I/O buffers */
  2493. X   UHWORD Nout, Nx;
  2494. X   int i, Ycount, last;
  2495. X
  2496. X   /* Calc reach of LP filter wing & give some creeping room */
  2497. X   Xoff = ((Nmult+1)/2.0) * MAX(1.0,1.0*MAXFACTOR) + 10;
  2498. X   if (IBUFFSIZE < 2*Xoff)      /* Check input buffer size */
  2499. X      fail("IBUFFSIZE (or Factor) is too small");
  2500. X   Nx = IBUFFSIZE - 2*Xoff;     /* # of samples to proccess each iteration */
  2501. X
  2502. X   last = FALSE;                /* Have we read last input sample yet? */
  2503. X   Ycount = 0;                  /* Output sample # and length of out file */
  2504. X   Xp = Xoff;                   /* Current position in input buffer */
  2505. X   Xread = Xoff;                /* Position in input array to read into */
  2506. X   Time = (Xoff<<Np);           /* Current-time pointer for converter */
  2507. X   Acc = -Xoff;                 /* Acc + int(Time) = index into input file */
  2508. X
  2509. X   for (i=0; i<Xoff; X[i++]=0); /* Need Xoff zeros at begining of sample */
  2510. X
  2511. X   do {
  2512. X      if (!last)                /* If haven't read last sample yet */
  2513. X         {
  2514. X         last = readData(X, IBUFFSIZE, (int)Xread); /* Fill input buffer */
  2515. X         if (last && (last+Xoff<Nx))  /* If last sample has been read... */
  2516. X            Nx = last + Xoff;   /* ...calc last sample affected by filter */
  2517. X     }
  2518. X      Ycount += Nout = SrcUD(X,Y,&Time,Nx,Nwing,LpScl,Imp,ImpD,InterpFilt);
  2519. X      Time -= (Nx<<Np);           /* Move converter Nx samples back in time */
  2520. X      Xp += Nx;                   /* Advance by number of samples processed */
  2521. X      Acc += Nx;                  /* We moved Nx samples in the input file */
  2522. X      Ncreep = (Time>>Np) - Xoff; /* Calc time accumulation in Time */
  2523. X      if (Ncreep)
  2524. X         {
  2525. X         Time -= (Ncreep<<Np);    /* Remove time accumulation */
  2526. X         Xp += Ncreep;            /* and add it to read pointer */
  2527. X         Acc += Ncreep;
  2528. X         }
  2529. X      for (i=0; i<IBUFFSIZE-Xp+Xoff; i++)   /* Copy portion of input signal */
  2530. X         X[i] = X[i+Xp-Xoff];               /*    that must be re-used */
  2531. X      if (last)                             /* If near end of sample... */
  2532. X         {
  2533. X         last -= Xp;             /* ...keep track were it ends */
  2534. X         if (!last)              /* Lengthen input by 1 sample */
  2535. X            last++;              /*  if needed to keep flag TRUE */
  2536. X     }
  2537. X      Xread = i;                 /* Pos in input buff to read new data into */
  2538. X      Xp = Xoff;
  2539. X
  2540. X      if (Nout > OBUFFSIZE)      /* Check to see if output buff overflowed */
  2541. X         fail("Output array overflow");
  2542. X
  2543. X      writeData((int)Nout, Y);   /* Write data in output buff to file */
  2544. X      } while (last >= 0);       /* Continue until done processing samples */
  2545. X   return(Ycount);               /* Return # of samples in output file */
  2546. X}
  2547. X
  2548. X
  2549. X
  2550. X
  2551. main(argc,argv)
  2552. int argc;
  2553. char *argv[];
  2554. X{
  2555. X   BOOL InterpFilt;             /* TRUE means interpolate filter coeffs */
  2556. X   UHWORD LpScl, Nmult, Nwing;
  2557. X   HWORD Imp[MAXNWING];         /* Filter coefficients */
  2558. X   HWORD ImpD[MAXNWING];        /* ImpD[n] = Imp[n+1]-Imp[n] */
  2559. X   int outCount;
  2560. X
  2561. X   Nmult = 13;
  2562. X   InterpFilt = TRUE;
  2563. X   printf("\nDynamic Rate Resampling Program (for interesting effects)\n");
  2564. X   printf("Written by:  Christopher Lee Fraley (cf0v@spice.cs.cmu.edu)\n");
  2565. X   printf("Based upon SAIL program by Julius O. Smith (CCRMA)\n");
  2566. X   printf("Version %s\n", warpVERSION);
  2567. X   check();                      /* Check constants for validity */
  2568. X   openData(argc, argv);         /* Interp arguments and open i&o files */
  2569. X   initWarp();                   /* Set up the warp function's parameters */
  2570. X   if (readFilter(Imp, ImpD, &LpScl, Nmult, &Nwing))
  2571. X      fail("could not open Filter file, or syntax error in filter file");
  2572. X   printf("\nWarp Speed Full Ahead...\n");
  2573. X   outCount = resample(Imp, ImpD, LpScl, Nmult, Nwing, InterpFilt);
  2574. X   closeData();
  2575. X
  2576. X   printf("...Returning To Ion Drive:  %d output samples.\n\n", outCount);
  2577. X}
  2578. X
  2579. END_OF_FILE
  2580. if test 10961 -ne `wc -c <'warp.c'`; then
  2581.     echo shar: \"'warp.c'\" unpacked with wrong size!
  2582. fi
  2583. # end of 'warp.c'
  2584. fi
  2585. echo shar: End of archive 1 \(of 1\).
  2586. cp /dev/null ark1isdone
  2587. MISSING=""
  2588. for I in 1 ; do
  2589.     if test ! -f ark${I}isdone ; then
  2590.     MISSING="${MISSING} ${I}"
  2591.     fi
  2592. done
  2593. if test "${MISSING}" = "" ; then
  2594.     echo You have the archive.
  2595.     rm -f ark[1-9]isdone
  2596. else
  2597.     echo You still need to unpack the following archives:
  2598.     echo "        " ${MISSING}
  2599. fi
  2600. ##  End of shell archive.
  2601. exit 0
  2602.