ref: 19f64639e51ac6436c0487e8382dfd778a7d6d60
parent: 7b8a31bb5c241bd5db253ed28c2a8325711e8f7f
author: cbagwell <cbagwell>
date: Thu Nov 11 15:48:01 EST 1999
Adding a lot of patches from Stan Brooks.
--- a/Changelog
+++ b/Changelog
@@ -6,6 +6,25 @@
sox-12.17
---------
+ o Fixed a segfault problem with ulaw/alaw conversion, where
+ an out-of-range index into the tables could occur.
+ o More detailed output from the stat effect.
+ o Continued rewrite of resample.c, now it is almost as
+ fast with floating arithmetic as the old (buggy) version
+ was with 16-bit integer arithmetic. The older version
+ in sox-12.16 shifted frequencies slightly and was less
+ accurate.
+ o New effect 'filter' which is a high-quality DSP lowpass/
+ highpass/bandpass filter using windowed sinc function
+ methods, like polyphase and resample.
+ o New data file type supported, -sl or extension .sl for
+ signed 32-bit integers. Some simplification of the raw.c
+ source.
+ o Some test programs and scripts in the test directory, for
+ making gnuplot plots of frequency response, error-levels
+ of rate-conversion and filter effects.
+ o Removed sbdsp code. All modern unixes are support via OSS,
+ ALSA, or sun audio device interfaces.
o Added AVR handler from Jan Paul Schmidt.
o SoX now waits until the last possible moment before opening
the output file. This will allow all input and effect options
--- /dev/null
+++ b/Copyright
@@ -1,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- a/INSTALL
+++ b/INSTALL
@@ -9,7 +9,7 @@
Compiling
---------
-The perfered method for compiling sox is to use the "configure" scripts
+The prefered method for compiling sox is to use the "configure" scripts
compatible with most unix systems that contain "/bin/sh" or equivalent
(even the Win95/NT Cygwin setup will work with this).
@@ -37,7 +37,6 @@
OS/2 Makefile.unx (using EMX GCC compiler)
OS9 Makefile.os9
UNIX Makefile.unx (or most platforms using GCC compatible compiler)
- VMS descrip.mms & sox.opt (Support is outdated. Read vms.lis)
WIN95/NT Makefile.unx (using Cynus GCC for Win32)
or Makefile.dos (with a little modifying for Visual C++)
--- a/Makefile.ami
+++ b/Makefile.ami
@@ -18,11 +18,11 @@
FSRC = 8svx.c aiff.c alsa.c au.c auto.c avr.c cdr.c cvsd.c dat.c \
g721.c g723_24.c g723_40.c g72x.c gsm.c hcom.c maud.c oss.c raw.c \
- sbdsp.c sf.c smp.c sndrtool.c sunaudio.c tx16w.c voc.c wav.c wve.c
+ sf.c smp.c sndrtool.c sunaudio.c tx16w.c voc.c wav.c wve.c
ESRC = avg.c band.c chorus.c compandc copy.c cut.c deemphas.c dyn.c echo.c \
- echos.c flanger.c highp.c lowp.c map.c mask.c phaser.c pick.c \
- polyphas.c rate.c resample.c reverb.c reverse.c split.c \
+ echos.c filter.c flanger.c highp.c lowp.c map.c mask.c phaser.c \
+ pick.c polyphas.c rate.c resample.c reverb.c reverse.c split.c \
stat.c swap.c vibro.c
PSRC= sox.c
@@ -43,19 +43,16 @@
DOS = tests.bat testall.bat
-VMS = descrip.mms sound2au.com sound2sun.c sound2sun.opt \
- sox.opt tests.com vms.lis
-
-FILES = $(MISC) $(HEADERS) $(SOURCES) $(AMIGA) $(DOS) $(VMS) \
+FILES = $(MISC) $(HEADERS) $(SOURCES) $(AMIGA) $(DOS) \
$(SKEL) $(TESTS)
FOBJ = 8svx.o aiff.o alsa.o au.o auto.o avr.o cdr.o cvsd.o dat.o \
g721.o g723_24.o g723_40.o g72x.o gsm.o hcom.o maud.o oss.o raw.o \
- sbdsp.o sf.o smp.o sndrtool.o sunaudio.o tx16w.o voc.o wav.o wve.o
+ sf.o smp.o sndrtool.o sunaudio.o tx16w.o voc.o wav.o wve.o
EOBJ = avg.o band.o chorus.o compand.o copy.o cut.o deemphas.o dyn.o echo.o \
- echos.o flanger.o highp.o lowp.o map.o mask.o phaser.o pick.o \
- polyphas.o rate.o resample.o reverb.o reverse.o split.o \
+ echos.o filter.o flanger.o highp.o lowp.o map.o mask.o phaser.o \
+ pick.o polyphas.o rate.o resample.o reverb.o reverse.o split.o \
stat.o swap.o vibro.o
##SOUNDLIB is defined below
--- a/Makefile.dos
+++ b/Makefile.dos
@@ -12,12 +12,12 @@
FOBJ = 8svx.obj aiff.obj alsa.obj au.obj auto.obj avr.obj cdr.obj cvsd.obj \
dat.obj g721.obj g723_24.obj g723_40.obj g72x.obj gsm.obj \
- hcom.obj maud.obj oss.obj raw.obj sbdsp.obj sf.obj smp.obj \
+ hcom.obj maud.obj oss.obj raw.obj sf.obj smp.obj \
sndrtool.obj sunaudio.obj tx16w.obj voc.obj wav.obj wve.obj
EOBJ = avg.obj band.obj chorus.obj compand.obj copy.obj cut.obj \
- deemphas.obj dyn.obj echo.obj echos.obj flanger.obj highp.obj \
- lowp.obj map.obj mask.obj phaser.obj pick.obj polyphas.obj \
+ deemphas.obj dyn.obj echo.obj echos.obj filter.obj flanger.obj \
+ highp.obj lowp.obj map.obj mask.obj phaser.obj pick.obj polyphas.obj \
rate.obj resample.obj reverb.obj reverse.obj split.obj \
stat.obj swap.obj vibro.obj
--- a/Makefile.os9
+++ b/Makefile.os9
@@ -17,13 +17,14 @@
$(RDIR)/cdr.r $(RDIR)/cvsd.r $(RDIR)/dat.r \
$(RDIR)/g721.r $(RDIR)/g723_24.r $(RDIR)/g723_40.r \
$(RDIR)/g72x.r $(RDIR)/gsm.r $(RDIR)/hcom.r $(RDIR)/maud.r \
- $(RDIR)/oss.r $(RDIR)/raw.r $(RDIR)/sbdsp.r $(RDIR)/sf.r \
+ $(RDIR)/oss.r $(RDIR)/raw.r $(RDIR)/sf.r \
$(RDIR)/smp.r $(RDIR)/sndrtool.r $(RDIR)/sunaudio.r \
$(RDIR)/tx16w.r $(RDIR)/voc.r $(RDIR)/wav.r $(RDIR)/wve.r
EOBJ = $(RDIR)/avg.r $(RDIR)/band.r $(RDIR)/chorus.r \
$(RDIR)/copy.r $(RDIR)/comand.r $(RDIR)/cut.r $(RDIR)/deemphas.r \
- $(RDIR)/dyn.r $(RDIR)/echo.r $(RDIR)/echos.r $(RDIR)/flanger.r \
+ $(RDIR)/dyn.r $(RDIR)/echo.r $(RDIR)/echos.r $(RDIR)/filter.r \
+ $(RDIR)/flanger.r \
$(RDIR)/highp.r $(RDIR)/lowp.r $(RDIR)/map.r $(RDIR)/mask.r \
$(RDIR)/phaser.r $(RDIR)/pick.r $(RDIR)/polyphas.r $(RDIR)/rate.r \
$(RDIR)/resample.r $(RDIR)/reverb.r $(RDIR)/reverse.r \
--- a/Makefile.unx
+++ /dev/null
@@ -1,272 +1,0 @@
-#
-# Sound Tools Makefile
-#
-# builds libst.a and sox
-#
-# Updated on 02/24/97 - by Chris Bagwell (cbagwell@sprynet.com)
-# Inhanced Makefile to install software and documented a little better.
-#
-# Updated on 05 May 1998 by Chris Bagwell (cbagwell@sprynet.com)
-# Made some changes for various platforms based on others sugestions
-# and made my home system (Linux) the default. ;-)
-#
-# July 19, 1998 - Chris Bagwell (cbagwell@sprynet.com)
-# Redid makefile so that libraries could be optionally linked in.
-# Also made each specific portion of system specifics a seperate
-# line to comment/uncomment so that it will be easier to see how
-# to compiler on a wider array of systems (he says with a grin).
-#
-
-# These things are site dependant so you may want to change.
-PREFIX = /usr/local
-BINDIR = $(PREFIX)/bin
-LIBDIR = $(PREFIX)/lib
-MANDIR = $(PREFIX)/man
-INCDIR = $(PREFIX)/include
-
-SRCDIR = sox-12.16
-
-##############################################################################
-
-FSRC = 8svx.c aiff.c alsa.c au.c auto.c avr.c cdr.c cvsd.c dat.c \
- g721.c g723_24.c g723_40.c g72x.c gsm.c hcom.c maud.c oss.c raw.c \
- sbdsp.c sf.c smp.c sndrtool.c sunaudio.c tx16w.c voc.c wav.c wve.c
-
-ESRC = avg.c band.c chorus.c compand.c copy.c cut.c deemphas.c dyn.c echo.c \
- echos.c flanger.c highp.c lowp.c map.c mask.c phaser.c pick.c \
- polyphas.c rate.c resample.c reverb.c reverse.c split.c \
- stat.c swap.c vibro.c
-
-PSRC = sox.c
-
-SOURCES = $(PSRC) $(FSRC) $(ESRC) handlers.c libst.c misc.c util.c getopt.c
-
-##############################################################################
-
-HEADERS = st.h libst.h sfheader.h sfircam.h patchlvl.h version.h wav.h \
- g72x.h resdefs.h resampl.h
-
-TESTS = tests.sh testall.sh monkey.au monkey.voc
-
-MISC = README INSTALL TODO TIPS CHEAT CHEAT.eft Changelog sox.1 sox.txt \
- libst.3 libst.txt play.1 Makefile.unx Makefile.dos Makefile.b30 \
- Makefile.c70 soxeffect play rec
-
-SKEL = skel.c skeleff.c
-
-AMIGA = Makefile.ami amiga.h
-
-DOS = tests.bat testall.bat
-
-OS9 = Makefile.os9
-
-VMS = descrip.mms sound2au.com sound2sun.c sound2sun.opt \
- sox.opt tests.com vms.lis
-
-FILES = $(MISC) $(HEADERS) $(SOURCES) \
- $(AMIGA) $(DOS) $(OS9) $(VMS) \
- $(SKEL) $(TESTS)
-
-##############################################################################
-
-FOBJ = 8svx.o aiff.o alsa.o au.o auto.o avr.o cdr.o cvsd.o dat.o \
- g721.o g723_24.o g723_40.o g72x.o gsm.o hcom.o maud.o oss.o raw.o \
- sbdsp.o sf.o smp.o sndrtool.o sunaudio.o tx16w.o voc.o wav.o wve.o
-
-EOBJ = avg.o band.o chorus.o compand.o copy.o cut.o deemphas.o dyn.o echo.o \
- echos.o flanger.o highp.o lowp.o map.o mask.o phaser.o pick.o \
- polyphas.o rate.o resample.o reverb.o reverse.o split.o \
- stat.o swap.o vibro.o
-
-SOUNDLIB = libst.a
-LIBOBJS = $(FOBJ) $(EOBJ) handlers.o libst.o misc.o util.o getopt.o
-
-##############################################################################
-
-#
-# System dependency parameters
-# Find anything related to your system and uncomment.
-#
-
-# Default way to delete files.
-RM = rm -f
-
-# Chose the best compiler you got from the following:
-#
-# GCC with all warnings and debug info
-CC = gcc -g -Wall
-#
-# GCC with no special options
-# CC = gcc
-#
-# Generic compiler on your system
-# CC = cc
-#
-# EMX GCC under OS/2 seems to need the following
-# CC = gcc -Zcrtdll -Zexe
-
-# For optimized compilation, uncomment one of the following that your
-# compiler understands.
-#
-# gcc's all understand this as do lots of standard compilers. Try this one
-# first.
-# O = -O2
-
-# getopt() support is defined here. If you have a built-in
-# getopt() that is compatible with SVR5 then you don't need to
-# do anything special.
-#
-# If you don't have any getopt() function then use the following
-# define to use Sox's builtin version
-# GETOPT_DEFINES = -DHAVE_GETOPT
-#
-# If your system has the more advanced version of getopt() that
-# also has its own getopt.h file (Such as the case with GNU libc 2.0)
-# then uncomment the following line. Don't uncomment anything if
-# its in stdlib.h.
-GETOPT_DEFINES = -DHAVE_GETOPT_H
-
-# Uncomment the following if your system does not have a built in
-# strerror(). This includes SunOS.
-#
-# STRERR_DEFINES = -DHAVE_STRERROR
-
-# Uncomment the following if your system does not have a built in
-# MEMMOVE function. Sox will attempt to use bcopy instead.
-# SunOS has this problem.
-#
-# MEMMOVE_DEFINES = -DHAVE_MEMMOVE
-
-# If you have the GSM 6.10 libraries installed then uncomment the follow
-# 4 lines, and change to reflect your installation paths.
-#
-# GSM_PRE_LIBS = -L/usr/local/lib
-# GSM_POST_LIBS = -lgsm
-# GSM_INCLUDES = -I/usr/local/include/
-# GSM_DEFINES = -DHAVE_LIBGSM
-
-# For sound support on machines that include the OSS sound driver
-# (such as Linux) then uncomment the following line.
-#
-# PLAYER_DEFINES = -DOSS_PLAYER
-
-# For sound support using the ALSA driver then uncomment the following line.
-#
-# PLAYER_DEFINES = -DALSA_PLAYER
-
-# For sound support under SunOS and Solaris then uncomment the following line.
-#
-# PLAYER_DEFINES = -DSUNAUDIO_PLAYER
-
-# For sound support on 386 AT&T Unix then uncomment the following line
-#
-# PLAYER_DEFINES = -DBLASTER
-
-# For sound support on Intel BSD-derived Unix's using Steve Haenichen's SBLAST
-# driver uncomment the following line.
-#
-# PLAYER_DEFINES = -DSBLAST
-
-# Uncomment the following lines if your compiling under DOS or Windows.
-# defines .snd to mean a DOS soundtool file (starts with SOUND)
-#
-# DOS_DEFINES = -DDOS
-# RM = del /q
-
-# Uncomment the following line if compiling under NeXT.
-# defines .snd to mean a NeXT sound format file only.
-#
-# NEXT_DEFINES = -DNeXT
-
-# MISC DEFINES - The catch all for things that make even less sense
-# then normal under unix. If you need more than one of the following
-# MISC DEFINES remember to include them on one line so it isn't just
-# redefined.
-#
-# If your sysetem has unistd.h then you'll most like need to add
-# HAVE_UNISTD_H to your misd defines.
-# MISC_DEFINES = -DHAVE_UNISTD_H
-#
-# If your system has malloc.h then you'll most likely need to add
-# HAVE_MALLOC_H to your misd defines.
-# MSIC_DEFINS = -DHAVE_UNISTD_H
-#
-# Testing new improved rate code. You can use the older version if ther
-# are problems.
-# MISC_DEFINES = -DUSE_OLD_RATE
-#
-# For an extra 32k memory, you can include u-law/a-law lookup
-# tables to speed compressiong/decompression of this type data.
-# MISC_DEFINES = -DFAST_ULAW_COMPRESSION -DFAST_ALAW_COMPRESSION
-
-
-##############################################################################
-
-# Library setup
-
-# How should libaries be created. Most systems can simply use the following.
-AR = ar r
-
-# How should 'ranlib' be performed. HPUX, Linux, BSD-ish, SunOS, Solaris
-RANLIB = ranlib
-
-# AT&T System V and GCC on DOS or OS/2 based systems
-# RANLIB = ar ts
-
-# Some systems don't have a ranlib that you can run. Use the following
-# for those systems.
-# RANLIB = true
-
-# Some systems (i.e. MacOsX Server) don't need a separate math library
-MATHLIB = -lm
-# MATHLIB =
-
-##############################################################################
-
-SOX_PRE_LIBS = $(GSM_PRE_LIBS)
-SOX_POST_LIBS = $(GSM_POST_LIBS) $(MATHLIB)
-SOX_INCLUDES = $(GSM_INCLUDES)
-SOX_DEFINES = $(GSM_DEFINES) $(PLAYER_DEFINES) \
- $(GETOPT_DEFINES) $(STRERR_DEFINES) $(MEMMOVE_DEFINES) \
- $(DOS_DEFINES) $(NEXT_DEFINES) $(MISC_DEFINES)
-
-CFLAGS = $O $(SOX_DEFINES) $(SOX_INCLUDES)
-
-all: sox
-
-sox: sox.o $(SOUNDLIB)
- $(CC) $(CFLAGS) -o sox sox.o $(SOUNDLIB) $(SOX_PRE_LIBS) $(SOX_POST_LIBS)
-
-$(SOUNDLIB): $(LIBOBJS)
- $(RM) $(SOUNDLIB)
- $(AR) $(SOUNDLIB) $(LIBOBJS)
- $(RANLIB) $(SOUNDLIB)
-
-sox.o: sox.c st.h
-
-$(LIBOBJS): st.h version.h patchlvl.h
-
-man: sox.1 libst.3
- $(RM) sox.txt libst.txt
- nroff -man sox.1 | col -b > sox.txt
- nroff -man libst.3 | col -b > libst.txt
-
-install: sox
- if [ -f $(BINDIR)/rec ] ; then $(RM) $(BINDIR)/rec ; fi
- if [ -f $(MANDIR)/man1/rec.1 ] ; then $(RM) $(MANDIR)/man1/rec.1 ; fi
- install -c -m 755 sox play $(BINDIR)
- install -c -m 644 sox.1 play.1 $(MANDIR)/man1
- ln -s $(BINDIR)/play $(BINDIR)/rec
- ln -s $(MANDIR)/man1/play.1 $(MANDIR)/man1/rec.1
-
-install-lib: libst.a
- install -c -m 644 libst.a $(LIBDIR)
- install -c -m 644 libst.3 $(MANDIR)/man3
- install -c -m 644 st.h $(INCDIR)
-
-clean:
- $(RM) *~ *.o *.raw *.sf core sox libst.a
-
-tar: clean
- $(RM) ../$(SRCDIR).tar
- cd ..; tar cvf $(SRCDIR).tar $(SRCDIR)
--- a/README
+++ b/README
@@ -59,7 +59,7 @@
History:
-This is the 12th release, Patchlevel 16 of the Sound Tools.
+This is the 12th release, Patchlevel 17 of the Sound Tools.
SoX was originally written and maintained by Lance Norskog but
unfortunetly he has stopped maintaining it since 1995. I, Chris
Bagwell (cbagwell@sprynet.com), have started maintaining it since
@@ -96,9 +96,9 @@
tools for computer multimedia work, similar to the PBM toolkit for
image manipulation.
-Sound Tools may be used for any purpose. Source
-distributions must include the copyright notices. Binary
-distributions must include acknowledgements to the creators.
+Sound Tools may be used for any purpose. Source distributions must
+must include the copyright notices, and (lack of) warranty information.
+Binary distributions must include acknowledgements to the creators.
Files are copyright by their respective authors.
If you have bug fixes/enhancements, please send it to me as I would like
@@ -180,6 +180,9 @@
Libst porting bugs
Lauren Weinstein lauren@vortex.com
DOS porting, scripts, professional use
+ Stan Brooks stabro@megsinet.net
+ Rewrite of resample and polyphase code.
+ DSP filter effect. Some test code/scripts.
Chris Bagwell cbagwell@sprynet.com
OSS and Sun players, bugfixes, ADPCM support,
patch collection and maintance.
--- a/configure.in
+++ b/configure.in
@@ -59,15 +59,6 @@
CFLAGS="$CFLAGS -D_ALL_SOURCE"
;;
- *att* )
- dnl 386 AT&T Unix.
- CFLAGS="$CFLAGS -DBLASTER"
- ;;
-
- i*86-*-bsd* )
- CFLAGS="$CFLAGS -DSBLAST"
- ;;
-
*hpux* )
CFLAGS="$CFLAGS -D_HPUX_SOURCE"
;;
--- a/descrip.mms
+++ /dev/null
@@ -1,284 +1,0 @@
-#
-# MMS description file for SOX/SoundTools (and Gopstein/Harris sound2sun)
-#
-# Modification History
-# 12 Dec 1992, K. S. Kubo, Created
-#
-# NOTES (todo):
-# * This does not yet provide support for VMS distribution (e.g. shar
-# target).
-# * It may be nice to link the library as a shareable image.
-# * To do this "right" this should also provide support for sounds
-# in the DDIF format... someday, maybe.
-#
-# !!!!!!!! IMPORTANT !!!!!!!!!! This file is outdated. Please refer
-# to Makefile.unx to see which source files need to be compiled
-# and update accordingly. Please send any updates to cbagwell@sprynet.com
-
-.IFDEF DEBUG
-DEBUGFLAGS = /debug/nooptimize
-LINKDBGFLAGS = /nouserlibrary/traceback/debug
-.ELSE
-DEBUGFLAGS = /nodebug/optimize
-LINKDBGFLAGS = /nouserlibrary/notraceback/nodebug
-.ENDIF
-
-CC = cc
-CFLAGS = /object=$*.OBJ$(DEBUGFLAGS)
-LINK = link
-LINKFLAGS = /executable=$*.EXE$(LINKDBGFLAGS)
-
-
-FSRC = raw.c, \
- voc.c, \
- au.c, \
- sf.c, \
- aiff.c, \
- hcom.c, \
- 8svx.c, \
- sndrtool.c, \
- wav.c, \
- sbdsp.c, \
- sunaduo.c, \
- oss.c, \
- smp.c, \
- auto.c
-
-ESRC = copy.c, \
- avg.c, \
- stat.c, \
- vibro.c, \
- echo.c, \
- rate.c, \
- band.c, \
- lowp.c, \
- highp.c, \
- reverse.c, \
- dyn.c, \
- cut.c, \
- map.c, \
- split.c, \
- pick.c, \
- mask.c, \
- resample.c
-
-PSRC = sox.c
-
-OSRC = sound2sun.c
-
-SOURCES = $(FSRC),$(ESRC),$(PSRC), \
- handlers.c, libst.c, misc.c, getopt.c, \
- $(OSRC)
-
-HDRS = st.h, \
- libst.h, \
- sfheader.h, \
- sfircam.h, \
- patchlevel.h, \
- version.h, \
- wav.h, \
- g72x.h,\
- resdefs.h, \
- resampl.h
-
-TESTS = tests.sh, \
- testall.sh, \
- monkey.au, \
- monkey.voc
-
-MISC = readme., readme2., install., todo, tips, cheat, sox.1, \
- sox.txt, libst.3, libst.txt, makefile.unx, makefile.bor, \
- Makefile.b30, Makefile.c70, soxeffect, play, rec
-
-VMS = descrip.mms, sox.opt, vms.lis, sound2au.com, sound2sun.opt, \
- sound2sun.c, tests.com
-
-SKEL = skel.c skeleff.c
-
-SOUNDLIB = soundtools.olb
-
-LIBMODS = \
- $(SOUNDLIB)(raw) \
- $(SOUNDLIB)(voc) \
- $(SOUNDLIB)(au) \
- $(SOUNDLIB)(sf) \
- $(SOUNDLIB)(aiff) \
- $(SOUNDLIB)(hcom) \
- $(SOUNDLIB)(8svx) \
- $(SOUNDLIB)(sndrtool) \
- $(SOUNDLIB)(wav) \
- $(SOUNDLIB)(sbdsp) \
- $(SOUNDLIB)(sunaudio) \
- $(SOUNDLIB)(oss) \
- $(SOUNDLIB)(smp) \
- $(SOUNDLIB)(auto) \
- $(SOUNDLIB)(copy) \
- $(SOUNDLIB)(avg) \
- $(SOUNDLIB)(stat) \
- $(SOUNDLIB)(vibro) \
- $(SOUNDLIB)(echo) \
- $(SOUNDLIB)(rate) \
- $(SOUNDLIB)(band) \
- $(SOUNDLIB)(lowp) \
- $(SOUNDLIB)(reverse) \
- $(SOUNDLIB)(handlers) \
- $(SOUNDLIB)(libst) \
- $(SOUNDLIB)(misc) \
- $(SOUNDLIB)(getopt)
-
-.FIRST
- @ if F$TrnLnm("VAXC$INCLUDE") .eqs. "" then define VAXC$INCLUDE sys$library
- @ if F$TrnLnm("SYS") .eqs. "" then define SYS sys$library
-
-#
-# Actual targets
-#
-all : sox.exe sound2sun.exe
- @ ! dummy argument
-
-clean :
- - delete *.obj;
- - delete *.raw;
- - delete *.sf;
-
-depend : $(HDRS) $(SOURCES)
- set command/replace clddir:depend
- depend $(SOURCES)
- ! dependencies updated
-
-sox.exe : sox.obj $(SOUNDLIB) descrip.mms sox.opt
- $(LINK) $(LINKFLAGS) sox.obj, sox.opt/options
-
-sound2sun.exe : sound2sun.obj descrip.mms sound2sun.opt
- $(LINK) $(LINKFLAGS) sound2sun.obj, sound2sun.opt/options
-
-$(SOUNDLIB) : $(LIBMODS)
- ! $(SOUNDLIB) updated
-
-#DO NOT DELETE THIS LINE!
-
-raw.obj : libst.h
-raw.obj : raw.c
-raw.obj : st.h
-raw.obj : sys$library:stddef.h
-raw.obj : sys$library:stdio.h
-voc.obj : st.h
-voc.obj : voc.c
-voc.obj : sys$library:stddef.h
-voc.obj : sys$library:stdio.h
-au.obj : au.c
-au.obj : st.h
-au.obj : sys$library:stddef.h
-au.obj : sys$library:stdio.h
-sf.obj : sf.c
-sf.obj : sfheader.h
-sf.obj : st.h
-sf.obj : sys$library:stddef.h
-sf.obj : sys$library:stdio.h
-aiff.obj : aiff.c
-aiff.obj : st.h
-aiff.obj : sys$library:math.h
-aiff.obj : sys$library:stddef.h
-aiff.obj : sys$library:stdio.h
-hcom.obj : hcom.c
-hcom.obj : st.h
-hcom.obj : sys$library:stddef.h
-hcom.obj : sys$library:stdio.h
-8svx.obj : 8svx.c
-8svx.obj : st.h
-8svx.obj : sys$library:errno.h
-8svx.obj : sys$library:math.h
-8svx.obj : sys$library:perror.h
-8svx.obj : sys$library:stddef.h
-8svx.obj : sys$library:stdio.h
-8svx.obj : sys:types.h
-sndrtool.obj : sndrtool.c
-sndrtool.obj : st.h
-sndrtool.obj : sys$library:errno.h
-sndrtool.obj : sys$library:math.h
-sndrtool.obj : sys$library:perror.h
-sndrtool.obj : sys$library:stddef.h
-sndrtool.obj : sys$library:stdio.h
-wav.obj : st.h
-wav.obj : wav.c
-wav.obj : sys$library:stddef.h
-wav.obj : sys$library:stdio.h
-sbdsp.obj : sbdsp.c
-smp.obj : st.h
-smp.obj : smp.c
-smp.obj : sys$library:stddef.h
-smp.obj : sys$library:stdio.h
-smp.obj : sys$library:string.h
-auto.obj : st.h
-auto.obj : wav.c
-auto.obj : sys$library:stddef.h
-auto.obj : sys$library:stdio.h
-copy.obj : copy.c
-copy.obj : st.h
-copy.obj : sys$library:stddef.h
-copy.obj : sys$library:stdio.h
-avg.obj : avg.c
-avg.obj : st.h
-avg.obj : sys$library:stddef.h
-avg.obj : sys$library:stdio.h
-stat.obj : st.h
-stat.obj : stat.c
-stat.obj : sys$library:stddef.h
-stat.obj : sys$library:stdio.h
-vibro.obj : st.h
-vibro.obj : vibro.c
-vibro.obj : sys$library:math.h
-vibro.obj : sys$library:stddef.h
-vibro.obj : sys$library:stdio.h
-echo.obj : echo.c
-echo.obj : st.h
-echo.obj : sys$library:math.h
-echo.obj : sys$library:stddef.h
-echo.obj : sys$library:stdio.h
-rate.obj : rate.c
-rate.obj : st.h
-rate.obj : sys$library:math.h
-rate.obj : sys$library:stddef.h
-rate.obj : sys$library:stdio.h
-band.obj : band.c
-band.obj : st.h
-band.obj : sys$library:math.h
-band.obj : sys$library:stddef.h
-band.obj : sys$library:stdio.h
-lowp.obj : lowp.c
-lowp.obj : st.h
-lowp.obj : sys$library:math.h
-lowp.obj : sys$library:stddef.h
-lowp.obj : sys$library:stdio.h
-reverse.obj : reverse.c
-reverse.obj : st.h
-reverse.obj : sys$library:math.h
-reverse.obj : sys$library:stddef.h
-reverse.obj : sys$library:stdio.h
-sox.obj : sox.c
-sox.obj : st.h
-sox.obj : sys$library:errno.h
-sox.obj : sys$library:ctype.h
-sox.obj : sys$library:perror.h
-sox.obj : sys$library:stat.h
-sox.obj : sys$library:stddef.h
-sox.obj : sys$library:stdio.h
-sox.obj : sys$library:string.h
-sox.obj : sys$library:varargs.h
-sox.obj : sys:types.h
-handlers.obj : handlers.c
-handlers.obj : st.h
-handlers.obj : sys$library:stddef.h
-handlers.obj : sys$library:stdio.h
-libst.obj : libst.c
-misc.obj : misc.c
-misc.obj : st.h
-misc.obj : sys$library:stddef.h
-misc.obj : sys$library:stdio.h
-getopt.obj : getopt.c
-getopt.obj : st.h
-getopt.obj : sys$library:stddef.h
-getopt.obj : sys$library:stdio.h
-sound2sun.obj : sound2sun.c
-sound2sun.obj : sys$library:stddef.h
-sound2sun.obj : sys$library:stdio.h
--- a/libst.c
+++ b/libst.c
@@ -33,9 +33,10 @@
unsigned char
st_linear_to_ulaw( sample )
-int sample;
+short sample;
{
- static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
+ static const int exp_lut[256] =
+ {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
@@ -2208,7 +2209,7 @@
unsigned char
st_linear_to_Alaw( sample )
-int sample;
+short sample;
{
static int exp_lut[128] = {1,1,2,2,3,3,3,3,
4,4,4,4,4,4,4,4,
--- a/libst.h
+++ b/libst.h
@@ -16,9 +16,9 @@
extern int ulaw_exp_table[256];
extern unsigned char ulaw_comp_table[16384];
#define st_ulaw_to_linear(ulawbyte) ulaw_exp_table[ulawbyte]
-#define st_linear_to_ulaw(linearword) ulaw_comp_table[(linearword / 4) & 0x3fff]
+#define st_linear_to_ulaw(linearword) ulaw_comp_table[((short)linearword / 4) & 0x3fff]
#else
-unsigned char st_linear_to_ulaw( /* int sample */ );
+unsigned char st_linear_to_ulaw( /* short sample */ );
int st_ulaw_to_linear( /* unsigned char ulawbyte */ );
#endif
@@ -26,8 +26,8 @@
extern int Alaw_exp_table[256];
extern unsigned char Alaw_comp_table[16384];
#define st_Alaw_to_linear(Alawbyte) Alaw_exp_table[Alawbyte]
-#define st_linear_to_Alaw(linearword) Alaw_comp_table[(linearword / 4) & 0x3fff]
+#define st_linear_to_Alaw(linearword) Alaw_comp_table[((short)linearword / 4) & 0x3fff]
#else
-unsigned char st_linear_to_Alaw( /* int sample */ );
+unsigned char st_linear_to_Alaw( /* short sample */ );
int st_Alaw_to_linear( /* unsigned char ulawbyte */ );
#endif
--- a/libst.txt
+++ b/libst.txt
@@ -1,213 +1,212 @@
-ST(3) ST(3)
+C Library Functions ST(3)
+
NAME
- libst - Sound Tools : sound sample file and effects
- libraries.
+ libst - Sound Tools : sound sample file and effects
+ libraries.
SYNOPSIS
- cc file.c -o file libst.a
+ cc file.c -o file libst.a
DESCRIPTION
- Sound Tools is a library of sound sample file format read-
- ers/writers and sound effects processors.
+ Sound Tools is a library of sound sample file format
+ readers/writers and sound effects processors.
- Sound Tools includes skeleton C files to assist you in
- writing new formats and effects. The full skeleton
- driver, skel.c, helps you write drivers for a new format
- which has data structures. The simple skeleton drivers
- help you write a new driver for raw (headerless) formats,
- or for formats which just have a simple header followed by
- raw data.
+ Sound Tools includes skeleton C files to assist you in writ-
+ ing new formats and effects. The full skeleton driver,
+ skel.c, helps you write drivers for a new format which has
+ data structures. The simple skeleton drivers help you write
+ a new driver for raw (headerless) formats, or for formats
+ which just have a simple header followed by raw data.
- Most sound sample formats are fairly simple: they are just
- a string of bytes or words and are presumed to be sampled
- at a known data rate. Most of them have a short data
- structure at the beginning of the file.
+ Most sound sample formats are fairly simple: they are just a
+ string of bytes or words and are presumed to be sampled at a
+ known data rate. Most of them have a short data structure
+ at the beginning of the file.
INTERNALS
- The Sound Tools formats and effects operate on an internal
- buffer format of signed 32-bit longs. The data processing
- routines are called with buffers of these samples, and
- buffer sizes which refer to the number of samples pro-
- cessed, not the number of bytes. File readers translate
- the input samples to signed longs and return the number of
- longs read. For example, data in linear signed byte for-
- mat is left-shifted 24 bits.
+ The Sound Tools formats and effects operate on an internal
+ buffer format of signed 32-bit longs. The data processing
+ routines are called with buffers of these samples, and
+ buffer sizes which refer to the number of samples processed,
+ not the number of bytes. File readers translate the input
+ samples to signed longs and return the number of longs read.
+ For example, data in linear signed byte format is left-
+ shifted 24 bits.
- This does cause problems in processing the data. For
- example:
- *obuf++ = (*ibuf++ + *ibuf++)/2;
- would not mix down left and right channels into one mono-
- phonic channel, because the resulting samples would over-
- flow 32 bits. Instead, the ``avg'' effects must use:
- *obuf++ = *ibuf++/2 + *ibuf++/2;
+ This does cause problems in processing the data. For exam-
+ ple:
+ *obuf++ = (*ibuf++ + *ibuf++)/2;
+ would not mix down left and right channels into one mono-
+ phonic channel, because the resulting samples would overflow
+ 32 bits. Instead, the ``avg'' effects must use:
+ *obuf++ = *ibuf++/2 + *ibuf++/2;
- Stereo data is stored with the left and right speaker data
- in successive samples. Quadraphonic data is stored in
- this order: left front, right front, left rear, right
- rear.
+ Stereo data is stored with the left and right speaker data
+ in successive samples. Quadraphonic data is stored in this
+ order: left front, right front, left rear, right rear.
FORMATS
- A format is responsible for translating between sound sam-
- ple files and an internal buffer. The internal buffer is
- store in signed longs with a fixed sampling rate. The
- format operates from two data structures: a format struc-
- ture, and a private structure.
+ A format is responsible for translating between sound sample
+ files and an internal buffer. The internal buffer is store
+ in signed longs with a fixed sampling rate. The format
+ operates from two data structures: a format structure, and
+ a private structure.
- October 15 1996 1
+SunOS 5.6 Last change: October 15 1996 1
-ST(3) ST(3)
+C Library Functions ST(3)
- The format structure contains a list of control parameters
- for the sample: sampling rate, data size (bytes, words,
- floats, etc.), style (unsigned, signed, logarithmic), num-
- ber of sound channels. It also contains other state
- information: whether the sample file needs to be byte-
- swapped, whether fseek() will work, its suffix, its file
- stream pointer, its format pointer, and the private struc-
- ture for the format .
- The private area is just a preallocated data array for the
- format to use however it wishes. It should have a defined
- data structure and cast the array to that structure. See
- voc.c for the use of a private data area. Voc.c has to
- track the number of samples it writes and when finishing,
- seek back to the beginning of the file and write it out.
- The private area is not very large. The ``echo'' effect
- has to malloc() a much larger area for its delay line
- buffers.
- A format has 6 routines:
+ The format structure contains a list of control parameters
+ for the sample: sampling rate, data size (bytes, words,
+ floats, etc.), style (unsigned, signed, logarithmic), number
+ of sound channels. It also contains other state informa-
+ tion: whether the sample file needs to be byte-swapped,
+ whether fseek() will work, its suffix, its file stream
+ pointer, its format pointer, and the private structure for
+ the format .
- startread Set up the format parameters, or read
- in a data header, or do what needs to
- be done.
+ The private area is just a preallocated data array for the
+ format to use however it wishes. It should have a defined
+ data structure and cast the array to that structure. See
+ voc.c for the use of a private data area. Voc.c has to track
+ the number of samples it writes and when finishing, seek
+ back to the beginning of the file and write it out. The
+ private area is not very large. The ``echo'' effect has to
+ malloc() a much larger area for its delay line buffers.
- read Given a buffer and a length: read up
- to that many samples, transform them
- into signed long integers, and copy
- them into the buffer. Return the num-
- ber of samples actually read.
+ A format has 6 routines:
- stopread Do what needs to be done.
+ startread Set up the format parameters, or read in
+ a data header, or do what needs to be
+ done.
- startwrite Set up the format parameters, or write
- out a data header, or do what needs to
- be done.
+ read Given a buffer and a length: read up to
+ that many samples, transform them into
+ signed long integers, and copy them into
+ the buffer. Return the number of sam-
+ ples actually read.
- write Given a buffer and a length: copy that
- many samples out of the buffer, con-
- vert them from signed longs to the
- appropriate data, and write them to
- the file. If it can't write out all
- the samples, fail.
+ stopread Do what needs to be done.
- stopwrite Fix up any file header, or do what
- needs to be done.
+ startwrite Set up the format parameters, or write
+ out a data header, or do what needs to
+ be done.
+ write Given a buffer and a length: copy that
+ many samples out of the buffer, convert
+ them from signed longs to the appropri-
+ ate data, and write them to the file.
+ If it can't write out all the samples,
+ fail.
+
+ stopwrite Fix up any file header, or do what needs
+ to be done.
+
EFFECTS
- An effects loop has one input and one output stream. It
- has 5 routines.
+ An effects loop has one input and one output stream. It has
+ 5 routines.
- getopts is called with a character string
- argument list for the effect.
+ getopts is called with a character string argu-
+ ment list for the effect.
+SunOS 5.6 Last change: October 15 1996 2
- October 15 1996 2
-ST(3) ST(3)
+C Library Functions ST(3)
- start is called with the signal parameters
- for the input and output streams.
- flow is called with input and output data
- buffers, and (by reference) the input
- and output data sizes. It processes
- the input buffer into the output
- buffer, and sets the size variables to
- the numbers of samples actually pro-
- cessed. It is under no obligation to
- fill the output buffer.
+ start is called with the signal parameters for
+ the input and output streams.
- drain is called after there are no more
- input data samples. If the effect
- wishes to generate more data samples
- it copies the generated data into a
- given buffer and returns the number of
- samples generated. If it fills the
- buffer, it will be called again, etc.
- The echo effect uses this to fade
- away.
+ flow is called with input and output data
+ buffers, and (by reference) the input
+ and output data sizes. It processes the
+ input buffer into the output buffer, and
+ sets the size variables to the numbers
+ of samples actually processed. It is
+ under no obligation to fill the output
+ buffer.
- stop is called when there are no more input
- samples to process. stop may generate
- output samples on its own. See echo.c
- for how to do this, and see that what
- it does is absolutely bogus.
+ drain is called after there are no more input
+ data samples. If the effect wishes to
+ generate more data samples it copies the
+ generated data into a given buffer and
+ returns the number of samples generated.
+ If it fills the buffer, it will be
+ called again, etc. The echo effect uses
+ this to fade away.
+ stop is called when there are no more input
+ samples to process. stop may generate
+ output samples on its own. See echo.c
+ for how to do this, and see that what it
+ does is absolutely bogus.
+
COMMENTS
- Theoretically, formats can be used to manipulate several
- files inside one program. Multi-sample files, for example
- the download for a sampling keyboard, can be handled
- cleanly with this feature.
+ Theoretically, formats can be used to manipulate several
+ files inside one program. Multi-sample files, for example
+ the download for a sampling keyboard, can be handled cleanly
+ with this feature.
PORTABILITY PROBLEMS
- Many computers don't supply arithmetic shifting, so do
- multiplies and divides instead of << and >>. The compiler
- will do the right thing if the CPU supplies arithmetic
- shifting.
+ Many computers don't supply arithmetic shifting, so do mul-
+ tiplies and divides instead of << and >>. The compiler will
+ do the right thing if the CPU supplies arithmetic shifting.
- Do all arithmetic conversions one stage at a time. I've
- had too many problems with "obviously clean" combinations.
+ Do all arithmetic conversions one stage at a time. I've had
+ too many problems with "obviously clean" combinations.
- In general, don't worry about "efficiency". The sox.c
- base translator is disk-bound on any machine (other than a
- 8088 PC with an SMD disk controller). Just comment your
- code and make sure it's clean and simple. You'll find
- that DSP code is extremely painful to write as it is.
+ In general, don't worry about "efficiency". The sox.c base
+ translator is disk-bound on any machine (other than a 8088
+ PC with an SMD disk controller). Just comment your code and
+ make sure it's clean and simple. You'll find that DSP code
+ is extremely painful to write as it is.
BUGS
- The HCOM format is not re-entrant; it can only be used
- once in a program.
+ The HCOM format is not re-entrant; it can only be used once
+ in a program.
- The program/library interface is pretty weak. There's too
- October 15 1996 3
+SunOS 5.6 Last change: October 15 1996 3
-ST(3) ST(3)
- much ad-hoc information which a program is supposed to
- gather up. Sound Tools wants to be an object-oriented
- dataflow architecture.
+C Library Functions ST(3)
+ The program/library interface is pretty weak. There's too
+ much ad-hoc information which a program is supposed to
+ gather up. Sound Tools wants to be an object-oriented
+ dataflow architecture.
@@ -259,6 +258,7 @@
- October 15 1996 4
+SunOS 5.6 Last change: October 15 1996 4
+
--- a/sbdsp.c
+++ /dev/null
@@ -1,167 +1,0 @@
-
-char ansi_c_is_very_stupid_and_needs_a_variable_here;
-
-#if defined(BLASTER) || defined(SBLAST)
-/*
- * Copyright 1992 Rick Richardson
- * Copyright 1991 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose. This copyright notice must be maintained.
- * Rick Richardson, Lance Norskog And Sundry Contributors are not
- * responsible for the consequences of using this software.
- */
-
-/*
- * Direct to Sound Blaster device driver.
- * SBLAST patches by John T. Kohl.
- */
-
-#include <sys/types.h>
-#ifdef SBLAST
-#include <i386/isa/sblast.h>
-#else
-#include <sys/sb.h>
-#endif
-#include <signal.h>
-#include "st.h"
-
-/* Private data for SKEL file */
-typedef struct sbdspstuff {
- int samples; /* bytes remaining in current block */
-} *sbdsp_t;
-
-static got_int = 0;
-
-static void
-sigint(s)
-int s;
-{
- if (s) got_int = 1;
- else signal(SIGINT, sigint);
-}
-
-/*
- * Do anything required before you start reading samples.
- * Read file header.
- * Find out sampling rate,
- * size and style of samples,
- * mono/stereo/quad.
- */
-sbdspstartread(ft)
-ft_t ft;
-{
- sbdsp_t sbdsp = (sbdsp_t) ft->priv;
-#ifdef SBLAST
- int off = 0;
-#endif
-
- /* The following is needed to init block reads */
- rawstartread(ft);
-
- /* If you need to seek around the input file. */
- if (0 && ! ft->seekable)
- fail("SKEL input file must be a file, not a pipe");
-
- if (!ft->info.rate)
- ft->info.rate = 11000;
- ft->info.size = BYTE;
- ft->info.style = UNSIGNED;
- ft->info.channels = 1;
- ioctl(fileno(ft->fp), DSP_IOCTL_RESET, 0);
-#ifdef SBLAST
- ioctl(fileno(ft->fp), DSP_IOCTL_VOICE, &off);
- ioctl(fileno(ft->fp), DSP_IOCTL_SPEED, &ft->info.rate);
-#else
- ioctl(fileno(ft->fp), DSP_IOCTL_VOICE, 0);
- ioctl(fileno(ft->fp), DSP_IOCTL_SPEED, ft->info.rate);
-#endif
- sigint(0); /* Prepare to catch SIGINT */
-}
-
-/*
- * Read up to len samples from file.
- * Convert to signed longs.
- * Place in buf[].
- * Return number of samples read.
- */
-
-sbdspread(ft, buf, len)
-ft_t ft;
-LONG *buf, len;
-{
- sbdsp_t sbdsp = (sbdsp_t) ft->priv;
- int rc;
-
- if (got_int) return (0);
- rc = rawread(ft, buf, len);
- if (rc < 0) return 0;
- return (rc);
-}
-
-/*
- * Do anything required when you stop reading samples.
- * Don't close input file!
- */
-sbdspstopread(ft)
-ft_t ft;
-{
- rawstopread(ft);
-
-#ifdef SBLAST
- ioctl(fileno(ft->fp), DSP_IOCTL_FLUSH, 0);
-#endif
-}
-
-sbdspstartwrite(ft)
-ft_t ft;
-{
- sbdsp_t sbdsp = (sbdsp_t) ft->priv;
-#ifdef SBLAST
- int on = 1;
-#endif
-
- rawstartwrite(ft);
-
- /* If you have to seek around the output file */
- if (0 && ! ft->seekable)
- fail("Output .sbdsp file must be a file, not a pipe");
-
- if (!ft->info.rate)
- ft->info.rate = 11000;
- ft->info.size = BYTE;
- ft->info.style = UNSIGNED;
- ft->info.channels = 1;
- ioctl(fileno(ft->fp), DSP_IOCTL_RESET, 0);
-#ifdef SBLAST
- ioctl(fileno(ft->fp), DSP_IOCTL_FLUSH, 0);
- ioctl(fileno(ft->fp), DSP_IOCTL_VOICE, &on);
- ioctl(fileno(ft->fp), DSP_IOCTL_SPEED, &ft->info.rate);
-#else
- ioctl(fileno(ft->fp), DSP_IOCTL_VOICE, 1);
- ioctl(fileno(ft->fp), DSP_IOCTL_SPEED, ft->info.rate);
-#endif
-}
-
-sbdspwrite(ft, buf, len)
-ft_t ft;
-LONG *buf, len;
-{
- sbdsp_t sbdsp = (sbdsp_t) ft->priv;
-
- if (len == 0) return 0;
- return (rawwrite(ft, buf, len));
-}
-
-sbdspstopwrite(ft)
-ft_t ft;
-{
- /* This is needed to flush out block writes */
- rawstopwrite(ft);
-
- /* All samples are already written out. */
- /* If file header needs fixing up, for example it needs the */
- /* the number of samples in a field, seek back and write them here. */
- fflush(ft->fp);
- ioctl(fileno(ft->fp), DSP_IOCTL_FLUSH, 0);
-}
-#endif
--- a/sound2au.com
+++ /dev/null
@@ -1,52 +1,0 @@
-$ FVER = 'F$Verify(0)'
-$ !
-$ ! Sound2Au.Com
-$ ! translate a variety of sound formats into Sun .au format (compatible with
-$ ! DECsound) via SOX and SOUND2SUN.
-$ !
-$ ! sound2sun was written by Rich Gopstein and Harris Corporation.
-$ !
-$ ! SOX is part of the Sound Tools package written and distributed by
-$ ! Lance Norskog, et. al.
-$ !
-$ ! Usage
-$ ! @sound2au file_name [frequency]
-$ !
-$ ! where:
-$ ! file_name = filename template (may contain wildcards)
-$ ! frequency = sampling frequency (default 11000 Hz)
-$ !
-$ ! Modification History
-$ ! 14 Dec 1992, K. S. Kubo, Created
-$ !
-$ If P1 .Eqs. "" THEN GOTO USAGE_EXIT
-$ !
-$ FTMPL = F$Parse(P1,"*.SND;")
-$ If F$TrnLnm("SOX_DIR") .Nes. "" Then Goto MORE_DEFS
-$ SDIR = F$Element(0, "]", F$Environment("PROCEDURE")) + "]"
-$ Define/NoLog SOX_DIR 'SDIR'
-$ MORE_DEFS:
-$ SOX = "$ SOX_DIR:SOX"
-$ SOUND2SUN = "$ SOX_DIR:SOUND2SUN"
-$ ONAME = ""
-$ If P2 .Nes. "" Then SOUND2SUN = SOUND2SUN + " -f ''P2'"
-$ LOOP:
-$ FNAME = F$Search(FTMPL)
-$ If FNAME .Eqs. "" Then Goto REAL_EXIT
-$ If FNAME .Eqs. ONAME Then Goto REAL_EXIT
-$ ONAME = FNAME
-$ VER = F$Parse(FNAME,,,"VERSION")
-$ FTYPE = F$Parse(FNAME,,,"TYPE")
-$ FNAME = FNAME - VER - ";" ! strip version number off
-$ BNAME = FNAME - FTYPE ! get the base name
-$ SOX 'FNAME' -t .raw -u -b 'BNAME'.raw
-$ SOUND2SUN 'BNAME'.raw 'BNAME'.au
-$ Delete/NoLog 'BNAME'.raw;
-$ Goto LOOP
-$ !
-$ USAGE_EXIT:
-$ Write Sys$Output "Usage: @SOUND2AU file_name"
-$ !
-$ REAL_EXIT:
-$ FVER = F$Verify('FVER')
-$ EXIT
--- a/sound2sun.c
+++ /dev/null
@@ -1,201 +1,0 @@
-/************************************************************************/
-/* Copyright 1989 by Rich Gopstein and Harris Corporation */
-/* */
-/* Permission to use, copy, modify, and distribute this software */
-/* and its documentation for any purpose and without fee is */
-/* hereby granted, provided that the above copyright notice */
-/* appears in all copies and that both that copyright notice and */
-/* this permission notice appear in supporting documentation, and */
-/* that the name of Rich Gopstein and Harris Corporation not be */
-/* used in advertising or publicity pertaining to distribution */
-/* of the software without specific, written prior permission. */
-/* Rich Gopstein and Harris Corporation make no representations */
-/* about the suitability of this software for any purpose. It */
-/* provided "as is" without express or implied warranty. */
-/************************************************************************/
-
-/************************************************************************/
-/* sound2sun.c - Convert sampled audio files into uLAW format for the */
-/* Sparcstation 1. */
-/* Send comments to ..!rutgers!soleil!gopstein */
-/************************************************************************/
-/* */
-/* Modified November 27, 1989 to convert to 8000 samples/sec */
-/* (contrary to man page) */
-/* Modified December 13, 1992 to write standard Sun .au header with */
-/* unspecified length. Also made miscellaneous changes for */
-/* VMS port. (K. S. Kubo, ken@hmcvax.claremont.edu) */
-/* Fixed Bug with converting slow sample speeds */
-/* */
-/************************************************************************/
-
-
-#include <stdio.h>
-
-#define DEFAULT_FREQUENCY 11000
-
-#ifdef VAXC
-#define READ_OPEN "r", "mbf=16", "shr=get"
-#define WR_OPEN "w", "mbf=16"
-#else
-#define READ_OPEN "r"
-#define WR_OPEN "w"
-#endif
-
-FILE *infile, *outfile;
-
-/* convert two's complement ch into uLAW format */
-
-unsigned int cvt(ch)
-int ch;
-{
-
- int mask;
-
- if (ch < 0) {
- ch = -ch;
- mask = 0x7f;
- } else {
- mask = 0xff;
- }
-
- if (ch < 32) {
- ch = 0xF0 | 15 - (ch / 2);
- } else if (ch < 96) {
- ch = 0xE0 | 15 - (ch - 32) / 4;
- } else if (ch < 224) {
- ch = 0xD0 | 15 - (ch - 96) / 8;
- } else if (ch < 480) {
- ch = 0xC0 | 15 - (ch - 224) / 16;
- } else if (ch < 992) {
- ch = 0xB0 | 15 - (ch - 480) / 32;
- } else if (ch < 2016) {
- ch = 0xA0 | 15 - (ch - 992) / 64;
- } else if (ch < 4064) {
- ch = 0x90 | 15 - (ch - 2016) / 128;
- } else if (ch < 8160) {
- ch = 0x80 | 15 - (ch - 4064) / 256;
- } else {
- ch = 0x80;
- }
-return (mask & ch);
-}
-
-/* write a "standard" sun header with an unspecified length */
-#define wrulong(fp, ul) putc((ul >> 24) & 0xff, fp); \
- putc((ul >> 16) & 0xff, fp); putc((ul >> 8) & 0xff, fp); \
- putc(ul & 0xff, fp);
-
-static void
-wr_header(optr)
-FILE *optr;
-{
- wrulong(optr, 0x2e736e64); /* Sun magic */
- wrulong(optr, 24); /* header size in bytes */
- wrulong(optr, ((unsigned)(~0))); /* unspecified data size */
- wrulong(optr, 1); /* Sun uLaw format */
- wrulong(optr, 8000); /* sample rate by definition :-) */
- wrulong(optr, 1); /* single channel */
-}
-
-/*******************************************************
-/* */
-/* Usage is "sound2sun [-f frequency] infile outfile" */
-/* */
-/* "frequency" is the samples per second of the infile */
-/* the outfile is always 8000 samples per second. */
-/* */
-/*******************************************************/
-
-/***********************************************************************/
-/* */
-/* The input file is expected to be a stream of one-byte excess-128 */
-/* samples. Each sample is converted to 2's complement by subtracting */
-/* 128, then converted to uLAW and output. We calculate the proper */
-/* number of input bytes to skip in order to make the sample frequency */
-/* convert to 8000/sec properly. Interpolation could be added, but it */
-/* doesn't appear to be necessary. */
-/* */
-/***********************************************************************/
-
-
-main(argc, argv)
-int argc;
-char *argv[];
-{
-
- float sum = 0;
- float frequency, increment;
-
- unsigned char ch;
- unsigned char ulaw;
-
- int chr;
-
- if ((argc != 3) && (argc != 5)) {
- fprintf(stderr,"Usage: sound2sun [-f frequency] infile outfile\n");
- exit(1);
- }
-
- if (argc == 5) {
- if (strcmp(argv[1], "-f") != 0) {
- fprintf(stderr, "Usage: sound2sun [-f frequency] infile outfile\n");
- exit(1);
- } else {
- frequency = atoi(argv[2]);
- }
- } else {
- frequency = DEFAULT_FREQUENCY;
- }
-
- if ((infile = fopen(argv[argc-2], READ_OPEN)) == NULL) {
- perror("Error opening infile");
- exit(0);
- }
-
- if ((outfile = fopen(argv[argc-1], WR_OPEN)) == NULL) {
- perror("Error opening outfile");
- exit(0);
- }
-
- wr_header(outfile);
-
- /* increment is the number of bytes to read each time */
-
- increment = frequency / 8000;
-
- ch = fgetc(infile);
-
- while (!feof(infile)) {
-
- /* convert the excess 128 to two's complement */
-
- chr = 0x80 - ch;
-
- /* increase the volume */
- /* convert to uLAW */
-
- ulaw = cvt(chr * 16);
-
- /* output it */
-
- fputc((char) ulaw, outfile);
-
- /* skip enough input bytes to compensate for sampling frequency diff */
-
- sum += increment;
-
- while(sum > 0) {
- if (!feof(infile)) ch = fgetc(infile);
- sum--;
- }
-
- }
-
- fclose(infile);
- fclose(outfile);
-}
-
-/* DEC/CMS REPLACEMENT HISTORY, Element SOUND2SUN.C */
-/* *1 14-DEC-1992 17:46:37 CENYDD "main program" */
-/* DEC/CMS REPLACEMENT HISTORY, Element SOUND2SUN.C */
--- a/sound2sun.opt
+++ /dev/null
@@ -1,5 +1,0 @@
-identification="V1.0"
-!
-! Basic C library stuff
-!
-sys$share:vaxcrtl/shareable
--- a/sox.1
+++ b/sox.1
@@ -9,7 +9,7 @@
.if t .sp .5v
.if n .sp
..
-.TH SoX 1 "June 28, 1999"
+.TH SoX 1 "November 8, 1999"
.SH NAME
sox \- Sound eXchange : universal sound sample translator
.SH SYNOPSIS
@@ -69,6 +69,8 @@
.br
echos \fIgain-in gain-out delay decay\fB [ \fIdelay decay ...\fB]
.br
+ filter \fB[ \fIlow\fB ]\fI-\fB[ \fIhigh\fB ] [ \fIwindow-len\fB [ \fIbeta\fB ]]
+.br
flanger \fIgain-in gain-out delay decay speed -s\fB | -fI-t\fB
.br
highp \fIcenter\fB
@@ -456,12 +458,12 @@
of the sample file must be given.
The number of channels defaults to 1.
.TP 10
-.B ".ub, .sb, .uw, .sw, .ul"
+.B ".ub, .sb, .uw, .sw, .ul, .sl"
These are several suffices which serve as
a shorthand for raw files with a given size and style.
-Thus, \fBub, sb, uw, sw,\fR and \fBul\fR
+Thus, \fBub, sb, uw, sw, ul\fR and \fBsl\fR
correspond to "unsigned byte", "signed byte",
-"unsigned word", "signed word", and "ulaw" (byte).
+"unsigned word", "signed word", "ulaw" (byte), and "signed long".
The sample rate defaults to 8000 hz if not explicitly set,
and the number of channels (as always) defaults to 1.
There are lots of Sparc samples floating around in u-law format
@@ -513,11 +515,16 @@
.I -n
(for noise) option uses the alternate mode
for un-pitched signals.
+.B Warning:
+.I -n
+introduces a power-gain of about 11dB in the filter, so beware
+of output clipping.
.B Band
introduces noise in the shape of the filter,
i.e. peaking at the
.I center
frequency and settling around it.
+See \fBfilter\fR for a bandpass effect with steeper shoulders.
.TP
chorus \fIgain-in gain-out delay decay speed deptch
.TP 10
@@ -582,6 +589,24 @@
and the decay (relative to gain-in) of that echo.
Gain-out is the volume of the output.
.TP 10
+filter [ \fIlow\fR ]-[ \fIhigh\fR ] [ \fIwindow-len\fR [ \fIbeta\fR ] ]
+Apply a Sinc-windowed lowpass, highpass, or bandpass filter of given
+window length to the signal.
+\fIlow\fR refers to the frequency of the lower 6dB corner of the filter.
+\fIhigh\fR refers to the frequency of the upper 6dB corner of the filter.
+
+A lowpass filter is obtained by leaving \fIlow\fR unspecified, or 0.
+A highpass filter is obtained by leaving \fIhigh\fR unspecified, or 0,
+or greater than or equal to the Nyquist freq.
+
+The \fIwindow-len\fR, if unspecified, defaults to 128.
+Longer windows give a sharper cutoff, smaller windows a more gradual cutoff.
+
+The \fIbeta\fR, if unspecified, defaults to 16. This selects a Kaiser window.
+You can select a Nuttall window by specifying anything <= 2.0 here.
+For more discussion of beta, look under the \fBresample\fR effect.
+
+.TP 10
flanger \fIgain-in gain-out delay decay speed -s \fR| \fI-t
Add a flanger to a sound sample. Each triple
delay/decay/speed gives the delay in milliseconds
@@ -596,6 +621,7 @@
.I center
frequency in the middle of the drop.
The slope of the filter is quite gentle.
+See \fBfilter\fR for a highpass effect with sharper cutoff.
.TP 10
lowp \fIcenter
Apply a low-pass filter.
@@ -603,6 +629,7 @@
.I center
frequency in the middle of the drop.
The slope of the filter is quite gentle.
+See \fBfilter\fR for a lowpass effect with sharper cutoff.
.TP 10
map
Display a list of loops in a sample,
@@ -679,25 +706,53 @@
.B Sox's
rate changing effects to ues, you will want to read a
detailed analysis of all of them at http://eakaw2.et.tu-dresden.de/~andreas/resample/resample.html
+[Nov,1999: These tests need to be updated for sox-12.18, which has bugfixes to the
+resample and polyphase code.]
.TP 10
-resample [ \fIrolloff\fR [ \fIbeta\fR ] ]
+resample [ \fI-qs\fB | \fI-q\fB | \fI-ql\fB ] [ \fIrolloff\fB [ \fIbeta\fB ] ]\fR
Translate input sampling rate to output sampling rate
via simulated analog filtration.
This method is slower than
.B rate,
-but gives much
-better results. rolloff refers to the cut-off frequency of the
+but gives much better results.
+
+The \fI-qs\fR, \fI-q\fR, or \fI-ql\fR options specify increased accuracy
+at the cost of lower execution speed. By default, linear interpolation
+is used, with a window width about 37 samples at the lower rate.
+This gives an accuracy of about 16 bits, but insufficient stopband rejection
+in the case that you want to have rolloff greater than about 0.85 of
+the Nyquist frequency.
+The \fI-q*\fR options use quadratic interpolation of filter
+coefficients, resulting in about 22 bits precision.
+\fI-qs\fR, \fI-q\fR, or \fI-ql\fR use window lengths of 37, 75, or 150
+samples, respectively, at the lower sample-rate of the two files.
+This means progressively sharper stop-band rejection, at proportionally
+slower execution times.
+
+\fIrolloff\fR refers to the cut-off frequency of the
low pass filter and is given in terms of the
-Nyquist frequency for the lower sample rate. rolloff therefor should
-be something between 0. and 1., in practice 0.8-0.95. beta trades stop band
-rejection against transition width from passband to stop band. Larger
-beta means a slower transition and greater stopband rejection. beta
-should be at least greater than 2. The default is rollof 0.8, beta 17.5,
-which is rather conservative with respect to aliasing. Lower beta
-and higher rolloff values preserve more high frequency signal energy,
-but introduce measurable artifacts.
-This is the default effect
-if the two files have different sampling rates.
+Nyquist frequency for the lower sample rate. rolloff therefore should
+be something between 0. and 1., in practice 0.8-0.95. The default is 0.8.
+
+The \fIbeta\fR parameter
+determines the type of filter window used. Any value greater than 2.0 is
+the beta for a Kaiser window. Beta <= 2.0 selects a Nuttall window.
+If unspecified, the default is a Kaiser window with beta 16.
+
+In the case of Kaiser window beta > 2.0, lower betas produce a somewhat
+faster transition from passband to stopband, at the cost of noticeable artifacts.
+A beta of 16 is the default, beta less than 10 is not recommended. If you want
+a sharper cutoff, don't use low beta's, use a longer sample window.
+A Nuttall window is selected by specifying any 'beta' <= 2, and the
+Nuttall window has somewhat steeper cutoff than the default Kaiser window.
+You will probably not need to use the beta parameter at all, unless you are
+just curious about comparing the effects of Nuttall vs. Kaiser windows.
+
+This is the default effect if the two files have different sampling rates.
+Default parameters are Kaiser window of length 37, rolloff 0.80, beta 16,
+linear interpolation. \fI-qs\fR is only slightly slower, but more accurate for
+16-bit or higher precision.
+
.TP 10
reverb \fIgain-out delay \fR[ \fIdelay ... \fR]
Add reverbation to a sound sample. Each delay is given
--- a/sox.opt
+++ /dev/null
@@ -1,9 +1,0 @@
-identification="V5.7"
-!
-! SoundTools library
-!
-soundtools.olb/library
-!
-! Basic C library stuff
-!
-sys$share:vaxcrtl/shareable
--- a/sox.txt
+++ b/sox.txt
@@ -1,848 +1,858 @@
-SoX(1) SoX(1)
+User Commands SoX(1)
+
NAME
- sox - Sound eXchange : universal sound sample translator
+ sox - Sound eXchange : universal sound sample translator
SYNOPSIS
- sox infile outfile
- sox infile outfile [ effect [ effect options ... ] ]
- sox infile -e effect [ effect options ... ]
- sox [ general options ] [ format options ] ifile [ for-
- mat options ] ofile [ effect [ effect options ... ] ]
+ sox infile outfile
+ sox infile outfile [ effect [ effect options ... ] ]
+ sox infile -e effect [ effect options ... ]
+ sox [ general options ] [ format options ] ifile [ format
+ options ] ofile [ effect [ effect options ... ] ]
- General options: [ -e ] [ -h ] [ -p ] [ -v volume ] [ -V ]
+ General options: [ -e ] [ -h ] [ -p ] [ -v volume ] [ -V ]
- Format options: [ -t filetype ] [ -r rate ] [
- -s/-u/-U/-A/-a/-g ] [ -b/-w/-l/-f/-d/-D ] [ -c channels ]
- [ -x ]
+ Format options: [ -t filetype ] [ -r rate ] [ -s/-u/-U/-
+ A/-a/-g ] [ -b/-w/-l/-f/-d/-D ] [ -c channels ] [ -x ]
- Effects:
- avg [ -l | -r ]
- band [ -n ] center [ width ]
- check
- chorus gain-in gain out delay decay speed depth
- -s | -t [ delay decay speed depth -s | -fI-t ]
- compand attack1,decay1[,attack2,decay2...]
- in-dB1,out-dB1[,in-dB2,out-dB2...]
- [gain] [initial-volume]
- copy
- cut
- deemph
- echo gain-in gain-out delay decay [ delay decay ...]
- echos gain-in gain-out delay decay [ delay decay ...]
- flanger gain-in gain-out delay decay speed -s | -fI-t
- highp center
- lowp center
- map
- mask
- phaser gain-in gain-out delay decay speed -s | -t
- pick
- polyphase [ -w < num / ham > ]
- [ -width < long / short / # > ]
- [ -cutoff # ]
- rate
- resample
- reverb gain-out reverb-time delay [ delay ... ]
- reverse
- split
- stat [ debug | -v ]
- swap [ 1 2 3 4 ]
- vibro speed [ depth ]
+ Effects:
+ avg [ -l | -r ]
+ band [ -n ] center [ width ]
+ check
+ chorus gain-in gain out delay decay speed depth
+ -s | -t [ delay decay speed depth -s | -fI-t ]
+ compand attack1,decay1[,attack2,decay2...]
+ in-dB1,out-dB1[,in-dB2,out-dB2...]
+ [gain] [initial-volume]
+ copy
+ cut
+ deemph
+ echo gain-in gain-out delay decay [ delay decay ...]
+ echos gain-in gain-out delay decay [ delay decay ...]
+ filter [ low ]-[ high ] [ window-len [ beta ]]
+ flanger gain-in gain-out delay decay speed -s | -fI-t
+ highp center
+ lowp center
+ map
+ mask
+ phaser gain-in gain-out delay decay speed -s | -t
+ pick
+ polyphase [ -w < num / ham > ]
+ [ -width < long / short / # > ]
+ [ -cutoff # ]
+ rate
+ resample
+ reverb gain-out reverb-time delay [ delay ... ]
+ reverse
+ split
+ stat [ debug | -v ]
+ swap [ 1 2 3 4 ]
+ vibro speed [ depth ]
DESCRIPTION
- Sox translates sound files from one format to another,
- possibly doing a sound effect.
+ Sox translates sound files from one format to another, pos-
+ sibly doing a sound effect.
+SunOS 5.6 Last change: November 8, 1999 1
- June 28, 1999 1
+User Commands SoX(1)
-SoX(1) SoX(1)
OPTIONS
- The option syntax is a little grotty, but in essence:
- sox file.au file.voc
- translates a sound sample in SUN Sparc .AU format into a
- SoundBlaster .VOC file, while
- sox -v 0.5 file.au -r 12000 file.voc rate
- does the same format translation but also lowers the
- amplitude by 1/2 and changes the sampling rate from 8000
- hertz to 12000 hertz via the rate sound effect loop.
+ The option syntax is a little grotty, but in essence:
+ sox file.au file.voc
+ translates a sound sample in SUN Sparc .AU format into a
+ SoundBlaster .VOC file, while
+ sox -v 0.5 file.au -r 12000 file.voc rate
+ does the same format translation but also lowers the ampli-
+ tude by 1/2 and changes the sampling rate from 8000 hertz to
+ 12000 hertz via the rate sound effect loop.
- Format options:
+ Format options:
- Format options effect the file that they immediately
- percede. If they are placed before the input file name
- then they effect the input data. If they are placed
- before the output file name then they will effect the out-
- put data. It is also possible to read a given file in and
- output it in any supported data format by specifying out-
- put format options.
+ Format options effect the file that they immediately per-
+ cede. If they are placed before the input file name then
+ they effect the input data. If they are placed before the
+ output file name then they will effect the output data. It
+ is also possible to read a given file in and output it in
+ any supported data format by specifying output format
+ options.
- -t filetype
- gives the type of the sound sample file.
+ -t filetype
+ gives the type of the sound sample file.
- -r rate Give sample rate in Hertz of file. To cause the
- output file to have a different sample rate then
- the input file, include this option with the
- appropriate rate value along with the output
- options. If the input and output files have
- different rates then a sample rate change effect
- must be ran. If a sample rate changing effect
- is not specified then a default one will be used
- with its default parameters.
+ -r rate Give sample rate in Hertz of file. To cause the
+ output file to have a different sample rate then
+ the input file, include this option with the
+ appropriate rate value along with the output
+ options. If the input and output files have dif-
+ ferent rates then a sample rate change effect must
+ be ran. If a sample rate changing effect is not
+ specified then a default one will be used with its
+ default parameters.
- -s/-u/-U/-A/-a/-g
- The sample data is signed linear (2's comple-
- ment), unsigned linear, U-law (logarithmic), A-
- law (logarithmic), ADPCM, or GSM. U-law and A-
- law are the U.S. and international standards for
- logarithmic telephone sound compression. ADPCM
- is form of sound compression that has a good
- compromise between good sound quality and fast
- encoding/decoding time. GSM is a standard used
- for telephone sound compression in European
- countries and its gaining popularity because of
- its quality.
+ -s/-u/-U/-A/-a/-g
+ The sample data is signed linear (2's complement),
+ unsigned linear, U-law (logarithmic), A-law (loga-
+ rithmic), ADPCM, or GSM. U-law and A-law are the
+ U.S. and international standards for logarithmic
+ telephone sound compression. ADPCM is form of
+ sound compression that has a good compromise
+ between good sound quality and fast
+ encoding/decoding time. GSM is a standard used
+ for telephone sound compression in European coun-
+ tries and its gaining popularity because of its
+ quality.
- -b/-w/-l/-f/-d/-D
- The sample data is in bytes, 16-bit words,
- 32-bit longwords, 32-bit floats, 64-bit double
- floats, or 80-bit IEEE floats. Floats and dou-
- ble floats are in native machine format.
+ -b/-w/-l/-f/-d/-D
+ The sample data is in bytes, 16-bit words, 32-bit
+ longwords, 32-bit floats, 64-bit double floats, or
+ 80-bit IEEE floats. Floats and double floats are
+ in native machine format.
- -x The sample data is in XINU format; that is, it
- comes from a machine with the opposite word
- June 28, 1999 2
+SunOS 5.6 Last change: November 8, 1999 2
-SoX(1) SoX(1)
+User Commands SoX(1)
- order than yours and must be swapped according
- to the word-size given above. Only 16-bit and
- 32-bit integer data may be swapped. Machine-
- format floating-point data is not portable.
- IEEE floats are a fixed, portable format.
- -c channels
- The number of sound channels in the data file.
- This may be 1, 2, or 4; for mono, stereo, or
- quad sound data. To cause the output file to
- have a different number of channels then the
- input file, include this option with the appro-
- raite value with the output file options. If
- the input and output file have a different num-
- ber of channels then the avg effect must be
- used. If the avg effect is not specified on the
- command line it will be invoked with default
- parameters.
- General options:
+ -x The sample data is in XINU format; that is, it
+ comes from a machine with the opposite word order
+ than yours and must be swapped according to the
+ word-size given above. Only 16-bit and 32-bit
+ integer data may be swapped. Machine-format
+ floating-point data is not portable. IEEE floats
+ are a fixed, portable format.
- -e after the input file allows you to avoid giving
- an output file and just name an effect. This is
- mainly useful with the stat effect but can be
- used with others.
+ -c channels
+ The number of sound channels in the data file.
+ This may be 1, 2, or 4; for mono, stereo, or quad
+ sound data. To cause the output file to have a
+ different number of channels then the input file,
+ include this option with the approraite value with
+ the output file options. If the input and output
+ file have a different number of channels then the
+ avg effect must be used. If the avg effect is not
+ specified on the command line it will be invoked
+ with default parameters.
- -h Print version number and usage information.
+ General options:
- -p Run in preview mode and run fast. This will
- somewhat speed up sox when the output format has
- a different number of channels and a different
- rate then the input file. The order that the
- effects are run in will be arranged for maximum
- speed and not quality.
+ -e after the input file allows you to avoid giving an
+ output file and just name an effect. This is
+ mainly useful with the stat effect but can be used
+ with others.
- -v volume Change amplitude (floating point); less than 1.0
- decreases, greater than 1.0 increases. Note: we
- perceive volume logarithmically, not linearly.
- Note: see the stat effect.
+ -h Print version number and usage information.
- -V Print a description of processing phases. Use-
- ful for figuring out exactly how sox is mangling
- your sound samples.
+ -p Run in preview mode and run fast. This will some-
+ what speed up sox when the output format has a
+ different number of channels and a different rate
+ then the input file. The order that the effects
+ are run in will be arranged for maximum speed and
+ not quality.
- The input and output files may be standard input and out-
- put. This is specified by '-'. The -t type option must
- be given in this case, else sox will not know the format
- of the given file. The -t, -r, -s/-u/-U/-A,
- -b/-w/-l/-f/-d/-D and -x options refer to the input data
- when given before the input file name. After, they refer
- to the output data.
+ -v volume Change amplitude (floating point); less than 1.0
+ decreases, greater than 1.0 increases. Note: we
+ perceive volume logarithmically, not linearly.
+ Note: see the stat effect.
- If you don't give an output file name, sox will just read
- the input file. This is useful for validating structured
+ -V Print a description of processing phases. Useful
+ for figuring out exactly how sox is mangling your
+ sound samples.
+ The input and output files may be standard input and output.
+ This is specified by '-'. The -t type option must be given
+ in this case, else sox will not know the format of the given
+ file. The -t, -r, -s/-u/-U/-A, -b/-w/-l/-f/-d/-D and -x
+ options refer to the input data when given before the input
+ file name. After, they refer to the output data.
- June 28, 1999 3
+SunOS 5.6 Last change: November 8, 1999 3
-SoX(1) SoX(1)
- file formats; the stat effect may also be used via the -e
- option.
+User Commands SoX(1)
+
+
+
+ If you don't give an output file name, sox will just read
+ the input file. This is useful for validating structured
+ file formats; the stat effect may also be used via the -e
+ option.
+
FILE TYPES
- Sox needs to know the formats of the input and output
- files. File formats which have headers are checked, if
- that header doesn't seem right, the program exits with an
- appropriate message. Currently, raw (no header) binary
- and textual data, Amiga 8SVX, Apple/SGI AIFF, SPARC .AU
- (w/header), AVR, NeXT .SND, CD-R, CVSD, GSM 06.10, Mac
- HCOM, Sound Tools MAUD, OSS device drivers, Turtle Beach
- .SMP, Sound Blaster, Sndtool, and Sounder, Sun Audio
- device driver, Yamaha TX-16W Sampler, IRCAM Sound Files,
- Creative Labs VOC, Psion .WVE, and Microsoft RIFF/WAV are
- supported.
+ Sox needs to know the formats of the input and output files.
+ File formats which have headers are checked, if that header
+ doesn't seem right, the program exits with an appropriate
+ message. Currently, raw (no header) binary and textual
+ data, Amiga 8SVX, Apple/SGI AIFF, SPARC .AU (w/header), AVR,
+ NeXT .SND, CD-R, CVSD, GSM 06.10, Mac HCOM, Sound Tools
+ MAUD, OSS device drivers, Turtle Beach .SMP, Sound Blaster,
+ Sndtool, and Sounder, Sun Audio device driver, Yamaha TX-16W
+ Sampler, IRCAM Sound Files, Creative Labs VOC, Psion .WVE,
+ and Microsoft RIFF/WAV are supported.
+ .8svx Amiga 8SVX musical instrument description format.
- .8svx Amiga 8SVX musical instrument description for-
- mat.
+ .aiff AIFF files used on Apple IIc/IIgs and SGI. Note:
+ the AIFF format supports only one SSND chunk. It
+ does not support multiple sound chunks, or the
+ 8SVX musical instrument description format. AIFF
+ files are multimedia archives and and can have
+ multiple audio and picture chunks. You may need a
+ separate archiver to work with them.
- .aiff AIFF files used on Apple IIc/IIgs and SGI.
- Note: the AIFF format supports only one SSND
- chunk. It does not support multiple sound
- chunks, or the 8SVX musical instrument descrip-
- tion format. AIFF files are multimedia archives
- and and can have multiple audio and picture
- chunks. You may need a separate archiver to
- work with them.
+ .au SUN Microsystems AU files. There are apparently
+ many types of .au files; DEC has invented its own
+ with a different magic number and word order. The
+ .au handler can read these files but will not
+ write them. Some .au files have valid AU headers
+ and some do not. The latter are probably original
+ SUN u-law 8000 hz samples. These can be dealt
+ with using the .ul format (see below).
- .au SUN Microsystems AU files. There are apparently
- many types of .au files; DEC has invented its
- own with a different magic number and word
- order. The .au handler can read these files but
- will not write them. Some .au files have valid
- AU headers and some do not. The latter are
- probably original SUN u-law 8000 hz samples.
- These can be dealt with using the .ul format
- (see below).
+ .avr Audio Visual Research
+ The AVR format is produced by a number of commer-
+ cial packages on the Mac.
- .avr Audio Visual Research
- The AVR format is produced by a number of com-
- mercial packages on the Mac.
+ .cdr CD-R
+ CD-R files are used in mastering music Compact
+ Disks. The file format is, as you might expect,
+ raw stereo raw unsigned samples at 44khz. But,
+ there's some blocking/padding oddity in the for-
+ mat, so it needs its own handler.
- .cdr CD-R
- CD-R files are used in mastering music Compact
- Disks. The file format is, as you might expect,
- raw stereo raw unsigned samples at 44khz. But,
- there's some blocking/padding oddity in the for-
- mat, so it needs its own handler.
+ .cvs Continuously Variable Slope Delta modulation
+ Used to compress speech audio for applications
+ such as voice mail.
- .cvs Continuously Variable Slope Delta modulation
- Used to compress speech audio for applications
- such as voice mail.
+ .dat Text Data files
+SunOS 5.6 Last change: November 8, 1999 4
- June 28, 1999 4
-SoX(1) SoX(1)
+User Commands SoX(1)
- .dat Text Data files
- These files contain a textual representation of
- the sample data. There is one line at the
- beginning that contains the sample rate. Subse-
- quent lines contain two numeric data items: the
- time since the beginning of the sample and the
- sample value. Values are normalized so that the
- maximum and minimum are 1.00 and -1.00. This
- file format can be used to create data files for
- external programs such as FFT analyzers or graph
- routines. SoX can also convert a file in this
- format back into one of the other file formats.
- .gsm GSM 06.10 Lossy Speech Compression
- A standard for compressing speech which is used
- in the Global Standard for Mobil telecommunica-
- tions (GSM). Its good for its purpose, shrink-
- ing audio data size, but it will introduce lots
- of noise when a given sound sample is encoded
- and decoded multiple times. This format is used
- by some voice mail applications. It is rather
- CPU intensive. GSM in sox is optional and
- requires access to an external GSM library. To
- see if there is support for gsm run sox -h and
- look for it under the list of supported file
- formats.
+ These files contain a textual representation of
+ the sample data. There is one line at the begin-
+ ning that contains the sample rate. Subsequent
+ lines contain two numeric data items: the time
+ since the beginning of the sample and the sample
+ value. Values are normalized so that the maximum
+ and minimum are 1.00 and -1.00. This file format
+ can be used to create data files for external pro-
+ grams such as FFT analyzers or graph routines.
+ SoX can also convert a file in this format back
+ into one of the other file formats.
- .hcom Macintosh HCOM files. These are (apparently)
- Mac FSSD files with some variant of Huffman com-
- pression. The Macintosh has wacky file formats
- and this format handler apparently doesn't han-
- dle all the ones it should. Mac users will need
- your usual arsenal of file converters to deal
- with an HCOM file under Unix or DOS.
+ .gsm GSM 06.10 Lossy Speech Compression
+ A standard for compressing speech which is used in
+ the Global Standard for Mobil telecommunications
+ (GSM). Its good for its purpose, shrinking audio
+ data size, but it will introduce lots of noise
+ when a given sound sample is encoded and decoded
+ multiple times. This format is used by some voice
+ mail applications. It is rather CPU intensive.
+ GSM in sox is optional and requires access to an
+ external GSM library. To see if there is support
+ for gsm run sox -h and look for it under the list
+ of supported file formats.
- .maud An Amiga format
- An IFF-conform sound file type, registered by MS
- MacroSystem Computer GmbH, published along with
- the "Toccata" sound-card on the Amiga. Allows
- 8bit linear, 16bit linear, A-Law, u-law in mono
- and stereo.
+ .hcom Macintosh HCOM files. These are (apparently) Mac
+ FSSD files with some variant of Huffman compres-
+ sion. The Macintosh has wacky file formats and
+ this format handler apparently doesn't handle all
+ the ones it should. Mac users will need your
+ usual arsenal of file converters to deal with an
+ HCOM file under Unix or DOS.
- ossdsp OSS /dev/dsp device driver
- This is a psuedo-file type and can be optionally
- compiled into Sox. Run sox -h to see if you
- have support for this file type. When this
- driver is used it allows you to open up the OSS
- /dev/dsp file and configure it to use the same
- data type as passed in to Sox. It works for
- both playing and recording sound samples. When
- playing sound files it attempts to set up the
- OSS driver to use the same format as the input
- file. It is suggested to always override the
- output values to use the highest quality samples
+ .maud An Amiga format
+ An IFF-conform sound file type, registered by MS
+ MacroSystem Computer GmbH, published along with
+ the "Toccata" sound-card on the Amiga. Allows
+ 8bit linear, 16bit linear, A-Law, u-law in mono
+ and stereo.
+ ossdsp OSS /dev/dsp device driver
+ This is a psuedo-file type and can be optionally
+ compiled into Sox. Run sox -h to see if you have
+ support for this file type. When this driver is
+ used it allows you to open up the OSS /dev/dsp
+ file and configure it to use the same data type as
+ passed in to Sox. It works for both playing and
+ recording sound samples. When playing sound files
+ it attempts to set up the OSS driver to use the
+ same format as the input file. It is suggested to
+ always override the output values to use the
+ highest quality samples your sound card can
- June 28, 1999 5
+SunOS 5.6 Last change: November 8, 1999 5
-SoX(1) SoX(1)
- your sound card can handle. Example: -t ossdsp
- -w -s /dev/dsp
+User Commands SoX(1)
- .sf IRCAM Sound Files.
- SoundFiles are used by academic music software
- such as the CSound package, and the MixView
- sound sample editor.
- .smp Turtle Beach SampleVision files.
- SMP files are for use with the PC-DOS package
- SampleVision by Turtle Beach Softworks. This
- package is for communication to several MIDI
- samplers. All sample rates are supported by the
- package, although not all are supported by the
- samplers themselves. Currently loop points are
- ignored.
- sunau Sun /dev/audio device driver
- This is a psuedo-file type and can be optionally
- compiled into Sox. Run sox -h to see if you
- have support for this file type. When this
- driver is used it allows you to open up a Sun
- /dev/audio file and configure it to use the same
- data type as passed in to Sox. It works for
- both playing and recording sound samples. When
- playing sound files it attempts to set up the
- audio driver to use the same format as the input
- file. It is suggested to always override the
- output values to use the highest quality samples
- your hardware can handle. Example: -t sunau -w
- -s /dev/audio or -t sunau -U -c 1 /dev/audio for
- older sun equipment.
+ handle. Example: -t ossdsp -w -s /dev/dsp
+
+ .sf IRCAM Sound Files.
+ SoundFiles are used by academic music software
+ such as the CSound package, and the MixView sound
+ sample editor.
+
+ .smp Turtle Beach SampleVision files.
+ SMP files are for use with the PC-DOS package Sam-
+ pleVision by Turtle Beach Softworks. This package
+ is for communication to several MIDI samplers. All
+ sample rates are supported by the package,
+ although not all are supported by the samplers
+ themselves. Currently loop points are ignored.
- .txw Yamaha TX-16W sampler.
- A file format from a Yamaha sampling keyboard
- which wrote IBM-PC format 3.5" floppies. Han-
- dles reading of files which do not have the sam-
- ple rate field set to one of the expected by
- looking at some other bytes in the attack/loop
- length fields, and defaulting to 33kHz if the
- sample rate is still unknown.
+ sunau Sun /dev/audio device driver
+ This is a psuedo-file type and can be optionally
+ compiled into Sox. Run sox -h to see if you have
+ support for this file type. When this driver is
+ used it allows you to open up a Sun /dev/audio
+ file and configure it to use the same data type as
+ passed in to Sox. It works for both playing and
+ recording sound samples. When playing sound files
+ it attempts to set up the audio driver to use the
+ same format as the input file. It is suggested to
+ always override the output values to use the
+ highest quality samples your hardware can handle.
+ Example: -t sunau -w -s /dev/audio or -t sunau -U
+ -c 1 /dev/audio for older sun equipment.
- .vms More info to come.
- Used to compress speech audio for applications
- such as voice mail.
+ .txw Yamaha TX-16W sampler.
+ A file format from a Yamaha sampling keyboard
+ which wrote IBM-PC format 3.5" floppies. Handles
+ reading of files which do not have the sample rate
+ field set to one of the expected by looking at
+ some other bytes in the attack/loop length fields,
+ and defaulting to 33kHz if the sample rate is
+ still unknown.
- .voc Sound Blaster VOC files.
- VOC files are multi-part and contain silence
- parts, looping, and different sample rates for
- different chunks. On input, the silence parts
- are filled out, loops are rejected, and sample
- data with a new sample rate is rejected.
- Silence with a different sample rate is gener-
- ated appropriately. On output, silence is not
+ .vms More info to come.
+ Used to compress speech audio for applications
+ such as voice mail.
+ .voc Sound Blaster VOC files.
+ VOC files are multi-part and contain silence
+ parts, looping, and different sample rates for
+ different chunks. On input, the silence parts are
+ filled out, loops are rejected, and sample data
+ with a new sample rate is rejected. Silence with
+ a different sample rate is generated appropri-
+ ately. On output, silence is not detected, nor
+ are impossible sample rates.
- June 28, 1999 6
+SunOS 5.6 Last change: November 8, 1999 6
-SoX(1) SoX(1)
- detected, nor are impossible sample rates.
+User Commands SoX(1)
- .wav Microsoft .WAV RIFF files.
- These appear to be very similar to IFF files,
- but not the same. They are the native sound
- file format of Windows. (Obviously, Windows was
- of such incredible importance to the computer
- industry that it just had to have its own sound
- file format.) Normally .wav files have all for-
- matting information in their headers, and so do
- not need any format options specified for an
- input file. If any are, they will override the
- file header, and you will be warned to this
- effect. You had better know what you are doing!
- Output format options will cause a format con-
- version, and the .wav will written appropri-
- ately. Note that it is possible to write data
- of a type that cannot be specified by the .wav
- header, and you will be warned that you a writ-
- ing a bad file ! Sox currently can read PCM,
- ULAW, ALAW, MS ADPCM, and IMA (or DVI) ADPCM.
- It can output all of these formats except the
- ADPCM styles.
- .wve Psion 8-bit alaw
- These are 8-bit a-law 8khz sound files used on
- the Psion palmtop portable computer.
- .raw Raw files (no header).
- The sample rate, size (byte, word, etc), and
- style (signed, unsigned, etc.) of the sample
- file must be given. The number of channels
- defaults to 1.
+ .wav Microsoft .WAV RIFF files.
+ These appear to be very similar to IFF files, but
+ not the same. They are the native sound file for-
+ mat of Windows. (Obviously, Windows was of such
+ incredible importance to the computer industry
+ that it just had to have its own sound file for-
+ mat.) Normally .wav files have all formatting
+ information in their headers, and so do not need
+ any format options specified for an input file. If
+ any are, they will override the file header, and
+ you will be warned to this effect. You had better
+ know what you are doing! Output format options
+ will cause a format conversion, and the .wav will
+ written appropriately. Note that it is possible
+ to write data of a type that cannot be specified
+ by the .wav header, and you will be warned that
+ you a writing a bad file ! Sox currently can read
+ PCM, ULAW, ALAW, MS ADPCM, and IMA (or DVI) ADPCM.
+ It can output all of these formats except the
+ ADPCM styles.
- .ub, .sb, .uw, .sw, .ul
- These are several suffices which serve as a
- shorthand for raw files with a given size and
- style. Thus, ub, sb, uw, sw, and ul correspond
- to "unsigned byte", "signed byte", "unsigned
- word", "signed word", and "ulaw" (byte). The
- sample rate defaults to 8000 hz if not explic-
- itly set, and the number of channels (as always)
- defaults to 1. There are lots of Sparc samples
- floating around in u-law format with no header
- and fixed at a sample rate of 8000 hz. (Certain
- sound management software cheerfully ignores the
- headers.) Similarly, most Mac sound files are
- in unsigned byte format with a sample rate of
- 11025 or 22050 hz.
+ .wve Psion 8-bit alaw
+ These are 8-bit a-law 8khz sound files used on the
+ Psion palmtop portable computer.
- .auto This is a ``meta-type'': specifying this type
- for an input file triggers some code that tries
- to guess the real type by looking for magic
- words in the header. If the type can't be
+ .raw Raw files (no header).
+ The sample rate, size (byte, word, etc), and style
+ (signed, unsigned, etc.) of the sample file must
+ be given. The number of channels defaults to 1.
+ .ub, .sb, .uw, .sw, .ul
+ These are several suffices which serve as a short-
+ hand for raw files with a given size and style.
+ Thus, ub, sb, uw, sw, and ul correspond to
+ "unsigned byte", "signed byte", "unsigned word",
+ "signed word", and "ulaw" (byte). The sample rate
+ defaults to 8000 hz if not explicitly set, and the
+ number of channels (as always) defaults to 1.
+ There are lots of Sparc samples floating around in
+ u-law format with no header and fixed at a sample
+ rate of 8000 hz. (Certain sound management
+ software cheerfully ignores the headers.) Simi-
+ larly, most Mac sound files are in unsigned byte
+ format with a sample rate of 11025 or 22050 hz.
+ .auto This is a ``meta-type'': specifying this type for
+ an input file triggers some code that tries to
+ guess the real type by looking for magic words in
+ the header. If the type can't be guessed, the
+ program exits with an error message. The input
+ must be a plain file, not a pipe. This type can't
+ be used for output files.
- June 28, 1999 7
+SunOS 5.6 Last change: November 8, 1999 7
-SoX(1) SoX(1)
- guessed, the program exits with an error mes-
- sage. The input must be a plain file, not a
- pipe. This type can't be used for output files.
+User Commands SoX(1)
+
+
+
EFFECTS
- Only one effect from the palette may be applied to a sound
- sample. To do multiple effects you'll need to run sox in
- a pipeline.
+ Only one effect from the palette may be applied to a sound
+ sample. To do multiple effects you'll need to run sox in a
+ pipeline.
- avg [ -l | -r ]
- Reduce the number of channels by averaging the
- samples, or duplicate channels to increase the
- number of channels. This effect is automati-
- cally used when the number of input samples dif-
- fer then the number of output channels. When
- reducing the number of channels it is possible
- to manually specify the avg effect and use the
- -l and -r options to select only the left or
- right channel for the output instead of averag-
- ing the two channels.
+ avg [ -l | -r ]
+ Reduce the number of channels by averaging the
+ samples, or duplicate channels to increase the
+ number of channels. This effect is automatically
+ used when the number of input samples differ then
+ the number of output channels. When reducing the
+ number of channels it is possible to manually
+ specify the avg effect and use the -l and -r
+ options to select only the left or right channel
+ for the output instead of averaging the two chan-
+ nels.
- band [ -n ] center [ width ]
- Apply a band-pass filter. The frequency
- response drops logarithmically around the center
- frequency. The width gives the slope of the
- drop. The frequencies at center + width and
- center - width will be half of their original
- amplitudes. Band defaults to a mode oriented to
- pitched signals, i.e. voice, singing, or instru-
- mental music. The -n (for noise) option uses
- the alternate mode for un-pitched signals. Band
- introduces noise in the shape of the filter,
- i.e. peaking at the center frequency and set-
- tling around it.
+ band [ -n ] center [ width ]
+ Apply a band-pass filter. The frequency response
+ drops logarithmically around the center frequency.
+ The width gives the slope of the drop. The fre-
+ quencies at center + width and center - width will
+ be half of their original amplitudes. Band
+ defaults to a mode oriented to pitched signals,
+ i.e. voice, singing, or instrumental music. The
+ -n (for noise) option uses the alternate mode for
+ un-pitched signals. Warning: -n introduces a
+ power-gain of about 11dB in the filter, so beware
+ of output clipping. Band introduces noise in the
+ shape of the filter, i.e. peaking at the center
+ frequency and settling around it. See filter for
+ a bandpass effect with steeper shoulders.
- chorus gain-in gain-out delay decay speed deptch
+ chorus gain-in gain-out delay decay speed deptch
- -s | -t [ delay decay speed depth -s | -t ... ]
- Add a chorus to a sound sample. Each quadtuple
- delay/decay/speed/depth gives the delay in mil-
- liseconds and the decay (relative to gain-in)
- with a modulation speed in Hz using depth in
- milliseconds. The modulation is either sinodial
- (-s) or triangular (-t). Gain-out is the volume
- of the output.
+ -s | -t [ delay decay speed depth -s | -t ... ]
+ Add a chorus to a sound sample. Each quadtuple
+ delay/decay/speed/depth gives the delay in mil-
+ liseconds and the decay (relative to gain-in) with
+ a modulation speed in Hz using depth in mil-
+ liseconds. The modulation is either sinodial (-s)
+ or triangular (-t). Gain-out is the volume of the
+ output.
- compand attack1,decay1[,attack2,decay2...]
+ compand attack1,decay1[,attack2,decay2...]
- in-dB1,out-dB1[,in-dB2,out-dB2...]
+ in-dB1,out-dB1[,in-dB2,out-dB2...]
- [gain] [initial-volume]
- Compand (compress or expand) the dynamic range
- of a sample. The attack and decay time specify
- the integration time over which the absolute
+ [gain] [initial-volume]
+ Compand (compress or expand) the dynamic range of
+ a sample. The attack and decay time specify the
+ integration time over which the absolute value of
- June 28, 1999 8
+SunOS 5.6 Last change: November 8, 1999 8
-SoX(1) SoX(1)
+User Commands SoX(1)
- value of the input signal is integrated to
- determine its volume. Where more than one pair
- of attack/decay parameters are specified, each
- channel is treated separately and the number of
- pairs must agree with the number of input chan-
- nels. The second parameter is a list of points
- on the compander's transfer function specified
- in dB relative to the maximum possible signal
- amplitude. The input values must be in a
- strictly increasing order but the transfer func-
- tion does not have to be monotonically rising.
- The special value -inf may be used to indicate
- that the input volume should be associated out-
- put volume. The points -inf,-inf and 0,0 are
- assumed; the latter may be overridden, but the
- former may not. The third (optional) parameter
- is a postprocessing gain in dB which is applied
- after the compression has taken place; the
- fourth (optional) parameter is an initial volume
- to be assumed for each channel when the effect
- starts. This permits the user to supply a nomi-
- nal level initially, so that, for example, a
- very large gain is not applied to initial signal
- levels before the companding action has begun to
- operate: it is quite probable that in such an
- event, the output would be severely clipped
- while the compander gain properly adjusts
- itself.
- copy Copy the input file to the output file. This is
- the default effect if both files have the same
- sampling rate.
- cut loopnumber
- Extract loop #N from a sample.
+ the input signal is integrated to determine its
+ volume. Where more than one pair of attack/decay
+ parameters are specified, each channel is treated
+ separately and the number of pairs must agree with
+ the number of input channels. The second parame-
+ ter is a list of points on the compander's
+ transfer function specified in dB relative to the
+ maximum possible signal amplitude. The input
+ values must be in a strictly increasing order but
+ the transfer function does not have to be monoton-
+ ically rising. The special value -inf may be used
+ to indicate that the input volume should be asso-
+ ciated output volume. The points -inf,-inf and
+ 0,0 are assumed; the latter may be overridden, but
+ the former may not. The third (optional) parame-
+ ter is a postprocessing gain in dB which is
+ applied after the compression has taken place; the
+ fourth (optional) parameter is an initial volume
+ to be assumed for each channel when the effect
+ starts. This permits the user to supply a nominal
+ level initially, so that, for example, a very
+ large gain is not applied to initial signal levels
+ before the companding action has begun to operate:
+ it is quite probable that in such an event, the
+ output would be severely clipped while the com-
+ pander gain properly adjusts itself.
- deemph Apply a treble attenuation shelving filter to
- samples in audio cd format. The frequency
- response of pre-emphasized recordings is recti-
- fied. The filtering is defined in the standard
- document ISO 908.
+ copy Copy the input file to the output file. This is
+ the default effect if both files have the same
+ sampling rate.
- echo gain-in gain-out delay decay [ delay decay ... ]
- Add echoing to a sound sample. Each delay/decay
- part gives the delay in milliseconds and the
- decay (relative to gain-in) of that echo. Gain-
- out is the volume of the output.
+ cut loopnumber
+ Extract loop #N from a sample.
- echos gain-in gain-out delay decay [ delay decay ... ]
- Add a sequence of echos to a sound sample. Each
- delay/decay part gives the delay in milliseconds
- and the decay (relative to gain-in) of that
- echo. Gain-out is the volume of the output.
+ deemph Apply a treble attenuation shelving filter to sam-
+ ples in audio cd format. The frequency response
+ of pre-emphasized recordings is rectified. The
+ filtering is defined in the standard document ISO
+ 908.
+ echo gain-in gain-out delay decay [ delay decay ... ]
+ Add echoing to a sound sample. Each delay/decay
+ part gives the delay in milliseconds and the decay
+ (relative to gain-in) of that echo. Gain-out is
+ the volume of the output.
+ echos gain-in gain-out delay decay [ delay decay ... ]
+ Add a sequence of echos to a sound sample. Each
+ delay/decay part gives the delay in milliseconds
+ and the decay (relative to gain-in) of that echo.
+ Gain-out is the volume of the output.
- June 28, 1999 9
+SunOS 5.6 Last change: November 8, 1999 9
-SoX(1) SoX(1)
- flanger gain-in gain-out delay decay speed -s | -t
- Add a flanger to a sound sample. Each triple
- delay/decay/speed gives the delay in millisec-
- onds and the decay (relative to gain-in) with a
- modulation speed in Hz. The modulation is
- either sinodial (-s) or triangular (-t). Gain-
- out is the volume of the output.
- highp center
- Apply a high-pass filter. The frequency
- response drops logarithmically with center fre-
- quency in the middle of the drop. The slope of
- the filter is quite gentle.
+User Commands SoX(1)
- lowp center
- Apply a low-pass filter. The frequency response
- drops logarithmically with center frequency in
- the middle of the drop. The slope of the filter
- is quite gentle.
- map Display a list of loops in a sample, and miscel-
- laneous loop info.
- mask Add "masking noise" to signal. This effect
- deliberately adds white noise to a sound in
- order to mask quantization effects, created by
- the process of playing a sound digitally. It
- tends to mask buzzing voices, for example. It
- adds 1/2 bit of noise to the sound file at the
- output bit depth.
+ filter [ low ]-[ high ] [ window-len [ beta ] ]
+ Apply a Sinc-windowed lowpass, highpass, or
+ bandpass filter of given window length to the sig-
+ nal. low refers to the frequency of the lower 6dB
+ corner of the filter. high refers to the fre-
+ quency of the upper 6dB corner of the filter.
- phaser gain-in gain-out delay decay speed -s | -t
- Add a phaser to a sound sample. Each triple
- delay/decay/speed gives the delay in millisec-
- onds and the decay (relative to gain-in) with a
- modulation speed in Hz. The modulation is
- either sinodial (-s) or triangular (-t). The
- decay should be less than 0.5 to avoid feedback.
- Gain-out is the volume of the output.
+ A lowpass filter is obtained by leaving low
+ unspecified, or 0. A highpass filter is obtained
+ by leaving high unspecified, or 0, or greater than
+ or equal to the Nyquist freq.
- pick Select the left or right channel of a stereo
- sample, or one of four channels in a quadro-
- phonic sample.
+ The window-len, if unspecified, defaults to 128.
+ Longer windows give a sharper cutoff, smaller win-
+ dows a more gradual cutoff.
- polyphase [ -w < num / ham > ]
+ The beta, if unspecified, defaults to 16. This
+ selects a Kaiser window. You can select a Nuttall
+ window by specifying anything <= 2.0 here. For
+ more discussion of beta, look under the resample
+ effect.
- [ -width < long / short / # > ]
- [ -cutoff # ]
- Translate input sampling rate to output sampling
- rate via polyphase interpolation, a DSP algo-
- rithm. This method is slow and uses lots of
- RAM, but gives much better results then rate.
- -w < nut / ham > : select either a Nuttal (~90
+ flanger gain-in gain-out delay decay speed -s | -t
+ Add a flanger to a sound sample. Each triple
+ delay/decay/speed gives the delay in milliseconds
+ and the decay (relative to gain-in) with a modula-
+ tion speed in Hz. The modulation is either sino-
+ dial (-s) or triangular (-t). Gain-out is the
+ volume of the output.
+ highp center
+ Apply a high-pass filter. The frequency response
+ drops logarithmically with center frequency in the
+ middle of the drop. The slope of the filter is
+ quite gentle. See filter for a highpass effect
+ with sharper cutoff.
+ lowp center
+ Apply a low-pass filter. The frequency response
+ drops logarithmically with center frequency in the
+ middle of the drop. The slope of the filter is
+ quite gentle. See filter for a lowpass effect
+ with sharper cutoff.
- June 28, 1999 10
+ map Display a list of loops in a sample, and miscel-
+ laneous loop info.
+ mask Add "masking noise" to signal. This effect deli-
+ berately adds white noise to a sound in order to
+ mask quantization effects, created by the process
+ of playing a sound digitally. It tends to mask
+SunOS 5.6 Last change: November 8, 1999 10
-SoX(1) SoX(1)
- dB stopband) or Hamming (~43 dB stopband) win-
- dow. Warning: Nuttall windows require 2x length
- than Hamming windows. Default is nut.
- -width long / short / # : specify the width of
- the filter. long is 1024 samples; short is 128
- samples. Alternatively, an exact number can be
- used. Default is long.
- -cutoff # : specify the filter cutoff frequency
- in terms of fraction of bandwidth. If upsam-
- pling, then this is the fraction of the orignal
- signal that should go through. If downsampling,
- this is the fraction of the signal left after
- downsampling. Default is 0.95. Remember that
- this is a float.
- rate Translate input sampling rate to output sampling
- rate via linear interpolation to the Least Com-
- mon Multiple of the two sampling rates. This is
- the default effect if the two files have differ-
- ent sampling rates and the preview options was
- specified. This is fast but noisy: the spectrum
- of the original sound will be shifted upwards
- and duplicated faintly when up-translating by a
- multiple. Lerp-ing is acceptable for cheap
- 8-bit sound hardware, but for CD-quality sound
- you should instead use either resample or
- polyphase. If you are wondering which of Sox's
- rate changing effects to ues, you will want to
- read a detailed analysis of all of them at
- http://eakaw2.et.tu-dresden.de/~andreas/resam-
- ple/resample.html
- resample [ rolloff [ beta ] ]
- Translate input sampling rate to output sampling
- rate via simulated analog filtration. This
- method is slower than rate, but gives much bet-
- ter results. rolloff refers to the cut-off fre-
- quency of the low pass filter and is given in
- terms of the Nyquist frequency for the lower
- sample rate. rolloff therefor should be some-
- thing between 0. and 1., in practice 0.8-0.95.
- beta trades stop band rejection against transi-
- tion width from passband to stop band. Larger
- beta means a slower transition and greater stop-
- band rejection. beta should be at least greater
- than 2. The default is rollof 0.8, beta 17.5,
- which is rather conservative with respect to
- aliasing. Lower beta and higher rolloff values
- preserve more high frequency signal energy, but
- introduce measurable artifacts. This is the
- default effect if the two files have different
- sampling rates.
+User Commands SoX(1)
+ buzzing voices, for example. It adds 1/2 bit of
+ noise to the sound file at the output bit depth.
- June 28, 1999 11
+ phaser gain-in gain-out delay decay speed -s | -t
+ Add a phaser to a sound sample. Each triple
+ delay/decay/speed gives the delay in milliseconds
+ and the decay (relative to gain-in) with a modula-
+ tion speed in Hz. The modulation is either sino-
+ dial (-s) or triangular (-t). The decay should be
+ less than 0.5 to avoid feedback. Gain-out is the
+ volume of the output.
+ pick Select the left or right channel of a stereo sam-
+ ple, or one of four channels in a quadrophonic
+ sample.
+ polyphase [ -w < num / ham > ]
+ [ -width < long / short / # > ]
+ [ -cutoff # ]
+ Translate input sampling rate to output sampling
+ rate via polyphase interpolation, a DSP algorithm.
+ This method is slow and uses lots of RAM, but
+ gives much better results then rate.
+ -w < nut / ham > : select either a Nuttal (~90 dB
+ stopband) or Hamming (~43 dB stopband) window.
+ Warning: Nuttall windows require 2x length than
+ Hamming windows. Default is nut.
+ -width long / short / # : specify the width of the
+ filter. long is 1024 samples; short is 128 sam-
+ ples. Alternatively, an exact number can be used.
+ Default is long.
+ -cutoff # : specify the filter cutoff frequency in
+ terms of fraction of bandwidth. If upsampling,
+ then this is the fraction of the orignal signal
+ that should go through. If downsampling, this is
+ the fraction of the signal left after downsam-
+ pling. Default is 0.95. Remember that this is a
+ float.
-SoX(1) SoX(1)
+ rate Translate input sampling rate to output sampling
+ rate via linear interpolation to the Least Common
+ Multiple of the two sampling rates. This is the
+ default effect if the two files have different
+ sampling rates and the preview options was speci-
+ fied. This is fast but noisy: the spectrum of
+ the original sound will be shifted upwards and
+ duplicated faintly when up-translating by a multi-
+ ple. Lerp-ing is acceptable for cheap 8-bit sound
+ hardware, but for CD-quality sound you should
- reverb gain-out delay [ delay ... ]
- Add reverbation to a sound sample. Each delay
- is given in milliseconds and its feedback is
- depending on the reverb-time in milliseconds.
- Each delay should be in the range of half to
- quarter of reverb-time to get a realistic rever-
- bation. Gain-out is the volume of the output.
- reverse Reverse the sound sample completely. Included
- for finding Satanic subliminals.
- split Turn a mono sample into a stereo sample by copy-
- ing the input channel to the left and right
- channels.
+SunOS 5.6 Last change: November 8, 1999 11
- stat [ debug | -v ]
- Do a statistical check on the input file, and
- print results on the standard error file. stat
- may copy the file untouched from input to out-
- put, if you select an output file. The "Volume
- Adjustment:" field in the statistics gives you
- the argument to the -v number which will make
- the sample as loud as possible without clipping.
- There is an optional parameter -v that will
- print out the "Volume Adjustment:" field's value
- and return. This could be of use in scripts to
- auto convert the volume. There is an also an
- optional parameter debug that will place sox
- into debug mode and print out a hex dump of the
- sound file from the internal buffer that is in
- 32-bit signed PCM data. This is mainly only of
- use in tracking down endian problems that creep
- in to sox on cross-platform versions.
- swap [ 1 2 3 4 ]
- Swap channels in multi-channel sound files. In
- files with more than 2 channels you may specify
- the order that the channels should be rearranged
- in.
- vibro speed [ depth ]
- Add the world-famous Fender Vibro-Champ sound
- effect to a sound sample by using a sine wave as
- the volume knob. Speed gives the Hertz value of
- the wave. This must be under 30. Depth gives
- the amount the volume is cut into by the sine
- wave, ranging 0.0 to 1.0 and defaulting to 0.5.
- Sox enforces certain effects. If the two files have dif-
- ferent sampling rates, the requested effect must be one of
- copy, or rate, If the two files have different numbers of
- channels, the avg effect must be requested.
+User Commands SoX(1)
- June 28, 1999 12
+ instead use either resample or polyphase. If you
+ are wondering which of Sox's rate changing effects
+ to ues, you will want to read a detailed analysis
+ of all of them at http://eakaw2.et.tu-
+ dresden.de/~andreas/resample/resample.html
+ [Nov,1999: These tests need to be updated for
+ sox-12.18, which has bugfixes to the resample and
+ polyphase code.]
+ resample [ -qs | -q | -ql ] [ rolloff [ beta ] ]
+ Translate input sampling rate to output sampling
+ rate via simulated analog filtration. This method
+ is slower than rate, but gives much better
+ results.
+ The -qs, -q, or -ql options specify increased
+ accuracy at the cost of lower execution speed. By
+ default, linear interpolation is used, with a win-
+ dow width about 37 samples at the lower rate.
+ This gives an accuracy of about 16 bits, but
+ insufficient stopband rejection in the case that
+ you want to have rolloff greater than about 0.85
+ of the Nyquist frequency. The -q* options use
+ quadratic interpolation of filter coefficients,
+ resulting in about 22 bits precision. -qs, -q, or
+ -ql use window lengths of 37, 75, or 150 samples,
+ respectively, at the lower sample-rate of the two
+ files. This means progressively sharper stop-band
+ rejection, at proportionally slower execution
+ times.
+ rolloff refers to the cut-off frequency of the low
+ pass filter and is given in terms of the Nyquist
+ frequency for the lower sample rate. rolloff
+ therefore should be something between 0. and 1.,
+ in practice 0.8-0.95. The default is 0.8.
+ The beta parameter determines the type of filter
+ window used. Any value greater than 2.0 is the
+ beta for a Kaiser window. Beta <= 2.0 selects a
+ Nuttall window. If unspecified, the default is a
+ Kaiser window with beta 16.
-SoX(1) SoX(1)
+ In the case of Kaiser window beta > 2.0, lower
+ betas produce a somewhat faster transition from
+ passband to stopband, at the cost of noticeable
+ artifacts. A beta of 16 is the default, beta less
+ than 10 is not recommended. If you want a sharper
+ cutoff, don't use low beta's, use a longer sample
+ window. A Nuttall window is selected by specify-
+ ing any 'beta' <= 2, and the Nuttall window has
+ somewhat steeper cutoff than the default Kaiser
-BUGS
- The syntax is horrific. It's very tempting to include a
- default system that allows an effect name as the program
- name and just pipes a sound sample from standard input to
- standard output, but the problem of inputting the sample
- rates makes this unworkable.
- Please report any bugs found in this version of sox to
- Chris Bagwell (cbagwell@sprynet.com)
+SunOS 5.6 Last change: November 8, 1999 12
-FILES
-SEE ALSO
- play(1), rec(1)
-NOTICES
- The echoplex effect is: Copyright (C) 1989 by Jef
- Poskanzer.
- Permission to use, copy, modify, and distribute this soft-
- ware and its documentation for any purpose and without fee
- is hereby granted, provided that the above copyright
- notice appear in all copies and that both that copyright
- notice and this permission notice appear in supporting
- documentation. This software is provided "as is" without
- express or implied warranty.
- The version of Sox that accompanies this manual page is
- support by Chris Bagwell (cbagwell@sprynet.com). Please
- refer any questions regarding it to this address. You may
- obtain the latest version at the the web site
- http://home.sprynet.com/~cbagwell/sox.html
+User Commands SoX(1)
+ window. You will probably not need to use the
+ beta parameter at all, unless you are just curious
+ about comparing the effects of Nuttall vs. Kaiser
+ windows.
+ This is the default effect if the two files have
+ different sampling rates. Default parameters are
+ Kaiser window of length 37, rolloff 0.80, beta 16,
+ linear interpolation. -qs is only slightly
+ slower, but more accurate for 16-bit or higher
+ precision.
+ reverb gain-out delay [ delay ... ]
+ Add reverbation to a sound sample. Each delay is
+ given in milliseconds and its feedback is depend-
+ ing on the reverb-time in milliseconds. Each
+ delay should be in the range of half to quarter of
+ reverb-time to get a realistic reverbation.
+ Gain-out is the volume of the output.
+ reverse Reverse the sound sample completely. Included for
+ finding Satanic subliminals.
+ split Turn a mono sample into a stereo sample by copying
+ the input channel to the left and right channels.
+ stat [ debug | -v ]
+ Do a statistical check on the input file, and
+ print results on the standard error file. stat
+ may copy the file untouched from input to output,
+ if you select an output file. The "Volume Adjust-
+ ment:" field in the statistics gives you the argu-
+ ment to the -v number which will make the sample
+ as loud as possible without clipping. There is an
+ optional parameter -v that will print out the
+ "Volume Adjustment:" field's value and return.
+ This could be of use in scripts to auto convert
+ the volume. There is an also an optional parame-
+ ter debug that will place sox into debug mode and
+ print out a hex dump of the sound file from the
+ internal buffer that is in 32-bit signed PCM data.
+ This is mainly only of use in tracking down endian
+ problems that creep in to sox on cross-platform
+ versions.
+ swap [ 1 2 3 4 ]
+ Swap channels in multi-channel sound files. In
+ files with more than 2 channels you may specify
+ the order that the channels should be rearranged
+ in.
+SunOS 5.6 Last change: November 8, 1999 13
@@ -849,10 +859,66 @@
+User Commands SoX(1)
+ vibro speed [ depth ]
+ Add the world-famous Fender Vibro-Champ sound
+ effect to a sound sample by using a sine wave as
+ the volume knob. Speed gives the Hertz value of
+ the wave. This must be under 30. Depth gives the
+ amount the volume is cut into by the sine wave,
+ ranging 0.0 to 1.0 and defaulting to 0.5.
- June 28, 1999 13
+ Sox enforces certain effects. If the two files have dif-
+ ferent sampling rates, the requested effect must be one of
+ copy, or rate, If the two files have different numbers of
+ channels, the avg effect must be requested.
+
+BUGS
+ The syntax is horrific. It's very tempting to include a
+ default system that allows an effect name as the program
+ name and just pipes a sound sample from standard input to
+ standard output, but the problem of inputting the sample
+ rates makes this unworkable.
+
+ Please report any bugs found in this version of sox to Chris
+ Bagwell (cbagwell@sprynet.com)
+
+FILES
+SEE ALSO
+ play(1), rec(1)
+
+NOTICES
+ The echoplex effect is: Copyright (C) 1989 by Jef
+ Poskanzer.
+
+ Permission to use, copy, modify, and distribute this
+ software and its documentation for any purpose and without
+ fee is hereby granted, provided that the above copyright
+ notice appear in all copies and that both that copyright
+ notice and this permission notice appear in supporting docu-
+ mentation. This software is provided "as is" without
+ express or implied warranty.
+
+ The version of Sox that accompanies this manual page is sup-
+ port by Chris Bagwell (cbagwell@sprynet.com). Please refer
+ any questions regarding it to this address. You may obtain
+ the latest version at the the web site
+ http://home.sprynet.com/~cbagwell/sox.html
+
+
+
+
+
+
+
+
+
+
+
+SunOS 5.6 Last change: November 8, 1999 14
+
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -43,11 +43,11 @@
FSRC = 8svx.c aiff.c au.c auto.c avr.c cdr.c cvsd.c dat.c g721.c \
g723_24.c g723_40.c g72x.c gsm.c hcom.c maud.c raw.c \
- sbdsp.c sf.c smp.c sndrtool.c tx16w.c voc.c wav.c wve.c
+ sf.c smp.c sndrtool.c tx16w.c voc.c wav.c wve.c
ESRC = avg.c band.c bandpass.c breject.c btrworth.c chorus.c compand.c \
- copy.c cut.c deemphas.c dyn.c echo.c echos.c flanger.c highp.c \
- highpass.c lowp.c lowpass.c map.c mask.c phaser.c pick.c \
+ copy.c cut.c deemphas.c dyn.c echo.c echos.c filter.c flanger.c \
+ highp.c highpass.c lowp.c lowpass.c map.c mask.c phaser.c pick.c \
polyphas.c rate.c resample.c reverb.c reverse.c split.c \
stat.c swap.c vibro.c
@@ -65,11 +65,11 @@
FOBJ = 8svx.o aiff.o au.o auto.o avr.o cdr.o cvsd.o dat.o g721.o \
g723_24.o g723_40.o g72x.o gsm.o hcom.o maud.o raw.o \
- sbdsp.o sf.o smp.o sndrtool.o tx16w.o voc.o wav.o wve.o
+ sf.o smp.o sndrtool.o tx16w.o voc.o wav.o wve.o
EOBJ = avg.o band.o bandpass.o breject.o btrworth.o chorus.o compand.o \
- copy.o cut.o deemphas.o dyn.o echo.o echos.o flanger.o highp.o \
- highpass.o lowp.o lowpass.o map.o mask.o phaser.o pick.o \
+ copy.o cut.o deemphas.o dyn.o echo.o echos.o filter.o flanger.o \
+ highp.o highpass.o lowp.o lowpass.o map.o mask.o phaser.o pick.o \
polyphas.o rate.o resample.o reverb.o reverse.o split.o \
stat.o swap.o vibro.o
--- /dev/null
+++ b/src/filter.c
@@ -1,0 +1,289 @@
+/*
+ * Windowed sinc lowpass/bandpass/highpass filter.
+ */
+
+/*
+ * November 7, 1999
+ *
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#include "st.h"
+
+#ifndef HAVE_MEMMOVE
+#define memmove(dest,src,len) bcopy((src),(dest),(len))
+#endif
+
+#define Float double/*float*/
+
+#define ISCALE 0x10000
+#define BUFFSIZE 8192
+
+/* Private data for Lerp via LCM file */
+typedef struct filterstuff {
+ LONG rate;
+ LONG freq0; /* low corner freq */
+ LONG freq1; /* high corner freq */
+ double rolloff; /* roll-off frequency */
+ double beta; /* >2 is kaiser window beta, <=2 selects nuttall window */
+ LONG Nwin;
+ Float *Fp; /* [Xh+1] Filter coefficients */
+ LONG Xh; /* number of past/future samples needed by filter */
+ LONG Xt; /* target to enter new data into X */
+ Float *X, *Y; /* I/O buffers */
+} *filter_t;
+
+extern int
+makeFilter(P5(Float Fp[], LONG Nwing, double Froll, double Beta, LONG Num));
+
+static void FiltWin(P2(filter_t f, LONG Nx));
+
+/*
+ * Process options
+ */
+void filter_getopts(effp, n, argv)
+eff_t effp;
+int n;
+char **argv;
+{
+ filter_t f = (filter_t) effp->priv;
+
+ f->beta = 16; /* Kaiser window, beta 16 */
+ f->Nwin = 128;
+
+ f->freq0 = f->freq1 = 0;
+ if (n >= 1) {
+ char *p;
+ p = argv[0];
+ if (*p != '-')
+ f->freq1 = strtol(p, &p, 10);
+ if (*p == '-') {
+ f->freq0 = f->freq1;
+ f->freq1 = strtol(p+1, &p, 10);
+ }
+ if (*p) f->freq1 = f->freq0 = 0;
+ }
+ /* fprintf(stderr,"freq: %d-%d\n", f->freq0, f->freq1);fflush(stderr); */
+ if (f->freq0 == 0 && f->freq1 == 0)
+ fail("Usage: filter low-high [ windowlength [ beta ] ]");
+
+ if ((n >= 2) && !sscanf(argv[1], "%ld", &f->Nwin))
+ fail("Usage: filter low-high [ windowlength ]");
+ else if (f->Nwin < 4) {
+ fail("filter: window length (%ld) <4 is too short", f->Nwin);
+ }
+
+ if ((n >= 3) && !sscanf(argv[2], "%lf", &f->beta))
+ fail("Usage: filter low-high [ windowlength [ beta ] ]");
+
+ report("filter opts: cutoff %f, window-len %d, beta %f\n", f->rolloff, f->Nwin, f->beta);
+}
+
+/*
+ * Prepare processing.
+ */
+void filter_start(effp)
+eff_t effp;
+{
+ filter_t f = (filter_t) effp->priv;
+ Float *Fp0, *Fp1;
+ LONG Xh0, Xh1, Xh;
+ int i;
+
+ f->rate = effp->ininfo.rate;
+
+ if (f->freq1 > f->rate/2 || f->freq1 <= 0)
+ f->freq1 = f->rate/2;
+ if ((f->freq0 < 0) || (f->freq0 > f->freq1))
+ fail("filter: low(%d),high(%d) parameters must satisfy 0 <= low <= high <= %d",
+ f->freq0, f->freq1, f->rate/2);
+
+ Xh = f->Nwin/2;
+ Fp0 = (Float *) malloc(sizeof(Float) * (Xh + 2)) + 1;
+ if (f->freq0 > f->rate/200) {
+ Xh0 = makeFilter(Fp0, Xh, 2.0*(double)f->freq0/f->rate, f->beta, 1);
+ if (Xh0 <= 1)
+ fail("filter: Unable to make low filter\n");
+ } else {
+ Xh0 = 0;
+ }
+ Fp1 = (Float *) malloc(sizeof(Float) * (Xh + 2)) + 1;
+ /* need Fp[-1] and Fp[Xh] for makeFilter */
+ if (f->freq1 < f->rate/2) {
+ Xh1 = makeFilter(Fp1, Xh, 2.0*(double)f->freq1/f->rate, f->beta, 1);
+ if (Xh1 <= 1)
+ fail("filter: Unable to make high filter\n");
+ } else {
+ Fp1[0] = 1.0;
+ Xh1 = 1;
+ }
+ /* now subtract Fp0[] from Fp1[] */
+ Xh = (Xh0>Xh1)? Xh0:Xh1;
+ Xh -= 1;
+ for (i=0; i<Xh; i++) {
+ Float c0,c1;
+ c0 = (i<Xh0)? Fp0[i]:0;
+ c1 = (i<Xh1)? Fp1[i]:0;
+ Fp1[i] = c1-c0;
+ }
+
+ free(Fp0 - 1); /* all done with Fp0 */
+ f->Fp = Fp1;
+
+ Xh -= 1;
+ f->Nwin = 2*Xh + 1;
+ f->Xh = Xh;
+ f->Xt = Xh;
+
+ f->X = (Float *) malloc(sizeof(Float) * (2*BUFFSIZE + 2*Xh));
+ f->Y = f->X + BUFFSIZE + 2*Xh;
+
+ /* Need Xh zeros at beginning of X */
+ for (i = 0; i < Xh; i++)
+ f->X[i] = 0;
+}
+
+/*
+ * Processed signed long samples from ibuf to obuf.
+ * Return number of samples processed.
+ */
+
+void filter_flow(effp, ibuf, obuf, isamp, osamp)
+eff_t effp;
+LONG *ibuf, *obuf;
+LONG *isamp, *osamp;
+{
+ filter_t f = (filter_t) effp->priv;
+ LONG i, Nx, Nproc;
+
+ /* constrain amount we actually process */
+ /* fprintf(stderr,"Xh %d, Xt %d, isamp %d, ",f->Xh, f->Xt, *isamp);fflush(stderr); */
+ Nx = BUFFSIZE + 2*f->Xh - f->Xt;
+ if (Nx > *isamp) Nx = *isamp;
+ if (Nx > *osamp) Nx = *osamp;
+ *isamp = Nx;
+
+ {
+ Float *xp, *xtop;
+ xp = f->X + f->Xt;
+ xtop = xp + Nx;
+ if (ibuf != NULL) {
+ while (xp < xtop)
+ *xp++ = (Float)(*ibuf++) / ISCALE;
+ } else {
+ while (xp < xtop)
+ *xp++ = 0;
+ }
+ }
+
+ Nproc = f->Xt + Nx - 2*f->Xh;
+
+ if (Nproc <= 0) {
+ f->Xt += Nx;
+ *osamp = 0;
+ return;
+ }
+ /* fprintf(stderr,"flow Nproc %d\n",Nproc); */
+ FiltWin(f, Nproc);
+
+ /* Copy back portion of input signal that must be re-used */
+ Nx += f->Xt;
+ memmove(f->X, f->X + Nx - 2*f->Xh, sizeof(Float)*2*f->Xh);
+ f->Xt = 2*f->Xh;
+
+ for (i = 0; i < Nproc; i++)
+ *obuf++ = f->Y[i] * ISCALE;
+
+ *osamp = Nproc;
+}
+
+/*
+ * Process tail of input samples.
+ */
+void filter_drain(effp, obuf, osamp)
+eff_t effp;
+LONG *obuf;
+LONG *osamp;
+{
+ filter_t f = (filter_t) effp->priv;
+ LONG isamp_res, *Obuf, osamp_res;
+
+ /* fprintf(stderr,"Xh %d, Xt %d <--- DRAIN\n",f->Xh, f->Xt); */
+
+ /* stuff end with Xh zeros */
+ isamp_res = f->Xh;
+ osamp_res = *osamp;
+ Obuf = obuf;
+ while (isamp_res>0 && osamp_res>0) {
+ LONG Isamp, Osamp;
+ Isamp = isamp_res;
+ Osamp = osamp_res;
+ filter_flow(effp, NULL, Obuf, &Isamp, &Osamp);
+ /* fprintf(stderr,"DRAIN isamp,osamp (%d,%d) -> (%d,%d)\n",
+ * isamp_res,osamp_res,Isamp,Osamp); */
+ Obuf += Osamp;
+ osamp_res -= Osamp;
+ isamp_res -= Isamp;
+ };
+ *osamp -= osamp_res;
+ /* fprintf(stderr,"DRAIN osamp %d\n", *osamp); */
+ if (isamp_res)
+ warn("drain overran obuf by %d\n", isamp_res); fflush(stderr);
+}
+
+/*
+ * Do anything required when you stop reading samples.
+ * Don't close input file!
+ */
+void filter_stop(effp)
+eff_t effp;
+{
+ filter_t f = (filter_t) effp->priv;
+
+ free(f->Fp - 1);
+ free(f->X);
+}
+
+static double jprod(Fp, Xp, ct)
+const Float Fp[], *Xp;
+LONG ct;
+{
+ const Float *fp, *xp, *xq;
+ double v = 0;
+
+ fp = Fp + ct; /* so sum starts with smaller coef's */
+ xp = Xp - ct;
+ xq = Xp + ct;
+ do {
+ v += *fp * (*xp + *xq);
+ xp++; xq--;
+ } while (--fp > Fp);
+ v += *fp * *xp;
+ return v;
+}
+
+static void FiltWin(f, Nx)
+filter_t f;
+LONG Nx;
+{
+ Float *Y;
+ Float *X, *Xend;
+
+ Y = f->Y;
+ X = f->X + f->Xh; /* Ptr to current input sample */
+ Xend = X + Nx;
+ while (X < Xend) {
+ *Y++ = jprod(f->Fp, X, f->Xh);
+ X++;
+ }
+}
--- a/src/g72x.c
+++ b/src/g72x.c
@@ -348,6 +348,7 @@
a2p += fa1 >> 5;
if (pk0 ^ state_ptr->pk[1])
+ {
/* LIMC */
if (a2p <= -12160)
a2p = -12288;
@@ -355,6 +356,7 @@
a2p = 12288;
else
a2p -= 0x80;
+ }
else if (a2p <= -12416)
a2p = -12288;
else if (a2p >= 12160)
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -168,19 +168,6 @@
/* raw prototypes are defined in st.h since they are used globally. */
-#if defined(BLASTER) || defined(SBLAST)
-char *sbdspnames[] = {
- "sbdsp",
- (char *) 0
-};
-extern void sbdspstartread();
-extern LONG sbdspread();
-extern void sbdspstopread();
-extern void sbdspstartwrite();
-extern void sbdspwrite();
-extern void sbdspstopwrite();
-#endif
-
char *sbnames[] = {
"sb",
(char *) 0
@@ -200,6 +187,14 @@
(char *) 0,
};
+char *slnames[] = {
+ "sl",
+ (char *) 0,
+};
+
+extern void slstartread();
+extern void slstartwrite();
+
extern void smpstartread();
extern LONG smpread();
extern void smpwrite();
@@ -375,12 +370,6 @@
{rawnames, FILE_STEREO,
rawstartread, rawread, rawstopread, /* Raw format */
rawstartwrite, rawwrite, rawstopwrite},
-#if defined(BLASTER) || defined(SBLAST)
- /* 386 Unix sound blaster player. */
- {sbdspnames, FILE_STEREO,
- sbdspstartread, sbdspread, sbdspstopread, /* /dev/sbdsp */
- sbdspstartwrite, sbdspwrite, sbdspstopwrite},
-#endif
{sbnames, FILE_STEREO,
sbstartread, rawread, rawstopread, /* signed byte raw */
sbstartwrite, rawwrite, rawstopwrite},
@@ -387,6 +376,9 @@
{sfnames, FILE_STEREO,
sfstartread, rawread, rawstopread, /* IRCAM Sound File */
sfstartwrite, rawwrite, rawstopwrite},
+ { slnames, FILE_STEREO,
+ slstartread, rawread, rawstopread, /* signed long raw */
+ slstartwrite, rawwrite, rawstopwrite },
{smpnames, FILE_STEREO | FILE_LOOPS,
smpstartread, smpread, nothing, /* SampleVision sound */
smpstartwrite, smpwrite, smpstopwrite}, /* Turtle Beach */
@@ -497,6 +489,12 @@
extern void echos_drain();
extern void echos_stop();
+extern void filter_getopts();
+extern void filter_start();
+extern void filter_flow();
+extern void filter_drain();
+extern void filter_stop();
+
extern void flanger_getopts();
extern void flanger_start();
extern void flanger_flow();
@@ -629,6 +627,9 @@
{"echos", 0,
echos_getopts, echos_start, echos_flow,
echos_drain, echos_stop},
+ { "filter", 0,
+ filter_getopts, filter_start, filter_flow,
+ filter_drain, filter_stop},
{"flanger", 0,
flanger_getopts, flanger_start, flanger_flow,
flanger_drain, flanger_stop},
--- a/src/misc.c
+++ b/src/misc.c
@@ -227,19 +227,20 @@
}
/* here for linear interp. might be useful for other things */
-LONG gcd(a, b)
+LONG st_gcd(a, b)
LONG a, b;
{
if (b == 0)
return a;
else
- return gcd(b, a % b);
+ return st_gcd(b, a % b);
}
-LONG lcm(a, b)
+LONG st_lcm(a, b)
LONG a, b;
{
- return (a * b) / gcd(a, b);
+ /* parenthesize this way to avoid LONG overflow in the product term */
+ return a * (b / st_gcd(a, b));
}
/*
--- a/src/polyphas.c
+++ b/src/polyphas.c
@@ -1,4 +1,3 @@
-
/*
* July 14, 1998
* Copyright 1998 K. Bradley, Carnegie Mellon University
@@ -10,6 +9,16 @@
*/
/*
+ * October 29, 1999
+ * Various changes, bugfixes, speedups, by Stan Brooks.
+ *
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+/*
* Sound Tools rate change effect file.
*/
@@ -21,27 +30,30 @@
#endif
#include "st.h"
-typedef struct _list {
- int number;
- float *data_buffer;
- struct _list *next;
-} List;
+#define Float float/*double*/
+#define ISCALE 0x10000
+#define MF 30
+typedef struct {
+ int up,down; /* up/down conversion factors for this stage */
+ int filt_len; /* # coefficients in filter_array */
+ Float *filt_array; /* filter coefficients */
+ int held; /* # samples held in input but not yet processed */
+ int hsize; /* # samples of past-history kept in lower window */
+ int size; /* # samples current data which window can accept */
+ Float *window; /* this is past_hist[hsize], then input[size] */
+} polystage;
+
typedef struct polyphase {
- unsigned long lcmrate; /* least common multiple of rates */
- unsigned long inskip, outskip; /* LCM increments for I & O rates */
- unsigned long total;
- unsigned long intot, outtot; /* total samples in terms of LCM rate */
- long lastsamp;
+ unsigned long lcmrate; /* least common multiple of rates */
+ unsigned long inskip, outskip; /* LCM increments for I & O rates */
+ double Factor; /* out_rate/in_rate */
+ unsigned long total; /* number of filter stages */
+ unsigned long oskip; /* output samples to skip at start*/
+ double inpipe; /* output samples 'in the pipe' */
+ polystage *stage[MF]; /* array of pointers to polystage structs */
- float **filt_array;
- float **past_hist;
- float *input_buffer;
- int *filt_len;
-
- List *l1, *l2;
-
} *poly_t;
/*
@@ -53,8 +65,8 @@
-w <nut / ham> : window type
-width <short / long> : window width
short = 128 samples
- long = 1024 samples
- <num> num: explicit number
+ long = 1024 samples
+ <num> num: explicit number
-cutoff <float> : frequency cutoff for base bandwidth.
Default = 0.95 = 95%
@@ -62,12 +74,9 @@
static int win_type = 0;
static int win_width = 1024;
-static float cutoff = 0.95;
+static Float cutoff = 0.95;
-void poly_getopts(effp, n, argv)
-eff_t effp;
-int n;
-char **argv;
+void poly_getopts(eff_t effp, int n, char **argv)
{
/* 0: nuttall
1: hamming */
@@ -85,9 +94,9 @@
/* Window type check */
if(!strcmp(argv[0], "-w")) {
if(!strcmp(argv[1], "ham"))
- win_type = 1;
+ win_type = 1;
if(!strcmp(argv[1], "nut"))
- win_type = 0;
+ win_type = 0;
argv += 2;
n -= 2;
@@ -97,11 +106,11 @@
/* Window width check */
if(!strcmp(argv[0], "-width")) {
if(!strcmp(argv[1], "short"))
- win_width = 128;
+ win_width = 128;
else if(!strcmp(argv[1], "long"))
- win_width = 1024;
+ win_width = 1024;
else
- win_width = atoi(argv[1]);
+ win_width = atoi(argv[1]);
argv += 2;
n -= 2;
@@ -123,8 +132,7 @@
/*
* Prepare processing.
*/
-
-static int primes[] = {
+static const unsigned short primes[] = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89,
97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
@@ -138,7 +146,8 @@
661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743,
751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827,
829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
- 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997
+ 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,
+ 0
};
#ifndef max
@@ -145,56 +154,127 @@
#define max(x,y) ((x > y) ? x : y)
#endif
-List *prime(number)
-int number;
+#ifndef min
+#define min(x,y) ((x < y) ? x : y)
+#endif
+
+static int prime(int n, int *q0)
{
- int j;
- List *element = NULL;
+ const unsigned short *p;
+ int pr, *q;
- if(number == 1)
- return NULL;
-
- for(j=167;j>= 0;j--) {
- if(number % primes[j] == 0) {
- element = (List *) malloc(sizeof(List));
- element->number = primes[j];
- element->data_buffer = NULL;
- element->next = prime(number / primes[j]);
- break;
- }
+ p = primes;
+ q = q0;
+ report("factors(%d) =",n);
+ while (n > 1) {
+ while ((pr = *p) && (n % pr)) p++;
+ if (!pr) {
+ fail("Number %d too large of a prime.\n",n);
+ pr = n;
}
+ *q++ = pr;
+ n /= pr;
+ }
+ *q = 0;
+ for (pr=0; pr<q-q0; pr++) fprintf(stderr," %d",q0[pr]);
+ fprintf(stderr,"\n");
+ return (q-q0);
+}
- if(element == NULL) {
- fail("Number %d too large of a prime.\n",number);
- }
+static int permute(int *m, int *l, int ct, int ct1, int amalg)
+{
+ int k, n;
+ int *p;
+ int *q;
- return element;
+ p=l; q=m;
+ while (ct1>ct) { *q++=1; ct++;}
+ while ((*q++=*p++)) ;
+ if (ct<=1) return ct;
+
+ for (k=ct; k>1; ) {
+ int tmp, j;
+ j = random() % k;
+ k--;
+ if (j != k) {
+ tmp = m[k]; m[k]=m[j]; m[j]=tmp;
+ }
+ }
+ /* now m is a 'random' permutation of l */
+ p = q = m;
+ n = *q++;
+ while ((k=*q++)) {
+ if ((n * k <= amalg) && (random() & 1)) {
+ n *= k;
+ } else {
+ *p++ = n;
+ n = k;
+ }
+ }
+ if (n) *p++=n;
+ *p = 0;
+ /*for (k=0; k<p-m; k++) fprintf(stderr," %d",m[k]);*/
+ /*fprintf(stderr,"\n");*/
+ return (p-m);
}
-List *prime_inv(number)
-int number;
+static int optimize_factors(int numer, int denom, int *l1, int *l2)
{
- int j;
- List *element = NULL;
+ int f_min,c_min,u_min,ct1,ct2;
+ int amalg;
+ int k;
+ static int m1[MF],m2[MF];
+ static int b1[MF],b2[MF];
- if(number == 1)
- return NULL;
+ f_min = numer; if (f_min>denom) f_min = denom;
+ c_min = 1<<30;
+ u_min = 0;
- for(j=0;j<168;j++) {
- if(number % primes[j] == 0) {
- element = (List *) malloc(sizeof(List));
- element->number = primes[j];
- element->data_buffer = NULL;
- element->next = prime_inv(number / primes[j]);
- break;
- }
- }
+ /* Find the prime factors of numer and denom */
+ ct1 = prime(numer,l1);
+ ct2 = prime(denom,l2);
- if(element == NULL) {
- fail("Number %d too large of a prime.\n",number);
+ for (amalg = max(9,l2[0]); amalg<= 9+l2[ct2-1]; amalg++) {
+ for (k = 0; k<100000; k++) {
+ int u,u1,u2,j,f,cost;
+ cost = 0;
+ f = denom;
+ u = min(ct1,ct2) + 1;
+ /*fprintf(stderr,"pfacts(%d): ", numer);*/
+ u1 = permute(m1,l1,ct1,u,amalg);
+ /*fprintf(stderr,"pfacts(%d): ", denom);*/
+ u2 = permute(m2,l2,ct2,u,amalg);
+ u = max(u1,u2);
+ for (j=0; j<u; j++) {
+ if (j>=u1) m1[j]=1;
+ if (j>=u2) m2[j]=1;
+ f = (f * m1[j])/m2[j];
+ if (f < f_min) goto fail;
+ cost += f + m1[j]*m2[j];
+ }
+ if (c_min>cost) {
+ c_min = cost;
+ u_min = u;
+# if 0
+ fprintf(stderr,"c_min %d, [%d-%d]:",c_min,numer,denom);
+ for (j=0; j<u; j++)
+ fprintf(stderr," (%d,%d)",m1[j],m2[j]);
+ fprintf(stderr,"\n");
+# endif
+ memcpy(b1,m1,u*sizeof(int));
+ memcpy(b2,m2,u*sizeof(int));
+ }
+ fail:
}
-
- return element;
+ if (u_min) break;
+ }
+ if (u_min) {
+ memcpy(l1,b1,u_min*sizeof(int));
+ memcpy(l2,b2,u_min*sizeof(int));
+ }
+ l1[u_min] = 0;
+ l2[u_min] = 0;
+ return u_min;
}
#ifndef PI
@@ -205,20 +285,18 @@
Buffer must already be allocated to appropriate size.
*/
-void nuttall(buffer, length)
-float *buffer;
-int length;
+static void nuttall(Float *buffer, int length)
{
int j;
double N;
- double N1;
+ int N1;
- if(buffer == NULL || length < 0)
+ if(buffer == NULL || length <= 0)
fail("Illegal buffer %p or length %d to nuttall.\n", buffer, length);
/* Initial variable setups. */
- N = (double) length - 1.0;
- N1 = N / 2.0;
+ N = length;
+ N1 = length/2;
for(j = 0; j < length; j++) {
buffer[j] = 0.36335819 +
@@ -231,23 +309,22 @@
Buffer must already be allocated to appropriate size.
*/
-void hamming(buffer, length)
-float *buffer;
-int length;
+static void hamming(Float *buffer, int length)
{
int j;
+ int N1;
- if(buffer == NULL || length < 0)
+ if(buffer == NULL || length <= 0)
fail("Illegal buffer %p or length %d to hamming.\n",buffer,length);
+ N1 = length/2;
for(j=0;j<length;j++)
- buffer[j] = 0.5 - 0.46 * cos(2*PI*j/(length-1));
+ buffer[j] = 0.5 - 0.46 * cos(PI*j/N1);
}
/* Calculate the sinc function properly */
-float sinc(value)
-float value;
+static Float sinc(Float value)
{
return(fabs(value) < 1E-50 ? 1.0 : sin(value) / value);
}
@@ -258,55 +335,50 @@
buffer must already be allocated.
*/
-void fir_design(buffer, length, cutoff)
-float *buffer;
-int length;
-float cutoff;
+void fir_design(Float *buffer, int length, Float cutoff)
{
int j;
- float sum;
- float *ham_win;
+ double sum;
if(buffer == NULL || length < 0 || cutoff < 0 || cutoff > PI)
fail("Illegal buffer %p, length %d, or cutoff %f.\n",buffer,length,cutoff);
- /* Design Hamming window: 43 dB cutoff */
- ham_win = (float *)malloc(sizeof(float) * length);
-
/* Use the user-option of window type */
if(win_type == 0)
- nuttall(ham_win, length);
+ nuttall(buffer, length); /* Design Nuttall window: ** dB cutoff */
else
- hamming(ham_win,length);
+ hamming(buffer,length); /* Design Hamming window: 43 dB cutoff */
+ /* printf("# fir_design length=%d, cutoff=%8.4f\n",length,cutoff); */
/* Design filter: windowed sinc function */
sum = 0.0;
for(j=0;j<length;j++) {
- buffer[j] = sinc(PI*cutoff*(j-length/2)) * ham_win[j] / (2*cutoff);
- sum += buffer[j];
+ buffer[j] *= sinc(PI*cutoff*(j-length/2)); /* center at length/2 */
+ /* printf("%.1f %.6f\n",(float)j,buffer[j]); */
+ sum += buffer[j];
}
-
+ sum = (double)1.0/sum;
/* Normalize buffer to have gain of 1.0: prevent roundoff error */
- for(j=0;j<length;j++)
- buffer[j] /= sum;
-
- free((void *) ham_win);
+ for(j=0;j<length;j++) {
+ buffer[j] *= sum;
+ }
+ /* printf("# end\n\n"); */
}
-
+
+#define RIBLEN 2048
-void poly_start(effp)
-eff_t effp;
+void poly_start(eff_t effp)
{
poly_t rate = (poly_t) effp->priv;
- List *t, *t2;
- int num_l1, num_l2;
- int j,k;
- float f_cutoff;
+ static int l1[MF], l2[MF];
+ double skip = 0;
+ int total, size, uprate;
+ int k;
- extern long lcm();
-
- rate->lcmrate = lcm((long)effp->ininfo.rate, (long)effp->outinfo.rate);
+ extern long st_lcm();
+ rate->lcmrate = st_lcm((long)effp->ininfo.rate, (long)effp->outinfo.rate);
+
/* Cursory check for LCM overflow.
* If both rate are below 65k, there should be no problem.
* 16 bits x 16 bits = 32 bits, which we can handle.
@@ -314,155 +386,76 @@
rate->inskip = rate->lcmrate / effp->ininfo.rate;
rate->outskip = rate->lcmrate / effp->outinfo.rate;
+ rate->Factor = (double)rate->inskip / (double)rate->outskip;
+ rate->inpipe = 0;
+ {
+ int f = RIBLEN/max(rate->inskip,rate->outskip);
+ if (f == 0) f = 1;
+ size = f * rate->outskip; /* reasonable input block size */
+ }
/* Find the prime factors of inskip and outskip */
- rate->l1 = prime(rate->inskip);
+ total = optimize_factors(rate->inskip, rate->outskip, l1, l2);
+ rate->total = total;
+ /* l1 and l2 are now lists of the up/down factors for conversion */
- /* If we're going up, order things backwards. */
- if(effp->ininfo.rate < effp->outinfo.rate)
- rate->l2 = prime_inv(rate->outskip);
- else
- rate->l2 = prime(rate->outskip);
-
- /* Find how many factors there were */
- if(rate->l1 == NULL)
- num_l1 = 0;
- else
- for(num_l1=0, t = rate->l1; t != NULL; num_l1++, t=t->next);
+ report("Poly: input rate %d, output rate %d. %d stages.",
+ effp->ininfo.rate, effp->outinfo.rate,total);
+ report("Poly: window: %s size: %d cutoff: %f.",
+ (win_type == 0) ? ("nut") : ("ham"), win_width, cutoff);
- if(rate->l2 == NULL)
- num_l2 = 0;
- else
- for(num_l2=0, t = rate->l2; t != NULL; num_l2++, t=t->next);
+ /* Create an array of filters and past history */
+ uprate = effp->ininfo.rate;
+ for (k = 0; k < total; k++) {
+ int j, prod, f_cutoff, f_len;
+ polystage *s;
- k = 0;
- t = rate->l1;
+ rate->stage[k] = s = (polystage*) malloc(sizeof(polystage));
+ s->up = l1[k];
+ s->down = l2[k];
+ f_cutoff = max(s->up, s->down);
+ f_len = max(20 * f_cutoff, win_width);
+ prod = s->up * s->down;
+ if (prod > 2*f_len) prod = s->up;
+ f_len = ((f_len+prod-1)/prod) * prod; /* reduces rounding-errors in polyphase() */
+ s->size = size;
+ s->hsize = f_len/s->up; /* this much of window is past-history */
+ s->held = 0;
+ report("Poly: stage %d: Up by %d, down by %d, i_samps %d, hsize %d",
+ k+1,s->up,s->down,size, s->hsize);
+ s->filt_len = f_len;
+ s->filt_array = (Float *) malloc(sizeof(Float) * f_len);
+ s->window = (Float *) malloc(sizeof(Float) * (s->hsize+size));
+ /* zero past_history section of window */
+ for(j = 0; j < s->hsize; j++)
+ s->window[j] = 0.0;
- /* Compact the lists to be less than 10 */
- while(k < num_l1 - 1) {
- if(t->number * t->next->number < 10) {
- t->number = t->number * t->next->number;
- t2 = t->next;
- t->next = t->next->next;
- t2->next = NULL;
- free((void *) t2);
- num_l1--;
- } else {
- k++;
- t = t->next;
- }
- }
+ uprate *= s->up;
+ report("Poly: : filt_len %d, cutoff freq %.1f",
+ f_len, uprate*cutoff/f_cutoff);
+ uprate /= s->down;
+ fir_design(s->filt_array, f_len, cutoff/f_cutoff);
+ /* s->filt_array[f_len-1]=0; */
- k = 0;
- t = rate->l2;
+ skip *= s->up;
+ skip += f_len;
+ skip /= s->down;
- while(k < num_l2 - 1) {
- if(t->number * t->next->number < 10) {
- t->number = t->number * t->next->number;
- t2 = t->next;
- t->next = t->next->next;
- t2->next = NULL;
- free((void *) t2);
- num_l2--;
- } else {
- k++;
- t = t->next;
- }
+ size = (size * s->up) / s->down; /* this is integer */
}
-
- /* l1 and l2 are now lists of the prime factors compacted,
- meaning that they're the lists of up/down sampling we need
- */
-
- /* Stretch them to be the same length by padding with 1 (no-op) */
- if(num_l1 < num_l2) {
- t = rate->l1;
-
- if(t == NULL) {
- rate->l1 = (List *)malloc(sizeof(List));
- rate->l1->next = NULL;
- rate->l1->number = 1;
- rate->l1->data_buffer = NULL;
- t = rate->l1;
- num_l1++;
- }
-
- while(t->next != NULL)
- t = t->next;
-
- for(k=0;k<num_l2-num_l1;k++) {
- t->next = (List *) malloc(sizeof(List));
- t->next->number = 1;
- t->next->data_buffer = NULL;
- t = t->next;
- }
-
- t->next = NULL;
- num_l1 = num_l2;
- } else {
- t = rate->l2;
-
- if(t == NULL) {
- rate->l2 = (List *)malloc(sizeof(List));
- rate->l2->next = NULL;
- rate->l2->number = 1;
- rate->l2->data_buffer = NULL;
- t = rate->l2;
- num_l2++;
- }
-
- /*
- while(t->next != NULL)
- t = t->next;
- */
-
- for(k=0;k<num_l1-num_l2;k++) {
- t = rate->l2;
- rate->l2 = (List *) malloc(sizeof(List));
- rate->l2->number = 1;
- rate->l2->data_buffer = NULL;
- rate->l2->next = t;
- }
-
- /* t->next = NULL; */
- num_l2 = num_l1;
+ rate->oskip = skip/2;
+ { /* bogus last stage is for output buffering */
+ polystage *s;
+ rate->stage[k] = s = (polystage*) malloc(sizeof(polystage));
+ s->up = s->down = 0;
+ s->size = size;
+ s->hsize = 0;
+ s->held = 0;
+ s->filt_len = 0;
+ s->filt_array = NULL;
+ s->window = (Float *) malloc(sizeof(Float) * size);
}
-
- /* l1 and l2 are now the same size. */
- rate->total = num_l1;
-
- report("Poly: input rate %d, output rate %d. %d stages.",effp->ininfo.rate, effp->outinfo.rate,num_l1);
- report("Poly: window: %s size: %d cutoff: %f.", (win_type == 0) ? ("nut") : ("ham"), win_width, cutoff);
-
- for(k=0, t=rate->l1, t2=rate->l2;k<num_l1;k++,t=t->next,t2=t2->next)
- report("Poly: stage %d: Up by %d, down by %d.",k+1,t->number,t2->number);
-
- /* We'll have an array of filters and past history */
- rate->filt_array = (float **) malloc(sizeof(float *) * num_l1);
- rate->past_hist = (float **) malloc(sizeof(float *) * num_l1);
- rate->filt_len = (int *) malloc(sizeof(int) * num_l1);
-
- for(k = 0, t = rate->l1, t2 = rate->l2; k < num_l1; k++) {
-
- rate->filt_len[k] = max(2 * 10 * max(t->number,t2->number), win_width);
- rate->filt_array[k] = (float *) malloc(sizeof(float) * rate->filt_len[k]);
- rate->past_hist[k] = (float *) malloc(sizeof(float) * rate->filt_len[k]);
-
- t->data_buffer = (float *) malloc(sizeof(float) * 1024 * rate->inskip);
-
- for(j = 0; j < rate->filt_len[k]; j++)
- rate->past_hist[k][j] = 0.0;
-
- f_cutoff = (t->number > t2->number) ?
- (float) t->number : (float) t2->number;
-
- fir_design(rate->filt_array[k], rate->filt_len[k]-1, cutoff / f_cutoff);
-
- t = t->next;
- t2 = t2->next;
- }
-
- rate->input_buffer = (float *) malloc(sizeof(float) * 2048);
+ report("Poly: output samples %d, oskip %d",size, rate->oskip);
}
/*
@@ -470,141 +463,155 @@
* Return number of samples processed.
*/
-static float *h;
-static int M, L, N;
-
-void polyphase_init(coef, num_coef, up_rate, down_rate)
-float *coef;
-int num_coef;
-int up_rate;
-int down_rate;
+/* REMARK: putting this in a separate subroutine improves gcc's optimization */
+static double st_prod(const Float *q, int qstep, const Float *p, int n)
{
- h = coef;
- M = down_rate;
- L = up_rate;
- N = num_coef;
+ double sum = 0;
+ const Float *p0;
+ p0 = p-n;
+ while (p>p0) {
+ sum += *p * *q;
+ q += qstep;
+ p -= 1;
+ }
+ return sum;
}
-void polyphase(input, output, past, num_samples_input)
-float *input;
-float *output;
-float *past;
-int num_samples_input;
+void polyphase(Float *output, polystage *s)
{
- int num_output;
- int m,n;
- float sum;
- float inp;
- int base;
- int h_base;
+ int mm;
+ int up = s->up;
+ int down = s->down;
+ int f_len = s->filt_len;
+ const Float *in;
+ Float *o; /* output pointer */
+ Float *o_top;
- num_output = num_samples_input * L / M;
+ in = s->window + s->hsize;
+ /*for (mm=0; mm<s->filt_len; mm++) fprintf(stderr,"cf_%d %f\n",mm,s->filt_array[mm]);*/
+ /* assumes s->size divisible by down (now true) */
+ o_top = output + (s->size * up) / down;
+ /*report(" isize %d, osize %d, up %d, down %d, N %d", s->size, o_top-output, up, down, f_len);*/
+ for (mm=0, o=output; o < o_top; mm+=down, o++) {
+ double sum;
+ const Float *p, *q;
+ q = s->filt_array + (mm%up); /* decimated coef pointer */
+ p = in + (mm/up);
+ sum = st_prod(q, up, p, f_len/up);
+ *o = sum * up;
+ }
+}
- for(m=0;m<num_output;m++) {
- sum = 0.0;
- base = (int) (m*M/L);
- h_base = (m*M) % L;
+static inline void update_hist(Float *hist, int hist_size, int in_size)
+{
+ Float *p, *p1, *q;
+ p = hist;
+ p1 = hist+hist_size;
+ q = hist+in_size;
+ while (p<p1)
+ *p++ = *q++;
- for(n=0;n<N / L;n++) {
- if(base - n < 0)
- inp = past[base - n + N];
- else
- inp = input[base - n];
-
- sum += h[n*L + h_base] * inp;
- }
-
- output[m] = sum * L * 0.95;
- }
}
-void poly_flow(effp, ibuf, obuf, isamp, osamp)
-eff_t effp;
-long *ibuf, *obuf;
-int *isamp, *osamp;
+void poly_flow(eff_t effp, long *ibuf, long *obuf, long *isamp, long *osamp)
{
poly_t rate = (poly_t) effp->priv;
- float *temp_buf, *temp_buf2;
- int j,k;
- List *t1, *t2;
- int in_size, out_size;
+ polystage *s0,*s1;
/* Sanity check: how much can we tolerate? */
- in_size = *isamp;
- out_size = in_size * rate->inskip / rate->outskip;
- if(out_size > *osamp) {
- in_size = *osamp * rate->outskip / rate->inskip;
- *isamp = in_size;
+ /* fprintf(stderr, "*isamp=%d *osamp=%d\n",*isamp,*osamp); fflush(stderr); */
+ s0 = rate->stage[0]; /* the first stage */
+ s1 = rate->stage[rate->total]; /* the 'last' stage is output buffer */
+ {
+ int in_size, gap, k;
+
+ in_size = *isamp;
+ gap = s0->size - s0->held; /* space available in this 'input' buffer */
+ if ((in_size > gap) || (ibuf==NULL)) {
+ *isamp = in_size = gap;
+ }
+ if (in_size > 0) {
+ Float *q;
+ q = s0->window + s0->hsize;
+ if (s0!=s1) q += s0->held; /* the last (output) buffer doesn't shift history */
+ if (ibuf != NULL) {
+ rate->inpipe += rate->Factor * in_size;
+ for (k=0; k<in_size; k++)
+ *q++ = (Float)ibuf[k] / ISCALE;
+ } else { /* ibuf==NULL is draining */
+ for(k=0;k<in_size;k++)
+ *q++ = 0.0;
+ }
+ s0->held += in_size;
+ }
}
+
+ if (s0->held == s0->size && s1->held == 0) {
+ int k;
+ /* input buffer full, output buffer empty, so do process */
+
+ for(k=0; k<rate->total; k++) {
+ polystage *s;
+ Float *out;
- /* Check to see if we're really draining */
- if(ibuf != NULL) {
- for(k=0;k<*isamp;k++)
- rate->input_buffer[k] = (float) (ibuf[k] >> 16);
- } else {
- for(k=0;k<*isamp;k++)
- rate->input_buffer[k] = 0.0;
- }
+ s = rate->stage[k];
- temp_buf = rate->input_buffer;
+ out = rate->stage[k+1]->window + rate->stage[k+1]->hsize;
- t1 = rate->l1;
- t2 = rate->l2;
-
- for(k=0;k<rate->total;k++,t1=t1->next,t2=t2->next) {
-
- polyphase_init(rate->filt_array[k], rate->filt_len[k],
- t1->number,t2->number);
-
- out_size = (in_size) * t1->number / t2->number;
-
- temp_buf2 = t1->data_buffer;
-
- polyphase(temp_buf, temp_buf2, rate->past_hist[k], in_size);
-
- for(j = 0; j < rate->filt_len[k]; j++)
- rate->past_hist[k][j] = temp_buf[j+in_size - rate->filt_len[k]];
-
- in_size = out_size;
-
- temp_buf = temp_buf2;
+ /* fprintf(stderr, "k=%d insize=%d\n",k,in_size); fflush(stderr); */
+ polyphase(out, s);
+
+ /* copy input history into lower portion of rate->window[k] */
+ update_hist(s->window, s->hsize, s->size);
+ s->held = 0;
+ }
+
+ s1->held = s1->size;
+ s1->hsize = 0;
+
}
-
- if(out_size > *osamp)
- out_size = *osamp;
-
- *osamp = out_size;
- if(ibuf != NULL) {
- for(k=0;k < out_size;k++)
- obuf[k] = ((int) temp_buf[k]) << 16;
- } else {
+ {
+ long *q;
+ long out_size;
+ long oskip;
+ Float *out_buf;
+ int k;
- /* Wait for all-zero samples to come through.
- Should happen eventually with all-zero
- input */
- int found = 0;
+ oskip = rate->oskip;
+ out_size = s1->held;
+ out_buf = s1->window + s1->hsize;
- for(k=0; k < out_size; k++) {
- obuf[k] = ((int) temp_buf[k] << 16);
- if(obuf[k] != 0)
- found = 1;
+ if(ibuf == NULL && out_size > ceil(rate->inpipe)) {
+ out_size = ceil(rate->inpipe);
}
- if(!found)
- *osamp = 0;
+
+ if (out_size > oskip + *osamp) out_size = oskip + *osamp;
+
+ for(q=obuf, k=oskip; k < out_size; k++)
+ *q++ = out_buf[k] * ISCALE; /* should clip-limit */
+
+ *osamp = q-obuf;
+ rate->inpipe -= *osamp;
+ oskip -= out_size - *osamp;
+ rate->oskip = oskip;
+
+ s1->hsize += out_size;
+ s1->held -= out_size;
+ if (s1->held == 0) {
+ s1->hsize = 0;
+ }
+
}
+
}
/*
* Process tail of input samples.
*/
-void poly_drain(effp, obuf, osamp)
-eff_t effp;
-long *obuf;
-long *osamp;
+void poly_drain(eff_t effp, long *obuf, long *osamp)
{
- long in_size = 1024;
-
+ long in_size;
/* Call "flow" with NULL input. */
poly_flow(effp, NULL, obuf, &in_size, osamp);
}
@@ -613,39 +620,16 @@
* Do anything required when you stop reading samples.
* Don't close input file!
*/
-void poly_stop(effp)
-eff_t effp;
+void poly_stop(eff_t effp)
{
- List *t, *t2;
poly_t rate = (poly_t) effp->priv;
+ polystage *s;
int k;
- /* Free lists */
- for(t = rate->l1; t != NULL; ) {
- t2 = t->next;
- t->next = NULL;
- if(t->data_buffer != NULL)
- free((void *) t->data_buffer);
- free((void *) t);
- t = t2;
+ for(k = 0; k <= rate->total; k++) {
+ s = rate->stage[k];
+ free((void *) s->window);
+ if (s->filt_array) free((void *) s->filt_array);
+ free((void *) s);
}
-
- for(t = rate->l2; t != NULL; ) {
- t2 = t->next;
- t->next = NULL;
- if(t->data_buffer != NULL)
- free((void *) t->data_buffer);
- free((void *) t);
- t = t2;
- }
-
- for(k = 0; k < rate->total;k++) {
- free((void *) rate->past_hist[k]);
- free((void *) rate->filt_array[k]);
- }
-
- free((void *) rate->past_hist);
- free((void *) rate->filt_array);
- free((void *) rate->filt_len);
}
-
--- a/src/raw.c
+++ b/src/raw.c
@@ -26,8 +26,13 @@
#include <malloc.h>
#endif
+#include <string.h>
#include <stdlib.h>
+#ifndef HAVE_MEMMOVE
+#define memmove(dest, src, len) bcopy((src), (dest), (len))
+#endif
+
void rawstartread(ft)
ft_t ft;
{
@@ -59,8 +64,7 @@
{
if (ft->file.eof)
return(0);
- ft->file.count = fread(ft->file.buf, 1, ft->file.size,
- ft->fp);
+ ft->file.count = fread(ft->file.buf, 1, ft->file.size, ft->fp);
ft->file.pos = 0;
if (ft->file.count == 0)
{
@@ -72,63 +76,49 @@
return (rval);
}
-unsigned short blockrshort(ft)
-ft_t ft;
+static void swapn(p, n)
+char *p;
+int n;
{
- unsigned short rval;
- if (ft->file.pos > ft->file.count-2)
- {
- if (ft->file.eof)
- return(0);
-
- if (ft->file.pos == ft->file.count-1)
- {
- *ft->file.buf = *(ft->file.buf + ft->file.pos);
- ft->file.count = fread(ft->file.buf + 1,
- 1, ft->file.size-1,
- ft->fp);
+ char *q;
+ if (n>1) {
+ q = p+n-1;
+ while (q>p) {
+ char t = *q;
+ *q-- = *p;
+ *p++ = t;
}
- else
- {
- ft->file.count = fread(ft->file.buf, 1, ft->file.size,
- ft->fp);
- }
- ft->file.pos = 0;
- if (ft->file.count < 2)
- {
- ft->file.eof = 1;
- return(0);
- }
}
- rval = *((unsigned short *)(ft->file.buf + ft->file.pos));
- ft->file.pos += 2;
- if (ft->swap)
- rval = swapw(rval);
- return(rval);
}
-float blockrfloat(ft)
+static void blockr(p0, n, ft)
ft_t ft;
+int n;
+void *p0;
{
- float rval;
-
- if (ft->file.count < sizeof(float))
+ int rest;
+ char *p;
+ p = p0;
+
+ while ((rest = ft->file.count - ft->file.pos) < n)
{
- ft->file.count = fread(ft->file.buf, 1, ft->file.size,
- ft->fp);
- if (ft->file.count == 0)
- {
- ft->file.eof = 1;
- return(0);
+ if (ft->file.eof) {
+ memset(p,0,n);
+ return;
}
+
+ memmove(ft->file.buf, ft->file.buf+ft->file.pos, rest);
+
+ ft->file.pos = 0;
+ ft->file.count = rest;
+ ft->file.count += fread(ft->file.buf+rest, 1, ft->file.size-rest, ft->fp);
+ ft->file.eof = (ft->file.count < n);
}
- rval = *((float *)(ft->file.buf + (ft->file.size - ft->file.count)));
- ft->file.count -= sizeof(float);
+ memcpy(p, ft->file.buf + ft->file.pos, n);
+ ft->file.pos += n;
if (ft->swap)
- rval = swapf(rval);
- return(rval);
+ swapn(p,n);
}
-
LONG rawread(ft, buf, nsamp)
ft_t ft;
@@ -193,7 +183,9 @@
{
case SIGN2:
while(done < nsamp) {
- datum = blockrshort(ft);
+ short s;
+ blockr(&s, sizeof(short), ft);
+ datum = s;
if (ft->file.eof)
return done;
/* scale signed up to long's range */
@@ -203,7 +195,9 @@
return done;
case UNSIGNED:
while(done < nsamp) {
- datum = blockrshort(ft);
+ unsigned short s;
+ blockr(&s, sizeof(short), ft);
+ datum = s;
if (ft->file.eof)
return done;
/* Convert to signed */
@@ -221,12 +215,28 @@
return done;
}
break;
+ case DWORD:
+ switch(ft->info.style)
+ {
+ case SIGN2:
+ while(done < nsamp) {
+ blockr(buf, sizeof(LONG), ft);
+ if (ft->file.eof)
+ return done;
+ /* scale signed up to long's range */
+ buf++;
+ done++;
+ }
+ return done;
+ }
+ break;
case FLOAT:
while(done < nsamp) {
- datum = blockrfloat(ft);
+ float f;
+ blockr(&f, sizeof(float), ft);
if (ft->file.eof)
return done;
- *buf++ = LEFT(datum, 16);
+ *buf++ = f * 0x10000; /* hmm... */
done++;
}
return done;
@@ -244,7 +254,7 @@
free(ft->file.buf);
}
-void blockflush(ft)
+static void blockflush(ft)
ft_t ft;
{
if (fwrite(ft->file.buf, 1, ft->file.pos, ft->fp) != ft->file.pos)
@@ -263,33 +273,22 @@
ft->file.pos++;
}
-void blockwshort(ft,ui)
+static void blockw(p0, n, ft)
+void *p0;
+int n;
ft_t ft;
-unsigned short ui;
{
- if (ft->file.pos > ft->file.size-2) blockflush(ft);
+ if (ft->file.pos > ft->file.size-n) blockflush(ft);
+ memcpy(ft->file.buf + ft->file.pos, p0, n);
if (ft->swap)
- ui = swapw(ui);
- *(unsigned short *)(ft->file.buf + ft->file.pos) = ui;
- ft->file.pos += 2;
+ swapn(ft->file.pos, n);
+ ft->file.pos += n;
}
-void blockwfloat(ft,f)
-ft_t ft;
-float f;
-{
- if (ft->file.pos > ft->file.size - sizeof(float)) blockflush(ft);
- if (ft->swap)
- f = swapf(f);
- *(float *)(ft->file.buf + ft->file.pos) = f;
- ft->file.pos += sizeof(float);
-}
-
/* Convert the sox internal signed long format */
/* to the raw file data, and write it. */
-void
-rawwrite(ft, buf, nsamp)
+void rawwrite(ft, buf, nsamp)
ft_t ft;
LONG *buf, nsamp;
{
@@ -347,19 +346,22 @@
{
case SIGN2:
while(done < nsamp) {
+ short s;
/* scale signed up to long's range */
- datum = (int) RIGHT(*buf++, 16);
- blockwshort(ft, datum);
+ datum = *buf++ + 0x8000; /* round for 16 bit */
+ s = RIGHT(datum, 16);
+ blockw(&s, sizeof(short),ft);
done++;
}
return;
case UNSIGNED:
while(done < nsamp) {
+ unsigned short s;
/* scale signed up to long's range */
- datum = (int) RIGHT(*buf++, 16);
+ datum = *buf++ + 0x8000; /* round for 16 bit */
+ s = RIGHT(datum, 16) ^ 0x8000;
/* Convert to unsigned */
- datum ^= 0x8000;
- blockwshort(ft, datum);
+ blockw(&s, sizeof(short),ft);
done++;
}
return;
@@ -371,11 +373,25 @@
return;
}
break;
+ case DWORD:
+ switch(ft->info.style)
+ {
+ case SIGN2:
+ while(done < nsamp) {
+ /* scale signed up to long's range */
+ blockw(buf, sizeof(LONG), ft);
+ buf++;
+ done++;
+ }
+ return;
+ }
+ break;
case FLOAT:
while(done < nsamp) {
+ float f;
/* scale signed up to long's range */
- datum = (int) RIGHT(*buf++, 16);
- blockwfloat(ft, (double) datum);
+ f = (float)*buf++ / 0x10000;
+ blockw(&f, sizeof(float), ft);
done++;
}
return;
@@ -400,115 +416,47 @@
void rawdefaults();
-/* Signed byte */
-void sbstartread(ft)
-ft_t ft;
-{
- ft->info.size = BYTE;
- ft->info.style = SIGN2;
- rawstartread(ft);
- rawdefaults(ft);
+#define STARTREAD(NAME,SIZE,STYLE) \
+void NAME(ft) \
+ft_t ft; \
+{ \
+ ft->info.size = SIZE; \
+ ft->info.style = STYLE; \
+ rawstartread(ft); \
+ rawdefaults(ft); \
}
-void sbstartwrite(ft)
-ft_t ft;
-{
- ft->info.size = BYTE;
- ft->info.style = SIGN2;
- rawstartwrite(ft);
- rawdefaults(ft);
+#define STARTWRITE(NAME,SIZE,STYLE)\
+void NAME(ft) \
+ft_t ft; \
+{ \
+ ft->info.size = SIZE; \
+ ft->info.style = STYLE; \
+ rawstartwrite(ft); \
+ rawdefaults(ft); \
}
-void ubstartread(ft)
-ft_t ft;
-{
- ft->info.size = BYTE;
- ft->info.style = UNSIGNED;
- rawstartread(ft);
- rawdefaults(ft);
-}
+STARTREAD(sbstartread,BYTE,SIGN2)
+STARTREAD(sbstartwrite,BYTE,SIGN2)
-void ubstartwrite(ft)
-ft_t ft;
-{
- ft->info.size = BYTE;
- ft->info.style = UNSIGNED;
- rawstartwrite(ft);
- rawdefaults(ft);
-}
+STARTREAD(ubstartread,BYTE,UNSIGNED)
+STARTREAD(ubstartwrite,BYTE,UNSIGNED)
-void uwstartread(ft)
-ft_t ft;
-{
- ft->info.size = WORD;
- ft->info.style = UNSIGNED;
- rawstartread(ft);
- rawdefaults(ft);
-}
+STARTREAD(uwstartread,WORD,UNSIGNED)
+STARTREAD(uwstartwrite,WORD,UNSIGNED)
-void uwstartwrite(ft)
-ft_t ft;
-{
- ft->info.size = WORD;
- ft->info.style = UNSIGNED;
- rawstartwrite(ft);
- rawdefaults(ft);
-}
+STARTREAD(swstartread,WORD,SIGN2)
+STARTREAD(swstartwrite,WORD,SIGN2)
-void swstartread(ft)
-ft_t ft;
-{
- ft->info.size = WORD;
- ft->info.style = SIGN2;
- rawstartread(ft);
- rawdefaults(ft);
-}
+STARTREAD(slstartread,DWORD,SIGN2)
+STARTREAD(slstartwrite,DWORD,SIGN2)
-void swstartwrite(ft)
-ft_t ft;
-{
- ft->info.size = WORD;
- ft->info.style = SIGN2;
- rawstartwrite(ft);
- rawdefaults(ft);
-}
+STARTREAD(ulstartread,BYTE,ULAW)
+STARTREAD(ulstartwrite,BYTE,ULAW)
-void ulstartread(ft)
-ft_t ft;
-{
- ft->info.size = BYTE;
- ft->info.style = ULAW;
- rawstartread(ft);
- rawdefaults(ft);
-}
+STARTREAD(alstartread,BYTE,ALAW)
+STARTREAD(alstartwrite,BYTE,ALAW)
-void ulstartwrite(ft)
-ft_t ft;
-{
- ft->info.size = BYTE;
- ft->info.style = ULAW;
- rawstartwrite(ft);
- rawdefaults(ft);
-}
-
-void alstartread(ft)
-ft_t ft;
-{
- ft->info.size = BYTE;
- ft->info.style = ALAW;
- rawstartread(ft);
- rawdefaults(ft);
-}
-
-void alstartwrite(ft)
-ft_t ft;
-{
- ft->info.size = BYTE;
- ft->info.style = ALAW;
- rawstartwrite(ft);
- rawdefaults(ft);
-}
-
void rawdefaults(ft)
ft_t ft;
{
@@ -517,5 +465,4 @@
if (ft->info.channels == -1)
ft->info.channels = 1;
}
-
--- a/src/resampl.h
+++ b/src/resampl.h
@@ -1,4 +1,3 @@
-
/*
* FILE: resample.h
* BY: Julius Smith (at CCRMA, Stanford U)
@@ -8,68 +7,55 @@
* VERS: 2.0 (17-JUN-88, 3:00pm)
*/
-#define MAXNWING 5122
-#define MAXFACTOR 4 /* Maximum Factor without output buff overflow */
+/*
+ * October 29, 1999
+ * Various changes, bugfixes(?), increased precision, by Stan Brooks.
+ *
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
-
-
/* Conversion constants */
-#define Nhc 8
-#define Na 7
-#define Np (Nhc+Na)
-#define Npc (1<<Nhc)
-#define Amask ((1<<Na)-1)
-#define Pmask ((1<<Np)-1)
-#define Nh 16
-#define Nb 16
-#define Nhxn 14
-#define Nhg (Nh-Nhxn)
-#define NLpScl 13
+#define Lc 7
+#define Nc (1<<Lc)
+#define La 16
+#define Na (1<<La)
+#define Lp (Lc+La)
+#define Np (1<<Lp)
+#define Amask (Na-1)
+#define Pmask (Np-1)
+#define MAXNWING (80<<Lc)
/* Description of constants:
*
- * Npc - is the number of look-up values available for the lowpass filter
+ * Nc - is the number of look-up values available for the lowpass filter
* between the beginning of its impulse response and the "cutoff time"
* of the filter. The cutoff time is defined as the reciprocal of the
* lowpass-filter cut off frequence in Hz. For example, if the
- * lowpass filter were a sinc function, Npc would be the index of the
+ * lowpass filter were a sinc function, Nc would be the index of the
* impulse-response lookup-table corresponding to the first zero-
* crossing of the sinc function. (The inverse first zero-crossing
* time of a sinc function equals its nominal cutoff frequency in Hz.)
- * Npc must be a power of 2 due to the details of the current
- * implementation. The default value of 512 is sufficiently high that
+ * Nc must be a power of 2 due to the details of the current
+ * implementation. The default value of 128 is sufficiently high that
* using linear interpolation to fill in between the table entries
- * gives approximately 16-bit accuracy in filter coefficients.
+ * gives approximately 16-bit precision, and quadratic interpolation
+ * gives about 23-bit (float) precision in filter coefficients.
*
- * Nhc - is log base 2 of Npc.
+ * Lc - is log base 2 of Nc.
*
- * Na - is the number of bits devoted to linear interpolation of the
+ * La - is the number of bits devoted to linear interpolation of the
* filter coefficients.
*
- * Np - is Na + Nhc, the number of bits to the right of the binary point
+ * Lp - is La + Lc, the number of bits to the right of the binary point
* in the integer "time" variable. To the left of the point, it indexes
* the input array (X), and to the right, it is interpreted as a number
- * between 0 and 1 sample of the input X. Np must be less than 16 in
- * this implementation.
+ * between 0 and 1 sample of the input X. The default value of 23 is
+ * about right. There is a constraint that the filter window must be
+ * "addressable" in a LONG int, more precisely, if Nmult is the number
+ * of sinc zero-crossings in the right wing of the filter window, then
+ * (Nwing<<Lp) must be expressible in 31 bits.
*
- * Nh - is the number of bits in the filter coefficients. The sum of Nh and
- * the number of bits in the input data (typically 16) cannot exceed 32.
- * Thus Nh should be 16. The largest filter coefficient should nearly
- * fill 16 bits (32767).
- *
- * Nb - is the number of bits in the input data. The sum of Nb and Nh cannot
- * exceed 32.
- *
- * Nhxn - is the number of bits to right shift after multiplying each input
- * sample times a filter coefficient. It can be as great as Nh and as
- * small as 0. Nhxn = Nh-2 gives 2 guard bits in the multiply-add
- * accumulation. If Nhxn=0, the accumulation will soon overflow 32 bits.
- *
- * Nhg - is the number of guard bits in mpy-add accumulation (equal to Nh-Nhxn).
- *
- * NLpScl - is the number of bits allocated to the unity-gain normalization
- * factor. The output of the lowpass filter is multiplied by LpScl and
- * then right-shifted NLpScl bits. To avoid overflow, we must have
- * Nb+Nhg+NLpScl < 32.
*/
-
--- a/src/resample.c
+++ b/src/resample.c
@@ -28,6 +28,16 @@
* too low by 2 when downsampling.
* Andreas Wilde, 12. Feb. 1999, andreas@eakaw2.et.tu-dresden.de
*/
+/*
+ * October 29, 1999
+ * Various changes, bugfixes(?), increased precision, by Stan Brooks.
+ *
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
#include <math.h>
#include <stdlib.h>
#ifdef HAVE_MALLOC_H
@@ -39,67 +49,52 @@
#include "resdefs.h"
#include "resampl.h"
-#define IBUFFSIZE 4096 /* Input buffer size */
-#define OBUFFSIZE (IBUFFSIZE*MAXFACTOR+2) /* Calc'd out buffer size */
+#define Float double/*float*/
+#define ISCALE 0x10000
+#define BUFFSIZE 8192 /*16384*/ /* Total buffer size */
+#define L64 long long
+
/* Private data for Lerp via LCM file */
typedef struct resamplestuff {
- double Factor; /* Factor = Fout/Fin sample rates */
- double rolloff; /* roll-off frequency */
- double beta; /* passband/stopband tuning magic */
- short InterpFilt; /* TRUE means interpolate filter coeffs */
- UHWORD Oskip; /* number of bogus output samples at start */
- UHWORD LpScl, Nmult, Nwing;
- HWORD *Imp; /* impulse [MAXNWING] Filter coefficients */
- HWORD *ImpD; /* [MAXNWING] ImpD[n] = Imp[n+1]-Imp[n] */
- /* for resample main loop */
- UWORD Time; /* Current time/pos in input sample */
- UHWORD Xp, Xoff, Xread;
- HWORD *X, *Y; /* I/O buffers */
+ double Factor; /* Factor = Fout/Fin sample rates */
+ double rolloff; /* roll-off frequency */
+ double beta; /* passband/stopband tuning magic */
+ int quadr; /* non-zero to use qprodUD quadratic interpolation */
+ LONG Nmult;
+ LONG Nwing;
+ LONG Nq;
+ Float *Imp; /* impulse [Nwing+1] Filter coefficients */
+ double Time; /* Current time/pos in input sample */
+ LONG dhb;
+ LONG Xh; /* number of past/future samples needed by filter */
+ LONG Xoff; /* Xh plus some room for creep */
+ LONG Xread; /* X[Xread] is start-position to enter new samples */
+ LONG Xp; /* X[Xp] is position to start filter application */
+ LONG Xsize,Ysize; /* size (Floats) of X[],Y[] */
+ Float *X, *Y; /* I/O buffers */
} *resample_t;
-int makeFilter(P6(HWORD Imp[],
- HWORD ImpD[],
- UHWORD *LpScl,
- UHWORD Nwing,
+void LpFilter(P5(double c[],
+ LONG N,
+ double frq,
+ double Beta,
+ LONG Num));
+
+int makeFilter(P5(Float Imp[],
+ LONG Nwing,
double Froll,
- double Beta));
-HWORD SrcUp(P10(HWORD X[],
- HWORD Y[],
- double Factor,
- UWORD *Time,
- UHWORD Nx,
- UHWORD Nwing,
- UHWORD LpScl,
- HWORD Imp[],
- HWORD ImpD[],
- BOOL Interp));
-HWORD SrcUD(P10(HWORD X[],
- HWORD Y[],
- double Factor,
- UWORD *Time,
- UHWORD Nx,
- UHWORD Nwing,
- UHWORD LpScl,
- HWORD Imp[],
- HWORD ImpD[],
- BOOL Interp));
-IWORD FilterUp(P7(HWORD Imp[],
- HWORD ImpD[],
- UHWORD Nwing,
- BOOL Interp,
- HWORD *Xp,
- HWORD Ph,
- HWORD Inc));
-IWORD FilterUD(P8(HWORD Imp[],
- HWORD ImpD[],
- UHWORD Nwing,
- BOOL Interp,
- HWORD *Xp,
- HWORD Ph,
- HWORD Inc,
- UHWORD dhb));
+ double Beta,
+ LONG Num));
+static LONG SrcUD(P2(resample_t r, LONG Nx));
+
+
+#if 0
+static u_int32_t iprodC;
+static u_int32_t iprodM;
+#endif
+
/*
* Process options
*/
@@ -108,25 +103,48 @@
int n;
char **argv;
{
- resample_t resample = (resample_t) effp->priv;
+ resample_t r = (resample_t) effp->priv;
/* These defaults are conservative with respect to aliasing. */
- resample->rolloff = 0.8;
- resample->beta = 17.5;
+ r->rolloff = 0.8;
+ r->beta = 16; /* anything <=2 means Nutall window */
+ r->quadr = 0;
+ r->Nmult = 39;
/* This used to fail, but with sox-12.15 it works. AW */
- if ((n >= 1) && !sscanf(argv[0], "%lf", &resample->rolloff))
- fail("Usage: resample [ rolloff [ beta ] ]");
- else if ((resample->rolloff < 0.01) || (resample->rolloff > 1.0))
- fail("resample: rolloff factor (%f) no good, should be 0.01<x<1.0",
- resample->rolloff);
- if ((n >= 2) && !sscanf(argv[1], "%lf", &resample->beta))
- fail("Usage: resample [ rolloff [ beta ] ]");
- else if (resample->beta < 1.0)
- fail("resample: beta factor (%f) no good, should be >= 1.0",
- resample->beta);
- report("resample opts: %f, %f\n",
- resample->rolloff, resample->beta);
+ if ((n >= 1)) {
+ if (!strcmp(argv[0], "-qs")) {
+ r->quadr = 1;
+ n--; argv++;
+ }
+ else if (!strcmp(argv[0], "-q")) {
+ r->rolloff = 0.9;
+ r->quadr = 1;
+ r->Nmult = 75;
+ n--; argv++;
+ }
+ else if (!strcmp(argv[0], "-ql")) {
+ r->rolloff = 0.9;
+ r->quadr = 1;
+ r->Nmult = 149;
+ n--; argv++;
+ }
+ }
+
+ if ((n >= 1) && !sscanf(argv[0], "%lf", &r->rolloff))
+ fail("Usage: resample [ rolloff [ beta ] ]");
+ else if ((r->rolloff <= 0.01) || (r->rolloff >= 1.0))
+ fail("resample: rolloff factor (%f) no good, should be 0.01<x<1.0", r->rolloff);
+
+ if ((n >= 2) && !sscanf(argv[1], "%lf", &r->beta))
+ fail("Usage: resample [ rolloff [ beta ] ]");
+ else if (r->beta <= 2.0) {
+ r->beta = 0;
+ report("resample opts: Nuttall window, cutoff %f\n", r->rolloff);
+ } else {
+ report("resample opts: Kaiser window, cutoff %f, beta %f\n", r->rolloff, r->beta);
+ }
+
}
/*
@@ -135,69 +153,63 @@
void resample_start(effp)
eff_t effp;
{
- resample_t resample = (resample_t) effp->priv;
+ resample_t r = (resample_t) effp->priv;
+ LONG Xoff;
int i;
-
- resample->InterpFilt = 1; /* interpolate filter: slower */
- resample->Factor =
- (double)effp->outinfo.rate / (double)effp->ininfo.rate;
-
- /* Check for illegal constants */
- if (Np >= 16)
- fail("Error: Np>=16");
- if (Nb+Nhg+NLpScl >= 32)
- fail("Error: Nb+Nhg+NLpScl>=32");
- if (Nh+Nb > 32)
- fail("Error: Nh+Nb>32");
+ r->Factor = (double)effp->outinfo.rate / (double)effp->ininfo.rate;
- resample->Imp = (HWORD *) malloc(sizeof(HWORD) * MAXNWING);
- resample->ImpD = (HWORD *) malloc(sizeof(HWORD) * MAXNWING);
- resample->X = (HWORD *) malloc(sizeof(HWORD) * IBUFFSIZE);
- resample->Y = (HWORD *) malloc(sizeof(HWORD) * OBUFFSIZE);
+ r->Nq = Nc; /* for now */
- /* upsampling requires smaller Nmults */
- for(resample->Nmult = 37; resample->Nmult > 1; resample->Nmult -= 2) {
- /* # of filter coeffs in right wing */
- resample->Nwing = Npc*(resample->Nmult+1)/2;
- /* This prevents just missing last coeff */
- /* for integer conversion factors */
- resample->Nwing += Npc/2 + 1;
+ /* Check for illegal constants */
+# if 0
+ if (Lp >= 16) fail("Error: Lp>=16");
+ if (Nb+Nhg+NLpScl >= 32) fail("Error: Nb+Nhg+NLpScl>=32");
+ if (Nh+Nb > 32) fail("Error: Nh+Nb>32");
+# endif
- /* returns error # or 0 for success */
- if (makeFilter(resample->Imp, resample->ImpD,
- &resample->LpScl, resample->Nwing,
- resample->rolloff, resample->beta))
- continue;
- else
- break;
-
- }
+ /* Nwing: # of filter coeffs in right wing */
+ r->Nwing = r->Nq * (r->Nmult/2+1) + 1;
- if(resample->Nmult == 1)
+ r->Imp = (Float *)malloc(sizeof(Float) * (r->Nwing+2)) + 1;
+ /* need Imp[-1] and Imp[Nwing] for quadratic interpolation */
+ /* returns error # <=0, or adjusted wing-len > 0 */
+ i = makeFilter(r->Imp, r->Nwing, r->rolloff, r->beta, r->Nq);
+ if (i <= 0)
fail("resample: Unable to make filter\n");
- if (resample->Factor < 1)
- resample->LpScl = resample->LpScl*resample->Factor + 0.5;
- /* Calc reach of LP filter wing & give some creeping room */
- resample->Xoff = ((resample->Nmult+1)/2.0) *
- MAX(1.0,1.0/resample->Factor) + 10;
- if (IBUFFSIZE < 2*resample->Xoff) /* Check input buffer size */
- fail("IBUFFSIZE (or Factor) is too small");
+ report("Nmult: %ld, Nwing: %ld, Nq: %ld\n",r->Nmult,r->Nwing,r->Nq);
- /* Current "now"-sample pointer for input */
- resample->Xp = resample->Xoff;
+ r->dhb = Np; /* Fixed-point Filter sampling-time-increment */
+ if (r->Factor<1.0) r->dhb = r->Factor*Np + 0.5;
+ r->Xh = (r->Nwing<<La)/r->dhb;
+ /* (Xh * dhb)>>La is max index into Imp[] */
+
+ /* reach of LP filter wings + some creeping room */
+ Xoff = r->Xh + 10;
+ r->Xoff = Xoff;
+
+ /* Current "now"-sample pointer for input to filter */
+ r->Xp = Xoff;
/* Position in input array to read into */
- resample->Xread = resample->Xoff;
+ r->Xread = Xoff;
/* Current-time pointer for converter */
- resample->Time = (resample->Xoff<<Np);
+ r->Time = Xoff;
- /* Set sample drop at beginning */
- resample->Oskip = resample->Xread * resample->Factor;
+ i = BUFFSIZE - 2*Xoff;
+ if (i < r->Factor + 1.0/r->Factor) /* Check input buffer size */
+ fail("Factor is too small or large for BUFFSIZE");
+
+ r->Xsize = 2*Xoff + i/(1.0+r->Factor);
+ r->Ysize = BUFFSIZE - r->Xsize;
+ report("Xsize %d, Ysize %d, Xoff %d",r->Xsize,r->Ysize,r->Xoff);
- /* Need Xoff zeros at begining of sample */
- for (i=0; i<resample->Xoff; i++)
- resample->X[i] = 0;
+ r->X = (Float *) malloc(sizeof(Float) * (BUFFSIZE));
+ r->Y = r->X + r->Xsize;
+
+ /* Need Xoff zeros at beginning of sample */
+ for (i=0; i<Xoff; i++)
+ r->X[i] = 0;
}
/*
@@ -210,89 +222,78 @@
LONG *ibuf, *obuf;
LONG *isamp, *osamp;
{
- resample_t resample = (resample_t) effp->priv;
- LONG i, last, creep, Nout, Nx;
- UHWORD Nproc;
+ resample_t r = (resample_t) effp->priv;
+ LONG i, last, Nout, Nx, Nproc;
/* constrain amount we actually process */
- Nproc = IBUFFSIZE - resample->Xp;
- if (Nproc * resample->Factor >= OBUFFSIZE)
- Nproc = OBUFFSIZE / resample->Factor;
- if (Nproc * resample->Factor >= *osamp)
- Nproc = *osamp / resample->Factor;
-
- Nx = Nproc - resample->Xread;
+ //fprintf(stderr,"Xp %d, Xread %d, isamp %d, ",r->Xp, r->Xread,*isamp);
+
+ Nproc = r->Xsize - r->Xp;
+
+ i = MIN(r->Ysize, *osamp);
+ if (Nproc * r->Factor >= i)
+ Nproc = i / r->Factor;
+
+ Nx = Nproc - r->Xread; /* space for right-wing future-data */
if (Nx <= 0)
- fail("Nx negative: %d", Nx);
- if (Nx > *isamp) {
+ fail("Nx not positive: %d", Nx);
+ if (Nx > *isamp)
Nx = *isamp;
+ //fprintf(stderr,"Nx %d\n",Nx);
+
+ if (ibuf == NULL) {
+ for(i = r->Xread; i < Nx + r->Xread ; i++)
+ r->X[i] = 0;
+ } else {
+ for(i = r->Xread; i < Nx + r->Xread ; i++)
+ r->X[i] = (Float)(*ibuf++)/ISCALE;
}
- for(i = resample->Xread; i < Nx + resample->Xread ; i++)
- resample->X[i] = RIGHT(*ibuf++ + 0x8000, 16);
last = i;
- Nproc = last - (resample->Xoff * 2);
- for(; i < last + resample->Xoff ; i++)
- resample->X[i] = 0;
+ Nproc = last - r->Xoff - r->Xp;
- /* If we're draining out a buffer tail,
- * just do it next time or in drain.
- */
- if ((Nx == *isamp) && (Nx <= resample->Xoff)) {
+ if (Nproc <= 0) {
/* fill in starting here next time */
- resample->Xread = last;
+ r->Xread = last;
/* leave *isamp alone, we consumed it */
*osamp = 0;
return;
}
-
-
- /* SrcUp() is faster if we can use it */
- if (resample->Factor > 1) /* Resample stuff in input buffer */
- Nout = SrcUp(resample->X, resample->Y,
- resample->Factor, &resample->Time, Nproc,
- resample->Nwing, resample->LpScl,
- resample->Imp, resample->ImpD,
- resample->InterpFilt);
- else
- Nout = SrcUD(resample->X, resample->Y,
- resample->Factor, &resample->Time, Nproc,
- resample->Nwing, resample->LpScl,
- resample->Imp, resample->ImpD,
- resample->InterpFilt);
-
+ Nout = SrcUD(r, Nproc);
+ //fprintf(stderr,"Nproc %d --> %d\n",Nproc,Nout);
/* Move converter Nproc samples back in time */
- resample->Time -= (Nproc<<Np);
- /* Advance by number of samples processed */
- resample->Xp += Nproc;
+ r->Time -= Nproc;
+ /* Advance by number of samples processed */
+ r->Xp += Nproc;
/* Calc time accumulation in Time */
- creep = (resample->Time>>Np) - resample->Xoff;
- if (creep)
{
- resample->Time -= (creep<<Np); /* Remove time accumulation */
- resample->Xp += creep; /* and add it to read pointer */
+ LONG creep = r->Time - r->Xoff;
+ if (creep)
+ {
+ r->Time -= creep; /* Remove time accumulation */
+ r->Xp += creep; /* and add it to read pointer */
+ /* fprintf(stderr,"Nproc %ld, creep %ld\n",Nproc,creep); */
+ }
}
+ {
+ LONG i,k;
/* Copy back portion of input signal that must be re-used */
- for (i=0; i<last - resample->Xp + resample->Xoff; i++)
- resample->X[i] = resample->X[i + resample->Xp - resample->Xoff];
+ k = r->Xp - r->Xoff;
+ //fprintf(stderr,"k %d, last %d\n",k,last);
+ for (i=0; i<last - k; i++)
+ r->X[i] = r->X[i+k];
/* Pos in input buff to read new data into */
- resample->Xread = i;
- resample->Xp = resample->Xoff;
+ r->Xread = i;
+ r->Xp = r->Xoff;
- /* copy to output buffer, zero-filling beginning */
- /* zero-fill to preserve length and loop points */
- for(i = 0; i < resample->Oskip; i++) {
- *obuf++ = 0;
- }
- for(i = resample->Oskip; i < Nout + resample->Oskip; i++) {
- *obuf++ = LEFT(resample->Y[i], 16);
- }
+ for(i=0; i < Nout; i++)
+ *obuf++ = r->Y[i] * ISCALE;
*isamp = Nx;
*osamp = Nout;
- resample->Oskip = 0;
+ }
}
/*
@@ -300,46 +301,33 @@
*/
void resample_drain(effp, obuf, osamp)
eff_t effp;
-ULONG *obuf;
-ULONG *osamp;
+LONG *obuf;
+LONG *osamp;
{
- resample_t resample = (resample_t) effp->priv;
- LONG i, Nout;
- UHWORD Nx;
+ resample_t r = (resample_t) effp->priv;
+ LONG i, Nout, Nx;
- Nx = resample->Xread - resample->Xoff;
- if (Nx <= resample->Xoff * 2) {
- /* zero-fill end */
- for(i = 0; i < resample->Xoff; i++)
- *obuf++ = 0;
- *osamp = resample->Xoff;
- return;
- }
+ //fprintf(stderr,"Xp %d, Xread %d <--- DRAIN\n",r->Xp, r->Xread);
+ if (r->Xsize - r->Xread < r->Xoff)
+ fail("resample_drain: Problem!\n");
- if (Nx * resample->Factor >= *osamp)
+ /* fill out end with Xoff zeros */
+ for(i = 0; i < r->Xoff; i++)
+ r->X[i + r->Xread] = 0;
+
+ Nx = r->Xread - r->Xp;
+
+ if (Nx * r->Factor >= *osamp)
fail("resample_drain: Overran output buffer!\n");
- /* fill out end with zeros */
- for(i = 0; i < resample->Xoff; i++)
- resample->X[i + resample->Xread] = 0;
- /* SrcUp() is faster if we can use it */
- if (resample->Factor >= 1) /* Resample stuff in input buffer */
- Nout = SrcUp(resample->X, resample->Y,
- resample->Factor, &resample->Time, Nx,
- resample->Nwing, resample->LpScl,
- resample->Imp, resample->ImpD,
- resample->InterpFilt);
- else
- Nout = SrcUD(resample->X, resample->Y,
- resample->Factor, &resample->Time, Nx,
- resample->Nwing, resample->LpScl,
- resample->Imp, resample->ImpD,
- resample->InterpFilt);
-
- for(i = resample->Oskip; i < Nout; i++) {
- *obuf++ = LEFT(resample->Y[i], 16);
- }
- *osamp = Nout - resample->Oskip;
+ /* Resample stuff in input buffer */
+ Nout = SrcUD(r, Nx);
+ //fprintf(stderr,"Nproc %d --> %d\n",Nx,Nout);
+
+ for(i = 0; i < Nout; i++)
+ *obuf++ = r->Y[i] * ISCALE;
+
+ *osamp = Nout;
}
/*
@@ -349,160 +337,183 @@
void resample_stop(effp)
eff_t effp;
{
- resample_t resample = (resample_t) effp->priv;
+ resample_t r = (resample_t) effp->priv;
- free(resample->Imp);
- free(resample->ImpD);
- free(resample->X);
- free(resample->Y);
+ free(r->Imp - 1);
+ free(r->X);
+ /* free(r->Y); Y is in same block starting at X */
+ /*report("iC %d, iM %d, ratio %d", iprodC, iprodM, iprodM/iprodC);*/
}
-/* From resample:filters.c */
-
-/* Sampling rate up-conversion only subroutine;
- * Slightly faster than down-conversion;
- */
-HWORD SrcUp(X, Y, Factor, Time, Nx, Nwing, LpScl, Imp, ImpD, Interp)
-HWORD X[], Y[];
-double Factor;
-UWORD *Time;
-UHWORD Nx, Nwing, LpScl;
-HWORD Imp[], ImpD[];
-BOOL Interp;
+/* over 90% of CPU time spent in this iprodUD() function */
+/* quadratic interpolation */
+static double qprodUD(Imp, Xp, Inc, T0, dhb, ct)
+const Float Imp[], *Xp;
+LONG Inc, dhb, ct;
+double T0;
{
- HWORD *Xp, *Ystart;
- IWORD v;
+ const double f = 1.0/(1<<La);
+ double v;
+ LONG Ho;
- double dt; /* Step through input signal */
- UWORD dtb; /* Fixed-point version of Dt */
- UWORD endTime; /* When Time reaches EndTime, return to user */
+ Ho = T0 * dhb;
+ Ho += (ct-1)*dhb; /* so Float sum starts with smallest coef's */
+ Xp += (ct-1)*Inc;
+ v = 0;
+ do {
+ Float coef;
+ LONG Hoh;
+ Hoh = Ho>>La;
+ coef = Imp[Hoh];
+ {
+ Float dm,dp,t;
+ dm = coef - Imp[Hoh-1];
+ dp = Imp[Hoh+1] - coef;
+ t =(Ho & Amask) * f;
+ coef += ((dp-dm)*t + (dp+dm))*t*0.5;
+ }
+ /* filter coef, lower La bits by quadratic interpolation */
+ v += coef * *Xp; /* sum coeff * input sample */
+ Xp -= Inc; /* Input signal step. NO CHECK ON ARRAY BOUNDS */
+ Ho -= dhb; /* IR step */
+ } while(--ct);
+ return v;
+}
- dt = 1.0/Factor; /* Output sampling period */
- dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */
+/* linear interpolation */
+static double iprodUD(Imp, Xp, Inc, T0, dhb, ct)
+const Float Imp[], *Xp;
+LONG Inc, dhb, ct;
+double T0;
+{
+ const double f = 1.0/(1<<La);
+ double v;
+ LONG Ho;
- Ystart = Y;
- endTime = *Time + (1<<Np)*(IWORD)Nx;
- while (*Time < endTime)
- {
- Xp = &X[*Time>>Np]; /* Ptr to current input sample */
- v = FilterUp(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),
- -1); /* Perform left-wing inner product */
- v += FilterUp(Imp, ImpD, Nwing, Interp, Xp+1, (HWORD)((-*Time)&Pmask),
- 1); /* Perform right-wing inner product */
- v >>= Nhg; /* Make guard bits */
- v *= LpScl; /* Normalize for unity filter gain */
- *Y++ = v>>NLpScl; /* Deposit output */
- *Time += dtb; /* Move to next sample by time increment */
- }
- return (Y - Ystart); /* Return the number of output samples */
+ Ho = T0 * dhb;
+ Ho += (ct-1)*dhb; /* so Float sum starts with smallest coef's */
+ Xp += (ct-1)*Inc;
+ v = 0;
+ do {
+ Float coef;
+ LONG Hoh;
+ Hoh = Ho>>La;
+ /* if (Hoh >= End) break; */
+ coef = Imp[Hoh] + (Imp[Hoh+1]-Imp[Hoh]) * (Ho & Amask) * f;
+ /* filter coef, lower La bits by linear interpolation */
+ v += coef * *Xp; /* sum coeff * input sample */
+ Xp -= Inc; /* Input signal step. NO CHECK ON ARRAY BOUNDS */
+ Ho -= dhb; /* IR step */
+ } while(--ct);
+ return v;
}
-
+/* From resample:filters.c */
/* Sampling rate conversion subroutine */
-HWORD SrcUD(X, Y, Factor, Time, Nx, Nwing, LpScl, Imp, ImpD, Interp)
-HWORD X[], Y[];
-double Factor;
-UWORD *Time;
-UHWORD Nx, Nwing, LpScl;
-HWORD Imp[], ImpD[];
-BOOL Interp;
+static LONG SrcUD(r, Nx)
+resample_t r;
+LONG Nx;
{
- HWORD *Xp, *Ystart;
- IWORD v;
-
- double dh; /* Step through filter impulse response */
+ Float *Ystart, *Y;
+ double Factor;
double dt; /* Step through input signal */
- UWORD endTime; /* When Time reaches EndTime, return to user */
- UWORD dhb, dtb; /* Fixed-point versions of Dh,Dt */
+ double time;
+ double (*prodUD)();
+ int n;
- dt = 1.0/Factor; /* Output sampling period */
- dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */
+ prodUD = (r->quadr)? qprodUD:iprodUD; /* quadratic or linear interp */
+ Factor = r->Factor;
+ time = r->Time;
+ dt = 1.0/Factor; /* Output sampling period */
+ /*fprintf(stderr,"Factor %f, dt %f, ",Factor,dt); */
+ /*fprintf(stderr,"Time %f, ",r->Time);*/
+ /* (Xh * dhb)>>La is max index into Imp[] */
+ /*fprintf(stderr,"ct=%d\n",ct);*/
+ /*fprintf(stderr,"ct=%.2f %d\n",(double)r->Nwing*Na/r->dhb, r->Xh);*/
+ Ystart = Y = r->Y;
+ n = (int)ceil((double)Nx/dt);
+ while(n--)
+ {
+ Float *Xp;
+ double v;
+ double T;
+ T = time-floor(time); /* fractional part of Time */
+ Xp = r->X + (LONG)time; /* Ptr to current input sample */
- dh = MIN(Npc, Factor*Npc); /* Filter sampling period */
- dhb = dh*(1<<Na) + 0.5; /* Fixed-point representation */
+ /* Past inner product: */
+ v = (*prodUD)(r->Imp, Xp, -1, T, r->dhb, r->Xh); /* needs Np*Nmult in 31 bits */
+ /* Future inner product: */
+ v += (*prodUD)(r->Imp, Xp+1, 1, (1.0-T), r->dhb, r->Xh); /* prefer even total */
- Ystart = Y;
- endTime = *Time + (1<<Np)*(IWORD)Nx;
- while (*Time < endTime)
- {
- Xp = &X[*Time>>Np]; /* Ptr to current input sample */
- v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),
- -1, dhb); /* Perform left-wing inner product */
- v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1, (HWORD)((-*Time)&Pmask),
- 1, dhb); /* Perform right-wing inner product */
- v >>= Nhg; /* Make guard bits */
- v *= LpScl; /* Normalize for unity filter gain */
- *Y++ = v>>NLpScl; /* Deposit output */
- *Time += dtb; /* Move to next sample by time increment */
+ if (Factor < 1) v *= Factor;
+ *Y++ = v; /* Deposit output */
+ time += dt; /* Move to next sample by time increment */
}
+ r->Time = time;
+ /*fprintf(stderr,"Time %f\n",r->Time);*/
return (Y - Ystart); /* Return the number of output samples */
}
-void LpFilter();
-
-int makeFilter(Imp, ImpD, LpScl, Nwing, Froll, Beta)
-HWORD Imp[], ImpD[];
-UHWORD *LpScl, Nwing;
+int makeFilter(Imp, Nwing, Froll, Beta, Num)
+Float Imp[];
+LONG Nwing, Num;
double Froll, Beta;
{
- double DCgain, Scl, Maxh;
+ double DCgain;
double *ImpR;
- HWORD Dh;
- LONG i, temp;
+ LONG Mwing, Dh, i;
if (Nwing > MAXNWING) /* Check for valid parameters */
- return(1);
+ return(-1);
if ((Froll<=0) || (Froll>1))
- return(2);
- if (Beta < 1)
- return(3);
+ return(-2);
- ImpR = (double *) malloc(sizeof(double) * MAXNWING);
- LpFilter(ImpR, (int)Nwing, Froll, Beta, Npc); /* Design a Kaiser-window */
- /* Sinc low-pass filter */
+ /* it does help accuracy a bit to have the window stop at
+ * a zero-crossing of the sinc function */
+ Mwing = floor((double)Nwing/(Num/Froll))*(Num/Froll) +0.5;
+ if (Mwing==0)
+ return(-4);
- /* Compute the DC gain of the lowpass filter, and its maximum coefficient
- * magnitude. Scale the coefficients so that the maximum coeffiecient just
- * fits in Nh-bit fixed-point, and compute LpScl as the NLpScl-bit (signed)
- * scale factor which when multiplied by the output of the lowpass filter
- * gives unity gain. */
+ ImpR = (double *) malloc(sizeof(double) * Mwing);
+
+ /* Design a Nuttall or Kaiser windowed Sinc low-pass filter */
+ LpFilter(ImpR, Mwing, Froll, Beta, Num);
+
+ /* 'correct' the DC gain of the lowpass filter */
DCgain = 0;
- Dh = Npc; /* Filter sampling period for factors>=1 */
- for (i=Dh; i<Nwing; i+=Dh)
+ Dh = Num; /* Filter sampling period for factors>=1 */
+ for (i=Dh; i<Mwing; i+=Dh)
DCgain += ImpR[i];
DCgain = 2*DCgain + ImpR[0]; /* DC gain of real coefficients */
+ report("DCgain err=%.12f",DCgain-1.0);
- for (Maxh=i=0; i<Nwing; i++)
- Maxh = MAX(Maxh, fabs(ImpR[i]));
+ for (i=0; i<Mwing; i++) {
+ Imp[i] = ImpR[i]/DCgain;
+ }
+ free(ImpR);
+ for (i=Mwing; i<=Nwing; i++) Imp[i] = 0;
+ /* Imp[Nwing] and Imp[-1] needed for quadratic interpolation */
+ Imp[-1] = Imp[1];
- Scl = ((1<<(Nh-1))-1)/Maxh; /* Map largest coeff to 16-bit maximum */
- temp = fabs((1<<(NLpScl+Nh))/(DCgain*Scl));
- if (temp >= (1L<<16)) {
- free(ImpR);
- return(4); /* Filter scale factor overflows UHWORD */
- }
- *LpScl = temp;
+# if 0
+ {
+ double v = 0;
+ int s=-1;
+ for (i=Num; i<Mwing; i+=Num, s=-s)
+ v += s*Imp[i];
+ report("NYQgain %.12f vs %.12f",Imp[0], -2*v);
+ v = -2*v - Imp[0];
+ v *= (double)Nc/(double)(2*Mwing+1);
+ for (i=0; i<Mwing; i++)
+ Imp[i] += v*cos(M_PI*i/Nc);
- /* Scale filter coefficients for Nh bits and convert to integer */
- if (ImpR[0] < 0) /* Need pos 1st value for LpScl storage */
- Scl = -Scl;
- for (i=0; i<Nwing; i++) /* Scale them */
- ImpR[i] *= Scl;
- for (i=0; i<Nwing; i++) /* Round them */
- Imp[i] = ImpR[i] + 0.5;
-
- /* ImpD makes linear interpolation of the filter coefficients faster */
- for (i=0; i<Nwing-1; i++)
- ImpD[i] = Imp[i+1] - Imp[i];
- ImpD[Nwing-1] = - Imp[Nwing-1]; /* Last coeff. not interpolated */
-
- free(ImpR);
- return(0);
+ }
+# endif
+
+ return(Mwing);
}
-
-
/* LpFilter()
*
* reference: "Digital Filters, 2nd edition"
@@ -557,123 +568,33 @@
temp *= temp;
u *= temp;
sum += u;
- } while (u >= IzeroEPSILON*sum);
+ } while (u >= IzeroEPSILON*sum);
return(sum);
}
-
void LpFilter(c,N,frq,Beta,Num)
double c[], frq, Beta;
-int N, Num;
+LONG N, Num;
{
- double IBeta, temp;
- int i;
+ LONG i;
/* Calculate filter coeffs: */
c[0] = frq;
- for (i=1; i<N; i++)
- {
- temp = PI*(double)i/(double)Num;
- c[i] = sin(temp*frq)/temp;
+ for (i=1; i<N; i++) {
+ double x = M_PI*(double)i/(double)(Num);
+ c[i] = sin(x*frq)/x;
+ }
+
+ if (Beta>2) { /* Apply Kaiser window to filter coeffs: */
+ double IBeta = 1.0/Izero(Beta);
+ for (i=1; i<N; i++) {
+ double x = (double)i / (double)(N);
+ c[i] *= Izero(Beta*sqrt(1.0-x*x)) * IBeta;
}
-
- /* Calculate and Apply Kaiser window to filter coeffs: */
- IBeta = 1.0/Izero(Beta);
- for (i=1; i<N; i++)
- {
- temp = (double)i / ((double)N * (double)1.0);
- c[i] *= Izero(Beta*sqrt(1.0-temp*temp)) * IBeta;
+ } else { /* Apply Nuttall window: */
+ for(i = 0; i < N; i++) {
+ double x = M_PI*i / N;
+ c[i] *= 0.36335819 + 0.4891775*cos(x) + 0.1365995*cos(2*x) + 0.0106411*cos(3*x);
}
+ }
}
-
-
-
-
-IWORD FilterUp(Imp, ImpD, Nwing, Interp, Xp, Ph, Inc)
-HWORD Imp[], ImpD[];
-UHWORD Nwing;
-BOOL Interp;
-HWORD *Xp, Ph, Inc;
-{
- HWORD a=0, *Hp, *Hdp=0, *End;
- IWORD v, t;
-
- v=0;
- Hp = &Imp[Ph>>Na];
- End = &Imp[Nwing];
- if (Interp)
- {
- Hdp = &ImpD[Ph>>Na];
- a = Ph & Amask;
- }
- /* Possible Bug: Hdp and a are not initialized if Interp == 0 */
- if (Inc == 1) /* If doing right wing... */
- { /* ...drop extra coeff, so when Ph is */
- End--; /* 0.5, we don't do too many mult's */
- if (Ph == 0) /* If the phase is zero... */
- { /* ...then we've already skipped the */
- Hp += Npc; /* first sample, so we must also */
- Hdp += Npc; /* skip ahead in Imp[] and ImpD[] */
- }
- }
- while (Hp < End)
- {
- t = *Hp; /* Get filter coeff */
- if (Interp)
- {
- t += (((IWORD)*Hdp)*a)>>Na; /* t is now interp'd filter coeff */
- Hdp += Npc; /* Filter coeff differences step */
- }
- t *= *Xp; /* Mult coeff by input sample */
- if (t & (1<<(Nhxn-1))) /* Round, if needed */
- t += (1<<(Nhxn-1));
- t >>= Nhxn; /* Leave some guard bits, but come back some */
- v += t; /* The filter output */
- Hp += Npc; /* Filter coeff step */
- Xp += Inc; /* Input signal step. NO CHECK ON ARRAY BOUNDS */
- }
- return(v);
-}
-
-
-IWORD FilterUD(Imp, ImpD, Nwing, Interp, Xp, Ph, Inc, dhb)
-HWORD Imp[], ImpD[];
-UHWORD Nwing;
-BOOL Interp;
-HWORD *Xp, Ph, Inc;
-UHWORD dhb;
-{
- HWORD a, *Hp, *Hdp, *End;
- IWORD v, t;
- UWORD Ho;
-
- v=0;
- Ho = (Ph*(UWORD)dhb)>>Np;
- End = &Imp[Nwing];
- if (Inc == 1) /* If doing right wing... */
- { /* ...drop extra coeff, so when Ph is */
- End--; /* 0.5, we don't do too many mult's */
- if (Ph == 0) /* If the phase is zero... */
- Ho += dhb; /* ...then we've already skipped the */
- } /* first sample, so we must also */
- /* skip ahead in Imp[] and ImpD[] */
- while ((Hp = &Imp[Ho>>Na]) < End)
- {
- t = *Hp; /* Get IR sample */
- if (Interp)
- {
- Hdp = &ImpD[Ho>>Na]; /* get interp (lower Na) bits from diff table */
- a = Ho & Amask; /* a is logically between 0 and 1 */
- t += (((IWORD)*Hdp)*a)>>Na; /* t is now interp'd filter coeff */
- }
- t *= *Xp; /* Mult coeff by input sample */
- if (t & (1<<(Nhxn-1))) /* Round, if needed */
- t += (1<<(Nhxn-1));
- t >>= Nhxn; /* Leave some guard bits, but come back some */
- v += t; /* The filter output */
- Ho += dhb; /* IR step */
- Xp += Inc; /* Input signal step. NO CHECK ON ARRAY BOUNDS */
- }
- return(v);
-}
-
--- a/src/sox.c
+++ b/src/sox.c
@@ -556,7 +556,7 @@
int flow_effect(e)
int e;
{
- LONG i, idone, odone, idonel, odonel, idoner, odoner;
+ LONG i, done, idone, odone, idonel, odonel, idoner, odoner;
LONG *ibuf, *obuf;
/* I have no input data ? */
@@ -575,6 +575,7 @@
efftab[e-1].odone += idone;
efftab[e].odone = 0;
efftab[e].olen = odone;
+ done = idone + odone;
} else {
/* Put stereo data in two seperate buffers and run effect
@@ -609,9 +610,10 @@
efftab[e-1].odone += idonel + idoner;
efftab[e].odone = 0;
efftab[e].olen = odonel + odoner;
+ done = idonel + idoner + odonel + odoner;
}
- if (idone == 0)
- fail("Effect took no samples!");
+ if (done == 0)
+ fail("Effect took & gave no samples!");
return 1;
}
--- a/src/stat.c
+++ b/src/stat.c
@@ -15,20 +15,24 @@
* No output.
*/
+#include <math.h>
#include "st.h"
+#define MAXLONG 0x7fffffffL
+
/* Private data for STAT effect */
typedef struct statstuff {
- LONG min, max, mean; /* amplitudes */
- LONG dmin, dmax, dmean; /* deltas */
- LONG last; /* previous sample */
+ double min, max, asum, sum1, sum2; /* amplitudes */
+ double dmin, dmax, dsum1, dsum2; /* deltas */
+ double scale; /* scale-factor */
+ double last; /* previous sample */
+ double read;
int first;
- int total;
int volume;
- ULONG bin[4];
+ int srms;
+ ULONG bin[4];
} *stat_t;
-#define abs(val) (((val) < 0) ? -(val) : (val))
/*
* Process options
@@ -40,15 +44,44 @@
{
stat_t stat = (stat_t) effp->priv;
+ stat->scale = MAXLONG;
stat->volume = 0;
- if (n)
+ stat->srms = 0;
+ while (n>0)
{
- if (!(strcmp(argv[0], "-v")))
+ if (!(strcmp(argv[0], "-v"))) {
stat->volume = 1;
- else if (!(strcmp(argv[0], "debug")))
+ goto did1;
+ }
+ if (!(strcmp(argv[0], "-s"))) {
+ double scale;
+
+ if (n <= 1)
+ fail("-s option: invalid argument");
+ if (!strcmp(argv[1],"rms")) {
+ stat->srms=1;
+ goto did2;
+ }
+ if (!sscanf(argv[1], "%lf", &scale))
+ fail("-s option: invalid argument");
+ stat->scale = scale;
+ goto did2;
+ }
+ if (!(strcmp(argv[0], "-rms"))) {
+ double scale;
+ if (n <= 1 || !sscanf(argv[1], "%lf", &scale))
+ fail("-s option expects float argument");
+ stat->srms = 1;
+ goto did2;
+ }
+ if (!(strcmp(argv[0], "debug"))) {
stat->volume = 2;
+ goto did1;
+ }
else
- fail("Summary effect only allows debug or -v as options.");
+ fail("Summary effect: unknown option");
+ did2: --n; ++argv;
+ did1: --n; ++argv;
}
}
@@ -59,12 +92,18 @@
eff_t effp;
{
stat_t stat = (stat_t) effp->priv;
- int i;
+ int i;
- stat->min = stat->dmin = 0x7fffffffL;
- stat->max = stat->dmax = 0x80000000L;
stat->first = 1;
+ stat->min = stat->max = 0;
+ stat->asum = 0;
+ stat->sum1 = stat->sum2 = 0;
+ stat->dmin = stat->dmax = 0;
+ stat->dsum1 = stat->dsum2 = 0;
+
+ stat->read = 0;
+
for (i = 0; i < 4; i++)
stat->bin[i] = 0;
@@ -82,7 +121,7 @@
{
stat_t stat = (stat_t) effp->priv;
int len, done;
- LONG samp, delta;
+ double samp, delta;
short count;
count = 0;
@@ -89,54 +128,46 @@
len = ((*isamp > *osamp) ? *osamp : *isamp);
for(done = 0; done < len; done++) {
/* work in absolute levels for both sample and delta */
- samp = *ibuf++;
- *obuf++ = samp;
+ samp = (*ibuf)/stat->scale;
+ stat->bin[RIGHT(*ibuf,30)+2]++;
+ *obuf++ = *ibuf++;
if (stat->volume == 2)
{
-#ifdef __alpha__
- fprintf(stderr,"%8x ",samp);
-#else
- fprintf(stderr,"%8lx ",samp);
-#endif
+ fprintf(stderr,"%f ",samp);
if (count++ == 5)
{
- fprintf(stderr,"\n");
- count = 0;
+ fprintf(stderr,"\n");
+ count = 0;
}
}
- stat->bin[RIGHT(samp,30)+2]++;
- samp = abs(samp);
- if (samp < stat->min)
- stat->min = samp;
- if (samp > stat->max)
- stat->max = samp;
if (stat->first) {
+ stat->min = stat->max = samp;
stat->first = 0;
- stat->mean = samp;
- stat->dmean = 0;
- } else {
- /* overflow avoidance */
- if ((stat->mean > 0x20000000L) || (samp > 0x20000000L))
- stat->mean = stat->mean/2 + samp/2;
- else
- stat->mean = (stat->mean + samp)/2;
-
- delta = abs(samp - stat->last);
- if (delta < stat->dmin)
- stat->dmin = delta;
- if (delta > stat->dmax)
- stat->dmax = delta;
- /* overflow avoidance */
- if ((delta > 0x20000000L) || (stat->dmean > 0x20000000L))
- stat->dmean = stat->dmean/2 + delta/2;
- else
- stat->dmean = (stat->dmean + delta)/2;
}
+ if (stat->min > samp)
+ stat->min = samp;
+ else if (stat->max < samp)
+ stat->max = samp;
+
+ stat->sum1 += samp;
+ stat->sum2 += samp*samp;
+ stat->asum += fabs(samp);
+
+ delta = fabs(samp - stat->last);
+ if (delta < stat->dmin)
+ stat->dmin = delta;
+ else if (delta > stat->dmax)
+ stat->dmax = delta;
+
+ stat->dsum1 += delta;
+ stat->dsum2 += delta*delta;
+
stat->last = samp;
}
+ stat->read += len;
/* Process all samples */
}
@@ -149,39 +180,61 @@
eff_t effp;
{
stat_t stat = (stat_t) effp->priv;
- double amp, range;
- float x;
+ double amp, scale, srms, freq;
+ double x, ct;
- stat->min = RIGHT(stat->min, 16);
- stat->max = RIGHT(stat->max, 16);
- stat->mean = RIGHT(stat->mean, 16);
- stat->dmin = RIGHT(stat->dmin, 16);
- stat->dmax = RIGHT(stat->dmax, 16);
- stat->dmean = RIGHT(stat->dmean, 16);
+ ct = stat->read;
- range = 32767.0;
+ if (stat->srms) {
+ double f;
+ srms = sqrt(stat->sum2/ct);
+ f = 1.0/srms;
+ stat->max *= f;
+ stat->min *= f;
+ stat->asum *= f;
+ stat->sum1 *= f;
+ stat->sum2 *= f*f;
+ stat->dmax *= f;
+ stat->dmin *= f;
+ stat->dsum1 *= f;
+ stat->dsum2 *= f*f;
+ stat->scale *= srms;
+ }
- amp = - stat->min;
+ scale = stat->scale;
+
+ amp = -stat->min;
if (amp < stat->max)
amp = stat->max;
+
/* Just print the volume adjustment */
- if (stat->volume == 1) {
- fprintf(stderr, "%.3f\n", 32767.0/amp);
+ if (stat->volume == 1 && amp > 0) {
+ fprintf(stderr, "%.3f\n", MAXLONG/(amp*scale));
return;
}
- else if (stat->volume == 2) {
+ if (stat->volume == 2) {
fprintf(stderr, "\n");
}
/* print them out */
- fprintf(stderr, "Maximum amplitude: %.3f\n", stat->max/range);
- fprintf(stderr, "Minimum amplitude: %.3f\n", stat->min/range);
- fprintf(stderr, "Mean amplitude: %.3f\n", stat->mean/range);
+ fprintf(stderr, "Samples read: %12lu\n", (unsigned long)ct);
+ if (stat->srms)
+ fprintf(stderr, "Scaled by rms: %12.6f\n", srms);
+ else
+ fprintf(stderr, "Scaled by: %12.1f\n", scale);
+ fprintf(stderr, "Maximum amplitude: %12.6f\n", stat->max);
+ fprintf(stderr, "Minimum amplitude: %12.6f\n", stat->min);
+ fprintf(stderr, "Mean norm: %12.6f\n", stat->asum/ct);
+ fprintf(stderr, "Mean amplitude: %12.6f\n", stat->sum1/ct);
+ fprintf(stderr, "RMS amplitude: %12.6f\n", sqrt(stat->sum2/ct));
- fprintf(stderr, "Maximum delta: %.3f\n", stat->dmax/range);
- fprintf(stderr, "Minimum delta: %.3f\n", stat->dmin/range);
- fprintf(stderr, "Mean delta: %.3f\n", stat->dmean/range);
+ fprintf(stderr, "Maximum delta: %12.6f\n", stat->dmax);
+ fprintf(stderr, "Minimum delta: %12.6f\n", stat->dmin);
+ fprintf(stderr, "Mean delta: %12.6f\n", stat->dsum1/ct);
+ fprintf(stderr, "RMS delta: %12.6f\n", sqrt(stat->dsum2/ct));
+ freq = sqrt(stat->dsum2/stat->sum2)*effp->ininfo.rate/(M_PI*2);
+ fprintf(stderr, "Rough frequency: %12d\n", (int)freq);
- fprintf(stderr, "Volume adjustment: %.3f\n", 32767.0/amp);
+ if (amp>0) fprintf(stderr, "Volume adjustment: %12.3f\n", MAXLONG/(amp*scale));
if (stat->bin[2] == 0 && stat->bin[3] == 0)
fprintf(stderr, "\nProbably text, not sound\n");
@@ -190,22 +243,36 @@
x = (float)(stat->bin[0] + stat->bin[3]) / (float)(stat->bin[1] + stat->bin[2]);
if (x >= 3.0) /* use opposite style */
+ {
if (effp->ininfo.style == UNSIGNED)
+ {
printf ("\nTry: -t raw -b -s \n");
+ }
else
+ {
printf ("\nTry: -t raw -b -u \n");
+ }
- else if (x <= 1.0/3.0); /* correctly decoded */
-
+ }
+ else if (x <= 1.0/3.0)
+ {
+ ;; /* correctly decoded */
+ }
else if (x >= 0.5 && x <= 2.0) /* use ULAW */
+ {
if (effp->ininfo.style == ULAW)
+ {
printf ("\nTry: -t raw -b -u \n");
+ }
else
+ {
printf ("\nTry: -t raw -b -U \n");
-
+ }
+ }
else
+ {
fprintf (stderr, "\nCan't guess the type\n");
+ }
}
}
-
--- a/tests.com
+++ /dev/null
@@ -1,41 +1,0 @@
-$ FVER = 'F$VERIFY(0)'
-$ !
-$ ! test files
-$ ! SOX Test script. This should run without access violating or printing
-$ ! any messages.
-$ !
-$ ! VMS translation of tests.shr
-$ !
-$ ! Modification History
-$ ! 14 Dec 1992, K. S. Kubo, Created
-$ !
-$ ! NOTES:
-$ ! Does not support the voc test w/o checksum and rate byte.
-$ !
-$ FILE = "monkey"
-$ PROC_PATH = F$Environment("PROCEDURE")
-$ SOX = "$ " + F$Parse(PROC_PATH,,,"DEVICE") + -
- F$Parse(PROC_PATH,,,"DIRECTORY") + "SOX"
-$ !
-$ ! verbose option -- uncomment the following line
-$ ! SOX = SOX + " ""-V"""
-$ !
-$ ON ERROR THEN GOTO COM_EXIT
-$ ON SEVERE THEN GOTO COM_EXIT
-$ ON WARNING THEN CONTINUE
-$ DELETE/NOLOG ub.raw;*, sb.raw;*, ub2.raw;*, ub2.voc;*, ub.au;*, ub2.sf;*
-$ SOX 'FILE'.voc ub.raw
-$ SOX -t raw -r 8196 -u -b -c 1 ub.raw -r 8196 -s -b sb.raw
-$ SOX -t raw -r 8196 -s -b -c 1 sb.raw -r 8196 -u -b ub2.raw
-$ SOX -r 8196 -u -b -c 1 ub2.raw -r 8196 ub2.voc
-$ DIFF/MODE=HEX ub.raw ub2.raw
-$ DELETE/NOLOG ub.raw;*, sb.raw;*, ub2.raw;*, ub2.voc;*
-$ SOX 'FILE'.au -u -r 8192 -u -b ub.raw
-$ SOX -r 8192 -u -b ub.raw -U -b ub.au
-$ SOX ub.au -u ub2.raw
-$ SOX ub.au -w ub2.sf
-$ DELETE/NOLOG ub.raw;*, ub.au;*, ub2.raw;*, ub2.sf;*
-$ !
-$ COM_EXIT:
-$ FVER = F$VERIFY('FVER')
-$ EXIT
--- a/vms.lis
+++ /dev/null
@@ -1,65 +1,0 @@
-VAX/VMS port of SOX, release 5, patchlevel 7
-
-As an important side note, the DECsound tool only recognizes DDIF and Sun .au
-format sounds (Sun .au sounds *must* be uLaw, 8000Hz sampling rate to be
-readable).
-
-The portmeister makes no representations about the suitability of this
-software for any purpose. This software is provided "as is" without
-warranties expressed or implied.
-
-New files:
-
- sox.opt - linker options file
- descrip.mms - MMS description file
- sound2au.com - VMS DCL command file to translate a sound to a Sun .au
- by way of sound2sun
- sound2sun.c - program to convert sampled audio files to uLAW format
- (by Rich Gopstein and Harris Corporation)
- sound2sun.opt - options file for sound2sun
- tests.com - VMS DCL command file equivalent of tests.sh
-
-Modified files:
-
- st.h -
- added VMS definitions for READBINARY and WRITEBINARY
- changed "#ifdef SYSV" to "#if defined(SYSV) || defined(VMS)"
- to pick up definitions of index, rindex, and bcopy
- added definitions of macros IMPORT and EXPORT (used on VMS
- for variable scope) -- collateral damage affects variables
- formats, informat, outformat, sizes, styles, effects
- wav.c -
- changed extern to IMPORT for volume, amplitude, summary, and
- verbose
- voc.c -
- changed extern to IMPORT for summary and verbose
- sox.c -
- replaced "extern errno" with "#include <errno.h>"
- replaced "extern sys_errlist[]| with "#include <perror.h>"
- added EXPORT to verbose, summary, volume, amplitdue,
- informat, outformat, and writing
- removed unneeded extern declaration of formats[] (already
- defined in st.h)
- sndrtool.c -
- replaced "extern errno" with "#include <errno.h>"
- replaced "extern sys_errlist[]| with "#include <perror.h>"
- skel.c -
- changed extern to IMPORT for volume, amplitude, summary, and
- verbose
- sf.c -
- changed extern to IMPORT for summary and verbose
- sbdsp.c -
- changed extern to IMPORT for volume, amplitude, summary, and
- verbose
- raw.c -
- changed extern to IMPORT for summary and verbose
- misc.c -
- moved "#include st.h" to top of file
- added EXPORT to sizes[] and styles[]
- handlers.c -
- added EXPORT to effects[] and formats[]
- echo.c -
- changed extern to IMPORT for writing
- 8svx.c -
- replaced "extern errno" with "#include <errno.h>"
- replaced "extern sys_errlist[]| with "#include <perror.h>"